Build, play and errors

From file to game

  1. You write Go files in the map's scripts/ folder.
  2. Build in the Triggers module (Ctrl 3) turns them into scripts/map.wasm.
  3. Play builds what changed, then starts the engine. The engine loads map.wasm, runs main, and the game begins.

The state under the file list says not built, changed since the build or up to date. When you press Play on a script that does not compile, the game does not start.

An exported .a4m carries the built script. A player needs no Go.

Building yourself

The editor's Build runs this in scripts/:

GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o map.wasm .

Run it in a terminal if you like. The editor notices the new file. It needs a recent Go (the SDK uses go:wasmexport, which came with Go 1.24).

Your code editor

Open in editor opens the scripts/ folder as the project, with the file. The folder holds go.mod and a go.work that points at the W4 API on your computer, so gopls finds w4/game right away and completes it as you type. The go.work file is rewritten before every build and open, and a .gitignore keeps it out of git, since the path is only true on your machine. Details are on Where the API lives.

If completion does nothing, look at the Script compiler card in the Triggers module. Under the tiles, Code hints in your editor says whether gopls is on; Turn on installs it.

Where mistakes show up

Mistake Where you see it
A typo or a wrong type In your code editor, as you type (gopls). If you miss it, Build fails
The script does not compile A toast in the editor and an entry in the Activity panel, with file and line. Play refuses to start
An event function of the wrong shape in event.Register The game log: event.Register: a ... does not fit event ...
A misspelled definition name in SpawnUnit The game log: SpawnUnit: there is no definition named "...". The unit is not alive and orders to it do nothing
A handler that runs too long The game log: script stopped in .... The script is off for the rest of the game

The game log is the message stream: click the chat lines for the full panel, or press F12 for its Debug view. It collects game.Print, game.Printf, everything the script writes to standard output, and these messages from the game itself. game.Warning and game.Error write a line with a (WARNING) (amber) or an (ERROR) (red) tag. game.Debug never writes to the chat: the note goes to the F12 log (Debug filter) and, when the setting "Debug readout in the corner" or AQUA4_DEV=1 is on, to a small dim readout at the top right (last three notes, four seconds each); in their text [#RRGGBB] switches colour for the rest of the line and [/] switches back. Text that imitates a chat tag such as [Team] is shown with < and > so a script cannot pass as a player.

Printing to find a bug

game.Printf takes the same format as fmt.Printf, and fmt.Println ends up in the same place. Print the numbers you doubt, play, and read the window. A %v of a game.Unit prints unit 7.

game.Printf("wave %d, %d units alive", wave, countAlive(1))

Remember that a handler sees the state from the start of the call. A unit you just spawned is not there yet. See Units.

Tests

Pure logic, like a function that computes how many grunts a wave has, is plain Go. Put it in its own package inside the scripts folder, one that does not import the W4 packages, and test it with go test as usual. The W4 packages themselves only make sense inside the game.

Reloading

There is no hot reload into a running game yet. Stop the game, build, play again.