stable
Ivory 2025-02-15 06:17:46 -05:00
parent 7e0e3f7501
commit d07d2e1a40
17 changed files with 486 additions and 103 deletions

View File

@ -5,16 +5,17 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
// === [ C IMPORTS ] ===
const c = b.addModule("c", .{ const c = b.addModule("c", .{
.root_source_file = b.path("src/c.zig"), .root_source_file = b.path("src/c.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
// c.addLibraryPath(b.path("/usr/local/lib"));
c.linkSystemLibrary("SDL3", .{}); c.linkSystemLibrary("SDL3", .{});
c.addIncludePath(b.path("open-simplex/include")); c.addIncludePath(b.path("open-simplex/include"));
c.linkSystemLibrary("SDL3_image", .{}); c.linkSystemLibrary("SDL3_image", .{});
// === [ ENGINE ] ===
const engine = b.addModule("engine", .{ const engine = b.addModule("engine", .{
.root_source_file = b.path("src/engine/root.zig"), .root_source_file = b.path("src/engine/root.zig"),
.target = target, .target = target,
@ -23,14 +24,27 @@ pub fn build(b: *std.Build) void {
engine.addImport("engine", engine); engine.addImport("engine", engine);
engine.addImport("c", c); engine.addImport("c", c);
const exe = b.addExecutable(.{ // === [ GAME CODE ] ===
.name = "hadean", const hadean = b.addModule("hadean", .{
.root_source_file = b.path("src/hadean/main.zig"), .root_source_file = b.path("src/hadean/hadean.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
hadean.addImport("c", c);
hadean.addImport("engine", engine);
hadean.addImport("hadean", hadean);
// === [ EXECUTABLE ] ===
const exe = b.addExecutable(.{
.name = "hadean",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("engine", engine); exe.root_module.addImport("engine", engine);
exe.root_module.addImport("hadean", hadean);
exe.root_module.addImport("c", c); exe.root_module.addImport("c", c);
exe.addCSourceFile(.{ .file = b.path("open-simplex/src/OpenSimplex2F.c") }); exe.addCSourceFile(.{ .file = b.path("open-simplex/src/OpenSimplex2F.c") });
exe.addIncludePath(b.path("open-simplex/include")); exe.addIncludePath(b.path("open-simplex/include"));
@ -49,14 +63,28 @@ pub fn build(b: *std.Build) void {
"assets/textures.png" "assets/textures.png"
)).step); )).step);
b.installArtifact(exe); b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe); const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep()); run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| { if (b.args) |args| {
run_cmd.addArgs(args); run_cmd.addArgs(args);
} }
const run_step = b.step("run", "Run the app"); const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step); run_step.dependOn(&run_cmd.step);
const pathfinder_perf_test = b.addTest(.{
.root_source_file = b.path("src/hadean/PathFinder.zig"),
.target = target,
.optimize = optimize,
});
pathfinder_perf_test.root_module.addImport("engine", engine);
const run_pathfinder_perf_test = b.addRunArtifact(pathfinder_perf_test);
const test_step = b.step("pathfinder_perf_test", "Run PathFinder Performance Test");
test_step.dependOn(&run_pathfinder_perf_test.step);
// because engine and hadean are diff modules their c modules // because engine and hadean are diff modules their c modules
// get different caches, causing opaques to be different between them. // get different caches, causing opaques to be different between them.

View File

@ -1,52 +0,0 @@
const Pawn = @This();
const std = @import("std");
const Entity = @import("Entity.zig");
const Scene = @import("Scene.zig");
const Camera = @import("Camera.zig");
const Terrain = @import("Terrain.zig");
const Tag = @import("Tag.zig");
const Vec2i = @import("geometry/Vec2i.zig");
const assets = @import("assets.zig");
const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
var prng = std.rand.DefaultPrng.init(0);
camera: *const Camera = undefined,
position: Vec2i = Vec2i.ZERO,
pub fn random() !*Pawn {
var self: Pawn = Pawn {};
self.position = Vec2i.create(
@intFromFloat(@floor(prng.random().float(f32) * @as(f32, @floatFromInt(Terrain.CHUNK_SIZE)))),
@intFromFloat(@floor(prng.random().float(f32) * @as(f32, @floatFromInt(Terrain.CHUNK_SIZE))))
);
return try Scene.EntityPool.allocate(self);
}
pub fn create() !*Pawn {
const self: Pawn = Pawn {};
return try Scene.allocate(self);
}
pub fn start(self: *Pawn, scene: *const Scene) void {
self.camera = scene.get(Camera.TAG, Camera);
}
pub fn destroy(self: *const Pawn) void {
Scene.EntityPool.deallocate(self);
}
pub fn entity(self: *Pawn) Entity {
return Entity.init(self, .{});
}
// pub fn tile(self: *Pawn) Tile {
// return Tile.init(.{
// .solid = true
// });
// }
pub fn draw(self: *const Pawn) void {
self.camera.draw_sprite_i(assets.pawn, self.position.to_unit_recti(), Layer.ENTITIES, Color.WHITE);
}

View File

@ -3,8 +3,8 @@ const c = @import("c");
const engine = @import("engine"); const engine = @import("engine");
const Control = engine.Control; const Control = engine.Control;
pub const camera = true; pub var camera = true;
pub const mouse = true; pub var mouse = true;
// later make this expandable in some way using an allocator. // later make this expandable in some way using an allocator.

View File

@ -34,11 +34,21 @@ pub fn create(renderer: *c.SDL_Renderer, path: []const u8) Texture {
// @panic("Failed to create IO for Texture"); // @panic("Failed to create IO for Texture");
// }; // };
// c.IMG_Load() // c.IMG_Load()
const surface: *c.SDL_Surface = c.IMG_Load(new_path) orelse { var surface: *c.SDL_Surface = c.IMG_Load(new_path) orelse {
std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() }); std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() });
@panic("Failed to create Surface for Texture"); @panic("Failed to create Surface for Texture");
}; };
const keys = [_]u32 { 0xFFFF00FF, 0xFF0000FF, };
for (keys) |key| {
_ = c.SDL_SetSurfaceColorKey(surface, true, key);
const new_surface: *c.SDL_Surface = c.SDL_CreateSurface(surface.w, surface.h, surface.format);
_ = c.SDL_BlitSurface(surface, null, new_surface, null);
c.SDL_DestroySurface(surface);
surface = new_surface;
}
defer c.SDL_DestroySurface(surface); defer c.SDL_DestroySurface(surface);
const texture = c.SDL_CreateTextureFromSurface(renderer, surface) orelse { const texture = c.SDL_CreateTextureFromSurface(renderer, surface) orelse {
std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() }); std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() });
@panic("Failed to create Texture"); @panic("Failed to create Texture");

View File

@ -96,6 +96,15 @@ pub fn to_vec2f(self: *const Vec2i) Vec2f {
}; };
} }
pub fn distance_from(self: Vec2i, other: Vec2i) f32 {
const x: f32 = @floatFromInt(@abs(self.x - other.x));
const y: f32 = @floatFromInt(@abs(self.y - other.y));
return @sqrt(x * x + y * y);
}
pub fn eql(self: Vec2i, other: Vec2i) bool {
return self.x == other.x and self.y == other.y;
}
pub const ZERO = create(0, 0); pub const ZERO = create(0, 0);
pub const ONE = create(1, 1); pub const ONE = create(1, 1);

View File

@ -0,0 +1,272 @@
const engine = @import("engine");
const std = @import("std");
const Vec2i = engine.geometry.Vec2i;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator;
const ArrayListUnmanaged = std.ArrayListUnmanaged;
var gpa = GeneralPurposeAllocator(.{}) {};
var nodes_arena = ArenaAllocator.init(gpa.allocator());
pub const Surface = struct {
const VTable = struct {
_is_pathable: *const fn (*const anyopaque, Vec2i) bool,
_is_valid: *const fn (*const anyopaque, Vec2i) bool,
};
ptr: *const anyopaque,
vtable: VTable,
fn InputFunctions(comptime T: type) type {
return struct {
_is_pathable: fn (T, Vec2i) bool,
_is_valid: fn (T, Vec2i) bool,
};
}
pub fn from(impl: anytype, functions: InputFunctions(@TypeOf(impl))) Surface {
const PtrType = @TypeOf(impl);
const gen = struct {
pub fn _is_pathable(ptr: *const anyopaque, pos: Vec2i) bool {
const self: PtrType = @ptrCast(@alignCast(ptr));
return functions._is_pathable(self, pos);
}
pub fn _is_valid(ptr: *const anyopaque, pos: Vec2i) bool {
const self: PtrType = @ptrCast(@alignCast(ptr));
return functions._is_valid(self, pos);
}
};
return Surface {
.ptr = impl,
.vtable = .{
._is_valid = gen._is_valid,
._is_pathable = gen._is_pathable,
}
};
}
pub fn is_valid(self: Surface, pos: Vec2i) bool {
return self.vtable._is_valid(self.ptr, pos);
}
pub fn is_pathable(self: Surface, pos: Vec2i) bool {
return self.vtable._is_pathable(self.ptr, pos);
}
};
const Node = struct {
pos: Vec2i,
g: u32,
h: u32,
parent: ?*Node,
pub const HeapContext = struct {};
pub fn compare(_: HeapContext, a: *const Node, b: *const Node) std.math.Order {
if (a.cost() < b.cost()) return std.math.Order.lt;
if (a.cost() > b.cost()) return std.math.Order.gt;
return std.math.Order.eq;
}
pub fn get_key(self: *const Node) Vec2i {
return self.pos;
}
pub fn to_vec2i(self: Node) Vec2i {
return Vec2i { .x = self.x, .y = self.y };
}
pub fn cost(self: Node) u32 {
return self.g + self.h;
}
pub fn asc(self: *const Node, other: *const Node) bool {
return self.cost() < other.cost();
}
};
fn heuristic(src: Vec2i, dst: Vec2i) u32 {
return @intFromFloat(@floor(src.distance_from(dst) * 10.0));
}
fn get_neighbor_positions(from: Vec2i) [4]Vec2i {
return .{
from.add(Vec2i.NORTH),
from.add(Vec2i.EAST),
from.add(Vec2i.SOUTH),
from.add(Vec2i.WEST),
};
}
// this function ONLY works for adjacent / diagonal positions
fn get_cost_between(src: Vec2i, dst: Vec2i) u32 {
if (src.x == dst.x or src.y == dst.y) return 10;
return 14;
}
fn HashedPriorityQueue(
comptime K: type,
comptime V: type,
comptime PriorityContext: type,
comptime compare_fn: fn (context: PriorityContext, V, V) std.math.Order,
comptime value_to_key: fn (V) K,
) type {
return struct {
const Self = @This();
priority_queue: std.PriorityQueue(V, PriorityContext, compare_fn),
hash_map: std.AutoHashMap(K, V),
pub fn init(allocator: Allocator) Self {
return Self {
.priority_queue = std.PriorityQueue(V, PriorityContext, compare_fn).init(allocator, .{}),
.hash_map = std.AutoHashMap(K, V).init(allocator),
};
}
pub fn put(self: *Self, key: K, value: V) !void {
try self.hash_map.put(key, value);
try self.priority_queue.add(value);
}
pub fn contains_key(self: Self, key: K) bool {
return self.hash_map.contains(key);
}
pub fn pop(self: *Self) V {
const value: V = self.priority_queue.remove();
const key = value_to_key(value);
_ = self.hash_map.remove(key);
return value;
}
pub fn get(self: Self, key: K) ?V {
return self.hash_map.get(key);
}
pub fn count(self: Self) usize {
return self.priority_queue.items.len;
}
};
}
pub fn get_path(return_allocator: Allocator, surface: Surface, src: Vec2i, dst: Vec2i) !?[]Vec2i {
// std.debug.print("pathfinding ({}, {}) => ({}, {})\n", .{ src.x, src.y, dst.x, dst.y });
defer _ = nodes_arena.reset(.retain_capacity);
const allocator = nodes_arena.allocator();
var open = HashedPriorityQueue(Vec2i, *Node, Node.HeapContext, Node.compare, Node.get_key).init(allocator);
var pos_lookup_table = std.AutoHashMap(Vec2i, *Node).init(allocator);
var closed = std.AutoHashMap(Vec2i, *Node).init(allocator);
const starting_node: *Node = try allocator.create(Node);
starting_node.* = Node {
.pos = src,
.g = 0,
.h = heuristic(src, dst),
.parent = null,
};
try pos_lookup_table.put(src, starting_node);
try open.put(starting_node.pos, starting_node);
while(open.count() != 0) {
const current_node: *Node = open.pop();
try closed.put(current_node.pos, current_node);
if (current_node.pos.eql(dst)) {
var reverse_path = std.ArrayList(*Node).init(allocator);
var walk_node: *Node = current_node;
while (walk_node.parent != null) {
try reverse_path.append(walk_node);
walk_node = walk_node.parent.?;
}
var path = std.ArrayList(Vec2i).init(return_allocator);
for (0..reverse_path.items.len) |rev_idx| {
const idx = reverse_path.items.len - 1 - rev_idx;
try path.append(reverse_path.items[idx].*.pos);
}
return try path.toOwnedSlice();
}
const neighbor_positions = get_neighbor_positions(current_node.pos);
for (neighbor_positions) |pos| {
if (pos.eql(current_node.pos)) continue;
if (!surface.is_valid(pos)) continue;
if (!surface.is_pathable(pos)) continue;
// the new g cost of this node is the g cost of the parent node + the g
// cost from the parent node, to this node.
const gCost: u32 = current_node.g + get_cost_between(current_node.pos, pos);
if (pos_lookup_table.contains(pos)) {
const known_node: *Node = pos_lookup_table.get(pos) orelse unreachable;
if (gCost < known_node.g) {
known_node.*.g = gCost;
known_node.*.parent = current_node;
if(closed.contains(pos)) _ = closed.remove(pos);
if(!open.contains_key(pos)) try open.put(pos, known_node);
}
} else {
const hCost: u32 = heuristic(pos, dst);
const new_node: *Node = try allocator.create(Node);
new_node.* = Node {
.pos = pos,
.g = gCost,
.h = hCost,
.parent = current_node,
};
try pos_lookup_table.put(pos, new_node);
try open.put(pos, new_node);
}
}
}
return null;
}
test "PathFinder" {
var test_gpa = std.heap.GeneralPurposeAllocator(.{}) {};
var allocator = test_gpa.allocator();
const Terrain = struct {
const Terrain = @This();
pub fn is_pathable(self: *const Terrain, pos: Vec2i) bool {
return Terrain.is_valid(self, pos);
}
pub fn is_valid(self: *const Terrain, pos: Vec2i) bool {
_ = self;
return pos.x >= 0 and pos.x < 100 and pos.y >= 0 and pos.y < 100;
}
};
const terrain = Terrain {};
const surface: Surface = Surface.from(&terrain, .{
._is_pathable = Terrain.is_pathable,
._is_valid = Terrain.is_valid,
});
const start: std.time.Instant = try std.time.Instant.now();
const iterations = 1000;
for (0..iterations) |_| {
const path: []Vec2i = try get_path(allocator, surface, Vec2i.ZERO, Vec2i.ONE.scale(40)) orelse continue;
allocator.free(path);
}
const end = try std.time.Instant.now();
const elapsed: f32 = @floatFromInt(end.since(start));
const average: f32 = elapsed / @as(f32, @floatFromInt(iterations));
const ms: f32 = average / 1_000_000.0;
std.debug.print("average path time: {d:.2}ms\n", .{ ms });
try std.testing.expect(true);
}

View File

View File

View File

@ -156,6 +156,7 @@ pub fn set_focus(self: *Camera, f: Vec2f) void {
pub fn mouse_properties(_: *const Camera) MouseListener.Properties { pub fn mouse_properties(_: *const Camera) MouseListener.Properties {
return MouseListener.Properties { return MouseListener.Properties {
.area = Recti.from_xywh(0, 0, engine.Control.window_width, engine.Control.window_height), .area = Recti.from_xywh(0, 0, engine.Control.window_width, engine.Control.window_height),
// .area = Recti.from_xywh(100, 100, 100, 100),
.layer = .CAMERA, .layer = .CAMERA,
.button = .Middle, .button = .Middle,
.click_through = true, .click_through = true,

View File

View File

@ -0,0 +1,69 @@
const Pawn = @This();
const std = @import("std");
const engine = @import("engine");
const hadean = @import("hadean");
const Camera = hadean.entities.Camera;
const Layer = engine.Layer;
const Color = engine.Color;
const Terrain = hadean.entities.Terrain;
const Chunk = hadean.entities.Terrain.Chunk;
const assets = hadean.assets;
const Vec2i = engine.geometry.Vec2i;
const Allocator = std.mem.Allocator;
const Tag = engine.Tag;
const Scene = engine.Scene;
var prng = std.rand.DefaultPrng.init(0);
camera: *const Camera = undefined,
terrain: *const Terrain = undefined,
scene: *const Scene = undefined,
pos: Vec2i = Vec2i.ZERO,
randomize_position_on_start: bool = true,
current_path: ?[]Vec2i = null,
pub fn random(allocator: Allocator) !*Pawn {
const self: *Pawn = try allocator.create(Pawn);
self.* = .{};
return self;
}
pub fn start(self: *Pawn, scene: *const Scene) void {
self.scene = scene;
self.camera = scene.get(Tag.CAMERA, Camera);
self.terrain = scene.get(Tag.TERRAIN, Terrain);
if (self.randomize_position_on_start) {
const chunk: *const Chunk = self.terrain.get_random_chunk();
const pos: Vec2i = chunk.get_random_pos_absolute();
self.pos = pos;
}
}
pub fn update(self: *Pawn, _: f32) void {
const dst = self.terrain.get_random_chunk().get_random_pos_absolute();
const surface = self.terrain.surface();
const allocator = self.scene.arena.allocator();
const new_path = hadean.PathFinder.get_path(allocator, surface, self.pos, dst)
catch unreachable
orelse unreachable;
defer allocator.free(new_path);
}
pub fn draw(self: *const Pawn, layer: Layer) void {
switch(layer) {
.ENTITIES => {
self.camera.draw_sprite_i(assets.pawn, self.pos.to_unit_recti(), Color.WHITE);
},
else => {},
}
}
fn set_path(self: *Pawn, path: []Vec2i) void {
if (self.current_path != null) self.scene.arena.allocator().destroy(self.current_path);
self.current_path = path;
}

View File

@ -3,6 +3,7 @@ const Terrain = @This();
const engine = @import("engine"); const engine = @import("engine");
const std = @import("std"); const std = @import("std");
const c = @import("c"); const c = @import("c");
const hadean = @import("hadean");
const Scene = engine.Scene; const Scene = engine.Scene;
const Entity = engine.Entity; const Entity = engine.Entity;
const Vec2i = engine.geometry.Vec2i; const Vec2i = engine.geometry.Vec2i;
@ -12,11 +13,11 @@ const Recti = engine.geometry.Recti;
const Noise = engine.Noise; const Noise = engine.Noise;
const Layer = engine.Layer; const Layer = engine.Layer;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Camera = hadean.entities.Camera;
const assets = hadean.assets;
var prng = std.rand.DefaultPrng.init(0); var prng = std.rand.DefaultPrng.init(0);
const Camera = @import("Camera.zig");
const assets = @import("assets.zig");
// pub const CHUNK_SIZE = 48; // pub const CHUNK_SIZE = 48;
pub const CHUNK_SIZE = 24; pub const CHUNK_SIZE = 24;
@ -47,8 +48,11 @@ pub fn start(self: *Terrain, scene: *Scene) void {
self.camera.set_focus(Vec2f.create(CHUNK_SIZE / 2, CHUNK_SIZE / 2)); self.camera.set_focus(Vec2f.create(CHUNK_SIZE / 2, CHUNK_SIZE / 2));
self.scene = scene; self.scene = scene;
self.gen_chunk(Vec2i { .x = 0, .y = 0 }) catch @panic("OOM"); for (0..3) |x| {
self.gen_chunk(Vec2i { .x = -1, .y = 0 }) catch @panic("OOM"); for (0..3) |y| {
self.gen_chunk(Vec2i { .x = @as(i32, @intCast(x)) - 1, .y = @as(i32, @intCast(y)) - 1 }) catch @panic("OOM");
}
}
// for (self.chunks.items) |chunk| scene.add(Entity.from(chunk, .{})) catch unreachable; // for (self.chunks.items) |chunk| scene.add(Entity.from(chunk, .{})) catch unreachable;
} }
@ -75,6 +79,10 @@ fn gen_chunk(self: *Terrain, chunk_pos: Vec2i) !void {
try self.scene.add(Entity.from(chunk, .{})); try self.scene.add(Entity.from(chunk, .{}));
} }
pub fn get_random_chunk(self: *const Terrain) *const Chunk {
const idx = prng.random().uintAtMost(usize, self.chunks.items.len - 1);
return self.chunks.items[idx];
}
pub fn destroy(self: *const Terrain) void { pub fn destroy(self: *const Terrain) void {
self.generator.destroy(); self.generator.destroy();
@ -82,6 +90,24 @@ pub fn destroy(self: *const Terrain) void {
// Scene.EntityPool.deallocate(self); // Scene.EntityPool.deallocate(self);
} }
const Surface = struct {
pub fn is_pathable(self: *const Terrain, pos: Vec2i) bool {
return Surface.is_valid(self, pos);
}
pub fn is_valid(self: *const Terrain, pos: Vec2i) bool {
_ = self;
return pos.x >= -24 and pos.x < 48 and pos.y >= -24 and pos.y < 48;
}
};
pub fn surface(self: *const Terrain) hadean.PathFinder.Surface {
return hadean.PathFinder.Surface.from(self, .{
._is_pathable = Surface.is_pathable,
._is_valid = Surface.is_valid,
});
}
// fn chance(percent: f32) bool { // fn chance(percent: f32) bool {
// return prng.random().float(f32) < percent; // return prng.random().float(f32) < percent;
// } // }
@ -140,7 +166,7 @@ pub fn destroy(self: *const Terrain) void {
// } // }
// } // }
const Chunk = struct { pub const Chunk = struct {
pub const Tile = struct { pub const Tile = struct {
texture_idx: usize, texture_idx: usize,
growth: f32, growth: f32,
@ -193,7 +219,7 @@ const Chunk = struct {
fn generate_tiles(self: *Chunk, generator: *const WorldGenerator) void { fn generate_tiles(self: *Chunk, generator: *const WorldGenerator) void {
for(0..CHUNK_LENGTH) |idx| { for(0..CHUNK_LENGTH) |idx| {
const x, const y = index_to_xy(@intCast(idx)); const x, const y = index_to_xy(@intCast(idx));
const abs_pos = self.chunk_pos.add(Vec2i.create(x, y)); const abs_pos = self.chunk_pos.add(Vec2i.create(x, y).add(self.chunk_pos.scale(CHUNK_SIZE)));
const tile = generator.gen_tile(abs_pos); const tile = generator.gen_tile(abs_pos);
self.tiles[idx] = tile; self.tiles[idx] = tile;
@ -212,15 +238,15 @@ const Chunk = struct {
const x, const y = index_to_xy(@intCast(idx)); const x, const y = index_to_xy(@intCast(idx));
const rect = Recti.from_xywh(x + chunk_offset_x, y + chunk_offset_y, 1, 1); const rect = Recti.from_xywh(x + chunk_offset_x, y + chunk_offset_y, 1, 1);
const sprite = assets.terrain[0][tile.texture_idx]; const sprite = assets.terrain[0][tile.texture_idx];
// self.camera.draw_sprite_i(sprite, rect, tile.grass_color); self.camera.draw_sprite_i(sprite, rect, tile.grass_color);
switch(tile.texture_idx) { // switch(tile.texture_idx) {
0 => self.camera.draw_sprite_i(sprite, rect, Color.WHITE), // 0 => self.camera.draw_sprite_i(sprite, rect, Color.WHITE),
1 => self.camera.draw_sprite_i(sprite, rect, Color.RED), // 1 => self.camera.draw_sprite_i(sprite, rect, Color.RED),
2 => self.camera.draw_sprite_i(sprite, rect, Color.GREEN), // 2 => self.camera.draw_sprite_i(sprite, rect, Color.GREEN),
3 => self.camera.draw_sprite_i(sprite, rect, Color.BLUE), // 3 => self.camera.draw_sprite_i(sprite, rect, Color.BLUE),
else => {} // else => {}
} // }
} }
}, },
else => {}, else => {},
@ -237,6 +263,14 @@ const Chunk = struct {
const x: i32 = @rem(index, CHUNK_SIZE); const x: i32 = @rem(index, CHUNK_SIZE);
return .{ x, y }; return .{ x, y };
} }
pub fn get_random_pos_absolute(self: *const Chunk) Vec2i {
return Vec2i.create(
prng.random().intRangeAtMost(i32, 0, Terrain.CHUNK_SIZE - 1),
prng.random().intRangeAtMost(i32, 0, Terrain.CHUNK_SIZE - 1)
).add(self.chunk_pos.scale(Terrain.CHUNK_SIZE));
}
}; };

View File

@ -0,0 +1,14 @@
pub const assets = @import("assets.zig");
pub const scenes = @import("scenes.zig");
pub const entities = struct {
pub const Terrain = @import("entities/Terrain.zig");
pub const Chunk = @import("entities/Chunk.zig");
pub const Camera = @import("entities/Camera.zig");
pub const Pawn = @import("entities/Pawn.zig");
pub const Selection = @import("entities/Selection.zig");
};
pub const PathFinder = @import("PathFinder.zig");

View File

@ -1,15 +0,0 @@
const std = @import("std");
const Engine = @import("engine");
// const assets = @import("assets.zig");
const scenes = @import("scenes.zig");
const assets = @import("assets.zig");
pub fn main() !void {
Engine.Control.set_loader(assets.load);
try Engine.Control.setup();
defer Engine.Control.destroy();
try Engine.Control.set_scene(scenes.game);
try Engine.Control.run();
}

View File

@ -1,23 +1,23 @@
const std = @import("std"); const std = @import("std");
const engine = @import("engine"); const engine = @import("engine");
const hadean = @import("hadean");
const Scene = engine.Scene; const Scene = engine.Scene;
const Camera = @import("Camera.zig"); const entities = hadean.entities;
const Selection = @import("Selection.zig");
const Terrain = @import("Terrain.zig");
const Entity = engine.Entity; const Entity = engine.Entity;
const Tag = engine.Tag; const Tag = engine.Tag;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
pub fn game(scene: *Scene) Allocator.Error!void { pub fn game(scene: *Scene) Allocator.Error!void {
const camera = try Camera.create(scene.arena.allocator()); const camera = try entities.Camera.create(scene.arena.allocator());
try scene.add(Entity.from(camera, .{ .tag = Tag.CAMERA })); try scene.add(Entity.from(camera, .{ .tag = Tag.CAMERA }));
const terrain = try Terrain.create(scene.arena.allocator(), 123); const terrain = try entities.Terrain.create(scene.arena.allocator(), 123);
try scene.add(Entity.from(terrain, .{ .tag = Tag.TERRAIN })); try scene.add(Entity.from(terrain, .{ .tag = Tag.TERRAIN }));
// try scene.add(try Selection.create()); // try scene.add(try Selection.create());
// for (0..5) |_| { for (0..1) |_| {
// try scene.add(try Pawn.random()); const pawn = try entities.Pawn.random(scene.arena.allocator());
// } try scene.add(Entity.from(pawn, .{}));
}
} }

13
src/main.zig 100644
View File

@ -0,0 +1,13 @@
const std = @import("std");
const engine = @import("engine");
const hadean = @import("hadean");
pub fn main() !void {
engine.Control.set_loader(hadean.assets.load);
try engine.Control.setup();
defer engine.Control.destroy();
try engine.Control.set_scene(hadean.scenes.game);
try engine.Control.run();
}