renamed 'Entity_Manager' to 'Scene'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 1 Mar 2022 21:15:07 +0000 (15:15 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 1 Mar 2022 21:15:07 +0000 (15:15 -0600)
src/entity/entities.onyx
src/entity/manager.onyx [deleted file]
src/entity/scene.onyx [new file with mode: 0644]
src/entity/schematics/furniture.onyx
src/entity/schematics/patron.onyx
src/entity/schematics/player.onyx
src/entity/schematics/tap.onyx
src/entity/store.onyx
src/game.onyx

index 1af81b2389f8d197bde7bff17f1e082284804f5c..f5c52344b1c4bdb6b735cc44a280d01c8a48be89 100644 (file)
@@ -14,7 +14,7 @@ use package glfw3
     }
 }
 
-wall_create :: (scene: ^Entity_Manager, pos, size: Vector2) -> ^Entity {
+wall_create :: (scene: ^Scene, pos, size: Vector2) -> ^Entity {
     this := scene->make();
     this.pos = pos;
     this.size = size;
@@ -72,7 +72,7 @@ DoorComponent :: struct {
     }
 }
 
-door_create :: (scene: ^Entity_Manager, pos, size: Vector2) -> ^Entity {
+door_create :: (scene: ^Scene, pos, size: Vector2) -> ^Entity {
     this := scene->make();
     this.pos  = pos;
     this.size = size;
diff --git a/src/entity/manager.onyx b/src/entity/manager.onyx
deleted file mode 100644 (file)
index ce42d97..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-
-use package core
-use package glfw3
-
-Entity_Nothing :: cast(Entity_ID) 0
-Entity_ID :: #distinct u32
-#match    hash.to_u32 macro (e: Entity_ID) => (package core.hash).to_u32(cast(u32) e);
-#operator == (a, b: Entity_ID) => cast(u32) a == cast(u32) b;
-#operator != (a, b: Entity_ID) => cast(u32) a != cast(u32) b;
-
-#init #after conv.custom_formatters_initialized () {
-    conv.register_custom_parser((e: ^Entity_ID, line: str, _: Allocator) => {
-        *e = ~~ cast(u32) conv.str_to_i64(line);
-        return true;
-    });
-}
-
-#local Component_Vtable :: struct {
-    //
-    // 'init' is called when the component is first created, before it
-    // has been added to any entity.
-    init       : (rawptr) -> void               = null_proc;
-
-    // 
-    // 'added' is called when the component is added to an entity.
-    // In theory, it could be called multiple times, if the component
-    // is shared between multiple entities.
-    added      : (rawptr, ^Entity) -> void      = null_proc;
-
-    //
-    // 'update' is called every update cycle. Currently, there is no
-    // specified as to the order in which components get updated.
-    // I think by circumstance, it is the order that you add them
-    // to the entity, but could break in the future.
-    update     : (rawptr, ^Entity, f32) -> void = null_proc;
-
-    //
-    // 'post_render' is called after the entity has been rendered
-    // normally. Entities must have a 'RenderComponent' in order
-    // to have 'post_render' called on their components. This
-    // can be used to add overlays or popups to an entity.
-    post_render: (rawptr, ^Entity) -> void      = null_proc;
-}
-
-Component :: struct {
-    #tag Editor_Hidden, Entity_Store.Skip
-    use vtable: ^Component_Vtable;
-
-    #tag Editor_Hidden, Entity_Store.Skip
-    type: type_expr;
-}
-
-IsComponent :: interface (c: $C) {
-    { c } -> ^Component;
-}
-
-RenderComponent :: struct {
-    use base: Component;
-
-    #tag Editor_Hidden, Entity_Store.Skip
-    func : (e: ^Entity) -> void;
-
-    layer := 0;
-    color := Color.{1, 1, 1};
-}
-
-SizeComponent :: struct {
-    use base: Component;
-    func : (e: ^Entity) -> Rect;
-
-    #struct_tag Entity_Store.Skip
-}
-
-InteractableComponent :: struct {
-    use base: Component;
-    interact: (e: ^Entity, interactor: ^Entity) -> void;
-
-    #struct_tag Entity_Store.Skip
-}
-
-Entity :: struct {
-    id: Entity_ID;
-    flags: Entity_Flags;
-
-    #tag Entity_Store.Skip
-    schematic: type_expr;
-
-    pos:  Vector2;
-
-    // Does every entity need to have a size?
-    size: Vector2;
-    get_rect :: (use e: ^Entity) => {
-        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 };
-    };
-
-    #tag Entity_Store.Skip, Editor_Hidden
-    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];
-    add :: (use this: ^Entity,  component: ^Component) => {
-        if components->has(component.type) do return;
-        components[component.type] = component;
-        if component.added != null_proc {
-            component->added(this);
-        }
-    }
-}
-
-
-Entity_Flags :: enum #flags {
-    // These have defined values for stable serialization.
-    Interactable :: 0x01;
-    Solid        :: 0x02;
-    Carryable    :: 0x04;
-    Dead         :: 0x80000000;
-}
-
-Entity_Schematic :: struct {
-    create: (^Entity_Manager) -> ^Entity;
-    type := void; // This will be filled out at runtime.
-}
-
-Entity_Manager :: struct {
-    entity_allocator: Allocator;
-
-    // Hmmm... Do they need to be stored in both ways?
-    entities: [..] ^Entity;
-    entity_map: Map(Entity_ID, ^Entity);
-
-    schematics: Map(str, ^Entity_Schematic);
-    component_vtables: Map(type_expr, ^Component_Vtable);
-
-    next_entity_id: Entity_ID;
-
-    add            :: entity_manager_add;
-    make           :: entity_manager_make;
-    update         :: entity_manager_update;
-    draw           :: entity_manager_draw;
-    get            :: entity_manager_get;
-    delete         :: entity_manager_delete;
-    query          :: entity_manager_query;
-    query_by_flags :: entity_manager_query_by_flags;
-
-    count_by_component :: entity_manager_count_by_component;
-
-    query_by_component :: entity_manager_query_by_component;
-    create_component :: entity_manager_create_component;
-    create_and_add :: entity_manager_create_and_add;
-
-    create_from_schematic :: entity_manager_create_from_schematic;
-
-    load_from_file :: entity_manager_load_from_file;
-    save_to_file   :: entity_manager_save_to_file;
-}
-
-entity_manager_create :: () -> Entity_Manager {
-    em: Entity_Manager;
-    em.entity_allocator = context.allocator; @TODO // Replace the allocator here.
-
-    array.init(^em.entities, 4);
-
-    // Entity ID 0 is reserved as a "empty / null" entity
-    em.next_entity_id = 1;
-
-    entity_manager_load_schematics(^em);
-    return em;
-}
-
-#local entity_manager_load_schematics :: (use this: ^Entity_Manager) {
-    use type_info;
-
-    index := 0;
-    for type_table {
-        defer index += 1;
-        if it.kind != .Struct do continue;
-
-        s_info := cast(^Type_Info_Struct) it;
-        for^ s_info.tags {
-            if it.type == Entity_Schematic {
-                schematic := cast(^Entity_Schematic) it.data;
-
-                // This is (mostly) safe to do as this data is in static memory
-                // and is not shared with any other type info.
-                schematic.type = cast(type_expr) index;
-
-                // This is safe to use as the key, as a struct's name exists in static memory.
-                schematics[s_info.name] = schematic;
-
-                debug_log(.Debug, "Discovered schematic: '{}'", s_info.name);
-                continue continue;
-            }
-        }
-
-        if struct_inherits(~~ index, Component) {
-            debug_log(.Debug, "Discovered component: '{}'", s_info.name);
-
-            comp_type := cast(type_expr) index;
-            if !component_vtables->has(comp_type) {
-                vtable := new(Component_Vtable, allocator=entity_allocator);
-                type_info.populate_struct_vtable(vtable, comp_type, safe=false);
-                component_vtables[comp_type] = vtable;
-            }
-        }
-    }
-}
-
-entity_manager_add :: (use this: ^Entity_Manager, entity: ^Entity) -> Entity_ID {
-    // Automatically assign an id if the entity does not have one.
-    // This will not be used when loading the entity from a file.
-    if entity.id == 0 {
-        entity.id = next_entity_id;
-        next_entity_id = ~~(cast(u32) next_entity_id + 1);
-    } else {
-        next_entity_id = ~~(math.max(cast(u32) next_entity_id, cast(u32) entity.id) + 1);
-    }
-
-    entities << entity;
-    entity_map[entity.id] = entity;
-    return entity.id;
-}
-
-entity_manager_make :: (use this: ^Entity_Manager) -> ^Entity {
-    entity := new(Entity, allocator=entity_allocator);
-    map.init(^entity.components);
-    return entity;
-}
-
-entity_manager_create_from_schematic :: (use this: ^Entity_Manager, schematic_name: str) -> ^Entity {
-    schematic := schematics[schematic_name];
-    if schematic == null do return null;
-
-    entity := schematic.create(this);
-    entity.schematic = schematic.type;
-    return entity;
-}
-
-entity_manager_create_component :: (use this: ^Entity_Manager, component_type: type_expr) -> ^Component {
-    comp := cast(^Component) 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);
-    if comp.init != null_proc {
-        comp->init();
-    }
-
-    return comp;
-}
-
-entity_manager_create_and_add :: macro (this: ^Entity_Manager, entity: ^Entity, $component_type: type_expr, init_block: Code) where IsComponent(^component_type) {
-    use package core.intrinsics.onyx {__initialize}
-
-    comp := cast(^component_type) this->create_component(component_type);
-
-    // The 'create_component' function does not initailize the component, as it is not
-    // a compile time known parameter and therefore cannot know how to initialize it.
-    // This 'create_and_add' function is more often used by the programmer, so initializing
-    // the component here before returning is a good idea.
-    __initialize(comp);
-
-    #insert init_block;
-    entity->add(comp);
-}
-
-entity_manager_update :: (use this: ^Entity_Manager, dt: f32) {
-    for entities {
-        for^ entry: it.components.entries {
-            comp := entry.value;
-            if comp.update != null_proc {
-                comp->update(it, dt);
-            }
-        }
-    }
-
-    while i := 0; i < entities.count {
-        defer i += 1;
-
-        if entities[i].flags & .Dead {
-            this->delete(entities[i]);
-            i -= 1;
-        }
-    }
-}
-
-entity_manager_draw :: (use this: ^Entity_Manager) {
-
-    //
-    // This is a rather expensive check.
-    // It could probably be done solely when entities are added/removed.
-    array.sort(entities, (e1, e2) => {
-        e1_comp := e1->get(RenderComponent);
-        e2_comp := e2->get(RenderComponent);
-
-        e1_layer := e1_comp.layer if e1_comp != null else 0;
-        e2_layer := e2_comp.layer if e2_comp != null else 0;
-
-        return e1_layer - e2_layer;
-    });
-
-    for entities {
-        render_comp := it->get(RenderComponent);
-        if render_comp != null {
-            immediate_set_color(render_comp.color);
-            render_comp.func(it);
-
-            for^ entry: it.components.entries {
-                comp := entry.value;
-                if comp.post_render != null_proc {
-                    comp->post_render(it);
-                }
-            }
-        }
-    }
-}
-
-entity_manager_get :: (use this: ^Entity_Manager, id: Entity_ID) => entity_map[id];
-
-entity_manager_delete :: (use this: ^Entity_Manager, ent: ^Entity, delete_from_array := true) {
-    map.delete(^entity_map, ent.id);
-
-    //
-    // Not deleting the entity from the array, because this messes with the
-    // order, and becaues of that, it breaks a for-loop.
-    if delete_from_array do array.remove(^entities, ent); // This preserves the order of the entities, but does that matter?
-
-    // This assuems that components cannot and will not be shared between entities.
-    for^ ent.components.entries {
-        if it.value != null {
-            raw_free(entity_allocator, it.value);
-        }
-    }     
-
-    map.free(^ent.components);
-    raw_free(entity_allocator, ent);
-}
-
-entity_manager_count_by_component :: (use this: ^Entity_Manager, comp_type: type_expr) -> u32 {
-    count := 0;
-    for entities {
-        if it->has(comp_type) {
-            count += 1;
-        }
-    }
-
-    return count;
-}
-
-entity_manager_query :: (use this: ^Entity_Manager, area: Rect) -> [] ^Entity {
-    ents: [..] ^Entity;
-    for entities {
-        if Rect.intersects(Entity.get_rect(it), area) {
-            ents << it;
-        }
-    }
-
-    return ents;
-}
-
-entity_manager_query_by_component :: (use this: ^Entity_Manager, area: Rect, comp_type: type_expr) -> [] ^Entity {
-    ents: [..] ^Entity;
-    for entities {
-        if !it.components->has(comp_type) do continue;
-
-        if Rect.intersects(Entity.get_rect(it), area) {
-            ents << it;
-        }
-    }
-
-    return ents;
-}
-
-entity_manager_query_by_flags :: (use this: ^Entity_Manager, area: Rect, flags: Entity_Flags) -> [] ^Entity {
-    ents: [..] ^Entity;
-
-    // Currently, enum #flags are not the greatest and & doesn't do what you want it to here.
-    expected_flags := cast(u32) flags;
-
-    for entities {
-        if ~~ it.flags & expected_flags != expected_flags do continue;
-
-        if Rect.intersects(Entity.get_rect(it), area) {
-            ents << it;
-        }
-    }
-
-    return ents;
-}
-
-
-
-
-
-@Relocate
-Sprite :: struct {
-    sheet: str;
-    pos:  Vector2;
-    size: Vector2;
-    color: Color;
-
-    render :: (use this: ^Sprite, r: Rect) {
-        texture, valid := texture_lookup(sheet);
-
-        immediate_set_color(color);
-        if !valid {
-            immediate_rectangle(r.x, r.y, r.w, r.h);
-        } else {
-            immediate_subimage(^texture, r.x, r.y, r.w, r.h, pos.x, pos.y, size.x, size.y);
-        }
-    }
-}
diff --git a/src/entity/scene.onyx b/src/entity/scene.onyx
new file mode 100644 (file)
index 0000000..968afba
--- /dev/null
@@ -0,0 +1,418 @@
+
+use package core
+use package glfw3
+
+Entity_Nothing :: cast(Entity_ID) 0
+Entity_ID :: #distinct u32
+#match    hash.to_u32 macro (e: Entity_ID) => (package core.hash).to_u32(cast(u32) e);
+#operator == (a, b: Entity_ID) => cast(u32) a == cast(u32) b;
+#operator != (a, b: Entity_ID) => cast(u32) a != cast(u32) b;
+
+#init #after conv.custom_formatters_initialized () {
+    conv.register_custom_parser((e: ^Entity_ID, line: str, _: Allocator) => {
+        *e = ~~ cast(u32) conv.str_to_i64(line);
+        return true;
+    });
+}
+
+#local Component_Vtable :: struct {
+    //
+    // 'init' is called when the component is first created, before it
+    // has been added to any entity.
+    init       : (rawptr) -> void               = null_proc;
+
+    // 
+    // 'added' is called when the component is added to an entity.
+    // In theory, it could be called multiple times, if the component
+    // is shared between multiple entities.
+    added      : (rawptr, ^Entity) -> void      = null_proc;
+
+    //
+    // 'update' is called every update cycle. Currently, there is no
+    // specified as to the order in which components get updated.
+    // I think by circumstance, it is the order that you add them
+    // to the entity, but could break in the future.
+    update     : (rawptr, ^Entity, f32) -> void = null_proc;
+
+    //
+    // 'post_render' is called after the entity has been rendered
+    // normally. Entities must have a 'RenderComponent' in order
+    // to have 'post_render' called on their components. This
+    // can be used to add overlays or popups to an entity.
+    post_render: (rawptr, ^Entity) -> void      = null_proc;
+}
+
+Component :: struct {
+    #tag Editor_Hidden, Entity_Store.Skip
+    use vtable: ^Component_Vtable;
+
+    #tag Editor_Hidden, Entity_Store.Skip
+    type: type_expr;
+}
+
+IsComponent :: interface (c: $C) {
+    { c } -> ^Component;
+}
+
+RenderComponent :: struct {
+    use base: Component;
+
+    #tag Editor_Hidden, Entity_Store.Skip
+    func : (e: ^Entity) -> void;
+
+    layer := 0;
+    color := Color.{1, 1, 1};
+}
+
+SizeComponent :: struct {
+    use base: Component;
+    func : (e: ^Entity) -> Rect;
+
+    #struct_tag Entity_Store.Skip
+}
+
+InteractableComponent :: struct {
+    use base: Component;
+    interact: (e: ^Entity, interactor: ^Entity) -> void;
+
+    #struct_tag Entity_Store.Skip
+}
+
+Entity :: struct {
+    id: Entity_ID;
+    flags: Entity_Flags;
+
+    #tag Entity_Store.Skip
+    schematic: type_expr;
+
+    pos:  Vector2;
+
+    // Does every entity need to have a size?
+    size: Vector2;
+    get_rect :: (use e: ^Entity) => {
+        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 };
+    };
+
+    #tag Entity_Store.Skip, Editor_Hidden
+    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];
+    add :: (use this: ^Entity,  component: ^Component) => {
+        if components->has(component.type) do return;
+        components[component.type] = component;
+        if component.added != null_proc {
+            component->added(this);
+        }
+    }
+}
+
+
+Entity_Flags :: enum #flags {
+    // These have defined values for stable serialization.
+    Interactable :: 0x01;
+    Solid        :: 0x02;
+    Carryable    :: 0x04;
+    Dead         :: 0x80000000;
+}
+
+Entity_Schematic :: struct {
+    create: (^Scene) -> ^Entity;
+    type := void; // This will be filled out at runtime.
+}
+
+Scene :: struct {
+    entity_allocator: Allocator;
+
+    // Hmmm... Do they need to be stored in both ways?
+    entities: [..] ^Entity;
+    entity_map: Map(Entity_ID, ^Entity);
+
+    schematics: Map(str, ^Entity_Schematic);
+    component_vtables: Map(type_expr, ^Component_Vtable);
+
+    next_entity_id: Entity_ID;
+
+    add            :: scene_add;
+    make           :: scene_make;
+    update         :: scene_update;
+    draw           :: scene_draw;
+    get            :: scene_get;
+    delete         :: scene_delete;
+    query          :: scene_query;
+    query_by_flags :: scene_query_by_flags;
+
+    count_by_component :: scene_count_by_component;
+
+    query_by_component :: scene_query_by_component;
+    create_component :: scene_create_component;
+    create_and_add :: scene_create_and_add;
+
+    create_from_schematic :: scene_create_from_schematic;
+
+    load_from_file :: scene_load_from_file;
+    save_to_file   :: scene_save_to_file;
+}
+
+scene_create :: () -> Scene {
+    em: Scene;
+    em.entity_allocator = context.allocator; @TODO // Replace the allocator here.
+
+    array.init(^em.entities, 4);
+
+    // Entity ID 0 is reserved as a "empty / null" entity
+    em.next_entity_id = 1;
+
+    scene_load_schematics(^em);
+    return em;
+}
+
+#local scene_load_schematics :: (use this: ^Scene) {
+    use type_info;
+
+    index := 0;
+    for type_table {
+        defer index += 1;
+        if it.kind != .Struct do continue;
+
+        s_info := cast(^Type_Info_Struct) it;
+        for^ s_info.tags {
+            if it.type == Entity_Schematic {
+                schematic := cast(^Entity_Schematic) it.data;
+
+                // This is (mostly) safe to do as this data is in static memory
+                // and is not shared with any other type info.
+                schematic.type = cast(type_expr) index;
+
+                // This is safe to use as the key, as a struct's name exists in static memory.
+                schematics[s_info.name] = schematic;
+
+                debug_log(.Debug, "Discovered schematic: '{}'", s_info.name);
+                continue continue;
+            }
+        }
+
+        if struct_inherits(~~ index, Component) {
+            debug_log(.Debug, "Discovered component: '{}'", s_info.name);
+
+            comp_type := cast(type_expr) index;
+            if !component_vtables->has(comp_type) {
+                vtable := new(Component_Vtable, allocator=entity_allocator);
+                type_info.populate_struct_vtable(vtable, comp_type, safe=false);
+                component_vtables[comp_type] = vtable;
+            }
+        }
+    }
+}
+
+scene_add :: (use this: ^Scene, entity: ^Entity) -> Entity_ID {
+    // Automatically assign an id if the entity does not have one.
+    // This will not be used when loading the entity from a file.
+    if entity.id == 0 {
+        entity.id = next_entity_id;
+        next_entity_id = ~~(cast(u32) next_entity_id + 1);
+    } else {
+        next_entity_id = ~~(math.max(cast(u32) next_entity_id, cast(u32) entity.id) + 1);
+    }
+
+    entities << entity;
+    entity_map[entity.id] = entity;
+    return entity.id;
+}
+
+scene_make :: (use this: ^Scene) -> ^Entity {
+    entity := new(Entity, allocator=entity_allocator);
+    map.init(^entity.components);
+    return entity;
+}
+
+scene_create_from_schematic :: (use this: ^Scene, schematic_name: str) -> ^Entity {
+    schematic := schematics[schematic_name];
+    if schematic == null do return null;
+
+    entity := schematic.create(this);
+    entity.schematic = schematic.type;
+    return entity;
+}
+
+scene_create_component :: (use this: ^Scene, component_type: type_expr) -> ^Component {
+    comp := cast(^Component) 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);
+    if comp.init != null_proc {
+        comp->init();
+    }
+
+    return comp;
+}
+
+scene_create_and_add :: macro (this: ^Scene, entity: ^Entity, $component_type: type_expr, init_block: Code) where IsComponent(^component_type) {
+    use package core.intrinsics.onyx {__initialize}
+
+    comp := cast(^component_type) this->create_component(component_type);
+
+    // The 'create_component' function does not initailize the component, as it is not
+    // a compile time known parameter and therefore cannot know how to initialize it.
+    // This 'create_and_add' function is more often used by the programmer, so initializing
+    // the component here before returning is a good idea.
+    __initialize(comp);
+
+    #insert init_block;
+    entity->add(comp);
+}
+
+scene_update :: (use this: ^Scene, dt: f32) {
+    for entities {
+        for^ entry: it.components.entries {
+            comp := entry.value;
+            if comp.update != null_proc {
+                comp->update(it, dt);
+            }
+        }
+    }
+
+    while i := 0; i < entities.count {
+        defer i += 1;
+
+        if entities[i].flags & .Dead {
+            this->delete(entities[i]);
+            i -= 1;
+        }
+    }
+}
+
+scene_draw :: (use this: ^Scene) {
+
+    //
+    // This is a rather expensive check.
+    // It could probably be done solely when entities are added/removed.
+    array.sort(entities, (e1, e2) => {
+        e1_comp := e1->get(RenderComponent);
+        e2_comp := e2->get(RenderComponent);
+
+        e1_layer := e1_comp.layer if e1_comp != null else 0;
+        e2_layer := e2_comp.layer if e2_comp != null else 0;
+
+        return e1_layer - e2_layer;
+    });
+
+    for entities {
+        render_comp := it->get(RenderComponent);
+        if render_comp != null {
+            immediate_set_color(render_comp.color);
+            render_comp.func(it);
+
+            for^ entry: it.components.entries {
+                comp := entry.value;
+                if comp.post_render != null_proc {
+                    comp->post_render(it);
+                }
+            }
+        }
+    }
+}
+
+scene_get :: (use this: ^Scene, id: Entity_ID) => entity_map[id];
+
+scene_delete :: (use this: ^Scene, ent: ^Entity, delete_from_array := true) {
+    map.delete(^entity_map, ent.id);
+
+    //
+    // Not deleting the entity from the array, because this messes with the
+    // order, and becaues of that, it breaks a for-loop.
+    if delete_from_array do array.remove(^entities, ent); // This preserves the order of the entities, but does that matter?
+
+    // This assuems that components cannot and will not be shared between entities.
+    for^ ent.components.entries {
+        if it.value != null {
+            raw_free(entity_allocator, it.value);
+        }
+    }     
+
+    map.free(^ent.components);
+    raw_free(entity_allocator, ent);
+}
+
+scene_count_by_component :: (use this: ^Scene, comp_type: type_expr) -> u32 {
+    count := 0;
+    for entities {
+        if it->has(comp_type) {
+            count += 1;
+        }
+    }
+
+    return count;
+}
+
+scene_query :: (use this: ^Scene, area: Rect) -> [] ^Entity {
+    ents: [..] ^Entity;
+    for entities {
+        if Rect.intersects(Entity.get_rect(it), area) {
+            ents << it;
+        }
+    }
+
+    return ents;
+}
+
+scene_query_by_component :: (use this: ^Scene, area: Rect, comp_type: type_expr) -> [] ^Entity {
+    ents: [..] ^Entity;
+    for entities {
+        if !it.components->has(comp_type) do continue;
+
+        if Rect.intersects(Entity.get_rect(it), area) {
+            ents << it;
+        }
+    }
+
+    return ents;
+}
+
+scene_query_by_flags :: (use this: ^Scene, area: Rect, flags: Entity_Flags) -> [] ^Entity {
+    ents: [..] ^Entity;
+
+    // Currently, enum #flags are not the greatest and & doesn't do what you want it to here.
+    expected_flags := cast(u32) flags;
+
+    for entities {
+        if ~~ it.flags & expected_flags != expected_flags do continue;
+
+        if Rect.intersects(Entity.get_rect(it), area) {
+            ents << it;
+        }
+    }
+
+    return ents;
+}
+
+
+
+
+
+@Relocate
+Sprite :: struct {
+    sheet: str;
+    pos:  Vector2;
+    size: Vector2;
+    color: Color;
+
+    render :: (use this: ^Sprite, r: Rect) {
+        texture, valid := texture_lookup(sheet);
+
+        immediate_set_color(color);
+        if !valid {
+            immediate_rectangle(r.x, r.y, r.w, r.h);
+        } else {
+            immediate_subimage(^texture, r.x, r.y, r.w, r.h, pos.x, pos.y, size.x, size.y);
+        }
+    }
+}
index 058692fd1caf1c543aeb55036f6ca504fa10a430..c21ca8442e3b3f6356165b543b28eeb355e0d1b1 100644 (file)
@@ -6,7 +6,7 @@ Furniture :: struct {
         (scene) => Furniture.create(scene, .{0, 0})
     }
 
-    create :: (scene: ^Entity_Manager, pos: Vector2) -> ^Entity {
+    create :: (scene: ^Scene, pos: Vector2) -> ^Entity {
         this := scene->make();
         this.pos = pos;
         this.size = .{16, 16};
index fd0dffd3986552268be5e00e2aa4c9820db7c4aa..1281629f05f75e9fd5971fb8e449c916064774d1 100644 (file)
@@ -6,7 +6,7 @@ Patron :: struct {
         (scene) => Patron.create(scene, .{0,0})
     }
 
-    create :: (scene: ^Entity_Manager, pos: Vector2) -> ^Entity {
+    create :: (scene: ^Scene, pos: Vector2) -> ^Entity {
         this := scene->make();
         this.pos = pos;
         this.size = .{32, 32};
index 3d516223491e4dbc6443a8d86286965e32d03efa..d5ea2d5dcfebedfc5efe9e6db6ef79f048ff62ce 100644 (file)
@@ -32,10 +32,10 @@ player_2_controls :: Player_Controls.{
 
 Player :: struct {
     #struct_tag Entity_Schematic.{
-        (scene: ^Entity_Manager) => Player.create(scene, .{0,0})
+        (scene: ^Scene) => Player.create(scene, .{0,0})
     }
 
-    create :: (scene: ^Entity_Manager, pos: Vector2, controls := player_1_controls) -> ^Entity {
+    create :: (scene: ^Scene, pos: Vector2, controls := player_1_controls) -> ^Entity {
         this := scene->make();
         this.pos = pos;
         this.size = .{32, 32};
index 4c00be0b82e789261240d5ab86c867287a51d20a..8db88e84ccc8e9c02f1fc7febc9538efa4264b91 100644 (file)
@@ -4,7 +4,7 @@ Tap :: struct {
         (scene) => Tap.create(scene, .{0,0}, .{0,0})
     }
 
-    create :: (scene: ^Entity_Manager, pos: Vector2, size: Vector2) -> ^Entity {
+    create :: (scene: ^Scene, pos: Vector2, size: Vector2) -> ^Entity {
         this := scene->make();
         this.pos = pos;
         this.size = size;
index 77be0bb58c0680d145b0b1d04043c51628b49f66..c9eb05c61a7d30a83cbe62c1f5dda0091879312e 100644 (file)
@@ -7,7 +7,7 @@ Entity_Store :: enum {
     Skip;
 }
 
-entity_manager_save_to_file :: (use this: ^Entity_Manager, filename: str) {
+scene_save_to_file :: (use this: ^Scene, filename: str) {
     err, output_file := os.open(filename, .Write);
     defer os.close(^output_file);
     writer_ := io.writer_make(^output_file);
@@ -83,7 +83,7 @@ entity_manager_save_to_file :: (use this: ^Entity_Manager, filename: str) {
     }
 }
 
-entity_manager_load_from_file :: (use this: ^Entity_Manager, filename: str) {
+scene_load_from_file :: (use this: ^Scene, filename: str) {
     err, input_file := os.open(filename, .Read);
     if err != .None {
         debug_log(.Error, "Failed to open file: {}", filename);
index fb5f83276943d3db250187098b3acd67486b9231..30994197c4455b972c521e54be2b44c7b1a883d8 100644 (file)
@@ -7,7 +7,7 @@ use package opengles
 // Game Global Variables
 //
 
-scene: Entity_Manager;
+scene: Scene;
 item_store: Item_Store;
 
 scene_render_offset: Vector2;
@@ -26,7 +26,7 @@ game_init :: () {
 
     load_assets();
 
-    scene = entity_manager_create();
+    scene = scene_create();
     scene->load_from_file(quick_save_file);
 
     item_store = item_store_make();