[Wall]
-id = 10
-flags = 2
-pos.x = 168.0000
-pos.y = 320.0000
-size.x = 336.0000
-size.y = 32.0000
+ id = 10
+ flags = 2
+ pos.x = 168.0000
+ pos.y = 320.0000
+ size.x = 336.0000
+ size.y = 32.0000
[Wall]
-id = 11
-flags = 2
-pos.x = 448.0000
-pos.y = 168.0000
-size.x = 32.0000
-size.y = 336.0000
+ id = 11
+ flags = 2
+ pos.x = 448.0000
+ pos.y = 168.0000
+ size.x = 32.0000
+ size.y = 336.0000
[Player]
-id = 12
-flags = 2
-pos.x = 200.0000
-pos.y = 152.0000
-size.x = 48.0000
-size.y = 48.0000
-:PlayerComponent
-holding = 0
-controls.up = 87
-controls.down = 83
-controls.left = 65
-controls.right = 68
-controls.interact = 70
-controls.pick_up = 71
-color.r = 1.0000
-color.g = 1.0000
-color.b = 1.0000
-color.a = 1.0000
-facing = 4
+ id = 12
+ flags = 2
+ pos.x = 200.0000
+ pos.y = 152.0000
+ size.x = 48.0000
+ size.y = 48.0000
+
+ :PlayerComponent
+ holding = 0
+ controls.up = 87
+ controls.down = 83
+ controls.left = 65
+ controls.right = 68
+ controls.interact = 70
+ controls.pick_up = 71
+ color.r = 1.0000
+ color.g = 1.0000
+ color.b = 1.0000
+ color.a = 1.0000
+ facing = 4
[Door]
-id = 13
-flags = 3
-pos.x = 352.0000
-pos.y = 320.0000
-size.x = 160.0000
-size.y = 32.0000
-:DoorComponent
-target_openness = 0.0000
+ id = 13
+ flags = 3
+ pos.x = 352.0000
+ pos.y = 320.0000
+ size.x = 160.0000
+ size.y = 32.0000
+
+ :DoorComponent
+ target_openness = 0.0000
[Item_Entity]
-id = 14
-flags = 4
-pos.x = 272.0000
-pos.y = 144.0000
-size.x = 32.0000
-size.y = 32.0000
-:ItemComponent
-item = "beer"
+ id = 14
+ flags = 4
+ pos.x = 272.0000
+ pos.y = 144.0000
+ size.x = 32.0000
+ size.y = 32.0000
+
+ :ItemComponent
+ item = "beer"
--- /dev/null
+[Wall]
+id = 10
+flags = 2
+pos.x = 168.0000
+pos.y = 320.0000
+size.x = 336.0000
+size.y = 32.0000
+
+[Wall]
+id = 11
+flags = 2
+pos.x = 448.0000
+pos.y = 168.0000
+size.x = 32.0000
+size.y = 336.0000
+
+[Player]
+id = 12
+flags = 2
+pos.x = 342.9302
+pos.y = 205.3930
+size.x = 48.0000
+size.y = 48.0000
+:PlayerComponent
+color.r = 1.0000
+color.g = 1.0000
+color.b = 1.0000
+color.a = 1.0000
+holding = 0
+controls.up = 87
+controls.down = 83
+controls.left = 65
+controls.right = 68
+controls.interact = 70
+controls.pick_up = 71
+facing = 4
+
+[Door]
+id = 13
+flags = 3
+pos.x = 352.0000
+pos.y = 320.0000
+size.x = 160.0000
+size.y = 32.0000
+:DoorComponent
+max_openness = 0.8000
+target_openness = 0.0000
+openness = 0.0000
+
+[Item_Entity]
+id = 14
+flags = 4
+pos.x = 386.9302
+pos.y = 205.3930
+size.x = 32.0000
+size.y = 32.0000
+:ItemComponent
+item = "beer"
+
});
}
+#local Component_Vtable :: struct {
+ init : (^Component) -> void = null_proc;
+ update: (^Component, ^Entity, f32) -> void = null_proc;
+}
+
Component :: struct {
- type: type_expr;
+ [Entity_Store.Skip] use vtable: ^Component_Vtable;
+ [Entity_Store.Skip] type: type_expr;
}
IsComponent :: interface (c: $C) {
{ c } -> ^Component;
}
-UpdateComponent :: struct {
- use base: Component;
- func : (e: ^Entity, dt: f32) -> void;
-}
-
RenderComponent :: struct {
use base: Component;
func : (e: ^Entity) -> void;
}
-SizeComponent :: struct {
+SizeComponent :: struct [Entity_Store.Skip] {
use base: Component;
func : (e: ^Entity) -> Rect;
}
-InteractableComponent :: struct {
+InteractableComponent :: struct [Entity_Store.Skip] {
use base: Component;
interact: (e: ^Entity, interactor: ^Entity) -> void;
}
Entity :: struct {
id: Entity_ID;
flags: Entity_Flags;
- schematic: type_expr;
+
+ [Entity_Store.Skip] schematic: type_expr;
pos: Vector2;
if e->has(SizeComponent) do return (e->get(SizeComponent)).func(e);
return Rect.{ pos.x - size.x / 2, pos.y - size.y / 2, size.x, size.y };
- }
+ };
+ [Entity_Store.Skip]
components: Map(type_expr, ^Component);
has :: (use this: ^Entity, component_type: type_expr) => components->has(component_type);
get :: (use this: ^Entity, $component_type: type_expr) => cast(^component_type) components[component_type];
entity_map: Map(Entity_ID, ^Entity);
schematics: Map(str, ^Entity_Schematic);
+ component_vtables: Map(type_expr, ^Component_Vtable);
next_entity_id: Entity_ID;
entity_manager_create_component :: (use this: ^Entity_Manager, $component_type: type_expr) -> ^component_type where IsComponent(^component_type) {
comp := new(component_type, allocator=entity_allocator);
comp.type = component_type;
+
+ if !component_vtables->has(comp.type) {
+ vtable := new(Component_Vtable, allocator=entity_allocator);
+ type_info.populate_struct_vtable(vtable, component_type, safe=false);
+ component_vtables[comp.type] = vtable;
+ }
+
+ comp.vtable = component_vtables->get(comp.type);
+
return comp;
}
entity_manager_create_and_add :: macro (this: ^Entity_Manager, entity: ^Entity, $component_type: type_expr, init_block: Code) where IsComponent(^component_type) {
- comp := new(component_type, allocator=this.entity_allocator);
- comp.type = component_type;
+ comp := this->create_component(component_type);
#insert init_block;
entity->add(comp);
entity_manager_update :: (use this: ^Entity_Manager, dt: f32) {
for entities {
- update_comp := it->get(UpdateComponent);
- if update_comp != null {
- update_comp.func(it, dt);
+ for^ entry: it.components.entries {
+ comp := entry.value;
+
+ @CompilerBug // comp->update(it, dt); should be legal here, but it says 'update' is not a member of '^Component'.
+ if comp.vtable.update != null_proc {
+ comp.vtable.update(comp, it, dt);
+ }
}
}
}
comp.color = .{1,1,1};
}
- scene->create_and_add(this, UpdateComponent) {
- comp.func = PlayerComponent.update;
- }
-
scene->create_and_add(this, RenderComponent) {
comp.func = PlayerComponent.render;
}
controls : Player_Controls;
facing := Facing.Up;
- update :: (use this: ^Entity, dt: f32) {
+ update :: (player: ^PlayerComponent, use this: ^Entity, dt: f32) {
speed :: 128.0f;
- player := this->get(PlayerComponent);
-
delta: Vector2;
if is_key_down(player.controls.left) { delta.x -= speed * dt; player.facing = .Left; }
if is_key_down(player.controls.right) { delta.x += speed * dt; player.facing = .Right; }
#local Door :: struct [Entity_Schematic.{create}] {
create :: (scene) => door_create(scene, .{0, 0}, .{0, 0});
- update :: (use this: ^Entity, dt: f32) {
- door := this->get(DoorComponent);
- door->update(dt);
- }
-
render :: (use this: ^Entity) {
immediate_set_color(.{0.7, 0.7, 0.1});
target_openness := 0.0f;
openness := 0.0f;
- update :: (use this: ^DoorComponent, dt: f32) {
+ update :: (use this: ^DoorComponent, door: ^Entity, dt: f32) {
if openness != target_openness {
move_towards(^openness, target_openness, dt * 2);
}
this.flags |= .Solid;
scene->create_and_add(this, DoorComponent) {}
- scene->create_and_add(this, UpdateComponent) { comp.func = Door.update; }
scene->create_and_add(this, RenderComponent) { comp.func = Door.render; }
scene->create_and_add(this, SizeComponent) { comp.func = Door.get_rect; }
scene->create_and_add(this, InteractableComponent) { comp.interact = Door.interact; }
}
entity_manager_save_to_file :: (use this: ^Entity_Manager, filename: str) {
- /*
err, output_file := os.open(filename, .Write);
defer os.close(^output_file);
writer_ := io.writer_make(^output_file);
use type_info;
for entities {
- info := cast(^Type_Info_Struct) get_type_info(it.type);
- io.write_format(writer, ":{}\n", info.name);
- emit_struct_fields(any.{~~ it, it.type}, writer, "");
+ info := cast(^Type_Info_Struct) get_type_info(it.schematic);
+ io.write_format(writer, "[{}]\n", info.name);
+ emit_struct_fields(any.{~~ it, Entity}, writer, "");
+
+ for^ it.components.entries {
+ info := cast(^Type_Info_Struct) get_type_info(it.key);
+ for info.tags {
+ if it.type != Entity_Store do continue;
+ if *(cast(^Entity_Store) it.data) == .Skip do continue continue;
+ }
+
+ io.write_format(writer, ":{}\n", info.name);
+ emit_struct_fields(any.{~~ it.value, it.key}, writer, "");
+ }
io.write(writer, "\n");
}
}
}
}
- */
}
entity_manager_load_from_file :: (use this: ^Entity_Manager, filename: str) {
load_assets();
scene = entity_manager_create();
- scene->load_from_file("scenes/quick_save.scene");
- /*
- // player := player_create(^scene);
-
- player := scene.schematics["Player"](^scene);
- scene->add(player);
-
- // wall := wall_create(^scene, .{0, 100}, .{300, 40});
- wall := scene.schematics["Wall"](^scene);
- wall.pos = .{0, 100};
- wall.size = .{300, 40};
- scene->add(wall);
-
- door := scene.schematics["Door"](^scene);
- door.pos = .{500, 300};
- door.size = .{100, 20};
- scene->add(door);
-
- item := scene.schematics["Item_Entity"](^scene);
- item.pos = .{100, 200};
- item.size = .{32, 32};
- with (item->get(ItemComponent)) {
- it.item = "beer";
- }
-
- scene->add(item);
- */
+ scene->load_from_file(quick_save_file);
item_store = item_store_make();
item_store->load_items_from_file("scenes/default.items");
}
-#local quick_save_file := "scenes/quick_save.scene";
+#local quick_save_file := "scenes/quick_save_new.scene";
game_update :: (dt: f32) {
if is_key_just_up(GLFW_KEY_F8) {