commit 7e3fb669f48770a55723c80e0302b661320cf331
parent a0e37348df914caae559bcdcf0ae385faa74e955
Author: brookjeynes <me@brookjeynes.dev>
Date: Wed, 29 Jul 2026 12:39:32 +1000
feat: player shoots bullets
Signed-off-by: brookjeynes <me@brookjeynes.dev>
Diffstat:
3 files changed, 111 insertions(+), 9 deletions(-)
diff --git a/src/bullet.zig b/src/bullet.zig
@@ -0,0 +1,61 @@
+const std = @import("std");
+const raylib = @import("raylib");
+const Timer = @import("./timer.zig").Timer;
+
+const speed: f16 = 300.0;
+const radius: f16 = 10.0;
+const spawn_cooldown: f16 = 0.4;
+
+pub const Bullet = struct {
+ position: raylib.Vector2,
+ direction: raylib.Vector2,
+ color: raylib.Color,
+};
+
+pub const Pool = struct {
+ bullets: std.ArrayList(Bullet) = .empty,
+ fire_timer: Timer = .{ .duration = spawn_cooldown },
+
+ pub fn tick(self: *Pool) bool {
+ return self.fire_timer.tick(raylib.GetFrameTime());
+ }
+
+ pub fn spawn(
+ self: *Pool,
+ allocator: std.mem.Allocator,
+ position: raylib.Vector2,
+ direction: raylib.Vector2,
+ ) !void {
+ try self.bullets.append(allocator, .{
+ .position = position,
+ .direction = direction,
+ .color = raylib.MAROON,
+ });
+ }
+
+ pub fn render(self: *Pool, screen_size: raylib.Vector2) void {
+ const delta = raylib.GetFrameTime();
+
+ var i: usize = 0;
+ while (i < self.bullets.items.len) {
+ var bullet = &self.bullets.items[i];
+ bullet.position.x += bullet.direction.x * speed * delta;
+ bullet.position.y += bullet.direction.y * speed * delta;
+
+ if (bullet.position.x < -radius * 2 or
+ bullet.position.x > screen_size.x + radius * 2 or
+ bullet.position.y < -radius * 2 or
+ bullet.position.y > screen_size.y + radius * 2)
+ {
+ _ = self.bullets.orderedRemove(i);
+ } else {
+ raylib.DrawCircleV(bullet.position, radius, bullet.color);
+ i += 1;
+ }
+ }
+ }
+
+ pub fn deinit(self: *Pool, allocator: std.mem.Allocator) void {
+ self.bullets.deinit(allocator);
+ }
+};
diff --git a/src/main.zig b/src/main.zig
@@ -1,14 +1,22 @@
const std = @import("std");
+const Bullet = @import("./bullet.zig");
const raylib = @import("raylib");
const raymath = @import("raymath");
pub fn main() !void {
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer arena.deinit();
+ const allocator = arena.allocator();
+
const screen_width: f16 = 800.0;
const screen_height: f16 = 1000.0;
const fps: u8 = 60;
- const player_movement_speed: f16 = 170.0;
+ const player_movement_speed: f16 = 140.0;
const player_size: raylib.Vector2 = .{ .x = 50, .y = 50 };
+ var bullet_pool: Bullet.Pool = .{};
+ defer bullet_pool.deinit(allocator);
+
raylib.InitWindow(screen_width, screen_height, "1.44mb game jam");
defer raylib.CloseWindow();
@@ -21,22 +29,35 @@ pub fn main() !void {
while (!raylib.WindowShouldClose()) {
const delta: f32 = raylib.GetFrameTime();
- var direction: raylib.Vector2 = .{};
- if (raylib.IsKeyDown(raylib.KEY_RIGHT)) direction.x += 1;
- if (raylib.IsKeyDown(raylib.KEY_LEFT)) direction.x -= 1;
- if (raylib.IsKeyDown(raylib.KEY_UP)) direction.y -= 1;
- if (raylib.IsKeyDown(raylib.KEY_DOWN)) direction.y += 1;
+ var player_direction: raylib.Vector2 = .{};
+ if (raylib.IsKeyDown(raylib.KEY_RIGHT)) player_direction.x += 1;
+ if (raylib.IsKeyDown(raylib.KEY_LEFT)) player_direction.x -= 1;
+ if (raylib.IsKeyDown(raylib.KEY_UP)) player_direction.y -= 1;
+ if (raylib.IsKeyDown(raylib.KEY_DOWN)) player_direction.y += 1;
- direction = @bitCast(raymath.Vector2Normalize(@bitCast(direction)));
- player_position.x += direction.x * player_movement_speed * delta;
- player_position.y += direction.y * player_movement_speed * delta;
+ player_direction = @bitCast(raymath.Vector2Normalize(@bitCast(player_direction)));
+ player_position.x += player_direction.x * player_movement_speed * delta;
+ player_position.y += player_direction.y * player_movement_speed * delta;
const max_x: f32 = screen_width - player_size.x;
const max_y: f32 = screen_height - player_size.y;
player_position.x = @max(0, @min(max_x, player_position.x));
player_position.y = @max(0, @min(max_y, player_position.y));
+ if (player_direction.x != 0 or player_direction.y != 0) {
+ if (bullet_pool.tick()) {
+ try bullet_pool.spawn(
+ allocator,
+ .{
+ .x = player_position.x + (player_size.x / 2),
+ .y = player_position.y + (player_size.y / 2),
+ },
+ player_direction,
+ );
+ }
+ }
+
raylib.BeginDrawing();
defer raylib.EndDrawing();
@@ -47,5 +68,10 @@ pub fn main() !void {
player_size,
raylib.MAROON,
);
+
+ bullet_pool.render(.{
+ .x = screen_width,
+ .y = screen_height,
+ });
}
}
diff --git a/src/timer.zig b/src/timer.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub const Timer = struct {
+ duration: f32,
+ elapsed: f32 = 0,
+
+ pub fn tick(self: *Timer, delta: f32) bool {
+ self.elapsed += delta;
+ if (self.elapsed >= self.duration) {
+ self.elapsed -= self.duration;
+ return true;
+ }
+ return false;
+ }
+};