Hello World
Let's take a look at an example of a basic program: Drawing a rectangle.
import * as w4 from "./wasm4";
export function update (): void { w4.rect(10, 10, 32, 32);}#include "wasm4.h"
void update () { rect(10, 10, 32, 32);}import w4;
fn void update() @wasm { w4::rect(10, 10, 32, 32);}import w4 = wasm4;
extern(C) void update() { w4.rect(10, 10, 32, 32);}package main
import "cart/w4"
//go:export updatefunc update () { w4.Rect(10, 10, 32, 32)}require "wasm4"
local function update () rect(10, 10, 32, 32)end
## setup_wasm4_callbacks(update)import cart/wasm4
proc update {.exportWasm.} = rect(10, 10, 32, 32)package main
import "w4"
@exportupdate :: proc "c" () { w4.rect(10, 10, 32, 32)}import "wasm4.pn";
pub extern fn update(){ rect(10, 10, 32, 32);}import proc rect int int int int in end
export main "start"proc main in end
export update "update"proc update in // Draw a rectangle at (10, 10) with size (32, 32). 32 32 10 10 rectendproc start() {}
proc update() { rect(10, 10, 32, 32);}mod wasm4;use wasm4::*;
#[no_mangle]fn update () { rect(10, 10, 32, 32);}(import "env" "rect" (func $rect (param i32 i32 i32 i32)))
(func (export "update") ;; Draw a rectangle at (10, 10) with size (32, 32). (call $rect (i32.const 10) (i32.const 10) (i32.const 32) (i32.const 32)))const w4 = @import("wasm4.zig");
export fn update() void { w4.rect(10, 10, 32, 32);}note
Sometimes we may need to initialize a few things before starting our game. On these occasions, a start() function can be used, which will be called only once, which is when the game is started.
The first line imports the WASM-4 API definitions. This is a stub source file included with all projects that describes which functions are available.
One of those functions is rect(), which we use to draw a 32x32 rectangle at position (10, 10).
We place this in a callback function called update() which is marked for export to WebAssembly
(exact syntax varies by language). The WASM-4 runtime calls the update() callback every frame, at
60 frames per second.
Accessing Memory#
Memory in WebAssembly is a contiguous, linear block that can be randomly accessed. WASM-4 reserves a region of that memory to map its state registers.
One of those registers is DRAW_COLORS at address $14. Its value affects the color of all drawing
functions. Let's draw a different color rectangle by setting DRAW_COLORS to 2 (the second color in
the palette).
store<u16>(w4.DRAW_COLORS, 2);
w4.rect(10, 10, 32, 32);*DRAW_COLORS = 2;
rect(10, 10, 32, 32);*w4::DRAW_COLORS = 2;
w4::rect(10, 10, 32, 32);*w4.drawColors = 2;
w4.rect(10, 10, 32, 32)*w4.DRAW_COLORS = 2
w4.Rect(10, 10, 32, 32)$DRAW_COLORS = 2
rect(10, 10, 32, 32)DRAW_COLORS[] = 2
rect(10, 10, 32, 32)w4.DRAW_COLORS^ = 2
w4.rect(10, 10, 32, 32)DRAW_COLORS = 2;
rect(10, 10, 32, 32);// Set DRAW_COLORS to 2.2 $DRAW_COLORS !16
// Draw a rectangle at (10, 10) with size (32, 32).32 32 10 10 rectDRAW_COLORS~ = 2;
rect(10, 10, 32, 32);unsafe { *DRAW_COLORS = 2 }
rect(10, 10, 32, 32);;; Set DRAW_COLORS to 2.(i32.store16 (global.get $DRAW_COLORS) (i32.const 2))
;; Draw a rectangle at (10, 10) with size (32, 32).(call $rect (i32.const 10) (i32.const 10) (i32.const 32) (i32.const 32))w4.DRAW_COLORS.* = 2;
w4.rect(10, 10, 32, 32);Debugging#
Use trace() to output a message to the console, which can be very useful for quick debugging.
w4.trace("Hello world!");trace("Hello world!");w4::trace("Hello world!");w4.trace("Hello world!");w4.Trace("Hello world!")trace("Hello World!")trace("Hello world!")w4.trace("Hello world!")trace("Hello world!");import proc trace ptr in end
"Hello world!"c tracetrace("Hello world!");trace("Hello world!");(import "env" "trace" (func $trace (param i32)))
;; Put the string at address 0x2000 in memory.(data (i32.const 0x2000) "Hello world!\00")
(call $trace (i32.const 0x2000))w4.trace("Hello world!");tip
Press F8 to toggle the WASM-4 developer tools, which displays system state, memory usage, and more.