diff --git a/src/input.zig b/src/input.zig new file mode 100644 index 0000000..bfee326 --- /dev/null +++ b/src/input.zig @@ -0,0 +1,66 @@ +const w4 = @import("wasm4.zig"); + +const clearMouse = w4.Mouse{ .x = 0, .y = 0, .buttons = .{ .left = false, .right = false, .middle = false } }; +const clear: u8 = 0x00; +pub var mouseLast: w4.Mouse = clearMouse; +pub var gamepad1Last: w4.Gamepad = @bitCast(w4.Gamepad, clear); +pub var gamepad2Last: w4.Gamepad = @bitCast(w4.Gamepad, clear); +pub var gamepad3Last: w4.Gamepad = @bitCast(w4.Gamepad, clear); +pub var gamepad4Last: w4.Gamepad = @bitCast(w4.Gamepad, clear); + +pub var mouseJustPressed: w4.Mouse = clearMouse; +pub var gamepad1JustPressed: w4.Gamepad = @bitCast(w4.Gamepad, clear); +pub var gamepad2JustPressed: w4.Gamepad = @bitCast(w4.Gamepad, clear); +pub var gamepad3JustPressed: w4.Gamepad = @bitCast(w4.Gamepad, clear); +pub var gamepad4JustPressed: w4.Gamepad = @bitCast(w4.Gamepad, clear); + +pub const Gamepad = enum { one, two, three, four }; +pub const Button = enum { up, down, left, right, one, two }; + +pub fn btn(gamepad: Gamepad, button: Button) bool { + const g = switch (gamepad) { + .one => w4.GAMEPAD1.*, + .two => w4.GAMEPAD2.*, + .three => w4.GAMEPAD3.*, + .four => w4.GAMEPAD4.*, + }; + return switch (button) { + .up => g.button_up, + .down => g.button_down, + .left => g.button_left, + .right => g.button_right, + .one => g.button_1, + .two => g.button_2, + }; +} + +pub fn btnp(gamepad: Gamepad, button: Button) bool { + const g = switch (gamepad) { + .one => gamepad1JustPressed, + .two => gamepad2JustPressed, + .three => gamepad3JustPressed, + .four => gamepad4JustPressed, + }; + return switch (button) { + .up => g.button_up, + .down => g.button_down, + .left => g.button_left, + .right => g.button_right, + .one => g.button_1, + .two => g.button_2, + }; +} + +pub fn update() void { + mouseJustPressed.buttons = w4.MOUSE.*.buttons.justPressed(mouseLast.buttons); + gamepad1JustPressed = w4.GAMEPAD1.*.justPressed(gamepad1Last); + gamepad2JustPressed = w4.GAMEPAD2.*.justPressed(gamepad2Last); + gamepad3JustPressed = w4.GAMEPAD3.*.justPressed(gamepad3Last); + gamepad4JustPressed = w4.GAMEPAD4.*.justPressed(gamepad4Last); + + mouseLast = w4.MOUSE.*; + gamepad1Last = w4.GAMEPAD1.*; + gamepad2Last = w4.GAMEPAD2.*; + gamepad3Last = w4.GAMEPAD3.*; + gamepad4Last = w4.GAMEPAD4.*; +} diff --git a/src/main.zig b/src/main.zig index 4f8c6be..88ad52f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,6 +2,7 @@ const std = @import("std"); const w4 = @import("wasm4.zig"); const ecs = @import("ecs.zig"); const assets = @import("assets"); +const input = @import("input.zig"); const Vec2 = std.meta.Vector(2, i32); const Vec2f = std.meta.Vector(2, f32); @@ -67,7 +68,7 @@ const Control = struct { const Sprite = struct { offset: Vec2f = Vec2f{ 0, 0 }, size: w4.Vec2, index: usize, flags: w4.BlitFlags }; const StaticAnim = Anim; const ControlAnim = struct { anims: []AnimData, state: Anim }; -const Kinematic = struct { col: AABB }; +const Kinematic = struct { col: AABB, onWall: bool = false, onFloor: bool = false, onCeil: bool = false }; const Wire = struct { end: Vec2f, grabbed: ?enum { begin, end } = null }; const Gravity = Vec2f; const Component = struct { @@ -122,10 +123,8 @@ export fn start() void { }) catch unreachable; for (assets.wire) |wire| { - // w4.trace("begin {}, end {}", .{ wire[0], wire[1] }); const begin = Vec2f{ @intToFloat(f32, wire[0][0]), @intToFloat(f32, wire[0][1]) }; const end = Vec2f{ @intToFloat(f32, wire[1][0]), @intToFloat(f32, wire[1][1]) }; - // w4.trace("{}, {}, begin {d:3.0}, end {d:3.0}", .{ wire[0], wire[1], begin, end }); const w = Wire{ .end = end }; _ = world.create(.{ .pos = begin, @@ -134,7 +133,6 @@ export fn start() void { w4.trace("problem", .{}); unreachable; }; - // w4.trace("{}", .{world.components.items(.wire)[e]}); } } @@ -144,7 +142,7 @@ export fn update() void { world.process(1, &.{ .pos, .lastpos }, velocityProcess); world.process(1, &.{ .pos, .gravity }, gravityProcess); - world.process(1, &.{ .pos, .control }, controlProcess); + world.process(1, &.{ .pos, .control, .gravity, .kinematic }, controlProcess); world.process(1, &.{ .pos, .lastpos, .kinematic }, kinematicProcess); world.process(1, &.{ .sprite, .staticAnim }, staticAnimProcess); world.process(1, &.{ .sprite, .controlAnim, .control }, controlAnimProcess); @@ -165,8 +163,7 @@ export fn update() void { } world.process(1, &.{ .pos, .wire }, wireProcess); - mouseLast = w4.MOUSE.buttons.left; - button_1_last = w4.GAMEPAD1.button_1; + input.update(); } fn distance(a: w4.Vec2, b: w4.Vec2) i32 { @@ -181,7 +178,7 @@ var mouseLast = false; fn wireProcess(_: f32, pos: *Pos, wire: *Wire) void { const begin = w4.Vec2{ @floatToInt(i32, pos.*[0]), @floatToInt(i32, pos.*[1]) }; const end = w4.Vec2{ @floatToInt(i32, wire.end[0]), @floatToInt(i32, wire.end[1]) }; - // if (w4.MOUSE.buttons.left and !mouseLast) w4.trace("pos {}, wire {}, begin {}, end {}", .{ pos.*, wire.end, begin, end }); + w4.DRAW_COLORS.* = 0x0001; w4.line(begin, end); w4.DRAW_COLORS.* = 0x0031; @@ -234,22 +231,30 @@ fn controlAnimProcess(_: f32, sprite: *Sprite, anim: *ControlAnim, control: *Con anim.state.update(&sprite.index); } -var button_1_last = false; - -fn controlProcess(_: f32, pos: *Pos, control: *Control) void { +fn controlProcess(_: f32, pos: *Pos, control: *Control, gravity: *Gravity, kinematic: *Kinematic) void { var delta = Vec2f{ 0, 0 }; - if (w4.GAMEPAD1.button_1 and !button_1_last) delta[1] -= 23; - if (w4.GAMEPAD1.button_left) delta[0] -= 1; - if (w4.GAMEPAD1.button_right) delta[0] += 1; - if (delta[0] != 0 or delta[1] != 0) { - control.state = .walk; - var move = delta * @splat(2, @as(f32, 0.2)); - pos.* += move; - if (delta[0] > 0) control.facing = .right; - if (delta[0] < 0) control.facing = .left; + if (kinematic.onFloor) { + if (input.btnp(.one, .one)) delta[1] -= 23; + if (input.btn(.one, .left)) delta[0] -= 1; + if (input.btn(.one, .right)) delta[0] += 1; + if (delta[0] != 0 or delta[1] != 0) { + control.state = .walk; + if (delta[0] > 0) control.facing = .right; + if (delta[0] < 0) control.facing = .left; + } else { + control.state = .stand; + } + } else if (kinematic.onWall) { + if (input.btn(.one, .left) and input.btnp(.one, .one)) delta = Vec2f{ -1, -23 }; + if (input.btn(.one, .right) and input.btnp(.one, .one)) delta = Vec2f{ 1, -23 }; + gravity.* = Vec2f{ 0, 0.01 }; } else { - control.state = .stand; + if (w4.GAMEPAD1.button_left) delta[0] -= 1; + if (w4.GAMEPAD1.button_right) delta[0] += 1; + gravity.* = Vec2f{ 0, 0.25 }; } + var move = delta * @splat(2, @as(f32, 0.2)); + pos.* += move; } /// pos should be in tile coordinates, not world coordinates @@ -291,13 +296,21 @@ fn kinematicProcess(_: f32, pos: *Pos, lastpos: *LastPos, kinematic: *Kinematic) next[0] = pos.*[0]; var hcol = level_collide(kinematic.col.addv(next)); if (hcol.len > 0) { + kinematic.onWall = true; next[0] = lastpos.*[0]; + } else { + kinematic.onWall = false; } next[1] = pos.*[1]; var vcol = level_collide(kinematic.col.addv(next)); if (vcol.len > 0) { + if (next[1] > lastpos.*[1]) kinematic.onFloor = true; + if (next[1] < lastpos.*[1]) kinematic.onCeil = true; next[1] = lastpos.*[1]; + } else { + kinematic.onFloor = false; + kinematic.onCeil = false; } pos.* = next; diff --git a/src/wasm4.zig b/src/wasm4.zig index ad7d852..95afdb1 100644 --- a/src/wasm4.zig +++ b/src/wasm4.zig @@ -131,6 +131,16 @@ pub const Gamepad = packed struct { if (@sizeOf(@This()) != @sizeOf(u8)) unreachable; } + pub fn diff(this: @This(), other: @This()) @This() { + return @bitCast(@This(), @bitCast(u8, this) ^ @bitCast(u8, other)); + } + + pub fn justPressed(this: @This(), last: @This()) @This() { + const thisbits = @bitCast(u8, this); + const lastbits = @bitCast(u8, last); + return @bitCast(@This(), (thisbits ^ lastbits) & thisbits); + } + pub fn format(value: @This(), comptime _: []const u8, _: @import("std").fmt.FormatOptions, writer: anytype) !void { if (value.button_1) try writer.writeAll("1"); if (value.button_2) try writer.writeAll("2"); @@ -158,6 +168,14 @@ pub const MouseButtons = packed struct { right: bool, middle: bool, _: u5 = 0, + pub fn diff(this: @This(), other: @This()) @This() { + return @bitCast(@This(), @bitCast(u8, this) ^ @bitCast(u8, other)); + } + pub fn justPressed(this: @This(), last: @This()) @This() { + const thisbits = @bitCast(u8, this); + const lastbits = @bitCast(u8, last); + return @bitCast(@This(), (thisbits ^ lastbits) & thisbits); + } comptime { if (@sizeOf(@This()) != @sizeOf(u8)) unreachable; }