diff --git a/ProcessAssetsStep.zig b/ProcessAssetsStep.zig index fa00fc7..f03fa0d 100644 --- a/ProcessAssetsStep.zig +++ b/ProcessAssetsStep.zig @@ -138,28 +138,13 @@ fn make(step: *std.build.Step) !void { const template = object.template orelse continue; if (std.mem.endsWith(u8, template, "zero.tj")) { try writer.writeAll("Entity{.class = .player,"); - try writer.print(".box = Box{{ .x = {}, .y = {}, .w = {}, .h = {} }},}},", .{ - object.x + 8, - object.y - 24, - 16, - 24, - }); + try writer.print(".box = Box{{ .x = {}, .y = {}, .w = {}, .h = {} }},}},", .{ object.x + 8, object.y - 24, 16, 24 }); } else if (std.mem.endsWith(u8, template, "gopher.tj")) { try writer.writeAll("Entity{.class = .gopher,"); - try writer.print(".box = Box{{ .x = {}, .y = {}, .w = {}, .h = {} }},}},", .{ - object.x + 8, - object.y - 24, - 16, - 24, - }); + try writer.print(".box = Box{{ .x = {}, .y = {}, .w = {}, .h = {} }},}},", .{ object.x + 4, object.y - 24, 16, 24 }); } else if (std.mem.endsWith(u8, template, "spike.tj")) { try writer.writeAll("Entity{.class = .spike,"); - try writer.print(".box = Box{{ .x = {}, .y = {}, .w = {}, .h = {} }},}},", .{ - object.x, - object.y - 24, - 16, - 24, - }); + try writer.print(".box = Box{{ .x = {}, .y = {}, .w = {}, .h = {} }},}},", .{ object.x, object.y - 24, 16, 24 }); } } try writer.writeAll("},\n"); diff --git a/maps/stages/needleman/room0.json b/maps/stages/needleman/room0.json index 1704fd2..c75aac8 100644 --- a/maps/stages/needleman/room0.json +++ b/maps/stages/needleman/room0.json @@ -48,8 +48,14 @@ { "id":5, "template":"..\/..\/objects\/gopher.tj", - "x":304, - "y":192 + "x":368, + "y":144 + }, + { + "id":6, + "template":"..\/..\/objects\/gopher.tj", + "x":576, + "y":144 }], "opacity":1, "type":"objectgroup", @@ -58,7 +64,7 @@ "y":0 }], "nextlayerid":3, - "nextobjectid":6, + "nextobjectid":7, "orientation":"orthogonal", "renderorder":"right-down", "tiledversion":"1.9.2", diff --git a/src/Box.zig b/src/Box.zig index 3009936..af0d086 100644 --- a/src/Box.zig +++ b/src/Box.zig @@ -20,7 +20,7 @@ pub fn toRect2(self: Box) Rect2 { }; } -pub fn overlap(self: Box, other: Box) bool { +pub fn overlaps(self: Box, other: Box) bool { return self.x < other.x + other.w and self.x + self.w > other.x and self.y < other.y + other.h and self.y + self.h > other.y; } diff --git a/src/Enemy.zig b/src/Enemy.zig index 04c0eae..b79d0d7 100644 --- a/src/Enemy.zig +++ b/src/Enemy.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const GameData = @import("main.zig").GameData; const Box = @import("Box.zig"); const Attrib = @import("Tile.zig").Attrib; const Room = @import("Room.zig"); @@ -21,11 +22,11 @@ pub const Type = enum { pub var gopher_sprite: Renderer.Texture = undefined; active: bool = false, -@"type": Type = undefined, +type: Type = undefined, box: Box = undefined, state: u8 = 0, frame: u8 = 0, -counter: u32 = 0, +counter: i32 = 0, flip_x: bool = false, pub fn load() void { @@ -34,7 +35,7 @@ pub fn load() void { pub fn activate(self: *Self, @"type": Type, box: Box) void { self.active = true; - self.@"type" = @"type"; + self.type = @"type"; self.box = box; switch (@"type") { .gopher => {}, @@ -44,14 +45,14 @@ pub fn activate(self: *Self, @"type": Type, box: Box) void { self.counter = 0; } -pub fn tick(self: *Self, room: Room, attribs: []const Attrib) void { - switch (self.@"type") { - .gopher => tickGopher(self, room, attribs), +pub fn tick(self: *Self, r: std.rand.Random, game: *GameData, attribs: []const Attrib) void { + switch (self.type) { + .gopher => tickGopher(self, r, game, attribs), } } pub fn draw(self: Self) void { - switch (self.@"type") { + switch (self.type) { .gopher => drawGopher(self), } } @@ -61,37 +62,43 @@ const GopherState = enum(u8) { walk = 1, }; -fn tickGopher(self: *Self, room: Room, attribs: []const Attrib) void { - var state = @ptrCast(*GopherState, &self.state); +fn tickGopher(self: *Self, r: std.rand.Random, game: *GameData, attribs: []const Attrib) void { + const room = game.getCurrentRoom(); + const state = @ptrCast(*GopherState, &self.state); switch (state.*) { .idle => { self.frame = 0; self.flip_x = self.counter & 16 != 0; - if (self.counter >= 128) { - self.counter = 0; + if (self.counter <= 0) { + self.counter = r.intRangeLessThan(i32, 100, 500); state.* = .walk; } }, .walk => { self.frame = if (self.counter & 8 != 0) 1 else 2; - const amount: i32 = if (self.flip_x) - 1 else 1; - if (room.clipX(attribs, self.box, amount) != amount) { + const amount: i32 = if (self.flip_x) -1 else 1; + const sense_x = self.box.x + @divTrunc(self.box.w + amount * self.box.w, 2); + if (room.getTileAttribAtPixel(attribs, sense_x, self.box.y + self.box.h) != .solid or room.clipX(attribs, self.box, amount) != amount) { self.flip_x = !self.flip_x; } else { self.box.x += amount; } - if (self.counter >= 128) { - self.counter = 0; + if (self.counter <= 0) { + self.counter = r.intRangeLessThan(i32, 100, 200); state.* = .idle; } }, } - self.counter += 1; + self.counter -= 1; + + if (self.box.overlaps(game.player.box)) { + game.killPlayer(); + } } fn drawGopher(self: Self) void { var src_rect = Rect2.init(@intToFloat(f32, self.frame * 24), 0, 24, 24); - var dst_rect = Rect2.init(@intToFloat(f32, self.box.x) - 8, @intToFloat(f32, self.box.y), src_rect.w, src_rect.h); + var dst_rect = Rect2.init(@intToFloat(f32, self.box.x) - 4, @intToFloat(f32, self.box.y), src_rect.w, src_rect.h); if (self.flip_x) { src_rect.x += src_rect.w; src_rect.w = -src_rect.w; diff --git a/src/Room.zig b/src/Room.zig index 517927c..9886930 100644 --- a/src/Room.zig +++ b/src/Room.zig @@ -112,7 +112,7 @@ pub fn overlap(self: Room, attribs: []const Tile.Attrib, mover: Box) bool { const attrib = attribs[tile_index]; if (attrib == .solid) { const solid = Box{ .x = x * Tile.size, .y = y * Tile.size, .w = Tile.size, .h = Tile.size }; - if (box.overlap(solid)) return true; + if (box.overlaps(solid)) return true; } } } diff --git a/src/main.zig b/src/main.zig index bd2a8f3..de35ee9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -40,6 +40,8 @@ const text_w = screen_width / 8; const text_h = screen_height / 8; var text_buffer: [text_w * text_h]u8 = undefined; +var prng = std.rand.DefaultPrng.init(0); + const GameState = enum { title, start, @@ -65,7 +67,7 @@ const door_duration = 16; var room_transition: RoomTransition = .none; var mode_frame: i32 = 0; -const GameData = struct { +pub const GameData = struct { state: GameState = .title, counter: u8 = 0, // number of frames to wait in a state title_any_key_pressed: bool = false, @@ -93,7 +95,7 @@ const GameData = struct { self.prev_input = std.mem.zeroes(Player.Input); self.cur_room_index = 0; self.prev_room_index = 0; - const room = cur_stage.rooms[self.cur_room_index]; + const room = self.getCurrentRoom(); uploadRoomTexture(&cur_room_tex, room); self.scrollr.x = room.bounds.x; self.scrollr.y = room.bounds.y; @@ -143,7 +145,11 @@ const GameData = struct { self.* = std.json.parse(GameData, &ts, .{ .ignore_unknown_fields = true, }) catch return; - uploadRoomTexture(&cur_room_tex, cur_stage.rooms[self.cur_room_index]); // FIXME + uploadRoomTexture(&cur_room_tex, self.getCurrentRoom()); // FIXME + } + + pub fn getCurrentRoom(self: GameData) Room { + return cur_stage.rooms[self.cur_room_index]; } fn tickTitle(self: *GameData) void { @@ -241,7 +247,7 @@ const GameData = struct { } } - fn killPlayer(self: *GameData) void { + pub fn killPlayer(self: *GameData) void { if (!self.player.no_clip) { self.state = .gameover; self.counter = 0; @@ -263,7 +269,7 @@ const GameData = struct { updatePlayer(&self.player); for (self.enemies) |*enemy| { - if (enemy.active) enemy.tick(cur_stage.rooms[self.cur_room_index], cur_stage.attribs); + if (enemy.active) enemy.tick(prng.random(), self, cur_stage.attribs); } if (findNextRoom(cur_stage.rooms, self.cur_room_index, self.player.box)) |next_room_index| { @@ -273,7 +279,7 @@ const GameData = struct { } const cur_room = cur_stage.rooms[self.cur_room_index]; - if (!cur_room.bounds.overlap(self.player.box)) { + if (!cur_room.bounds.overlaps(self.player.box)) { if (self.player.box.y > cur_room.bounds.y + cur_room.bounds.h) { self.killPlayer(); return; @@ -288,7 +294,7 @@ const GameData = struct { .w = Tile.size, .h = 4 * Tile.size, }; - if (self.player.box.overlap(door_box)) { + if (self.player.box.overlaps(door_box)) { door_box.x -= 1; if (findNextRoom(cur_stage.rooms, self.cur_room_index, door_box)) |next_room_index| { setNextRoom(next_room_index); @@ -306,7 +312,7 @@ const GameData = struct { .w = Tile.size, .h = 4 * Tile.size, }; - if (self.player.box.overlap(door_box)) { + if (self.player.box.overlaps(door_box)) { door_box.x += 1; if (findNextRoom(cur_stage.rooms, self.cur_room_index, door_box)) |next_room_index| { setNextRoom(next_room_index); @@ -319,7 +325,7 @@ const GameData = struct { // check spikes for (cur_room.entities) |entity| { if (entity.class == .spike) { - if (self.player.box.overlap(entity.box)) { + if (self.player.box.overlaps(entity.box)) { self.killPlayer(); } } @@ -431,7 +437,7 @@ fn findNextRoom(rooms: []const Room, skip_room_index: u8, box: Box) ?u8 { var room_index: u8 = 0; while (room_index < rooms.len) : (room_index += 1) { if (room_index == skip_room_index) continue; - if (rooms[room_index].bounds.overlap(box)) { + if (rooms[room_index].bounds.overlaps(box)) { return room_index; } } diff --git a/src/stages/needleman.zig b/src/stages/needleman.zig index e283d93..a985cee 100644 --- a/src/stages/needleman.zig +++ b/src/stages/needleman.zig @@ -38,7 +38,11 @@ pub const needleman = Stage{ }, Entity{ .class = .gopher, - .box = Box{ .x = 312, .y = 168, .w = 16, .h = 24 }, + .box = Box{ .x = 372, .y = 120, .w = 16, .h = 24 }, + }, + Entity{ + .class = .gopher, + .box = Box{ .x = 580, .y = 120, .w = 16, .h = 24 }, }, }, },