Browse Source

Add a generic JS logger (see https://github.com/daneelsan/zig-wasm-logger/)

Daniel Sanchez 3 months ago
parent
commit
a977a4630b
5 changed files with 60 additions and 79 deletions
  1. 14 27
      script.js
  2. 2 1
      src/GameState.zig
  3. 34 37
      src/JS.zig
  4. 10 14
      src/projectile.zig
  5. BIN
      zig-out/bin/DodgeBallz.wasm

+ 14 - 27
script.js

@@ -1,4 +1,5 @@
-//document.addEventListener("DOMContentLoaded", main, false);
+const text_decoder = new TextDecoder();
+let console_log_buffer = "";
 
 const startGameButton = document.getElementById("start-game-button");
 const currentScoreElement = document.getElementById("current-score");
@@ -20,10 +21,6 @@ function colorToStyle(r, g, b, a) {
 
 /* WASM imported symbols */
 
-function jsRandom() {
-    return Math.random();
-}
-
 function jsClearRectangle(x, y, width, height) {
     // context.clearRect(x, y, width, height);
     context.fillStyle = "rgba(0, 0, 0, .1)";
@@ -49,23 +46,6 @@ function jsUpdateScore(score) {
     currentScoreElement.innerHTML = score;
 }
 
-// Lots of jsConsole<type> functions. Leaving it here until I find a better way to print to console from wasm.
-function jsConsoleLogu32(n) {
-    console.log("u32: " + n);
-}
-
-function jsConsoleLogf32(n) {
-    console.log("f32: " + n);
-}
-
-function jsConsoleLogbool(b) {
-    console.log("bool: " + b);
-}
-
-function jsConsoleLogVector2D(x, y) {
-    console.log("{x: " + x + ", y:" + y + "}");
-}
-
 // See build.zig for reasoning
 var memory = new WebAssembly.Memory({
     initial: 17 /* pages */,
@@ -75,16 +55,23 @@ var memory = new WebAssembly.Memory({
 const wasm = {
     imports: {
         env: {
-            jsRandom: jsRandom,
+            jsRandom: function () {
+                return Math.random();
+            },
             jsClearRectangle: jsClearRectangle,
             jsDrawCircle: jsDrawCircle,
             jsDrawRectangle: jsDrawRectangle,
             jsUpdateScore: jsUpdateScore,
 
-            jsConsoleLogu32: jsConsoleLogu32,
-            jsConsoleLogf32: jsConsoleLogf32,
-            jsConsoleLogbool: jsConsoleLogbool,
-            jsConsoleLogVector2D: jsConsoleLogVector2D,
+            jsConsoleLogWrite: function (ptr, len) {
+                const str = text_decoder.decode(new Uint8Array(memory.buffer, ptr, len));
+                console_log_buffer += str;
+            },
+            jsConsoleLogFlush: function () {
+                console.log(console_log_buffer);
+                console_log_buffer = "";
+            },
+
             memory: memory,
         },
     },

+ 2 - 1
src/GameState.zig

@@ -61,7 +61,7 @@ pub fn shootProjectile(self: *Self, client_pos: Vector2D) void {
 pub fn handleCollisions(self: *Self) void {
     const player = self.player;
 
-    for (self.enemies.array_list.items) |*enemy| {
+    for (self.enemies.array_list.items, 0..) |*enemy, e_i| {
         if (Ball2D.collision(player.ball, enemy.ball)) {
             // If some enemy touches the player, game over.
             self.game_over = true;
@@ -74,6 +74,7 @@ pub fn handleCollisions(self: *Self) void {
                 //    * Delete the projectile
                 //    * Generate impact particles
                 //    * reduce the radius of the enemy
+                JS.Console.log("Enemy {d} hit!\n", .{e_i});
                 self.projectiles.delete(p_i);
                 self.particles.generate(self, enemy, projectile);
                 enemy.ball.radius *= 0.8;

+ 34 - 37
src/JS.zig

@@ -1,62 +1,59 @@
+const std = @import("std");
 const utils = @import("utils.zig");
 
-const Ball2D = utils.Ball2D;
-const RGBColor = utils.RGBColor;
-const Vector2D = utils.Vector2D;
+const Imports = struct {
+    extern fn jsConsoleLogWrite(ptr: [*]const u8, len: usize) void;
+    extern fn jsConsoleLogFlush() void;
 
-extern fn jsRandom() f32;
-extern fn jsClearRectangle(x: f32, y: f32, width: f32, height: f32) void;
-extern fn jsDrawCircle(x: f32, y: f32, radius: f32, r: u8, g: u8, b: u8, a: f32) void;
-extern fn jsDrawRectangle(x: f32, y: f32, width: f32, height: f32, r: u8, g: u8, b: u8, a: f32) void;
+    extern fn jsRandom() f32;
 
-extern fn jsUpdateScore(score: u32) void;
+    extern fn jsClearRectangle(x: f32, y: f32, width: f32, height: f32) void;
+    extern fn jsDrawCircle(x: f32, y: f32, radius: f32, r: u8, g: u8, b: u8, a: f32) void;
+    extern fn jsDrawRectangle(x: f32, y: f32, width: f32, height: f32, r: u8, g: u8, b: u8, a: f32) void;
+    extern fn jsUpdateScore(score: u32) void;
+};
 
-// Lots of imported functions that log to console. See related comment in script.js.
-extern fn jsConsoleLogu32(n: u32) void;
-extern fn jsConsoleLogf32(n: f32) void;
-extern fn jsConsoleLogbool(b: bool) void;
-extern fn jsConsoleLogVector2D(x: f32, y: f32) void;
+const Ball2D = utils.Ball2D;
+const RGBColor = utils.RGBColor;
+const Vector2D = utils.Vector2D;
 
 pub inline fn random() f32 {
-    return jsRandom();
+    return Imports.jsRandom();
 }
 
 pub inline fn clearRectangle(pos: Vector2D, width: f32, height: f32) void {
-    jsClearRectangle(pos.x, pos.y, width, height);
+    Imports.jsClearRectangle(pos.x, pos.y, width, height);
 }
 
 pub inline fn drawBall2D(ball: Ball2D) void {
     const p = ball.pos;
     const r = ball.radius;
     const c = ball.color;
-    jsDrawCircle(p.x, p.y, r, c.r, c.g, c.b, c.a);
+    Imports.jsDrawCircle(p.x, p.y, r, c.r, c.g, c.b, c.a);
 }
 
 pub inline fn drawRectangle(pos: Vector2D, width: f32, height: f32, color: RGBColor) void {
-    jsDrawRectangle(pos.x, pos.y, width, height, color.r, color.g, color.b, color.a);
+    Imports.jsDrawRectangle(pos.x, pos.y, width, height, color.r, color.g, color.b, color.a);
 }
 
 pub inline fn updateScore(score: u32) void {
-    jsUpdateScore(score);
+    Imports.jsUpdateScore(score);
 }
 
-// TODO: Write a wasm Writer.
-pub fn consoleLog(comptime T: type, val: T) void {
-    switch (T) {
-        u32 => {
-            jsConsoleLogu32(val);
-        },
-        f32 => {
-            jsConsoleLogf32(val);
-        },
-        bool => {
-            jsConsoleLogbool(val);
-        },
-        Vector2D => {
-            jsConsoleLogVector2D(val.x, val.y);
-        },
-        else => {
-            @compileError("consoleLog does not support the given type");
-        },
+pub const Console = struct {
+    pub const Logger = struct {
+        pub const Error = error{};
+        pub const Writer = std.io.Writer(void, Error, write);
+
+        fn write(_: void, bytes: []const u8) Error!usize {
+            Imports.jsConsoleLogWrite(bytes.ptr, bytes.len);
+            return bytes.len;
+        }
+    };
+
+    const logger = Logger.Writer{ .context = {} };
+    pub fn log(comptime format: []const u8, args: anytype) void {
+        logger.print(format, args) catch return;
+        Imports.jsConsoleLogFlush();
     }
-}
+};

+ 10 - 14
src/projectile.zig

@@ -12,21 +12,19 @@ const Vector2D = utils.Vector2D;
 pub const Projectile = struct {
     ball: Ball2D,
 
-    const Self = @This();
-
-    pub fn init(pos: Vector2D, vel: Vector2D, radius: f32, color: RGBColor) Self {
+    pub fn init(pos: Vector2D, vel: Vector2D, radius: f32, color: RGBColor) Projectile {
         assert(0.0 <= radius);
         return .{
             .ball = Ball2D.init(pos, vel, radius, color),
         };
     }
 
-    pub fn update(self: *Self) void {
+    pub fn update(self: *Projectile) void {
         self.ball.pos.x += self.ball.vel.x;
         self.ball.pos.y += self.ball.vel.y;
     }
 
-    pub fn draw(self: Self) void {
+    pub fn draw(self: Projectile) void {
         JS.drawBall2D(self.ball);
     }
 };
@@ -37,31 +35,29 @@ pub const ProjectileArrayList = struct {
     const radius = 5.0;
     const color = RGBColor.init(255, 255, 255);
 
-    const Self = @This();
-
-    pub fn init() Self {
+    pub fn init() ProjectileArrayList {
         return .{
             .array_list = std.ArrayListUnmanaged(Projectile){},
         };
     }
 
-    pub fn reset(self: *Self, game_state: *GameState) void {
+    pub fn reset(self: *ProjectileArrayList, game_state: *GameState) void {
         self.array_list.clearAndFree(game_state.allocator);
     }
 
-    pub inline fn count(self: Self) usize {
+    pub inline fn count(self: ProjectileArrayList) usize {
         return self.array_list.items.len;
     }
 
-    pub inline fn delete(self: *Self, index: usize) void {
+    pub inline fn delete(self: *ProjectileArrayList, index: usize) void {
         _ = self.array_list.swapRemove(index);
     }
 
-    pub inline fn push(self: *Self, game_state: *GameState, projectile: Projectile) void {
+    pub inline fn push(self: *ProjectileArrayList, game_state: *GameState, projectile: Projectile) void {
         self.array_list.append(game_state.allocator, projectile) catch unreachable;
     }
 
-    pub fn emit(self: *Self, game_state: *GameState, client_pos: Vector2D) void {
+    pub fn emit(self: *ProjectileArrayList, game_state: *GameState, client_pos: Vector2D) void {
         const player_ball = game_state.player.ball;
 
         // The projectile's direction depends on event.clientX and event.clientY coming from JS.
@@ -77,7 +73,7 @@ pub const ProjectileArrayList = struct {
         self.push(game_state, projectile);
     }
 
-    pub fn step(self: *Self, game_state: *GameState) void {
+    pub fn step(self: *ProjectileArrayList, game_state: *GameState) void {
         const board = game_state.board;
         var items = self.array_list.items;
 

BIN
zig-out/bin/DodgeBallz.wasm