From c4d8770e25f40a8ecff757cbfb5eebb7097cdce8 Mon Sep 17 00:00:00 2001 From: abux Date: Mon, 13 Jul 2026 19:37:50 +0100 Subject: [PATCH] Added proper damage n stuff | TODO: Clean this shit up --- build.zig.zon | 8 +-- src/component/aabb.zig | 2 + src/component/caster.zig | 2 +- src/component/health.zig | 2 +- src/component/projectile.zig | 2 + src/component/root.zig | 3 + src/event/collision.zig | 2 + src/event/root.zig | 1 + src/event/take_damage.zig | 5 +- src/plugin/default.zig | 3 + src/system/ai.zig | 14 ++-- src/system/core.zig | 1 + src/system/frame.zig | 130 ++++++++++++++++++++++++++++++++++- 13 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 src/component/aabb.zig create mode 100644 src/event/collision.zig diff --git a/build.zig.zon b/build.zig.zon index 66435f3..12ebd13 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,12 +9,12 @@ .dependencies = .{ .app = .{ - .url = "git+http://2.120.146.66:25569/abux/NYXA.git#7b8b2833a9047969031bb9a179abad0115c2ca07", - .hash = "app-0.0.0-AOV9_Q_ZAADKe6v7NIwmnTpQR3Yup9j-NUc1OM522R-7", + .url = "git+http://2.120.146.66:25569/abux/NYXA.git#3dec2867e5071dadc11f0a2c9160bcb35832926a", + .hash = "app-0.0.0-AOV9_RHcAAClVi83nkW3iGxlHNCqIhJ-McIKmzv4UYGZ", }, .gtl = .{ - .url = "git+http://2.120.146.66:25569/abux/GTL.git#b87f315b57788ee81af592fc85532f751951966d", - .hash = "gtl-0.0.0-e3QoJJZIAAB7ni5BsH4mVVuBkVfEbJ4lPNb38Dlm-kUg", + .url = "git+http://2.120.146.66:25569/abux/GTL.git#7e1f1c5e4a732b714839a2405b5e7deced39e131", + .hash = "gtl-0.0.0-e3QoJDJWAACRWynLlOqI_e9n6oHu1SIEgel-CcyrX8ez", }, }, diff --git a/src/component/aabb.zig b/src/component/aabb.zig new file mode 100644 index 0000000..fee66d7 --- /dev/null +++ b/src/component/aabb.zig @@ -0,0 +1,2 @@ +offset: @Vector(2, f32) = .{ 0, 0 }, +size: @Vector(2, f32) = .{ 32, 32 }, diff --git a/src/component/caster.zig b/src/component/caster.zig index e71afa8..601fb96 100644 --- a/src/component/caster.zig +++ b/src/component/caster.zig @@ -1,2 +1,2 @@ -cooldown: f32 = 1.2, +cooldown: f32 = 0.8, current_cooldown: f32 = 0.0, diff --git a/src/component/health.zig b/src/component/health.zig index 44ad121..531c002 100644 --- a/src/component/health.zig +++ b/src/component/health.zig @@ -1,2 +1,2 @@ max: u32 = 100, -current: u32 = 0, +current: u32 = 100, diff --git a/src/component/projectile.zig b/src/component/projectile.zig index e69de29..a3e7397 100644 --- a/src/component/projectile.zig +++ b/src/component/projectile.zig @@ -0,0 +1,2 @@ +owner: u64, +damage: u32 = 10, diff --git a/src/component/root.zig b/src/component/root.zig index 627ecb9..d1aea16 100644 --- a/src/component/root.zig +++ b/src/component/root.zig @@ -9,6 +9,9 @@ pub const Material = @import("material.zig"); pub const Animate = @import("animate.zig"); pub const Text = @import("text.zig"); +// --- INTERACTION --- +pub const AABB = @import("aabb.zig"); + // --- LIFETIME --- pub const Health = @import("health.zig"); diff --git a/src/event/collision.zig b/src/event/collision.zig new file mode 100644 index 0000000..13ee1b4 --- /dev/null +++ b/src/event/collision.zig @@ -0,0 +1,2 @@ +a: u64, +b: u64, diff --git a/src/event/root.zig b/src/event/root.zig index 82ef2dd..894e630 100644 --- a/src/event/root.zig +++ b/src/event/root.zig @@ -1 +1,2 @@ pub const TakeDamage = @import("take_damage.zig"); +pub const Collision = @import("collision.zig"); diff --git a/src/event/take_damage.zig b/src/event/take_damage.zig index 735e002..cc68358 100644 --- a/src/event/take_damage.zig +++ b/src/event/take_damage.zig @@ -1,2 +1,3 @@ -entity: u32, -value: u32, +target: u64, +source: u64, +amount: u32, diff --git a/src/plugin/default.zig b/src/plugin/default.zig index af1ed7d..cbd38b6 100644 --- a/src/plugin/default.zig +++ b/src/plugin/default.zig @@ -28,6 +28,9 @@ fn build( // --- UPDATE --- try ctx.app.schedules.add(App.stage.inputs, system.inputs.pollEvents); try ctx.app.schedules.addMany(App.stage.update, &.{ + system.frame.checkAABB, + system.frame.resolveCollisions, + system.frame.resolveHealth, system.frame.updateTimers, system.frame.updateTransforms, system.frame.cast, diff --git a/src/system/ai.zig b/src/system/ai.zig index 13eda83..ba14c50 100644 --- a/src/system/ai.zig +++ b/src/system/ai.zig @@ -33,9 +33,17 @@ pub fn spawn(ctx: App.scheduler.Context) !void { if (res.game.current_wave_time >= 0) return; + // --- DRAW SIZE --- + const size: f32 = @floatFromInt(res.io.rng.intRangeAtMost( + i32, + 16, + 64, + )); + // --- SPAWN --- for (0..@intCast(res.game.next_wave_enemy_count)) |_| { try ctx.app.world.spawn(.{ + component.Health{}, component.AI{ .target_to_chase = target orelse return, }, @@ -44,11 +52,9 @@ pub fn spawn(ctx: App.scheduler.Context) !void { @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 }; - }, + .size = .{ size, size }, }, + component.AABB{ .size = .{ size, size } }, component.Velocity{}, component.Friction{}, component.Speed{ .value = 200 }, diff --git a/src/system/core.zig b/src/system/core.zig index f56e1f1..facd23c 100644 --- a/src/system/core.zig +++ b/src/system/core.zig @@ -66,6 +66,7 @@ pub fn init(ctx: App.scheduler.Context) !void { component.Player{}, component.Caster{}, component.Speed{}, + component.AABB{}, component.Friction{}, component.Velocity{}, diff --git a/src/system/frame.zig b/src/system/frame.zig index fb9c33a..f9a7e50 100644 --- a/src/system/frame.zig +++ b/src/system/frame.zig @@ -5,6 +5,7 @@ const App = @import("app"); const component = @import("../component/root.zig"); const resource = @import("../resource/root.zig"); +const event = @import("../event/root.zig"); /// ---------------------------------------------------- /// ---------------------------------------------------- @@ -214,13 +215,16 @@ pub fn cast(ctx: App.scheduler.Context) !void { e.transform.pos[1] + (e.transform.size[1] / 2.0), }, }, + component.AABB{}, component.Velocity{ - .value = .{ 200, 0 }, + .value = .{ 600, 0 }, }, component.Material{ .style = .{ .textured = try res.textures.load("src/assets/textures/projectile.png"), } }, - component.Projectile{}, + component.Projectile{ + .owner = query.entity(), + }, }); // --- SET COOLDOWN --- @@ -228,3 +232,125 @@ pub fn cast(ctx: App.scheduler.Context) !void { e.caster.cooldown; } } + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn resolveHealth(ctx: App.scheduler.Context) !void { + if (ctx.app.events.get(event.TakeDamage)) |queue| { + for (queue.items()) |take_dmg| { + const health = ctx.app.world.getComponent(component.Health, take_dmg.target) orelse continue; + if (health.current <= 0) continue; + health.current -= take_dmg.amount; + + std.debug.print("{s}[TAKE_DAMAGE]{s} source({}) target({}) amount({})\n", .{ + gtl.ansi.red, + gtl.ansi.reset, + take_dmg.source, + take_dmg.target, + take_dmg.amount, + }); + } + queue.clear(); + } + + var query = ctx.app.world.query(struct { + health: *component.Health, + }, .{}); + while (query.next()) |e| { + if (e.health.current <= 0) { + ctx.app.world.despawn(query.entity()); + } + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn resolveCollisions(ctx: App.scheduler.Context) !void { + if (ctx.app.events.get(event.Collision)) |queue| { + for (queue.items()) |coll| { + const proj_a = ctx.app.world.getComponent(component.Projectile, coll.a); + const proj_b = ctx.app.world.getComponent(component.Projectile, coll.b); + + if (proj_a) |projectile| { + if (projectile.owner != coll.b and + ctx.app.world.hasComponent(component.Health, coll.b)) + { + try ctx.app.events.send(event.TakeDamage{ + .target = coll.b, + .source = coll.a, + .amount = projectile.damage, + }); + + ctx.app.world.despawn(coll.a); + } + } + + if (proj_b) |projectile| { + if (projectile.owner != coll.a and + ctx.app.world.hasComponent(component.Health, coll.a)) + { + try ctx.app.events.send(event.TakeDamage{ + .target = coll.a, + .source = coll.b, + .amount = projectile.damage, + }); + + ctx.app.world.despawn(coll.b); + } + } + } + + queue.clear(); + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn checkAABB(ctx: App.scheduler.Context) !void { + var outer = ctx.app.world.query(struct { + aabb: *component.AABB, + transform: *component.Transform, + }, .{}); + + while (outer.next()) |a| { + const entity_a = outer.entity(); + + var inner = ctx.app.world.query(struct { + aabb: *component.AABB, + transform: *component.Transform, + }, .{}); + + while (inner.next()) |b| { + const entity_b = inner.entity(); + + // --- PREVENT SAME ENTITY --- + if (entity_a == entity_b) + continue; + + // --- CHECK IF OVERLAPS --- + if (overlaps( + a.transform.pos, + a.aabb, + b.transform.pos, + b.aabb, + )) { + try ctx.app.events.send(event.Collision{ + .a = entity_a, + .b = entity_b, + }); + } + } + } +} + +fn overlaps( + a_pos: @Vector(2, f32), + a: *component.AABB, + b_pos: @Vector(2, f32), + b: *component.AABB, +) bool { + return a_pos[0] + a.offset[0] < b_pos[0] + b.offset[0] + b.size[0] and + a_pos[0] + a.offset[0] + a.size[0] > b_pos[0] + b.offset[0] and + a_pos[1] + a.offset[1] < b_pos[1] + b.offset[1] + b.size[1] and + a_pos[1] + a.offset[1] + a.size[1] > b_pos[1] + b.offset[1]; +}