going on the bus, idk where im at

stable
Ivory 2024-10-15 09:01:44 -04:00
parent 274cfb471b
commit 8796331efa
6 changed files with 261 additions and 138 deletions

View File

@ -151,7 +151,7 @@ pub fn set_scene(scene: Scene) void {
next_scene = scene;
}
pub fn run() Error!void {
pub fn run() !void {
if (window == null) return Error.WindowNotInitialized;
if (current_scene != null) return Error.AlreadyRunning;
if (next_scene == null) return Error.NoScene;

View File

@ -174,7 +174,15 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
pub fn _start(pointer: *anyopaque, scene: *Scene) void {
const self: MutablePointer = @ptrCast(@alignCast(pointer));
if(@hasDecl(type_info.Pointer.child, "start")) {
type_info.Pointer.child.start(self, scene);
const return_type = @typeInfo(@typeInfo(@TypeOf(type_info.Pointer.child.start)).Fn.return_type.?);
// @compileLog(return_type);
switch (return_type) {
.Void => type_info.Pointer.child.start(self, scene),
.ErrorUnion => {
type_info.Pointer.child.start(self, scene) catch @panic("fuck");
},
else => {}
}
}
}
pub fn _resize(pointer: *anyopaque, width: i32, height: i32) void {

View File

@ -14,18 +14,24 @@ const AutoHashMap = std.AutoHashMap;
// cache and list bothe store entities. treat entities as fat pointers.
// Pointers into an arraylist WILL become invalid.
mouse_ready_entities: ArrayList(Entity) = undefined,
entities: ArrayList(Entity) = undefined,
tagged_entities: AutoHashMap(Tag.ID, Entity) = undefined,
mouse_ready_entities: ArrayList(Entity),
entities: ArrayList(Entity),
entities_to_add: ArrayList(Entity),
tagged_entities: AutoHashMap(Tag.ID, Entity),
mouse_inside: bool = false,
current_hover_item: ?Entity = null,
mouse_pos: ?Vec2i = null,
started: bool = false,
pub fn create() Scene {
var self = Scene {};
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
self.mouse_ready_entities = ArrayList(Entity).init(std.heap.page_allocator);
self.tagged_entities = AutoHashMap(Tag.ID, Entity).init(std.heap.page_allocator);
const self = Scene {
.entities = ArrayList(Entity).init(std.heap.page_allocator),
.entities_to_add = ArrayList(Entity).init(std.heap.page_allocator),
.mouse_ready_entities = ArrayList(Entity).init(std.heap.page_allocator),
.tagged_entities = AutoHashMap(Tag.ID, Entity).init(std.heap.page_allocator),
};
return self;
}
@ -40,6 +46,7 @@ pub fn start(self: *Scene) !void {
std.debug.print("[Scene:start] Scene starting...\n", .{});
std.debug.print("[Scene:start] entities: {}\n", .{ self.entities.items.len });
self.started = true;
for (self.entities.items) |*entity| {
if (entity.tag.id == Tag.NONE.id) {
std.debug.print("[Scene:start] - {s}\n", .{ entity.name() });
@ -51,6 +58,8 @@ pub fn start(self: *Scene) !void {
for (self.entities.items) |entity| {
entity.start(self);
}
try self.add_queued();
}
pub fn get(self: *const Scene, tag: Tag, comptime T: type) *T {
@ -84,6 +93,26 @@ pub fn add(self: *Scene, instance_ptr: anytype) !void {
// again, entities are fat pointers. they are okay to be copied
const entity: Entity = instance_ptr.entity();
if (self.started) {
try self.entities_to_add.append(entity);
} else {
try self.add_unsafe(entity);
}
}
inline fn add_queued(self: *Scene) !void {
for (self.entities_to_add.items) |entity| {
try self.entities.append(entity);
entity.start(self);
}
self.entities_to_add.clearAndFree();
}
inline fn add_unsafe(self: *Scene, entity: Entity) !void {
std.debug.print("[Scene:add] Adding {s}\n", .{
entity.name()
});
try self.entities.append(entity);
if (entity.tag.id != Tag.NONE.id) {
try self.tagged_entities.put(entity.tag.id, entity);

View File

@ -4,6 +4,7 @@ const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
const Recti = @import("geometry/Recti.zig");
const Vec2f = @import("geometry/Vec2f.zig");
const Vec2i = @import("geometry/Vec2i.zig");
const Entity = @import("Entity.zig");
const Scene = @import("Scene.zig");
const Camera = @import("Camera.zig");
@ -19,52 +20,16 @@ const CHUNK_LENGTH = CHUNK_SIZE * CHUNK_SIZE;
const tile_size: usize = 16;
pub inline fn xy_to_index(x: i32, y: i32) i32 {
return x + y * CHUNK_SIZE;
}
pub inline fn index_to_xy(index: i32) struct { i32, i32 } {
const y: i32 = @divFloor(index, CHUNK_SIZE);
const x: i32 = @rem(index, CHUNK_SIZE);
return .{ x, y };
}
const GROWS = true;
const GROWTH_RATE: f32 = 0.5;
pub const Tile = struct {
texture_idx: usize,
growth: f32,
stone_decoration: f32,
grass_color: Color,
dirt_color: Color,
stone_color: Color,
pub const NULL = Tile {
.texture_idx = 0,
.growth = 0,
.stone_decoration = 0,
.grass_color = Color.WHITE,
.dirt_color = Color.WHITE,
.stone_color = Color.WHITE,
};
};
tiles: []Tile = undefined,
// the noise for deciding random textures
texture_noise: Noise,
// noise for deciding grass growth
growth_noise: Noise,
// noise for stone decoration placement
stone_decoration_noise: Noise.Custom,
// noise for colors
dirt_color_noise: Noise.Color,
grass_color_noise: Noise.Color,
stone_color_noise: Noise.Color,
chunks: std.ArrayList(*Chunk),
generator: WorldGenerator,
camera: *Camera = undefined,
scene: ?*Scene = null,
pub fn entity(self: *Terrain) Entity {
return Entity.init(self, .{
@ -72,9 +37,12 @@ pub fn entity(self: *Terrain) Entity {
});
}
pub fn start(self: *Terrain, scene: *Scene) void {
pub fn start(self: *Terrain, scene: *Scene) !void {
self.camera = scene.get(Camera.TAG, Camera);
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;
for (self.chunks.items) |chunk| try scene.add(chunk);
}
fn contrast(n: f32, blend_strength: f32) f32 {
@ -89,107 +57,72 @@ fn contrast(n: f32, blend_strength: f32) f32 {
return (unadjusted_total + 1.0) / 2.0;
}
fn generate_tiles(self: *Terrain) void {
for(0..CHUNK_LENGTH) |idx| {
const x, const y = index_to_xy(@intCast(idx));
const fx: f32 = @floatFromInt(x);
const fy: f32 = @floatFromInt(y);
const texture_random = self.texture_noise.get(fx, fy);
self.tiles[idx] = Tile {
.texture_idx = @intFromFloat(@floor(texture_random * 4)),
.growth = contrast(self.growth_noise.get(fx, fy), 10),
.stone_decoration = self.stone_decoration_noise.get(fx, fy),
.dirt_color = self.dirt_color_noise.get(fx, fy),
.grass_color = self.grass_color_noise.get(fx, fy),
.stone_color = self.stone_color_noise.get(fx, fy),
};
}
fn gen_chunk(self: *Terrain, chunk_pos: Vec2i) !void {
std.debug.print("[Terrain:gen_chunk] {}\n", .{ chunk_pos });
const chunk = try Chunk.generate(chunk_pos, &self.generator);
try self.chunks.append(chunk);
if (self.scene != null) try self.scene.?.add(chunk);
}
pub fn create(seed: i64) !*Terrain {
var self: *Terrain = try Scene.EntityPool.allocate(Terrain {
.tiles = try Entity.allocate_array(Tile, CHUNK_LENGTH, Tile.NULL),
.growth_noise = Noise.create(seed, 10, 0.03),
.texture_noise = Noise.create(seed + 1, 1, 3),
.stone_decoration_noise = try Noise.Custom.create(seed + 2, 1, &.{
.{ .frequency = 0.03, .amplitude = 1 },
.{ .frequency = 1, .amplitude = 1 }
}),
.dirt_color_noise = try Noise.Color.create(seed + 3, Noise.ColorRange.DIRT),
.grass_color_noise = try Noise.Color.create(seed + 4, Noise.ColorRange.GRASS),
.stone_color_noise = try Noise.Color.create(seed + 5, Noise.ColorRange.STONE)
.chunks = std.ArrayList(*Chunk).init(std.heap.page_allocator),
.generator = try WorldGenerator.create(seed),
});
self.generate_tiles();
try self.gen_chunk(Vec2i.ZERO);
try self.gen_chunk(Vec2i { .x = -1, .y = 0 });
return self;
}
pub fn destroy(self: *const Terrain) void {
self.texture_noise.destroy();
self.growth_noise.destroy();
self.stone_decoration_noise.destroy();
self.dirt_color_noise.destroy();
self.grass_color_noise.destroy();
self.stone_color_noise.destroy();
Entity.free_array(self.tiles);
self.generator.destroy();
self.chunks.deinit();
Scene.EntityPool.deallocate(self);
}
fn chance(percent: f32) bool {
return prng.random().float(f32) < percent;
}
// fn chance(percent: f32) bool {
// return prng.random().float(f32) < percent;
// }
fn grow(self: *Terrain, x: i32, y: i32, amt: f32) void {
if (x < 0 or x >= CHUNK_SIZE) return;
if (y < 0 or y >= CHUNK_SIZE) return;
const idx: usize = @intCast(xy_to_index(x, y));
const tile = &self.tiles[idx];
// @compileLog(tile);
tile.*.growth = @min(@max(tile.growth + amt, 0), 1);
}
// fn grow(self: *Terrain, x: i32, y: i32, amt: f32) void {
// if (x < 0 or x >= CHUNK_SIZE) return;
// if (y < 0 or y >= CHUNK_SIZE) return;
// const idx: usize = @intCast(xy_to_index(x, y));
// const tile = &self.tiles[idx];
// // @compileLog(tile);
// tile.*.growth = @min(@max(tile.growth + amt, 0), 1);
// }
pub fn update(self: *Terrain, dt: f32) void {
if (GROWS) {
for (0..CHUNK_LENGTH) |idx| {
const x, const y = index_to_xy(@intCast(idx));
const tile = self.tiles[idx];
const should_grow = chance(dt * GROWTH_RATE) and chance(tile.growth);
if (should_grow) {
self.grow(x, y, 0.010);
// pub fn update(self: *Terrain, dt: f32) void {
// if (GROWS) {
// for (0..CHUNK_LENGTH) |idx| {
// const x, const y = index_to_xy(@intCast(idx));
// const tile = self.tiles[idx];
// const should_grow = chance(dt * GROWTH_RATE) and chance(tile.growth);
// if (should_grow) {
// self.grow(x, y, 0.010);
//
// self.grow(x + 1, y, 0.008);
// self.grow(x - 1, y, 0.008);
// self.grow(x, y + 1, 0.008);
// self.grow(x, y - 1, 0.008);
//
// self.grow(x + 1, y + 1, 0.004);
// self.grow(x + 1, y - 1, 0.004);
// self.grow(x - 1, y + 1, 0.004);
// self.grow(x - 1, y - 1, 0.004);
// }
// }
// }
// }
//
self.grow(x + 1, y, 0.008);
self.grow(x - 1, y, 0.008);
self.grow(x, y + 1, 0.008);
self.grow(x, y - 1, 0.008);
self.grow(x + 1, y + 1, 0.004);
self.grow(x + 1, y - 1, 0.004);
self.grow(x - 1, y + 1, 0.004);
self.grow(x - 1, y - 1, 0.004);
}
}
}
}
pub fn draw(self: *const Terrain) void {
for(0..CHUNK_LENGTH) |idx| {
const tile = self.tiles[idx];
const x, const y = index_to_xy(@intCast(idx));
const rect = Recti.from_xywh(x, y, 1, 1);
const sprite = assets.terrain[0][tile.texture_idx];
self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, tile.grass_color);
// switch(tile.texture_idx) {
// 0 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.WHITE),
// 1 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.RED),
// 2 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.GREEN),
// 3 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.BLUE),
// else => {}
// }
}
}
// pub fn draw(self: *const Terrain) void {
// for (self.chunks.items) |chunk| {
// chunk.draw... we dont need this. chunks draw themselves...
// }
// }
// pub fn draw_opacity(self: *const Terrain) void {
// for(0..CHUNK_LENGTH) |idx| {
@ -205,3 +138,149 @@ pub fn draw(self: *const Terrain) void {
// self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, color);
// }
// }
const Chunk = struct {
pub const Tile = struct {
texture_idx: usize,
growth: f32,
stone_decoration: f32,
grass_color: Color,
dirt_color: Color,
stone_color: Color,
pub const NULL = Tile {
.texture_idx = 0,
.growth = 0,
.stone_decoration = 0,
.grass_color = Color.WHITE,
.dirt_color = Color.WHITE,
.stone_color = Color.WHITE,
};
};
tiles: []Tile = undefined,
chunk_pos: Vec2i,
chunk_pos_world: Vec2i,
camera: *Camera = undefined,
pub fn generate(chunk_pos: Vec2i, generator: *const WorldGenerator) !*Chunk {
var self = try Scene.EntityPool.allocate(Chunk {
.chunk_pos = chunk_pos,
.chunk_pos_world = Vec2i {
.x = chunk_pos.x * CHUNK_SIZE,
.y = chunk_pos.y * CHUNK_SIZE,
},
.tiles = try Entity.allocate_array(Tile, CHUNK_LENGTH, Tile.NULL),
});
self.generate_tiles(generator);
return self;
}
pub fn destroy(self: *const Chunk) void {
Entity.free_array(self.tiles);
Scene.EntityPool.deallocate(self);
}
pub fn entity(self: *Chunk) Entity {
return Entity.init(self, .{});
}
pub fn start(self: *Chunk, scene: *Scene) void {
self.camera = scene.get(Camera.TAG, Camera);
}
fn generate_tiles(self: *Chunk, generator: *const WorldGenerator) void {
for(0..CHUNK_LENGTH) |idx| {
const x, const y = index_to_xy(@intCast(idx));
const abs_pos = self.chunk_pos.add(Vec2i.create(x, y));
const tile = generator.gen_tile(abs_pos);
self.tiles[idx] = tile;
}
}
pub fn draw(self: *const Chunk) void {
for(0..CHUNK_LENGTH) |idx| {
const tile = self.tiles[idx];
const x, const y = index_to_xy(@intCast(idx));
const rect = Recti.from_xywh(x, y, 1, 1);
const sprite = assets.terrain[0][tile.texture_idx];
self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, tile.grass_color);
// switch(tile.texture_idx) {
// 0 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.WHITE),
// 1 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.RED),
// 2 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.GREEN),
// 3 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.BLUE),
// else => {}
// }
}
}
// some helper functions
pub inline fn xy_to_index(x: i32, y: i32) i32 {
return x + y * CHUNK_SIZE;
}
pub inline fn index_to_xy(index: i32) struct { i32, i32 } {
const y: i32 = @divFloor(index, CHUNK_SIZE);
const x: i32 = @rem(index, CHUNK_SIZE);
return .{ x, y };
}
};
const WorldGenerator = struct {
// the noise for deciding random textures
texture_noise: Noise,
// noise for deciding grass growth
growth_noise: Noise,
// noise for stone decoration placement
stone_decoration_noise: Noise.Custom,
// noise for colors
dirt_color_noise: Noise.Color,
grass_color_noise: Noise.Color,
stone_color_noise: Noise.Color,
pub fn create(seed: i64) !WorldGenerator {
return WorldGenerator {
.growth_noise = Noise.create(seed, 10, 0.03),
.texture_noise = Noise.create(seed + 1, 1, 3),
.stone_decoration_noise = try Noise.Custom.create(seed + 2, 1, &.{
.{ .frequency = 0.03, .amplitude = 1 },
.{ .frequency = 1, .amplitude = 1 }
}),
.dirt_color_noise = try Noise.Color.create(seed + 3, Noise.ColorRange.DIRT),
.grass_color_noise = try Noise.Color.create(seed + 4, Noise.ColorRange.GRASS),
.stone_color_noise = try Noise.Color.create(seed + 5, Noise.ColorRange.STONE)
};
}
pub fn destroy(self: *const WorldGenerator) void {
self.texture_noise.destroy();
self.growth_noise.destroy();
self.stone_decoration_noise.destroy();
self.dirt_color_noise.destroy();
self.grass_color_noise.destroy();
self.stone_color_noise.destroy();
}
pub fn gen_tile(self: *const WorldGenerator, position: Vec2i) Chunk.Tile {
const fx: f32 = @floatFromInt(position.x);
const fy: f32 = @floatFromInt(position.y);
const texture_random = self.texture_noise.get(fx, fy);
return Chunk.Tile {
.texture_idx = @intFromFloat(@floor(texture_random * 4)),
.growth = contrast(self.growth_noise.get(fx, fy), 10),
.stone_decoration = self.stone_decoration_noise.get(fx, fy),
.dirt_color = self.dirt_color_noise.get(fx, fy),
.grass_color = self.grass_color_noise.get(fx, fy),
.stone_color = self.stone_color_noise.get(fx, fy),
};
}
};

View File

@ -32,6 +32,13 @@ pub fn to_unit_recti(self: *const Vec2i) Recti {
return Recti.from_xywh(self.x, self.y, 1, 1);
}
pub fn add(self: Vec2i, other: Vec2i) Vec2i {
return Vec2i {
.x = self.x + other.x,
.y = self.y + other.y,
};
}
pub fn draw(self: *const Vec2i, radius: f32, layer: Layer, color: Color) void {
shaders.disable_textures();

View File

@ -11,9 +11,9 @@ pub fn game() !Scene {
try scene.add(try Camera.create());
try scene.add(try Terrain.create(123));
try scene.add(try Selection.create());
for (0..5) |_| {
try scene.add(try Pawn.random());
}
// for (0..5) |_| {
// try scene.add(try Pawn.random());
// }
return scene;
}