W4

roc-wasm4

Build wasm4 games using Roc

Palette : [ None, Color1, Color2, Color3, Color4 ]

The Palette consists of four colors. There is also None which is used to represent a transparent or no change color. Each pixel on the screen will be drawn using one of these colors.

You may find it helpful to create an alias for your game.

red = Color2
green = Color3

W4.setTextColors { fg: red, bg: green }

Gamepad

Represents the current state of a Player gamepad.

Gamepad : {
    button1 : Bool,
    button2 : Bool,
    left : Bool,
    right : Bool,
    up : Bool,
    down : Bool,
}

Mouse

Represents the current state of the mouse.

Mouse : {
    x : I16,
    y : I16,
    left : Bool,
    right : Bool,
    middle : Bool,
}

Netplay

Represents the current state of Netplay.

Netplay connects gamepad inputs over the Internet using WebRTC.

Netplay : [
    Enabled Player,
    Disabled,
]

Player : [ Player1, Player2, Player3, Player4 ]

Represents Player.

WASM-4 supports realtime multiplayer of up to 4 players, either locally or online.

Shader

Represents fragment shader for raw operations with the framebuffer.

Shader : U8, U8, Palette -> Palette

screenWidth

screenHeight

setPalette : { color1 : U32, color2 : U32, color3 : U32, color4 : U32 } -> Task {} *

Set the color Palette for your game.

W4.setPalette {
    color1: 0xffffff,
    color2: 0xff0000,
    color3: 0x000ff00,
    color4: 0x0000ff,
}

Warning: this will overwrite the existing Palette, changing all colors on the screen.

getPalette : Task { color1 : U32, color2 : U32, color3 : U32, color4 : U32 } *

Get the color Palette for your game.

{color1, color2, color3, color4} <- W4.getPalette |> Task.await

setDrawColors : DrawColors -> Task {} *

Set the draw colors for the next draw command.

blue = Color1
white = Color4
W4.setDrawColors {
    primary : blue,
    secondary : white,
    tertiary : None,
    quaternary : None,
}

Warning: this will overwrite any existing draw colors that are set.

getDrawColors : Task DrawColors *

Get the currently set draw colors.

{primary, secondary} <- W4.getDrawColors |> Task.await

setPrimaryColor : W4.Palette -> Task {} *

Helper for primary drawing color.

blue = Color1
W4.setPrimaryColor blue

Warning: this will overwrite any existing draw colors, and sets the secondary, tertiary and quaternary values to None.

setTextColors : { fg : Palette, bg : Palette } -> Task {} *

Helper for setting the draw colors for text.

blue = Color1
white = Color4
W4.setTextColors { fg : blue, bg : white }

Warning: this will overwrite any existing draw colors, and sets the tertiary and quaternary values to None.

setShapeColors : { border : W4.Palette, fill : W4.Palette } -> Task {} *

Helper for colors when drawing a shape.

blue = Color1
white = Color4
W4.setShapeColors { border : blue, fill : white }

Warning: this will overwrite any existing draw colors, and sets the tertiary and quaternary values to None.

text : Str, { x : I32, y : I32 } -> Task {} *

Draw text to the screen.

W4.text "Hello, World" {x: 0, y: 0}

Text color is the Primary draw color.

Background color is the Secondary draw color.

Refer w4 docs for more information

rect : { x : I32, y : I32, width : U32, height : U32 } -> Task {} *

Draw a rectangle to the screen.

W4.rect {x: 0, y: 10, width: 40, height: 60}

Fill color is the Primary draw color.

Border color is the Secondary draw color.

Refer w4 docs for more information

oval : { x : I32, y : I32, width : U32, height : U32 } -> Task {} *

Draw an oval to the screen.

W4.oval {x, y, width: 20, height: 30}

Fill color is the Primary draw color.

Border color is the Secondary draw color.

Refer w4 docs for more information

line : { x : I32, y : I32 }, { x : I32, y : I32 } -> Task {} *

Draw a line between two points to the screen.

W4.line {x: 0, y: 0}, {x: 10, y: 10}

Line color is the Primary draw color.

Refer w4 docs for more information

hline : { x : I32, y : I32, len : U32 } -> Task {} *

Draw a horizontal line starting at (x, y) with len to the screen.

W4.hline {x: 10, y: 20, len: 30}

Line color is the Primary draw color.

Refer w4 docs for more information

vline : { x : I32, y : I32, len : U32 } -> Task {} *

Draw a vertical line starting at (x, y) with len to the screen.

W4.vline {x: 10, y: 20, len: 30}

Line color is the Primary draw color.

Refer w4 docs for more information

getGamepad : Player -> Task Gamepad *

Get the controls for a Gamepad.

{button1,button2,left,right,up,down} <- W4.getGamepad Player1 |> Task.await

getMouse : Task Mouse *

Get the current Mouse position.

{x,y,left,right,middle} <- W4.getMouse |> Task.await

getNetplay : Task Netplay *

Get the Netplay status.

netplay <- W4.getNetplay |> Task.await
when netplay is
    Enabled Player1 -> # ..
    Enabled Player2 -> # ..
    Enabled Player3 -> # ..
    Enabled Player4 -> # ..
    Disabled -> # ..

Note: All WASM-4 games that support local multiplayer automatically support netplay. There are no additional steps developers need to take to make their games netplay-ready. Netplay can be used to implement advanced features such as non-shared screen multiplayer

Refer w4 docs for more information

seedRand : U64 -> Task {} *

Seeds the global pseudo-random number generator.

{} <- W4.seedRand framesSinceStart |> Task.await

Wasm4 exposes no way to seed a random number generator. As such, anything random will be exactly the same on every run by default. To work around this, it is suggested to count the number of frames the user is on the title screen before starting the game and use that to seed the prng.

rand : Task I32 *

Generate a pseudo-random number.

# pseudo-random number between Num.minI32 and Num.maxI32 (inclusive of both)
i <- W4.rand |> Task.await

Warning: Wasm4 exposes no way to seed a random number generator. As such, anything random will be exactly the same on every run by default. To work around this, it is suggested to count the number of frames the user is on the title screen before starting the game and use that to seed the prng.

randBetween : { start : I32, before : I32 } -> Task I32 *

Generate a pseudo-random number in the range.

The range has an inclusive start and exclusive end.

# random number in the range 0-99
i <- W4.randBetween {start: 0, before: 100} |> Task.await

Warning: Wasm4 exposes no way to seed a random number generator. As such, anything random will be exactly the same on every run by default. To work around this, it is suggested to count the number of frames the user is on the title screen before starting the game and use that to seed the prng.

trace : Str -> Task {} *

Prints a message to the debug console.

W4.trace "Hello, World"

Refer w4 docs for more information

debug : Str, val -> Task {} * where val implements Inspect.Inspect

Prints a message with a debug formatting of the value to the console.

W4.debug "my int" 7

saveToDisk : List U8 -> Task {} [SaveFailed]

Saves data to persistent storage. Any previously saved data on the disk is replaced.

Returns Err SaveFailed on failure.

result <- W4.saveToDisk [0x10] |> Task.attempt
when result is
   Ok {} -> # success
   Err SaveFailed -> # handle failure

Games can persist up to 1024 bytes of data.

Refer w4 docs for more information

loadFromDisk : Task (List U8) *

Gets all saved data from persistent storage.

data <- W4.loadFromDisk |> Task.await

Games can persist up to 1024 bytes of data.

Refer w4 docs for more information

preserveFrameBuffer : Task {} *

Set a flag to keep the framebuffer between frames.

This can be helpful if you only want to update part of the screen.

clearFrameBufferEachUpdate : Task {} *

Set a flag to clear the framebuffer between frames.

hideGamepadOverlay : Task {} *

Set a flag to hide the game overlay.

showGamepadOverlay : Task {} *

Set a flag to show the game overlay.

getPixel : { x : U8, y : U8 } -> Task Palette *

Get the color for an individual pixel in the framebuffer.

setPixel : { x : U8, y : U8 }, Palette -> Task {} *

Set the color for an individual pixel in the framebuffer.

runShader : Shader -> Task {} *

tone : { startFreq ? U16, endFreq ? U16, channel ? [ Pulse1 [ Eighth, Quarter, Half, ThreeQuarters ], Pulse2 [ Eighth, Quarter, Half, ThreeQuarters ], Triangle, Noise ], pan ? [ Center, Left, Right ], sustainTime ? U8, releaseTime ? U8, decayTime ? U8, attackTime ? U8, volume ? U8, peakVolume ? U8 } -> Task {} *

Plays a tone sound.

Please refer to the wasm4 audio docs.

The sound.roc example app along with the wasm4 sound tools can be quite helpful to play with.