2 Commits

Author SHA1 Message Date
53ba21084d implement random walk for enemies 2023-04-10 14:05:06 +02:00
3424976d40 start implementing a pacman-like game in zig 2023-04-10 13:26:58 +02:00
7 changed files with 195 additions and 8 deletions

View File

@@ -1,2 +1,2 @@
/zig-cache/ zig-cache/
/zig-out/ zig-out/

View File

@@ -0,0 +1,31 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
const mode = std.builtin.Mode.ReleaseSmall;
const lib = b.addSharedLibrary("cart", "main.zig", .unversioned);
lib.setBuildMode(mode);
lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, .cpu_features_add = std.Target.wasm.featureSet(&.{.nontrapping_fptoint}) });
lib.import_memory = true;
lib.initial_memory = 262144;
lib.max_memory = 262144;
lib.global_base = 81920;
lib.stack_size = 8192;
lib.install();
if (lib.install_step) |install_step| {
const run_filter_exports = b.addSystemCommand(&[_][]const u8{ "uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm" });
run_filter_exports.step.dependOn(&install_step.step);
const run_wasm_opt = b.addSystemCommand(&[_][]const u8{ "wasm-opt", "--enable-nontrapping-float-to-int", "-Oz", "-o", "zig-out/cart.wasm", "zig-out/lib/cart-filtered.wasm" });
run_wasm_opt.step.dependOn(&run_filter_exports.step);
const run_uw8_pack = b.addSystemCommand(&[_][]const u8{ "uw8", "pack", "-l", "5", "zig-out/cart.wasm", "zig-out/cart.uw8" });
run_uw8_pack.step.dependOn(&run_wasm_opt.step);
const make_opt = b.step("make_opt", "make size optimized cart");
make_opt.dependOn(&run_uw8_pack.step);
b.default_step = make_opt;
}
}

142
examples/zig/game/main.zig Normal file
View File

@@ -0,0 +1,142 @@
const uw8 = @import("uw8.zig");
var redBallSprite: [16 * 16]u8 = undefined;
var greenBallSprite: [16 * 16]u8 = undefined;
var blueBallSprite: [16 * 16]u8 = undefined;
var wallSprite: [24 * 24]u8 = undefined;
const SphereConfigStep = struct { size: u8, color: u8 };
// zig fmt: off
const redSphereConfig: [4]SphereConfigStep = .{
.{ .size = 0, .color = 0x3d },
.{ .size = 2, .color = 0x48 },
.{ .size = 6, .color = 0x65 },
.{ .size = 9, .color = 0x55 }
};
const greenSphereConfig: [4]SphereConfigStep = .{
.{ .size = 0, .color = 0x7d },
.{ .size = 2, .color = 0x88 },
.{ .size = 6, .color = 0x96 },
.{ .size = 9, .color = 0xa3 }
};
const blueSphereConfig: [4]SphereConfigStep = .{
.{ .size = 0, .color = 0x2e },
.{ .size = 2, .color = 0x19 },
.{ .size = 6, .color = 0x17 },
.{ .size = 9, .color = 0x24 }
};
const levelData: [14] *const [19]u8 = .{
"xxxxxxxxxxxxxxxxxxx",
"x x x x",
"x x xx x xx x x",
"x x xxx x xxx x x",
"x xx x x xx x",
"x xx xxxxx xx x",
"x x x x",
"x xx xx xxx xx xx x",
"x x xx xx x x",
"xx x x x x xx",
"x xx xxx xxx xx x",
"x xx x x xx x",
"x x x x x",
"xxxxxxxxxxxxxxxxxxx",
};
// zig fmt: on
export fn start() void {
blitSphere(&redBallSprite, &redSphereConfig);
blitSphere(&greenBallSprite, &greenSphereConfig);
blitSphere(&blueBallSprite, &blueSphereConfig);
createWallSprite();
}
fn blitSphere(sprite: [*]u8, config: []const SphereConfigStep) void {
for (config) |circle| {
uw8.circle(8, 8, 8, circle.color);
uw8.circle(5, 6, @intToFloat(f32, circle.size), 0);
uw8.grabSprite(sprite, 16, 0, 0, 0x100);
}
}
fn createWallSprite() void {
uw8.cls(0xe4);
var i: i32 = 0;
while (i < 50) : (i += 1) {
const x = uw8.randomf() * 16;
const y = uw8.randomf() * 16;
const radius = uw8.randomf() * 2 + 1;
const c = @intCast(u8, (uw8.random() & 3)) + 0x95;
var j: i32 = 0;
while (j < 9) : (j += 1) {
uw8.circle(x + @intToFloat(f32, @rem(j, 3) * 16), y + @intToFloat(f32, @divFloor(j, 3) * 16), radius, c);
}
}
uw8.grabSprite(&wallSprite, 16, 16, 16, 0);
}
export fn upd() void {
uw8.cls(0);
var y: usize = 0;
while (y < levelData.len) : (y += 1) {
var x: usize = 0;
while (x < levelData[y].len) : (x += 1) {
if (levelData[y][x] == 'x') {
uw8.blitSprite(&wallSprite, 16, 8 + @intCast(i32, x) * 16, @intCast(i32, y) * 16, 0);
}
}
}
updateEnemy(&enemies[0], &redBallSprite);
updateEnemy(&enemies[1], &greenBallSprite);
updateEnemy(&enemies[2], &blueBallSprite);
}
const EntityState = struct { x: i32, y: i32, dir: u2 };
var enemies: [3]EntityState = .{
.{ .x = 16, .y = 16, .dir = 1 },
.{ .x = 16 * 18, .y = 16, .dir = 3 },
.{ .x = 16, .y = 16 * 12, .dir = 1 },
};
fn updateEnemy(enemy: *EntityState, sprite: [*]u8) void {
switch (enemy.dir) {
0 => enemy.y -= 1,
1 => enemy.x += 1,
2 => enemy.y += 1,
3 => enemy.x -= 1,
}
if (((enemy.x | enemy.y) & 15) == 0) {
const tx = @intCast(usize, enemy.x) / 16;
const ty = @intCast(usize, enemy.y) / 16;
var dir = enemy.dir;
var count: u32 = 0;
if (enemy.dir != 2 and levelData[ty - 1][tx] == ' ') {
dir = 0;
count += 1;
}
if (enemy.dir != 3 and levelData[ty][tx + 1] == ' ') {
count += 1;
if (uw8.random() % count == 0) {
dir = 1;
}
}
if (enemy.dir != 0 and levelData[ty + 1][tx] == ' ') {
count += 1;
if (uw8.random() % count == 0) {
dir = 2;
}
}
if (enemy.dir != 1 and levelData[ty][tx - 1] == ' ') {
count += 1;
if (uw8.random() % count == 0) {
dir = 3;
}
}
enemy.dir = dir;
}
uw8.blitSprite(sprite, 16, 8 + enemy.x, enemy.y, 0x100);
}

10
examples/zig/game/uw8.zig Normal file
View File

@@ -0,0 +1,10 @@
pub extern fn random() u32;
pub extern fn randomf() f32;
pub extern fn time() f32;
pub extern fn cls(color: u8) void;
pub extern fn circle(x: f32, y: f32, radiu: f32, color: u8) void;
pub extern fn blitSprite(spriteData: [*]u8, size: u32, x: i32, y: i32, ctrl: u32) void;
pub extern fn grabSprite(spriteData: [*]u8, size: u32, x: i32, y: i32, ctrl: u32) void;
pub extern fn printString(str: [*:0]u8) void;
pub extern fn printInt(value: i32) void;
pub extern fn printChar(char: u32) void;

View File

@@ -1,13 +1,17 @@
use std::path::Path;
use anyhow::Result; use anyhow::Result;
use std::path::Path;
pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> { pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> {
let mut module = walrus::Module::from_file(in_path)?; let mut module = walrus::Module::from_file(in_path)?;
let exports_to_delete: Vec<_> = module.exports.iter().filter_map(|export| match export.name.as_str() { let exports_to_delete: Vec<_> = module
"upd" => None, .exports
_ => Some(export.id()) .iter()
}).collect(); .filter_map(|export| match export.name.as_str() {
"upd" | "snd" | "start" => None,
_ => Some(export.id()),
})
.collect();
for id in exports_to_delete { for id in exports_to_delete {
module.exports.delete(id); module.exports.delete(id);
@@ -18,4 +22,4 @@ pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> {
module.emit_wasm_file(out_path)?; module.emit_wasm_file(out_path)?;
Ok(()) Ok(())
} }