make it clear how to use module system without mach.Core (remove mach.App)

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2024-08-24 21:34:35 -07:00 committed by Stephen Gutekanst
parent 7ac5bef717
commit 642cc9b7f7
20 changed files with 567 additions and 334 deletions

View file

@ -22,6 +22,7 @@ pub const components = .{
};
pub const systems = .{
.start = .{ .handler = start },
.init = .{ .handler = init },
.deinit = .{ .handler = deinit },
.tick = .{ .handler = tick },
@ -42,6 +43,16 @@ pub fn deinit(core: *mach.Core.Mod, renderer: *Renderer.Mod) void {
core.schedule(.deinit);
}
fn start(
core: *mach.Core.Mod,
renderer: *Renderer.Mod,
app: *Mod,
) !void {
core.schedule(.init);
renderer.schedule(.init);
app.schedule(.init);
}
fn init(
// These are injected dependencies - as long as these modules were registered in the top-level
// of the program we can have these types injected here, letting us work with other modules in
@ -49,10 +60,10 @@ fn init(
entities: *mach.Entities.Mod,
core: *mach.Core.Mod,
renderer: *Renderer.Mod,
game: *Mod,
app: *Mod,
) !void {
core.schedule(.init);
renderer.schedule(.init);
core.state().on_tick = app.system(.tick);
core.state().on_exit = app.system(.deinit);
// Create our player entity.
const player = try entities.new();
@ -68,9 +79,9 @@ fn init(
try renderer.set(player, .scale, 1.0);
// Initialize our game module's state - these are the struct fields defined at the top of this
// file. If this is not done, then game.state() will panic indicating the state was never
// file. If this is not done, then app.state() will panic indicating the state was never
// initialized.
game.init(.{
app.init(.{
.timer = try mach.Timer.start(),
.spawn_timer = try mach.Timer.start(),
.player = player,
@ -83,11 +94,11 @@ fn tick(
entities: *mach.Entities.Mod,
core: *mach.Core.Mod,
renderer: *Renderer.Mod,
game: *Mod,
app: *Mod,
) !void {
var iter = core.state().pollEvents();
var direction = game.state().direction;
var spawning = game.state().spawning;
var direction = app.state().direction;
var spawning = app.state().spawning;
while (iter.next()) |event| {
switch (event) {
.key_press => |ev| {
@ -118,18 +129,18 @@ fn tick(
// Keep track of which direction we want the player to move based on input, and whether we want
// to be spawning entities.
//
// Note that game.state() simply returns a pointer to a global singleton of the struct defined
// Note that app.state() simply returns a pointer to a global singleton of the struct defined
// by this file, so we can access fields defined at the top of this file.
game.state().direction = direction;
game.state().spawning = spawning;
app.state().direction = direction;
app.state().spawning = spawning;
// Get the current player position
var player_pos = renderer.get(game.state().player, .position).?;
var player_pos = renderer.get(app.state().player, .position).?;
// If we want to spawn new entities, then spawn them now. The timer just makes spawning rate
// independent of frame rate.
if (spawning and game.state().spawn_timer.read() > 1.0 / 60.0) {
_ = game.state().spawn_timer.lap(); // Reset the timer
if (spawning and app.state().spawn_timer.read() > 1.0 / 60.0) {
_ = app.state().spawn_timer.lap(); // Reset the timer
for (0..5) |_| {
// Spawn a new entity at the same position as the player, but smaller in scale.
const new_entity = try entities.new();
@ -137,19 +148,19 @@ fn tick(
try renderer.set(new_entity, .scale, 1.0 / 6.0);
// Tag the entity as one that follows the player
try game.set(new_entity, .follower, {});
try app.set(new_entity, .follower, {});
}
}
// Multiply by delta_time to ensure that movement is the same speed regardless of the frame rate.
const delta_time = game.state().timer.lap();
const delta_time = app.state().timer.lap();
// Calculate the player position, by moving in the direction the player wants to go
// by the speed amount.
const speed = 1.0;
player_pos.v[0] += direction.x() * speed * delta_time;
player_pos.v[1] += direction.y() * speed * delta_time;
try renderer.set(game.state().player, .position, player_pos);
try renderer.set(app.state().player, .position, player_pos);
// Query all the entities that have the .follower tag indicating they should follow the player.
// TODO(important): better querying API