Skip to content

Instantly share code, notes, and snippets.

@avelican
Created May 31, 2024 19:07
Show Gist options
  • Save avelican/356e464e82da364b60b72cdd02000942 to your computer and use it in GitHub Desktop.
Save avelican/356e464e82da364b60b72cdd02000942 to your computer and use it in GitHub Desktop.
const w4 = @import("wasm4.zig");
// actual render resolution
const SCREEN_SIZE = w4.SCREEN_SIZE;
// game resolution (everything is rendered 2x)
// const SCREEN_WIDTH = 48*2;
const SCREEN_WIDTH = 96;
const SCREEN_HEIGHT = SCREEN_SIZE;
// const PADDING_X = (SCREEN_SIZE - SCREEN_WIDTH) / 2;
const PADDING_X = 32;
const SCREEN_START_X = 32;
// const SCREEN_END_X = SCREEN_SIZE - PADDING_X;
const SCREEN_END_X = 128;
////
// const RandomGenerator = struct {
// const Self = @This();
// a: u32,
// b: u32,
// c: u32,
// d: u32,
// pub fn next(self: *Self) u32 {
// self.a &= 0; self.b &= 0; self.c &= 0; self.d &= 0;
// var t: u32 = (self.a + self.b) + self.d;
// self.d += 1;
// self.a = self.b ^ (self.b >> 9);
// self.b = self.c + (self.c << 3);
// self.c = (self.c << 21) | (self.c >> 11);
// self.c += t;
// return t;
// }
// };
// pub fn make_rand(seed: u32) RandomGenerator {
// return RandomGenerator { .a = 0x9E3779B9, .b = 0x243F6A88, .c = 0xB7E15162, .d = seed };
// }
const SEED = 1337 ^ 0xDEADBEEF;
// var rng: RandomGenerator = make_rand(SEED);
fn abs(v: i32) i32 {
if (v < 0) return -v;
return v;
}
var sponge : u32 = SEED;
fn rand () u32 {
// sponge *= 7374837;
// sponge = @mulWithOverflow(sponge, 7374837);
// UGH ZIG
// @mulWithOverflow(u64, x, radix, &x); // OBSOLETE EXAMPLE CODE GREAT
var wtf = @mulWithOverflow(sponge, 7374837);
sponge = wtf[0];
return sponge;
}
fn rand_range(min: i32, max: i32) i32 {
var range = max-min+1;
// var ru : u32 = rng.next();
var ru: u32 = rand();
var ri : i32 = @bitCast(ru);
// return abs(ri) % range + min;
return @mod(abs(ri), range) + min;
}
fn rand_range2(min: i32, max: i32) i32 {
var r : i32 = rand_range(min, max);
return nokia_int(r);
}
fn is_even(n: i32) bool {
return @mod(n,2) == 0;
}
/////////////////////////
// fn rectRect(r1: Rect, r2: Rect) bool {
// return (r1.x + r1.w >= r2.x && // r1 right edge past r2 left
// r1.x <= r2.x + r2.w && // r1 left edge past r2 right
// r1.y + r1.h >= r2.y && // r1 top edge past r2 bottom
// r1.y <= r2.y + r2.h); // r1 bottom edge past r2 top
// }
fn rect_rect(x1: i32, y1: i32, w1: i32, h1: i32, x2: i32, y2: i32, w2: i32, h2: i32) bool {
return (x1 + w1 >= x2) and // r1 right edge past r2 left
(x1 <= x2 + w2) and // r1 left edge past r2 right
(y1 + h1 >= y2) and // r1 top edge past r2 bottom
(y1 <= y2 + h2); // r1 bottom edge past r2 top
}
fn rect_rect_fuzzy(_x1: i32, _y1: i32, _w1: i32, _h1: i32, _x2: i32, _y2: i32, _w2: i32, _h2: i32) bool {
// zig moment...
var x1 = _x1;
var y1 = _y1;
var w1 = _w1;
var h1 = _h1;
var x2 = _x2;
var y2 = _y2;
var w2 = _w2;
var h2 = _h2;
// // shrink boxes by half
// var cx1 = x1 + w1/2; // centerpoints
// var cx2 = x2 + w2/2;
// var cy1 = y1 + h1/2;
// var cy2 = y2 + h2/2;
// x1 = cx1 - w1/2;
// x2 = cx2 - w2/2;
// w1 = w1/2;
// w2 = w2/2;
// y1 = cy1 - h1/2;
// y2 = cy2 - h2/2;
// h1 = h1/2;
// h2 = h2/2;
// wtf is wrong with zig
var cx1 = x1 + @divFloor(w1, 2); // centerpoints
var cx2 = x2 + @divFloor(w2, 2);
var cy1 = y1 + @divFloor(h1, 2);
var cy2 = y2 + @divFloor(h2, 2);
x1 = cx1 - @divFloor(w1, 2);
x2 = cx2 - @divFloor(w2, 2);
w1 = @divFloor(w1, 2);
w2 = @divFloor(w2, 2);
y1 = cy1 - @divFloor(h1, 2);
y2 = cy2 - @divFloor(h2, 2);
h1 = @divFloor(h1, 2);
h2 = @divFloor(h2, 2);
return rect_rect(x1, y1, w1, h1, x2, y2, w2, h2);
}
////////////////////
// note: all sprites have been scaled 2x before import
// to comply with the Nokia jam resolution restrictions
const skifreeguy_width = 16;
const skifreeguy_height = 30;
// const skifreeguy_flags = 0; // BLIT_1BPP
const skifreeguy_flags = w4.BLIT_1BPP;
// const skifreeguy_sprite = [15]u8{ 0xe7,0xe7,0xff,0xc3,0xa5,0xa5,0xe7,0xe7,0x5a,0x5a,0xbd,0xbd,0xdb,0xdb,0xdb };
const skifreeguy_sprite = [60]u8{ 0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xff,0xff,0xff,0xff,0xf0,0x0f,0xf0,0x0f,0xcc,0x33,0xcc,0x33,0xcc,0x33,0xcc,0x33,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0x33,0xcc,0x33,0xcc,0x33,0xcc,0x33,0xcc,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf };
///
pub const tree_tall_width = 24;
pub const tree_tall_height = 38;
// pub const tree_tall_flags = 1; // BLIT_2BPP
pub const tree_tall_flags = w4.BLIT_2BPP;
// pub const tree_tall_sprite = [57]u8{ 0x55,0x45,0x55,0x55,0x45,0x55,0x55,0x11,0x55,0x55,0x11,0x55,0x55,0x11,0x55,0x54,0x54,0x55,0x54,0x54,0x55,0x54,0x54,0x55,0x51,0x55,0x15,0x51,0x55,0x15,0x51,0x55,0x15,0x51,0x55,0x15,0x45,0x55,0x45,0x45,0x55,0x45,0x45,0x55,0x45,0x50,0x00,0x15,0x55,0x11,0x55,0x55,0x11,0x55,0x55,0x01,0x5e };
pub const tree_tall_sprite = [228]u8{ 0x55,0x55,0x50,0x55,0x55,0x55,0x55,0x55,0x50,0x55,0x55,0x55,0x55,0x55,0x50,0x55,0x55,0x55,0x55,0x55,0x50,0x55,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x55,0x05,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x50,0x55,0x55,0x55,0x50,0x55,0x55,0x00,0x00,0x00,0x05,0x55,0x55,0x00,0x00,0x00,0x05,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x05,0x05,0x55,0x55,0x55,0x55,0x00,0x05,0x55,0xfa,0x55,0x55,0x00,0x05,0x55,0xfa };
var tree_tall_x : i32 = -100;
var tree_tall_y : f32 = -100;
//
// tree_smol2
pub const tree_smol_width = 16;
pub const tree_smol_height = 22;
// pub const tree_smol_flags = 0; // BLIT_1BPP
pub const tree_smol_flags = w4.BLIT_1BPP;
// pub const tree_smol = [11]u8{ 0xe7,0xdb,0xdb,0xbd,0xbd,0x7e,0x7e,0x7e,0x81,0xe7,0xe7 };
// 2x
pub const tree_smol_sprite = [44]u8{ 0xfc,0x3f,0xfc,0x3f,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0xc0,0x03,0xc0,0x03,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f };
var tree_smol_x : i32 = -100;
var tree_smol_y : f32 = -100;
fn spawn_tree_smol() void {
// tree_smol_x = rand_range2( SCREEN_START_X - tree_smol_width, SCREEN_END_X );
tree_smol_x = rand_range2(SCREEN_START_X,128);
var y = rand_range2(SCREEN_SIZE, SCREEN_SIZE + 32);
tree_smol_y = @floatFromInt(y);
}
fn spawn_tree_tall() void {
tree_tall_x = rand_range2( SCREEN_START_X - tree_tall_width, SCREEN_END_X );
var y = 64 + rand_range2(SCREEN_SIZE, SCREEN_SIZE + 32);
tree_tall_y = @floatFromInt(y);
}
// // //
export fn start() void {
w4.PALETTE.* = .{
0xc7f0d8,
0x43523d,
0xff00ff,
0x00ffff,
};
}
var player_x: i32 = SCREEN_SIZE / 2 - skifreeguy_width/2;
// var player_y: i32 = SCREEN_SIZE / 2 - skifreeguy_height/2;
var player_y: i32 = nokia_int(32 - skifreeguy_height/2);
var speed : f32 = 1.3;
// var speed : f32 = 20.3;
// var speedCounter : i32 = 0;
var game_over = false;
var whee = false;
export fn update() void {
if ( ! game_over ) upd();
draw();
}
fn upd() void {
speed += 0.0005;
// input
const gamepad = w4.GAMEPAD1.*;
if (gamepad & w4.BUTTON_LEFT != 0) {
player_x -= 2;
}
if (gamepad & w4.BUTTON_RIGHT != 0) {
player_x += 2;
}
if (gamepad & w4.BUTTON_DOWN != 0) {
speed += 0.01;
whee = true;
} else {
whee = false;
}
if (player_x <= ( SCREEN_START_X - skifreeguy_width/2) ) {
player_x = SCREEN_START_X - skifreeguy_width/2;
}
if (player_x <= SCREEN_START_X ) {
player_x = SCREEN_START_X;
}
// w4.tracef("%d", player_x);
if (player_x >= SCREEN_END_X - skifreeguy_width) {
player_x = (SCREEN_END_X - skifreeguy_width );
}
// if (gamepad & w4.BUTTON_UP != 0) {
// w4.trace("Up button is down!");
// }
// update
tree_smol_y -= speed;
tree_tall_y -= speed;
// collide
var coll_tree_smol = rect_rect_fuzzy(
player_x,
player_y,
skifreeguy_width,
skifreeguy_height,
tree_smol_x,
nokia_intFromFloat(tree_smol_y),
tree_smol_width,
tree_smol_height);
var coll_tree_tall = rect_rect_fuzzy(
player_x,
player_y,
skifreeguy_width,
skifreeguy_height,
tree_tall_x,
nokia_intFromFloat(tree_tall_y),
tree_tall_width,
tree_tall_height);
if (coll_tree_smol or coll_tree_tall) {
game_over = true;
whee = false; // :(
}
}
fn draw() void {
// left padding
w4.rect(0, 0, PADDING_X, SCREEN_SIZE);
// rightp adding
w4.rect(SCREEN_END_X, 0, PADDING_X, SCREEN_SIZE);
w4.DRAW_COLORS.* = 2; // TODO what is this
// if (tmp_y > SCREEN_SIZE) tmp_y = 0;
// const gamepad = w4.GAMEPAD1.*;
// if (gamepad & w4.BUTTON_1 != 0) {
// w4.DRAW_COLORS.* = 4;
// }
if (tree_smol_y <= (-tree_smol_height)) spawn_tree_smol();
if (tree_tall_y <= (-tree_tall_height)) spawn_tree_tall();
w4.blit(&tree_smol_sprite, tree_smol_x, nokia_intFromFloat(tree_smol_y), tree_smol_width, tree_smol_height, tree_smol_flags);
w4.blit(&tree_tall_sprite, tree_tall_x, nokia_intFromFloat(tree_tall_y), tree_tall_width, tree_tall_height, tree_tall_flags);
w4.blit(&skifreeguy_sprite, player_x, player_y, skifreeguy_width, skifreeguy_height, skifreeguy_flags);
if ( whee ) {
w4.text("wheee!", player_x - 15, player_y - 12);
// w4.tone (frequency, duration, volume, flags);
w4.tone (220, 2, 10, w4.TONE_MODE3);
}
w4.text("SCORE", SCREEN_SIZE/2 - 8 * 4, SCREEN_SIZE - 20 );
draw_number(@intFromFloat(speed * 1000), SCREEN_SIZE/2 - 8*4, SCREEN_SIZE-10);
if (game_over) {
w4.text("GAME OVER", SCREEN_SIZE/2-34, SCREEN_SIZE/2);
w4.text("PRESS R TO", SCREEN_SIZE/2-38, SCREEN_SIZE/2 + 16);
w4.text(" RESTART", SCREEN_SIZE/2-34, SCREEN_SIZE/2 + 24);
}
}
fn num_digits(_num: i32) i32 {
var num = _num;
var digits : i32 = 1;
while(true) {
if (num < 10) {
return digits;
}
digits += 1;
// num = num / 10;
num = @divFloor(num, 10);
}
}
fn draw_number(_num: i32, x_start: i32, y: i32) void {
var num = _num;
const CHAR_WIDTH = 8;
var x = x_start + num_digits(num) * CHAR_WIDTH;
while(true) {
var digit = @mod(num, 10);
draw_digit(digit, x, y);
x -= CHAR_WIDTH;
if (num < 10) { return; }
num = @divFloor(num, 10);
}
}
fn draw_digit(num: i32, x: i32, y: i32) void {
switch(num) {
0 => { w4.text("0", x, y); },
1 => { w4.text("1", x, y); },
2 => { w4.text("2", x, y); },
3 => { w4.text("3", x, y); },
4 => { w4.text("4", x, y); },
5 => { w4.text("5", x, y); },
6 => { w4.text("6", x, y); },
7 => { w4.text("7", x, y); },
8 => { w4.text("8", x, y); },
9 => { w4.text("9", x, y); },
else => { w4.text("",0,0); }
}
}
fn nokia_intFromFloat(f: f32) i32 {
var i : i32 = @intFromFloat(f);
return nokia_int(i);
}
fn nokia_int(i: i32) i32 {
if ( is_even(i) ) {
return i;
} else {
return i - 1;
}
}
// //////
// ///
// /// crap the font will get me disqualified
// /// pray to god this works
// const fontWidth = 208;
// const fontFlags = w4.BLIT_1BPP;
// const charWidth = 8;
// const charHeight = 8;
// const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// const font = [_]u8{
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3c, 0x18, 0x3e,
// 0x1c, 0x26, 0x10, 0x2c, 0x12, 0x08, 0x24, 0x26,
// 0x1c, 0x3c, 0x1c, 0x78, 0x1c, 0x3c, 0x62, 0x42,
// 0x82, 0xc4, 0x42, 0x66, 0x08, 0x32, 0x22, 0x52,
// 0x24, 0x51, 0x22, 0x25, 0x28, 0x14, 0x14, 0x08,
// 0x24, 0x26, 0x22, 0x52, 0x22, 0xa4, 0x22, 0x52,
// 0x22, 0xa5, 0x44, 0x2a, 0x24, 0x1c, 0x14, 0x52,
// 0x20, 0x12, 0x20, 0x10, 0x20, 0x26, 0x28, 0x04,
// 0x14, 0x08, 0x2c, 0x24, 0x22, 0x52, 0x22, 0xa4,
// 0x20, 0x10, 0x22, 0x24, 0x54, 0x10, 0x24, 0x04,
// 0x14, 0x5c, 0x40, 0x22, 0x38, 0x38, 0x4e, 0x7c,
// 0x28, 0x08, 0x28, 0x10, 0x54, 0x58, 0x42, 0x14,
// 0x44, 0x78, 0x18, 0x10, 0x24, 0x28, 0x54, 0x10,
// 0x14, 0x08, 0x24, 0xa4, 0x40, 0x62, 0x40, 0x20,
// 0x44, 0x48, 0x10, 0x08, 0x34, 0x30, 0x54, 0x48,
// 0x44, 0x20, 0x54, 0x48, 0x04, 0x20, 0x44, 0x28,
// 0x2c, 0x28, 0x08, 0x10, 0x3c, 0xa4, 0x42, 0xa4,
// 0x44, 0xa0, 0x44, 0xc9, 0x10, 0x48, 0x24, 0x52,
// 0x44, 0x4a, 0x44, 0xa0, 0x3a, 0x48, 0x44, 0xa0,
// 0x44, 0x10, 0x28, 0xa8, 0x48, 0x38, 0x42, 0x5b,
// 0x3c, 0x58, 0x38, 0x40, 0x38, 0x46, 0x68, 0x34,
// 0x42, 0x2c, 0x82, 0x84, 0x3a, 0x40, 0x08, 0x86,
// 0x38, 0x40, 0x3a, 0x10, 0x48, 0x46, 0x30, 0x66
// };
// fn drawSpace(x: i32, y: i32, column: i32, line: i32, colors: u16) void {
// // store<u16>(w4.DRAW_COLORS, w4.DRAW_COLORS & 0x0F);
// w4.DRAW_COLORS.* = w4.DRAW_COLORS.* & 0x0F;
// w4.rect(
// x + (column * charWidth),
// y + (line * charHeight),
// charWidth,
// charHeight
// );
// // store<u16>(w4.DRAW_COLORS, colors);
// w4.DRAW_COLORS.* = colors;
// }
// fn w4.text(str: []const u8, x: i32, y: i32) void {
// // write(str, x, y, 0x11);
// write(str, x, y, 0x10);
// w4.DRAW_COLORS.* = 2;
// }
// fn write(text: []const u8, x: i32, y: i32, colors: u16) void {
// // Set draw colors...
// // store<u16>(w4.DRAW_COLORS, colors);
// w4.DRAW_COLORS.* = colors;
// // Line and column counters.
// var line : i32 = 0;
// var column: i32 = 0;
// // Iterate through each character...
// // for(var i = 0; i < text.length; i += 1) {
// var i : usize = 0;
// while(true) { // zig's for loops are confusing
// w4.trace("AAAA");
// if (i >= text.len) break;
// w4.trace("BBBB");
// // const char: string = text.charAt(i);
// // const charCode: i32 = char.charCodeAt(0);
// const char = text[i];
// const charCode = text[i];
// // w4.tracef("%c", char);
// w4.trace("CCCC");
// // Break into next line when encounter a "\n" (newline)...
// if(charCode == 10) {
// line += 1;
// column = 0;
// i+=1;
// continue;
// }
// w4.trace("DDDD");
// // Character index on charset.
// // var charIndex: i32 = charset.indexOf(char);
// var charIndex = char-65;
// // Skip invalid characters, spaces, etc.
// if( (charIndex < 0) or (charIndex >= charset.len)) {
// w4.trace("EEEEE");
// drawSpace(x, y, column, line, colors);
// column += 1;
// i+=1;
// w4.trace("EEEEE");
// continue;
// }
// w4.trace("FFFF");
// // Draw character...
// w4.blitSub(
// &font,
// x + (column * charWidth),
// y + (line * charHeight),
// charWidth,
// charHeight,
// charIndex * charWidth,
// 0,
// fontWidth,
// fontFlags
// );
// // Advance to next column...
// column += 1;
// i += 1;
// }
// }
// // export function update (): void {
// // write("HELLO WORLD WITH\nOUR CUSTOM FONT", 4, 4, 0x30);
// // }
@Hexa3333
Copy link

Quite Incredible.
11/10

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