Added basic game stage | Animations, ig?

This commit is contained in:
abux 2026-07-13 13:13:17 +01:00
parent c8a735314e
commit d149a61f46
26 changed files with 293 additions and 31 deletions

View file

@ -9,8 +9,8 @@
.dependencies = .{ .dependencies = .{
.app = .{ .app = .{
.url = "git+http://2.120.146.66:25569/abux/NYXA.git#4113f667319559c6bddb83c89042deb54e63b3de", .url = "git+http://2.120.146.66:25569/abux/NYXA.git#7b8b2833a9047969031bb9a179abad0115c2ca07",
.hash = "app-0.0.0-AOV9_eK_AAA4ZmEGkvsFUM2xMTb0lYbzq4vSShMRnKZj", .hash = "app-0.0.0-AOV9_Q_ZAADKe6v7NIwmnTpQR3Yup9j-NUc1OM522R-7",
}, },
.gtl = .{ .gtl = .{
.url = "git+http://2.120.146.66:25569/abux/GTL.git#b87f315b57788ee81af592fc85532f751951966d", .url = "git+http://2.120.146.66:25569/abux/GTL.git#b87f315b57788ee81af592fc85532f751951966d",

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

1
src/component/ai.zig Normal file
View file

@ -0,0 +1 @@
target_to_chase: u64,

View file

@ -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,

View file

@ -1,2 +1,2 @@
cooldown: f32 = 0.2, cooldown: f32 = 1.2,
current_cooldown: f32 = 0.0, current_cooldown: f32 = 0.0,

2
src/component/health.zig Normal file
View file

@ -0,0 +1,2 @@
max: u32 = 100,
current: u32 = 0,

View file

@ -2,9 +2,18 @@
pub const Transform = @import("transform.zig"); pub const Transform = @import("transform.zig");
pub const Velocity = @import("velocity.zig"); pub const Velocity = @import("velocity.zig");
pub const Friction = @import("friction.zig"); pub const Friction = @import("friction.zig");
pub const Speed = @import("speed.zig");
// --- STYLE --- // --- STYLE ---
pub const Material = @import("material.zig"); 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 --- // --- CAMERA ---
pub const Camera = @import("camera.zig"); pub const Camera = @import("camera.zig");

1
src/component/speed.zig Normal file
View file

@ -0,0 +1 @@
value: f32 = 100.0,

5
src/component/text.zig Normal file
View file

@ -0,0 +1,5 @@
const Handle = @import("gtl").Handle;
const Font = @import("../resource/fonts.zig").Font;
content: []const u8 = "Hello World!",
font: Handle(Font),

View file

@ -0,0 +1 @@
pub const TakeDamage = @import("take_damage.zig");

View file

@ -0,0 +1,2 @@
entity: u32,
value: u32,

View file

@ -17,6 +17,15 @@ pub fn main(init: std.process.Init) !void {
try app.schedules.run(App.stage.init, .{ .app = &app }); try app.schedules.run(App.stage.init, .{ .app = &app });
defer app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable; 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 { // errdefer {
// app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable; // app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable;
// } // }

View file

@ -31,6 +31,8 @@ fn build(
system.frame.updateTimers, system.frame.updateTimers,
system.frame.updateTransforms, system.frame.updateTransforms,
system.frame.cast, system.frame.cast,
system.ai.spawn,
system.ai.chaseTarget,
}); });
try ctx.app.schedules.add(App.stage.draw, system.draw.draw); try ctx.app.schedules.add(App.stage.draw, system.draw.draw);
} }

64
src/resource/fonts.zig Normal file
View file

@ -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,
});
}

6
src/resource/game.zig Normal file
View file

@ -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,

5
src/resource/io.zig Normal file
View file

@ -0,0 +1,5 @@
const std = @import("std");
io: std.Io,
rng: std.Random,
prng: std.Random.DefaultPrng,

View file

@ -1,6 +1,13 @@
// --- CORE --- // --- CORE ---
pub const IO = @import("io.zig");
pub const Window = @import("window.zig"); pub const Window = @import("window.zig");
pub const Renderer = @import("renderer.zig"); pub const Renderer = @import("renderer.zig");
pub const Frame = @import("frame.zig"); pub const Frame = @import("frame.zig");
pub const Time = @import("time.zig"); pub const Time = @import("time.zig");
// --- ASSETS ---
pub const Fonts = @import("fonts.zig");
pub const Textures = @import("textures.zig"); pub const Textures = @import("textures.zig");
// --- GAME ---
pub const Game = @import("game.zig");

View file

@ -4,12 +4,6 @@ const gtl = @import("gtl");
const sdl = @import("sdl"); const sdl = @import("sdl");
const Self = @This(); const Self = @This();
//
//
//
pub const Player = struct {};
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub const Texture = struct { id: u64 }; pub const Texture = struct { id: u64 };
@ -51,17 +45,20 @@ pub fn deinit(self: *Self) void {
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn load( pub fn load(
self: *Self, self: *Self,
comptime T: type,
path: []const u8, path: []const u8,
) !gtl.Handle(Texture) { ) !gtl.Handle(Texture) {
// --- ID --- // --- ID ---
const id = gtl.TypeID(T); const id = std.hash.Wyhash.hash(
6969,
path,
);
// --- # --- // --- # ---
if (self.data.getHandle(.{ .id = id })) |h| { if (self.data.getHandle(.{ .id = id })) |h| {
return h; return h;
} }
// --- # ---
return try self.data.put(.{ .id = id }, .{ return try self.data.put(.{ .id = id }, .{
.path = path, .path = path,
.raw = null, .raw = null,

View file

@ -1,5 +1,6 @@
dt: f32 = 0.0, dt: f32 = 0.0,
now: u64 = 0, now: u64 = 0,
last: u64 = 0, last: u64 = 0,
elapsed: f32 = 0.0,
frequency: u64 = 0, frequency: u64 = 0,
target_dt: f32 = 1.0 / 60.0, target_dt: f32 = 1.0 / 60.0,

110
src/system/ai.zig Normal file
View file

@ -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;
}
}
}

View file

@ -9,7 +9,7 @@ const resource = @import("../resource/root.zig");
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn init(ctx: App.scheduler.Context) !void { pub fn init(ctx: App.scheduler.Context) !void {
// --- SDL3 INIT --- // --- 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; return error.SDL_Init;
} }
@ -38,6 +38,14 @@ pub fn init(ctx: App.scheduler.Context) !void {
.frequency = sdl.SDL_GetPerformanceFrequency(), .frequency = sdl.SDL_GetPerformanceFrequency(),
}); });
try ctx.app.resources.set(resource.Frame{}); 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)); const textures = try ctx.app.resources.getOrSet(resource.Textures.init(ctx.app.alloc));
// --- DEBUG --- // --- DEBUG ---
@ -57,12 +65,13 @@ pub fn init(ctx: App.scheduler.Context) !void {
try ctx.app.world.spawn(.{ try ctx.app.world.spawn(.{
component.Player{}, component.Player{},
component.Caster{}, component.Caster{},
component.Speed{},
component.Friction{}, component.Friction{},
component.Velocity{}, component.Velocity{},
component.Transform{ .size = .{ 64, 64 } }, component.Transform{ .size = .{ 64, 64 } },
component.Material{ .style = .{ 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{}, component.CameraTarget{},
}); });
@ -83,10 +92,14 @@ pub fn deinit(ctx: App.scheduler.Context) !void {
window: *resource.Window, window: *resource.Window,
renderer: *resource.Renderer, renderer: *resource.Renderer,
textures: *resource.Textures, textures: *resource.Textures,
fonts: *resource.Fonts,
}); });
res.fonts.deinit();
res.textures.deinit(); res.textures.deinit();
sdl.SDL_DestroyRenderer(res.renderer.raw); sdl.SDL_DestroyRenderer(res.renderer.raw);
sdl.SDL_DestroyWindow(res.window.raw); sdl.SDL_DestroyWindow(res.window.raw);
sdl.TTF_Quit();
sdl.SDL_Quit(); sdl.SDL_Quit();
} }

View file

@ -12,7 +12,10 @@ pub fn draw(ctx: App.scheduler.Context) !void {
window: *resource.Window, window: *resource.Window,
renderer: *resource.Renderer, renderer: *resource.Renderer,
frame: *resource.Frame, frame: *resource.Frame,
time: *resource.Time,
textures: *resource.Textures, textures: *resource.Textures,
fonts: *resource.Fonts,
}); });
// --- SET CLEAR COLOR --- // --- SET CLEAR COLOR ---
@ -33,14 +36,27 @@ pub fn draw(ctx: App.scheduler.Context) !void {
transform: *component.Transform, transform: *component.Transform,
material: *component.Material, material: *component.Material,
camera_target: ?*component.CameraTarget, camera_target: ?*component.CameraTarget,
animate: ?*component.Animate,
text: ?*component.Text,
}, .{}); }, .{});
while (query.next()) |e| { while (query.next()) |e| {
// --- DATA ---
const camera = if (res.frame.camera) |*v| v else continue; 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 = .{ var rect: sdl.SDL_FRect = .{
.x = e.transform.pos[0] + camera.transform.pos[0], .x = draw_pos[0] + camera.transform.pos[0],
.y = e.transform.pos[1] + camera.transform.pos[1], .y = draw_pos[1] + camera.transform.pos[1],
.w = e.transform.size[0], .w = e.transform.size[0],
.h = e.transform.size[1], .h = e.transform.size[1],
}; };

View file

@ -88,7 +88,7 @@ pub fn beginFrame(ctx: App.scheduler.Context) !void {
// --- SET TEXTURE FILTER --- // --- SET TEXTURE FILTER ---
_ = sdl.SDL_SetTextureScaleMode( _ = sdl.SDL_SetTextureScaleMode(
entry.value.raw, raw,
sdl.SDL_SCALEMODE_PIXELART, sdl.SDL_SCALEMODE_PIXELART,
); );
@ -115,6 +115,7 @@ pub fn endFrame(ctx: App.scheduler.Context) !void {
}); });
res.frame.camera = null; res.frame.camera = null;
res.time.elapsed += res.time.dt;
const frame_time = const frame_time =
@as(f32, @floatFromInt(sdl.SDL_GetPerformanceCounter() - res.time.now)) / @as(f32, @floatFromInt(sdl.SDL_GetPerformanceCounter() - res.time.now)) /
@ -208,17 +209,17 @@ pub fn cast(ctx: App.scheduler.Context) !void {
// --- SPAWN PROJECTILE --- // --- SPAWN PROJECTILE ---
try ctx.app.world.spawn(.{ try ctx.app.world.spawn(.{
component.Transform{ component.Transform{
.pos = e.transform.pos, .pos = .{
}, e.transform.pos[0] + (e.transform.size[0] / 2.0),
component.Velocity{ e.transform.pos[1] + (e.transform.size[1] / 2.0),
.value = .{ 400, 0 },
},
component.Material{
.style = .{
// .solid = .{ 200, 20, 20, 255 },
.textured = try res.textures.load(resource.Textures.Player, "src/assets/textures/player.png"),
}, },
}, },
component.Velocity{
.value = .{ 200, 0 },
},
component.Material{ .style = .{
.textured = try res.textures.load("src/assets/textures/projectile.png"),
} },
component.Projectile{}, component.Projectile{},
}); });

View file

@ -28,12 +28,12 @@ pub fn pollEvents(ctx: App.scheduler.Context) !void {
var query = ctx.app.world.query(struct { var query = ctx.app.world.query(struct {
player: *component.Player, player: *component.Player,
velocity: *component.Velocity, velocity: *component.Velocity,
speed: *component.Speed,
}, .{}); }, .{});
while (query.next()) |e| { while (query.next()) |e| {
const speed: f32 = 100.0; if (keyboard[sdl.SDL_SCANCODE_W]) e.velocity.value[1] = -e.speed.value;
if (keyboard[sdl.SDL_SCANCODE_W]) e.velocity.value[1] = -speed; if (keyboard[sdl.SDL_SCANCODE_S]) e.velocity.value[1] = e.speed.value;
if (keyboard[sdl.SDL_SCANCODE_S]) e.velocity.value[1] = speed; if (keyboard[sdl.SDL_SCANCODE_A]) e.velocity.value[0] = -e.speed.value;
if (keyboard[sdl.SDL_SCANCODE_A]) e.velocity.value[0] = -speed; if (keyboard[sdl.SDL_SCANCODE_D]) e.velocity.value[0] = e.speed.value;
if (keyboard[sdl.SDL_SCANCODE_D]) e.velocity.value[0] = speed;
} }
} }

View file

@ -2,3 +2,4 @@ pub const core = @import("core.zig");
pub const frame = @import("frame.zig"); pub const frame = @import("frame.zig");
pub const inputs = @import("inputs.zig"); pub const inputs = @import("inputs.zig");
pub const draw = @import("draw.zig"); pub const draw = @import("draw.zig");
pub const ai = @import("ai.zig");