From d149a61f46c465ea288ab74293183c6f8a823716 Mon Sep 17 00:00:00 2001 From: abux Date: Mon, 13 Jul 2026 13:13:17 +0100 Subject: [PATCH] Added basic game stage | Animations, ig? --- build.zig.zon | 4 +- src/assets/fonts/Dynamix.ttf | Bin 0 -> 18048 bytes src/assets/textures/projectile.png | Bin 0 -> 461 bytes src/component/ai.zig | 1 + src/component/animate.zig | 9 +++ src/component/caster.zig | 2 +- src/component/health.zig | 2 + src/component/root.zig | 9 +++ src/component/speed.zig | 1 + src/component/text.zig | 5 ++ src/event/root.zig | 1 + src/event/take_damage.zig | 2 + src/main.zig | 9 +++ src/plugin/default.zig | 2 + src/resource/fonts.zig | 64 +++++++++++++++++ src/resource/game.zig | 6 ++ src/resource/io.zig | 5 ++ src/resource/root.zig | 7 ++ src/resource/textures.zig | 13 ++-- src/resource/time.zig | 1 + src/system/ai.zig | 110 +++++++++++++++++++++++++++++ src/system/core.zig | 17 ++++- src/system/draw.zig | 22 +++++- src/system/frame.zig | 21 +++--- src/system/inputs.zig | 10 +-- src/system/root.zig | 1 + 26 files changed, 293 insertions(+), 31 deletions(-) create mode 100644 src/assets/fonts/Dynamix.ttf create mode 100644 src/assets/textures/projectile.png create mode 100644 src/component/ai.zig create mode 100644 src/component/animate.zig create mode 100644 src/component/health.zig create mode 100644 src/component/speed.zig create mode 100644 src/component/text.zig create mode 100644 src/event/take_damage.zig create mode 100644 src/resource/fonts.zig create mode 100644 src/resource/game.zig create mode 100644 src/resource/io.zig create mode 100644 src/system/ai.zig diff --git a/build.zig.zon b/build.zig.zon index bad24b0..66435f3 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,8 +9,8 @@ .dependencies = .{ .app = .{ - .url = "git+http://2.120.146.66:25569/abux/NYXA.git#4113f667319559c6bddb83c89042deb54e63b3de", - .hash = "app-0.0.0-AOV9_eK_AAA4ZmEGkvsFUM2xMTb0lYbzq4vSShMRnKZj", + .url = "git+http://2.120.146.66:25569/abux/NYXA.git#7b8b2833a9047969031bb9a179abad0115c2ca07", + .hash = "app-0.0.0-AOV9_Q_ZAADKe6v7NIwmnTpQR3Yup9j-NUc1OM522R-7", }, .gtl = .{ .url = "git+http://2.120.146.66:25569/abux/GTL.git#b87f315b57788ee81af592fc85532f751951966d", diff --git a/src/assets/fonts/Dynamix.ttf b/src/assets/fonts/Dynamix.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b6769397fd3858fa3ef4c035ae4116b0e0e796e4 GIT binary patch literal 18048 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 CNYr}( literal 0 HcmV?d00001 diff --git a/src/assets/textures/projectile.png b/src/assets/textures/projectile.png new file mode 100644 index 0000000000000000000000000000000000000000..321a9bf436b7da2c77753a38e3ea57162c612ae5 GIT binary patch literal 461 zcmV;;0W$uHP)}%FDyV8H-Np@#ANOF6(`K5uv{dzUfAVBEhR;Wcp z#(h8we&0S(t#P)vrW)}?%o{Si70k&Q9R1?|oi>n)|C0`$JR3lPiG{}T| z!4fILC8&soA05xB1{Rk~sy!@;L!3aga2d+kzC2Rx$()>?R}w(6z}08NH9QG`OF$Q9 zG*ZZh1H2;{okkpe}VTmDj&2`^k?o(G@{ z^2LM_)*G@FtgRdwtvq@v>N$=9yyI2tqY{88^7{NxuJU&!x4RMmG7=uGaG;t%xCD?D ziG%~{BqAk%mWT`ntZ=}*!HI}ugOTO~5>18^3FYhn5qP+)QD|KM00000NkvXXu0mjf D7_hqW literal 0 HcmV?d00001 diff --git a/src/component/ai.zig b/src/component/ai.zig new file mode 100644 index 0000000..6791b31 --- /dev/null +++ b/src/component/ai.zig @@ -0,0 +1 @@ +target_to_chase: u64, diff --git a/src/component/animate.zig b/src/component/animate.zig new file mode 100644 index 0000000..530ab8b --- /dev/null +++ b/src/component/animate.zig @@ -0,0 +1,9 @@ +pub const Style = union(enum) { + bob: struct { + amplitude: f32 = 6.0, + frequency: f32 = 6.0, + phase: f32 = 0.0, + }, +}; + +style: Style, diff --git a/src/component/caster.zig b/src/component/caster.zig index 6cb2934..e71afa8 100644 --- a/src/component/caster.zig +++ b/src/component/caster.zig @@ -1,2 +1,2 @@ -cooldown: f32 = 0.2, +cooldown: f32 = 1.2, current_cooldown: f32 = 0.0, diff --git a/src/component/health.zig b/src/component/health.zig new file mode 100644 index 0000000..44ad121 --- /dev/null +++ b/src/component/health.zig @@ -0,0 +1,2 @@ +max: u32 = 100, +current: u32 = 0, diff --git a/src/component/root.zig b/src/component/root.zig index 6522d47..627ecb9 100644 --- a/src/component/root.zig +++ b/src/component/root.zig @@ -2,9 +2,18 @@ pub const Transform = @import("transform.zig"); pub const Velocity = @import("velocity.zig"); pub const Friction = @import("friction.zig"); +pub const Speed = @import("speed.zig"); // --- STYLE --- pub const Material = @import("material.zig"); +pub const Animate = @import("animate.zig"); +pub const Text = @import("text.zig"); + +// --- LIFETIME --- +pub const Health = @import("health.zig"); + +// --- AI --- +pub const AI = @import("ai.zig"); // --- CAMERA --- pub const Camera = @import("camera.zig"); diff --git a/src/component/speed.zig b/src/component/speed.zig new file mode 100644 index 0000000..222f701 --- /dev/null +++ b/src/component/speed.zig @@ -0,0 +1 @@ +value: f32 = 100.0, diff --git a/src/component/text.zig b/src/component/text.zig new file mode 100644 index 0000000..e4d3dc4 --- /dev/null +++ b/src/component/text.zig @@ -0,0 +1,5 @@ +const Handle = @import("gtl").Handle; +const Font = @import("../resource/fonts.zig").Font; + +content: []const u8 = "Hello World!", +font: Handle(Font), diff --git a/src/event/root.zig b/src/event/root.zig index e69de29..82ef2dd 100644 --- a/src/event/root.zig +++ b/src/event/root.zig @@ -0,0 +1 @@ +pub const TakeDamage = @import("take_damage.zig"); diff --git a/src/event/take_damage.zig b/src/event/take_damage.zig new file mode 100644 index 0000000..735e002 --- /dev/null +++ b/src/event/take_damage.zig @@ -0,0 +1,2 @@ +entity: u32, +value: u32, diff --git a/src/main.zig b/src/main.zig index 086642f..8e840c5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -17,6 +17,15 @@ pub fn main(init: std.process.Init) !void { try app.schedules.run(App.stage.init, .{ .app = &app }); defer app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable; + // --- IO --- + var prng = std.Random.DefaultPrng.init(6969); + const rng = prng.random(); + try app.resources.set(resource.IO{ + .io = init.io, + .rng = rng, + .prng = prng, + }); + // errdefer { // app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable; // } diff --git a/src/plugin/default.zig b/src/plugin/default.zig index 40dfee0..af1ed7d 100644 --- a/src/plugin/default.zig +++ b/src/plugin/default.zig @@ -31,6 +31,8 @@ fn build( system.frame.updateTimers, system.frame.updateTransforms, system.frame.cast, + system.ai.spawn, + system.ai.chaseTarget, }); try ctx.app.schedules.add(App.stage.draw, system.draw.draw); } diff --git a/src/resource/fonts.zig b/src/resource/fonts.zig new file mode 100644 index 0000000..5d6600b --- /dev/null +++ b/src/resource/fonts.zig @@ -0,0 +1,64 @@ +// --- # --- +const std = @import("std"); +const gtl = @import("gtl"); +const sdl = @import("sdl"); +const Self = @This(); + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const Font = struct { id: u64 }; + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const GPUFont = struct { + path: []const u8, + size: [2]i32 = .{ 0, 0 }, + raw: ?*sdl.TTF_Font, +}; + +// +// FIELDS +// + +data: gtl.KeyedSlotMap(Font, GPUFont), + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn init(alloc: std.mem.Allocator) Self { + return .{ + .data = .init(alloc), + }; +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn deinit(self: *Self) void { + for (self.data.items()) |entry| { + sdl.TTF_CloseFont(entry.value.raw); + } + self.data.deinit(); +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn load( + self: *Self, + path: []const u8, +) !gtl.Handle(Font) { + // --- ID --- + const id = std.hash.Wyhash.hash( + 6969, + path, + ); + + // --- # --- + if (self.data.getHandle(.{ .id = id })) |h| { + return h; + } + + // --- # --- + return try self.data.put(.{ .id = id }, .{ + .path = path, + .raw = null, + }); +} diff --git a/src/resource/game.zig b/src/resource/game.zig new file mode 100644 index 0000000..cb436dc --- /dev/null +++ b/src/resource/game.zig @@ -0,0 +1,6 @@ +// --- WAVES --- +current_wave: u32 = 0, +current_wave_time: f32 = 0, +time_for_next_wave: f32 = 20.0, +next_wave_enemy_count: u32 = 3, +enemy_multiplyer_each_wave: u32 = 2, diff --git a/src/resource/io.zig b/src/resource/io.zig new file mode 100644 index 0000000..d8d5d3f --- /dev/null +++ b/src/resource/io.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +io: std.Io, +rng: std.Random, +prng: std.Random.DefaultPrng, diff --git a/src/resource/root.zig b/src/resource/root.zig index 759a886..6d9f421 100644 --- a/src/resource/root.zig +++ b/src/resource/root.zig @@ -1,6 +1,13 @@ // --- CORE --- +pub const IO = @import("io.zig"); pub const Window = @import("window.zig"); pub const Renderer = @import("renderer.zig"); pub const Frame = @import("frame.zig"); pub const Time = @import("time.zig"); + +// --- ASSETS --- +pub const Fonts = @import("fonts.zig"); pub const Textures = @import("textures.zig"); + +// --- GAME --- +pub const Game = @import("game.zig"); diff --git a/src/resource/textures.zig b/src/resource/textures.zig index 82635dc..c92e18c 100644 --- a/src/resource/textures.zig +++ b/src/resource/textures.zig @@ -4,12 +4,6 @@ const gtl = @import("gtl"); const sdl = @import("sdl"); const Self = @This(); -// -// -// - -pub const Player = struct {}; - /// ---------------------------------------------------- /// ---------------------------------------------------- pub const Texture = struct { id: u64 }; @@ -51,17 +45,20 @@ pub fn deinit(self: *Self) void { /// ---------------------------------------------------- pub fn load( self: *Self, - comptime T: type, path: []const u8, ) !gtl.Handle(Texture) { // --- ID --- - const id = gtl.TypeID(T); + const id = std.hash.Wyhash.hash( + 6969, + path, + ); // --- # --- if (self.data.getHandle(.{ .id = id })) |h| { return h; } + // --- # --- return try self.data.put(.{ .id = id }, .{ .path = path, .raw = null, diff --git a/src/resource/time.zig b/src/resource/time.zig index 9cd9ee0..ca881e2 100644 --- a/src/resource/time.zig +++ b/src/resource/time.zig @@ -1,5 +1,6 @@ dt: f32 = 0.0, now: u64 = 0, last: u64 = 0, +elapsed: f32 = 0.0, frequency: u64 = 0, target_dt: f32 = 1.0 / 60.0, diff --git a/src/system/ai.zig b/src/system/ai.zig new file mode 100644 index 0000000..13eda83 --- /dev/null +++ b/src/system/ai.zig @@ -0,0 +1,110 @@ +const std = @import("std"); +const sdl = @import("sdl"); +const App = @import("app"); + +const component = @import("../component/root.zig"); +const resource = @import("../resource/root.zig"); + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn spawn(ctx: App.scheduler.Context) !void { + const res = try ctx.app.resources.getMany(struct { + io: *resource.IO, + time: *resource.Time, + game: *resource.Game, + textures: *resource.Textures, + }); + + // --- CURRENT TARGET --- + var target: ?u64 = 0; + + // --- GET TARGET --- + var query = ctx.app.world.query(struct { + player: *component.Player, + }, .{}); + while (query.next()) |_| { + target = query.entity(); + } + + // --- SUBTRACT COOLDOWN --- + res.game.current_wave_time -= @max(0, res.time.dt); + + // --- SKIP IF ON COOLDOWN --- + if (res.game.current_wave_time >= 0) + return; + + // --- SPAWN --- + for (0..@intCast(res.game.next_wave_enemy_count)) |_| { + try ctx.app.world.spawn(.{ + component.AI{ + .target_to_chase = target orelse return, + }, + component.Transform{ + .pos = .{ + @floatFromInt(res.io.rng.intRangeAtMost(i32, -400, 400)), + @floatFromInt(res.io.rng.intRangeAtMost(i32, -400, 400)), + }, + .size = blk: { + const size: f32 = @floatFromInt(res.io.rng.intRangeAtMost(i32, 16, 64)); + break :blk .{ size, size }; + }, + }, + component.Velocity{}, + component.Friction{}, + component.Speed{ .value = 200 }, + component.Animate{ .style = .{ .bob = .{} } }, + + component.Material{ + .style = .{ + // .solid = .{ 200, 20, 20, 255 }, + .textured = try res.textures.load("src/assets/textures/player.png"), + }, + }, + }); + } + + // --- SET COOLDOWN --- + res.game.current_wave_time = res.game.time_for_next_wave; + res.game.next_wave_enemy_count *= res.game.enemy_multiplyer_each_wave; +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn chaseTarget(ctx: App.scheduler.Context) !void { + const res = try ctx.app.resources.getMany(struct { + frame: *resource.Frame, + time: *resource.Time, + }); + + var query = ctx.app.world.query(struct { + ai: *component.AI, + speed: *component.Speed, + transform: *component.Transform, + velocity: *component.Velocity, + }, .{}); + while (query.next()) |e| { + // --- GET TARGETS POSITION --- + const target = ctx.app.world.getComponent( + component.Transform, + e.ai.target_to_chase, + ) orelse continue; + + // --- GET DIR --- + const dir: [2]f32 = .{ + (target.pos[0] + target.size[0] / 2) - (e.transform.pos[0] + e.transform.size[0] / 2), + (target.pos[1] + target.size[1] / 2) - (e.transform.pos[1] + e.transform.size[1] / 2), + }; + + // --- GET LEN --- + const len: f32 = @sqrt( + dir[0] * dir[0] + dir[1] * dir[1], + ); + + // --- MOVE --- + if (len > 0.0001) { + const accel = e.speed.value * res.time.dt; + e.velocity.value[0] += (dir[0] / len) * accel; + e.velocity.value[1] += (dir[1] / len) * accel; + } + } +} diff --git a/src/system/core.zig b/src/system/core.zig index c7d6061..f56e1f1 100644 --- a/src/system/core.zig +++ b/src/system/core.zig @@ -9,7 +9,7 @@ const resource = @import("../resource/root.zig"); /// ---------------------------------------------------- pub fn init(ctx: App.scheduler.Context) !void { // --- SDL3 INIT --- - if (!sdl.SDL_Init(sdl.SDL_INIT_VIDEO)) { + if (!sdl.SDL_Init(sdl.SDL_INIT_VIDEO) or !sdl.TTF_Init()) { return error.SDL_Init; } @@ -38,6 +38,14 @@ pub fn init(ctx: App.scheduler.Context) !void { .frequency = sdl.SDL_GetPerformanceFrequency(), }); try ctx.app.resources.set(resource.Frame{}); + + // --- GAME --- + try ctx.app.resources.set( + resource.Game{}, + ); + + // --- ASSETS --- + _ = try ctx.app.resources.getOrSet(resource.Fonts.init(ctx.app.alloc)); const textures = try ctx.app.resources.getOrSet(resource.Textures.init(ctx.app.alloc)); // --- DEBUG --- @@ -57,12 +65,13 @@ pub fn init(ctx: App.scheduler.Context) !void { try ctx.app.world.spawn(.{ component.Player{}, component.Caster{}, + component.Speed{}, component.Friction{}, component.Velocity{}, component.Transform{ .size = .{ 64, 64 } }, component.Material{ .style = .{ - .textured = try textures.load(resource.Textures.Player, "src/assets/textures/player.png"), + .textured = try textures.load("src/assets/textures/player.png"), } }, component.CameraTarget{}, }); @@ -83,10 +92,14 @@ pub fn deinit(ctx: App.scheduler.Context) !void { window: *resource.Window, renderer: *resource.Renderer, textures: *resource.Textures, + fonts: *resource.Fonts, }); + res.fonts.deinit(); res.textures.deinit(); + sdl.SDL_DestroyRenderer(res.renderer.raw); sdl.SDL_DestroyWindow(res.window.raw); + sdl.TTF_Quit(); sdl.SDL_Quit(); } diff --git a/src/system/draw.zig b/src/system/draw.zig index a0d1324..f0f824a 100644 --- a/src/system/draw.zig +++ b/src/system/draw.zig @@ -12,7 +12,10 @@ pub fn draw(ctx: App.scheduler.Context) !void { window: *resource.Window, renderer: *resource.Renderer, frame: *resource.Frame, + time: *resource.Time, + textures: *resource.Textures, + fonts: *resource.Fonts, }); // --- SET CLEAR COLOR --- @@ -33,14 +36,27 @@ pub fn draw(ctx: App.scheduler.Context) !void { transform: *component.Transform, material: *component.Material, camera_target: ?*component.CameraTarget, + animate: ?*component.Animate, + text: ?*component.Text, }, .{}); while (query.next()) |e| { + // --- DATA --- const camera = if (res.frame.camera) |*v| v else continue; + var draw_pos = e.transform.pos; - // --- SHAPE --- + // --- ANIMATIONS --- + if (e.animate) |animate| { + switch (animate.style) { + .bob => |bob| { + draw_pos[1] += @sin(res.time.elapsed * bob.frequency + bob.phase) * bob.amplitude; + }, + } + } + + // --- DRAW RECT --- var rect: sdl.SDL_FRect = .{ - .x = e.transform.pos[0] + camera.transform.pos[0], - .y = e.transform.pos[1] + camera.transform.pos[1], + .x = draw_pos[0] + camera.transform.pos[0], + .y = draw_pos[1] + camera.transform.pos[1], .w = e.transform.size[0], .h = e.transform.size[1], }; diff --git a/src/system/frame.zig b/src/system/frame.zig index 2297452..fb9c33a 100644 --- a/src/system/frame.zig +++ b/src/system/frame.zig @@ -88,7 +88,7 @@ pub fn beginFrame(ctx: App.scheduler.Context) !void { // --- SET TEXTURE FILTER --- _ = sdl.SDL_SetTextureScaleMode( - entry.value.raw, + raw, sdl.SDL_SCALEMODE_PIXELART, ); @@ -115,6 +115,7 @@ pub fn endFrame(ctx: App.scheduler.Context) !void { }); res.frame.camera = null; + res.time.elapsed += res.time.dt; const frame_time = @as(f32, @floatFromInt(sdl.SDL_GetPerformanceCounter() - res.time.now)) / @@ -208,17 +209,17 @@ pub fn cast(ctx: App.scheduler.Context) !void { // --- SPAWN PROJECTILE --- try ctx.app.world.spawn(.{ component.Transform{ - .pos = e.transform.pos, - }, - component.Velocity{ - .value = .{ 400, 0 }, - }, - component.Material{ - .style = .{ - // .solid = .{ 200, 20, 20, 255 }, - .textured = try res.textures.load(resource.Textures.Player, "src/assets/textures/player.png"), + .pos = .{ + e.transform.pos[0] + (e.transform.size[0] / 2.0), + e.transform.pos[1] + (e.transform.size[1] / 2.0), }, }, + component.Velocity{ + .value = .{ 200, 0 }, + }, + component.Material{ .style = .{ + .textured = try res.textures.load("src/assets/textures/projectile.png"), + } }, component.Projectile{}, }); diff --git a/src/system/inputs.zig b/src/system/inputs.zig index 250f4cb..541aa69 100644 --- a/src/system/inputs.zig +++ b/src/system/inputs.zig @@ -28,12 +28,12 @@ pub fn pollEvents(ctx: App.scheduler.Context) !void { var query = ctx.app.world.query(struct { player: *component.Player, velocity: *component.Velocity, + speed: *component.Speed, }, .{}); while (query.next()) |e| { - const speed: f32 = 100.0; - if (keyboard[sdl.SDL_SCANCODE_W]) e.velocity.value[1] = -speed; - if (keyboard[sdl.SDL_SCANCODE_S]) e.velocity.value[1] = speed; - if (keyboard[sdl.SDL_SCANCODE_A]) e.velocity.value[0] = -speed; - if (keyboard[sdl.SDL_SCANCODE_D]) e.velocity.value[0] = speed; + if (keyboard[sdl.SDL_SCANCODE_W]) e.velocity.value[1] = -e.speed.value; + if (keyboard[sdl.SDL_SCANCODE_S]) e.velocity.value[1] = e.speed.value; + if (keyboard[sdl.SDL_SCANCODE_A]) e.velocity.value[0] = -e.speed.value; + if (keyboard[sdl.SDL_SCANCODE_D]) e.velocity.value[0] = e.speed.value; } } diff --git a/src/system/root.zig b/src/system/root.zig index 9ef80d5..97290a4 100644 --- a/src/system/root.zig +++ b/src/system/root.zig @@ -2,3 +2,4 @@ pub const core = @import("core.zig"); pub const frame = @import("frame.zig"); pub const inputs = @import("inputs.zig"); pub const draw = @import("draw.zig"); +pub const ai = @import("ai.zig");