Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active March 23, 2024 04:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterhellberg/deb4fd19edd6221c54a51e0470a0fe83 to your computer and use it in GitHub Desktop.
Save peterhellberg/deb4fd19edd6221c54a51e0470a0fe83 to your computer and use it in GitHub Desktop.
Example of using a current (as of 2023-12-01) version of Zig ⚡ to build a cart for the Gamercade fantasy console. https://gamercade.io
const std = @import("std");
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "cart",
.root_source_file = .{ .path = "src/main.zig" },
.target = .{ .cpu_arch = .wasm32, .os_tag = .wasi },
.optimize = .ReleaseSmall,
});
exe.export_symbol_names = &[_][]const u8{
"init",
"update",
"draw",
};
exe.entry = .disabled;
b.installArtifact(exe);
}
const raw = @import("raw.zig");
const std = @import("std");
test {
std.testing.refAllDecls(@This());
}
// Audio Api
pub fn playBgm(bgm_index: usize) void {
raw.play_bgm(@intCast(bgm_index));
}
pub fn playSfx(sfx_index: usize, channel: usize) void {
raw.play_sfx(@intCast(sfx_index), @intCast(channel));
}
pub fn stopBgm() void {
raw.stop_bgm();
}
pub fn stopChannel(channel: usize) void {
raw.stop_channel(@intCast(channel));
}
pub fn playNote(note_id: usize, instrument_index: usize, channel: usize) void {
raw.play_note(@intCast(note_id), @intCast(instrument_index), @intCast(channel));
}
pub fn playFrequency(frequency: f32, instrument_index: usize, channel: usize) void {
raw.play_frequency(frequency, @intCast(instrument_index), @intCast(channel));
}
// Data Api
pub fn height() usize {
return @intCast(raw.height());
}
pub fn width() usize {
return @intCast(raw.width());
}
pub fn fps() usize {
return @intCast(raw.fps());
}
pub fn frameTime() f32 {
return raw.frame_time();
}
pub fn spriteSheetCount() usize {
return @intCast(raw.sprite_sheet_count());
}
pub fn paletteCount() usize {
return @intCast(raw.palette_count());
}
pub fn spriteHeight(sprite_sheet: usize) ?usize {
return i32ToOptionUsize(raw.sprite_height(@intCast(sprite_sheet)));
}
pub fn spriteWidth(sprite_sheet: usize) ?usize {
return i32ToOptionUsize(raw.sprite_width(@intCast(sprite_sheet)));
}
pub fn spriteCount(sprite_sheet: usize) ?usize {
return i32ToOptionUsize(raw.sprite_count(@intCast(sprite_sheet)));
}
pub fn bgmLengthSecs(bgm_index: usize) ?f32 {
return f32ToOption(raw.bgm_length_secs(@intCast(bgm_index)));
}
pub fn bgmLengthFrames(bgm_index: usize) ?usize {
return i32ToOptionUsize(raw.bgm_length_frames(@intCast(bgm_index)));
}
pub fn sfxLengthSecs(sfx_index: usize) ?f32 {
return f32ToOption(raw.sfx_length_secs(@intCast(sfx_index)));
}
pub fn sfxLengthFrames(sfx_index: usize) ?usize {
return i32ToOptionUsize(raw.sfx_length_frames(@intCast(sfx_index)));
}
// Graphics Params Api
pub fn paletteIndex(palette_index: usize) i32 {
return raw.palette_index(@intCast(palette_index));
}
pub fn spriteSheetIndex(sprite_sheet_index: usize) i32 {
return raw.sprite_sheet_index(@intCast(sprite_sheet_index));
}
pub fn spriteIndex(sprite_index: usize) i32 {
return raw.sprite_index(@intCast(sprite_index));
}
pub fn colorIndex(color_index: usize) i32 {
return raw.color_index(@intCast(color_index));
}
pub fn flipX(flip_x: bool) i32 {
return raw.flip_x(@intFromBool(flip_x));
}
pub fn flipY(flip_y: bool) i32 {
return raw.flip_y(@intFromBool(flip_y));
}
pub fn graphicsParameters(
palette_index: usize,
sprite_sheet_index: usize,
sprite_index: usize,
color_index: usize,
flip_x: bool,
flip_y: bool,
) i32 {
return raw.graphics_parameters(@intCast(palette_index), @intCast(sprite_sheet_index), @intCast(sprite_index), @intCast(color_index), @intFromBool(flip_x), @intFromBool(flip_y));
}
// Draw Api
pub fn clearScreen(graphics_parameters: i32) void {
raw.clear_screen(graphics_parameters);
}
pub fn setPixel(graphics_parameters: i32, x: i32, y: i32) void {
raw.set_pixel(graphics_parameters, x, y);
}
pub fn circle(graphics_parameters: i32, x: i32, y: i32, radius: i32) void {
raw.circle(graphics_parameters, x, y, radius);
}
pub fn circleFilled(graphics_parameters: i32, x: i32, y: i32, radius: i32) void {
raw.circle_filled(graphics_parameters, x, y, radius);
}
pub fn rect(graphics_parameters: i32, x: i32, y: i32, rect_width: i32, rect_height: i32) void {
raw.rect(graphics_parameters, x, y, rect_width, rect_height);
}
pub fn rectFilled(graphics_parameters: i32, x: i32, y: i32, rect_width: i32, rect_height: i32) void {
raw.rect_filled(graphics_parameters, x, y, rect_width, rect_height);
}
pub fn line(graphics_parameters: i32, x0: i32, y0: i32, x1: i32, y1: i32) void {
raw.line(graphics_parameters, x0, y0, x1, y1);
}
pub fn sprite(graphics_parameters: i32, transparency_mask: i64, x: i32, y: i32) void {
raw.sprite(graphics_parameters, transparency_mask, x, y);
}
// Text Api
pub fn consoleLog(text: []const u8) void {
raw.console_log(text.ptr, text.len);
}
// Random Api
pub fn setSeed(seed: i32) void {
raw.set_seed(seed);
}
pub fn randomIntRange(min: i32, max: i32) i32 {
return raw.random_int_range(min, max);
}
pub fn randomFloat() f32 {
return raw.random_float();
}
pub fn randomFloatRange(min: f32, max: f32) f32 {
return raw.random_float_range(min, max);
}
// Input Api
pub fn buttonAPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_a_pressed(@intCast(player_id)));
}
pub fn buttonAReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_a_released(@intCast(player_id)));
}
pub fn buttonAHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_a_held(@intCast(player_id)));
}
pub fn buttonBPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_b_pressed(@intCast(player_id)));
}
pub fn buttonBReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_b_released(@intCast(player_id)));
}
pub fn buttonBHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_b_held(@intCast(player_id)));
}
pub fn buttonCPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_c_pressed(@intCast(player_id)));
}
pub fn buttonCReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_c_released(@intCast(player_id)));
}
pub fn buttonCHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_c_held(@intCast(player_id)));
}
pub fn buttonDPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_d_pressed(@intCast(player_id)));
}
pub fn buttonDReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_d_released(@intCast(player_id)));
}
pub fn buttonDHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_d_held(@intCast(player_id)));
}
pub fn buttonUpPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_up_pressed(@intCast(player_id)));
}
pub fn buttonUpReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_up_released(@intCast(player_id)));
}
pub fn buttonUpHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_up_held(@intCast(player_id)));
}
pub fn buttonDownPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_down_pressed(@intCast(player_id)));
}
pub fn buttonDownReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_down_released(@intCast(player_id)));
}
pub fn buttonDownHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_down_held(@intCast(player_id)));
}
pub fn buttonLeftPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_pressed(@intCast(player_id)));
}
pub fn buttonLeftReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_released(@intCast(player_id)));
}
pub fn buttonLeftHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_held(@intCast(player_id)));
}
pub fn buttonRightPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_pressed(@intCast(player_id)));
}
pub fn buttonRightReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_released(@intCast(player_id)));
}
pub fn buttonRightHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_held(@intCast(player_id)));
}
pub fn buttonStartPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_start_pressed(@intCast(player_id)));
}
pub fn buttonStartReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_start_released(@intCast(player_id)));
}
pub fn buttonStartHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_start_held(@intCast(player_id)));
}
pub fn buttonSelectPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_select_pressed(@intCast(player_id)));
}
pub fn buttonSelectReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_select_released(@intCast(player_id)));
}
pub fn buttonSelectHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_select_held(@intCast(player_id)));
}
pub fn buttonLeftShoulderPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_shoulder_pressed(@intCast(player_id)));
}
pub fn buttonLeftShoulderReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_shoulder_released(@intCast(player_id)));
}
pub fn buttonLeftShoulderHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_shoulder_held(@intCast(player_id)));
}
pub fn buttonRightShoulderPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_shoulder_pressed(@intCast(player_id)));
}
pub fn buttonRightShoulderReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_shoulder_released(@intCast(player_id)));
}
pub fn buttonRightShoulderHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_shoulder_held(@intCast(player_id)));
}
pub fn buttonLeftStickPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_stick_pressed(@intCast(player_id)));
}
pub fn buttonLeftStickReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_stick_released(@intCast(player_id)));
}
pub fn buttonLeftStickHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_stick_held(@intCast(player_id)));
}
pub fn buttonRightStickPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_stick_pressed(@intCast(player_id)));
}
pub fn buttonRightStickReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_stick_released(@intCast(player_id)));
}
pub fn buttonRightStickHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_stick_held(@intCast(player_id)));
}
pub fn buttonLeftTriggerPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_trigger_pressed(@intCast(player_id)));
}
pub fn buttonLeftTriggerReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_trigger_released(@intCast(player_id)));
}
pub fn buttonLeftTriggerHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_left_trigger_held(@intCast(player_id)));
}
pub fn buttonRightRriggerPressed(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_trigger_pressed(@intCast(player_id)));
}
pub fn buttonRightTriggerReleased(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_trigger_released(@intCast(player_id)));
}
pub fn buttonRightTriggerHeld(player_id: usize) ?bool {
return i32ToOptionBool(raw.button_right_trigger_held(@intCast(player_id)));
}
pub fn analogLeftX(player_id: usize) ?f32 {
return f32ToOption(raw.analog_left_x(@intCast(player_id)));
}
pub fn analogLeftY(player_id: usize) ?f32 {
return f32ToOption(raw.analog_left_y(@intCast(player_id)));
}
pub fn analogRightX(player_id: usize) ?f32 {
return f32ToOption(raw.analog_right_x(@intCast(player_id)));
}
pub fn analogRightY(player_id: usize) ?f32 {
return f32ToOption(raw.analog_right_y(@intCast(player_id)));
}
pub fn triggerLeft(player_id: usize) ?f32 {
return f32ToOption(raw.trigger_left(@intCast(player_id)));
}
pub fn triggerRight(player_id: usize) ?f32 {
return f32ToOption(raw.trigger_right(@intCast(player_id)));
}
pub fn rawInputState(player_id: usize) ?i64 {
var val = raw.raw_input_state(@intCast(player_id));
if (val < 0) {
return null;
} else {
return val;
}
}
// Multiplayer Api
pub fn numPlayers() usize {
return @intCast(raw.num_players());
}
pub fn isLocalPlayer(player_id: usize) ?bool {
return i32ToOptionBool(raw.is_local_player(@intCast(player_id)));
}
pub fn isRemotePlayer(player_id: usize) ?bool {
return i32ToOptionBool(raw.is_remote_player(@intCast(player_id)));
}
fn f32ToOption(val: f32) ?f32 {
if (std.math.isFinite(val)) {
return val;
} else {
return null;
}
}
fn i32ToOptionBool(val: i32) ?bool {
return switch (val) {
0 => false,
1 => true,
else => null,
};
}
fn i32ToOptionUsize(val: i32) ?usize {
if (val < 0) {
return null;
} else {
return @intCast(val);
}
}
const gc = @import("gc.zig");
var frameCounter: usize = 0;
var xPos: i32 = 0;
var yPos: i32 = 0;
// Called once, at the start of the game.
export fn init() void {
gc.consoleLog("Hello, from Zig!");
xPos = @intCast(gc.width() / 2);
yPos = @intCast(gc.height() / 2);
}
// Called once every frame, before draw.
export fn update() void {
// Print a message if the user presses the A button.
// This defaults to the U key on the keyboard.
if (gc.buttonAPressed(0)) |state| {
if (state) {
gc.consoleLog("Pressed A.");
}
}
// Let's move the pixel with the arrow keys
// Handle up/down motion
if (gc.buttonUpHeld(0)) |state| {
if (state) {
yPos -= 1;
}
}
if (gc.buttonDownHeld(0)) |state| {
if (state) {
yPos += 1;
}
}
// And repeat for left/right
if (gc.buttonLeftHeld(0)) |state| {
if (state) {
xPos -= 1;
}
}
if (gc.buttonRightHeld(0)) |state| {
if (state) {
xPos += 1;
}
}
// Update the frame counter to keep the animation looping
frameCounter += 1;
}
// Called once every frame, after update.
export fn draw() void {
// Clear screen function takes a GraphicsParameters as a parameter,
// so let's make one.
var clearColor = gc.colorIndex(0);
// Now, we can clear the screen.
gc.clearScreen(clearColor);
// Let's draw a pixel.
var pixelColor = gc.colorIndex(16);
gc.setPixel(pixelColor, xPos, yPos);
// Let's draw a spinning pixel.
var spinningPixelColor = gc.colorIndex(9);
// Make it spin around
var frame: f32 = @floatFromInt(frameCounter);
var x = @sin(frame * 0.1) * 25.0;
var y = @cos(frame * 0.1) * 25.0;
x += @floatFromInt(xPos);
y += @floatFromInt(yPos);
// Draw the spinning pixel
gc.setPixel(spinningPixelColor, @intFromFloat(x), @intFromFloat(y));
}
// Raw bindings directly from WASM.
// Audio
pub extern fn play_bgm(bgm_index: i32) void;
pub extern fn play_sfx(sfx_index: i32, channel: i32) void;
pub extern fn stop_bgm() void;
pub extern fn stop_channel(channel: i32) void;
pub extern fn play_note(note_id: i32, instrument_index: i32, channel: i32) void;
pub extern fn play_frequency(frequency: f32, instrument_index: i32, channel: i32) void;
// Data
pub extern fn height() i32;
pub extern fn width() i32;
pub extern fn fps() i32;
pub extern fn frame_time() f32;
pub extern fn sprite_sheet_count() i32;
pub extern fn palette_count() i32;
pub extern fn sprite_height(sprite_sheet: i32) i32;
pub extern fn sprite_width(sprite_sheet: i32) i32;
pub extern fn sprite_count(sprite_sheet: i32) i32;
pub extern fn bgm_length_secs(bgm_index: i32) f32;
pub extern fn bgm_length_frames(bgm_index: i32) i32;
pub extern fn sfx_length_secs(sfx_index: i32) f32;
pub extern fn sfx_length_frames(sfx_index: i32) i32;
// Graphics Params
pub extern fn palette_index(palette_index: i32) i32;
pub extern fn sprite_sheet_index(sprite_sheet_index: i32) i32;
pub extern fn sprite_index(sprite_index: i32) i32;
pub extern fn color_index(color_index: i32) i32;
pub extern fn flip_x(flip_x: i32) i32;
pub extern fn flip_y(flip_y: i32) i32;
pub extern fn graphics_parameters(
palette_index: i32,
sprite_sheet_index: i32,
sprite_index: i32,
color_index: i32,
flip_x: i32,
flip_y: i32,
) i32;
// Draw
pub extern fn clear_screen(graphics_parameters: i32) void;
pub extern fn set_pixel(graphics_parameters: i32, x: i32, y: i32) void;
pub extern fn circle(graphics_parameters: i32, x: i32, y: i32, radius: i32) void;
pub extern fn circle_filled(graphics_parameters: i32, x: i32, y: i32, radius: i32) void;
pub extern fn rect(graphics_parameters: i32, x: i32, y: i32, width: i32, height: i32) void;
pub extern fn rect_filled(graphics_parameters: i32, x: i32, y: i32, width: i32, height: i32) void;
pub extern fn line(graphics_parameters: i32, x0: i32, y0: i32, x1: i32, y1: i32) void;
pub extern fn sprite(graphics_parameters: i32, transparency_mask: i64, x: i32, y: i32) void;
//Text
pub extern fn console_log(text_ptr: [*]const u8, len: usize) void;
// Random
pub extern fn set_seed(seed: i32) void;
pub extern fn random_int_range(min: i32, max: i32) i32;
pub extern fn random_float() f32;
pub extern fn random_float_range(min: f32, max: f32) f32;
// Input
pub extern fn button_a_pressed(player_id: i32) i32;
pub extern fn button_a_released(player_id: i32) i32;
pub extern fn button_a_held(player_id: i32) i32;
pub extern fn button_b_pressed(player_id: i32) i32;
pub extern fn button_b_released(player_id: i32) i32;
pub extern fn button_b_held(player_id: i32) i32;
pub extern fn button_c_pressed(player_id: i32) i32;
pub extern fn button_c_released(player_id: i32) i32;
pub extern fn button_c_held(player_id: i32) i32;
pub extern fn button_d_pressed(player_id: i32) i32;
pub extern fn button_d_released(player_id: i32) i32;
pub extern fn button_d_held(player_id: i32) i32;
pub extern fn button_up_pressed(player_id: i32) i32;
pub extern fn button_up_released(player_id: i32) i32;
pub extern fn button_up_held(player_id: i32) i32;
pub extern fn button_down_pressed(player_id: i32) i32;
pub extern fn button_down_released(player_id: i32) i32;
pub extern fn button_down_held(player_id: i32) i32;
pub extern fn button_left_pressed(player_id: i32) i32;
pub extern fn button_left_released(player_id: i32) i32;
pub extern fn button_left_held(player_id: i32) i32;
pub extern fn button_right_pressed(player_id: i32) i32;
pub extern fn button_right_released(player_id: i32) i32;
pub extern fn button_right_held(player_id: i32) i32;
pub extern fn button_start_pressed(player_id: i32) i32;
pub extern fn button_start_released(player_id: i32) i32;
pub extern fn button_start_held(player_id: i32) i32;
pub extern fn button_select_pressed(player_id: i32) i32;
pub extern fn button_select_released(player_id: i32) i32;
pub extern fn button_select_held(player_id: i32) i32;
pub extern fn button_left_shoulder_pressed(player_id: i32) i32;
pub extern fn button_left_shoulder_released(player_id: i32) i32;
pub extern fn button_left_shoulder_held(player_id: i32) i32;
pub extern fn button_right_shoulder_pressed(player_id: i32) i32;
pub extern fn button_right_shoulder_released(player_id: i32) i32;
pub extern fn button_right_shoulder_held(player_id: i32) i32;
pub extern fn button_left_stick_pressed(player_id: i32) i32;
pub extern fn button_left_stick_released(player_id: i32) i32;
pub extern fn button_left_stick_held(player_id: i32) i32;
pub extern fn button_right_stick_pressed(player_id: i32) i32;
pub extern fn button_right_stick_released(player_id: i32) i32;
pub extern fn button_right_stick_held(player_id: i32) i32;
pub extern fn button_left_trigger_pressed(player_id: i32) i32;
pub extern fn button_left_trigger_released(player_id: i32) i32;
pub extern fn button_left_trigger_held(player_id: i32) i32;
pub extern fn button_right_trigger_pressed(player_id: i32) i32;
pub extern fn button_right_trigger_released(player_id: i32) i32;
pub extern fn button_right_trigger_held(player_id: i32) i32;
pub extern fn analog_left_x(player_id: i32) f32;
pub extern fn analog_left_y(player_id: i32) f32;
pub extern fn analog_right_x(player_id: i32) f32;
pub extern fn analog_right_y(player_id: i32) f32;
pub extern fn trigger_left(player_id: i32) f32;
pub extern fn trigger_right(player_id: i32) f32;
pub extern fn raw_input_state(played_id: i32) i64;
// Multiplayer
pub extern fn num_players() i32;
pub extern fn is_local_player(player_id: i32) i32;
pub extern fn is_remote_player(player_id: i32) i32;
@peterhellberg
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment