diff --git a/src/game.zig b/src/game.zig index 8fa0391..6e22a96 100644 --- a/src/game.zig +++ b/src/game.zig @@ -29,19 +29,47 @@ const Game = @This(); const RNGState = std.Random.DefaultPrng; -const Player = struct { +const Kinetic = struct { pos: Vec2 = .zero, vel: Vec2 = .zero, acc: Vec2 = .zero, + + const UpdateOptions = struct { + max_speed: ?f32 = null, + friction: ?f32 = null, + }; + + pub fn update(self: *Kinetic, dt: f32, opts: UpdateOptions) void { + self.vel = self.vel.add(self.acc.multiplyScalar(dt)); + if (opts.max_speed) |max_speed| { + self.vel = self.vel.limitLength(max_speed); + } + if (opts.friction) |friction| { + const friction_force = std.math.pow(f32, 1 - friction, dt); + self.vel = self.vel.multiplyScalar(friction_force); + } + self.pos = self.pos.add(self.vel.multiplyScalar(dt)); + } +}; + +const Player = struct { + kinetic: Kinetic = .{}, last_shot_at: ?Nanoseconds = null }; const Bullet = struct { - pos: Vec2 = .zero, - vel: Vec2 = .zero, - size: f32 = 5 + kinetic: Kinetic, + size: f32 = 5, + dir: Vec2, + speed: f32 }; +const Enemy = struct { + kinetic: Kinetic, + speed: f32, + size: f32, +}; + arena: std.heap.ArenaAllocator, gpa: Allocator, rng: RNGState, @@ -49,6 +77,7 @@ assets: *Assets, player: Player = .{}, bullets: std.ArrayList(Bullet) = .empty, +enemies: std.ArrayList(Enemy) = .empty, pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game { var arena = std.heap.ArenaAllocator.init(gpa); @@ -59,7 +88,9 @@ pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game { .gpa = gpa, .assets = assets, .player = .{ - .pos = .init(50, 50), + .kinetic = .{ + .pos = .init(50, 50), + } }, .rng = RNGState.init(seed), }; @@ -68,6 +99,7 @@ pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game { pub fn deinit(self: *Game) void { self.arena.deinit(); self.bullets.deinit(self.gpa); + self.enemies.deinit(self.gpa); } pub fn tick(self: *Game, frame: *Engine.Frame) !void { @@ -104,16 +136,13 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void { } dir = dir.normalized(); - const max_speed = 400; const acceleration = 1500; - const friction_coef = 0.99988; - self.player.acc = dir.multiplyScalar(acceleration); - self.player.vel = self.player.vel.add(self.player.acc.multiplyScalar(dt)); - self.player.vel = self.player.vel.limitLength(max_speed); - const friction_force = std.math.pow(f32, 1 - friction_coef, dt); - self.player.vel = self.player.vel.multiplyScalar(friction_force); - self.player.pos = self.player.pos.add(self.player.vel.multiplyScalar(dt)); + self.player.kinetic.acc = dir.multiplyScalar(acceleration); + self.player.kinetic.update(dt, .{ + .friction = 0.99988, + .max_speed = 400 + }); if (frame.input.mouse_position) |mouse| { const cursor_size = Vec2.init(10, 10); @@ -125,7 +154,7 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void { .color = rgba(255, 200, 200, 0.5) }); - const bullet_dir = mouse.sub(self.player.pos).normalized(); + const bullet_dir = mouse.sub(self.player.kinetic.pos).normalized(); var cooldown_complete = true; if (self.player.last_shot_at) |last_shot_at| { @@ -136,8 +165,21 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void { if (frame.isMouseDown(.left) and cooldown_complete) { self.player.last_shot_at = frame.time_ns; try self.bullets.append(self.gpa, .{ - .pos = self.player.pos, - .vel = bullet_dir.multiplyScalar(50) + .kinetic = .{ + .pos = self.player.kinetic.pos, + }, + .dir = bullet_dir, + .speed = 50 + }); + } + + if (frame.isMousePressed(.right)) { + try self.enemies.append(self.gpa, .{ + .kinetic = .{ + .pos = mouse, + }, + .speed = 10, + .size = 20 }); } } @@ -145,23 +187,38 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void { var size = self.assets.players_tilemap.tile_size; frame.drawRectangle(.{ .rect = .{ - .pos = self.player.pos.sub(size.divideScalar(2)), + .pos = self.player.kinetic.pos.sub(size.divideScalar(2)), .size = size, }, .color = rgb(255, 255, 255) }); for (self.bullets.items) |*bullet| { - bullet.pos = bullet.pos.add(bullet.vel.multiplyScalar(dt)); + bullet.kinetic.vel = bullet.dir.multiplyScalar(bullet.speed); + bullet.kinetic.update(dt, .{}); frame.drawRectangle(.{ .rect = .{ - .pos = bullet.pos.sub(.init(bullet.size, bullet.size)), + .pos = bullet.kinetic.pos.sub(Vec2.init(bullet.size, bullet.size).multiplyScalar(0.5)), .size = .init(bullet.size, bullet.size), }, .color = rgb(200, 20, 255) }); } + + for (self.enemies.items) |*enemy| { + const dir_to_player = self.player.kinetic.pos.sub(enemy.kinetic.pos).normalized(); + enemy.kinetic.vel = dir_to_player.multiplyScalar(50); + enemy.kinetic.update(dt, .{}); + + frame.drawRectangle(.{ + .rect = .{ + .pos = enemy.kinetic.pos.sub(Vec2.init(enemy.size, enemy.size).multiplyScalar(0.5)), + .size = .init(enemy.size, enemy.size), + }, + .color = rgb(20, 200, 20) + }); + } } pub fn debug(self: *Game) !void {