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 0000000..b676939 Binary files /dev/null and b/src/assets/fonts/Dynamix.ttf differ diff --git a/src/assets/textures/projectile.png b/src/assets/textures/projectile.png new file mode 100644 index 0000000..321a9bf Binary files /dev/null and b/src/assets/textures/projectile.png differ 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");