~~(path_pos.x * grid_size),
~~(path_pos.y * grid_size),
};
- visited->delete(path_pos);
path_pos = visited[path_pos].prev;
}
ent_rect := Entity.get_rect(this);
holding: Entity_ID;
- if player := this->get(PlayerComponent); player != null {
+ if player := this->get(PlayerComponent); player {
holding = player.holding;
}
consume_timeout -= dt;
if consume_timeout < 0 {
holding_object := scene->get(holding);
- if holding_object != null {
+ if holding_object {
holding_object.flags |= .Dead;
holding = Entity_Nothing;
post_render :: (use this: ^PlayerComponent, entity: ^Entity) {
if nearby_interact != Entity_Nothing {
it := scene->get(nearby_interact);
- if it != null {
+ if it {
r := it->get_rect();
immediate_set_color(.{.2, .2, .8, .7});
immediate_rectangle(r.x, r.y, r.w, r.h);
if nearby_holding != Entity_Nothing && holding == Entity_Nothing {
it := scene->get(nearby_holding);
- if it != null {
+ if it {
r := it->get_rect();
immediate_set_color(.{.2, .8, .2, .7});
immediate_rectangle(r.x, r.y, r.w, r.h);
} else {
schematic := scene.schematics.entries[active_index - 1].value;
entity = schematic.create(^scene);
- entity.schematic = schematic.type;
+ entity.schematic = scene.schematics.entries[active_index - 1].key;
}
scene->add(entity);
}
defer scrolling_region_stop();
- info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(entity.schematic);
- if info != null {
- font_print(editor_big_font, x + 2, y + 24, info.name);
- }
+ font_print(editor_big_font, x + 2, y + 24, entity.schematic);
if active_index == Component_Selection_Active {
if draw_button(.{ x + w - 150, y, 150, 24 }, "Back") {
y += 32;
for^ entry: scene.component_vtables.entries {
- info = ~~ type_info.get_type_info(entry.key);
+ info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(entry.key);
if !string.contains(info.name, search_buffer) do continue;
if draw_button(.{ x, y, w, 32 }, info.name, increment=~~y) {
immediate_rectangle(x, y, w, 4);
y += 16;
- info = ~~ type_info.get_type_info(entry.key);
+ info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(entry.key);
font_print(editor_font, x + 2, y + 20, info.name);
if draw_button(.{ x + w - 100, y, 100, 20 }, "Remove", increment=~~y) {
use glfw3
use ogre
-@Entity_Schematic.{
- (scene: ^Scene) => wall_create(scene, .{0,0}, .{0,0})
-}
-#local Wall :: struct {
- render :: (use this: ^Entity) {
- r := Entity.get_rect(this);
- immediate_rectangle(r.x, r.y, r.w, r.h);
- }
-}
+@Entity_Schematic.{ "Wall" }
+(scene: ^Scene) => wall_create(scene, .{0,0}, .{0,0})
wall_create :: (scene: ^Scene, pos, size: Vector2) -> ^Entity {
this := scene->make();
this.flags |= .Solid;
scene->modify_component(this, RenderComponent) {
- comp.func = Wall.render;
+ comp.func = wall_render;
}
return this;
}
-@Entity_Schematic.{create}
-#local Door :: struct {
- create :: (scene: ^Scene) => door_create(scene, .Zero, .Zero);
+#local
+wall_render :: (use this: ^Entity) {
+ r := Entity.get_rect(this);
+ immediate_rectangle(r.x, r.y, r.w, r.h);
+}
+
+@Entity_Schematic.{"Door"}
+(scene: ^Scene) => door_create(scene, .Zero, .Zero);
+
+door_create :: (scene: ^Scene, pos, size: Vector2) -> ^Entity {
+ this := scene->make();
+ this.pos = pos;
+ this.size = size;
+
+ this.flags |= .Interactable;
+ this.flags |= .Solid;
+
+ scene->modify_component(this, DoorComponent) {}
+ scene->modify_component(this, RenderComponent) { comp.func = Door.render; }
+ scene->modify_component(this, SizeComponent) { comp.func = Door.get_rect; }
+ scene->modify_component(this, InteractableComponent) { comp.interact = Door.interact; }
+
+ return this;
+}
+#local Door :: struct {
render :: (use this: ^Entity) {
immediate_set_color(.{0.7, 0.7, 0.1});
}
}
-door_create :: (scene: ^Scene, pos, size: Vector2) -> ^Entity {
- this := scene->make();
- this.pos = pos;
- this.size = size;
-
- this.flags |= .Interactable;
- this.flags |= .Solid;
-
- scene->modify_component(this, DoorComponent) {}
- scene->modify_component(this, RenderComponent) { comp.func = Door.render; }
- scene->modify_component(this, SizeComponent) { comp.func = Door.get_rect; }
- scene->modify_component(this, InteractableComponent) { comp.interact = Door.interact; }
-
- return this;
-}
-
Item_Store :: struct {
item_allocator: Allocator;
items: Map(str, ^Item);
+}
+#inject Item_Store {
load_items_from_file :: item_store_load_items_from_file;
get_item :: item_store_get_item;
}
return items[id];
}
-@Entity_Schematic.{create}
-#local Item_Entity :: struct {
+@Entity_Schematic.{"Item_Entity"}
+(scene: ^Scene) => {
+ this := scene->make();
+ this.pos = .{0, 0};
+ this.size = .{0, 0};
+ this.flags |= .Carryable;
- create :: (scene) => {
- this := scene->make();
- this.pos = .{0, 0};
- this.size = .{0, 0};
- this.flags |= .Carryable;
+ scene->modify_component(this, RenderComponent) { comp.func = item_entity_render; comp.layer = 10; }
+ scene->modify_component(this, ItemComponent) {}
+ return this;
+}
- scene->modify_component(this, RenderComponent) { comp.func = render; comp.layer = 10; }
- scene->modify_component(this, ItemComponent) {}
- return this;
+#local
+item_entity_render :: (use this: ^Entity) {
+ r := this->get_rect();
+ item_comp := this->get(ItemComponent);
+ item_data := item_store->get_item(item_comp.item);
+ if item_data == null {
+ immediate_set_color(.{1,0,0});
+ immediate_rectangle(r.x, r.y, r.w, r.h);
+ return;
}
- render :: (use this: ^Entity) {
- r := this->get_rect();
- item_comp := this->get(ItemComponent);
- item_data := item_store->get_item(item_comp.item);
- if item_data == null {
- immediate_set_color(.{1,0,0});
- immediate_rectangle(r.x, r.y, r.w, r.h);
- return;
- }
-
- item_data.sprite->render(r);
- }
+ item_data.sprite->render(r);
}
ItemComponent :: struct {
@Editor_Custom_Field.{render_item_picker}
item: str;
+}
+#inject ItemComponent {
get_info :: (use this: ^ItemComponent) -> ^Item {
return item_store->get_item(item);
}
flags: Entity_Flags;
@Entity_Store.Skip
- schematic: type_expr;
+ schematic: str;
nickname: str;
// Does every entity need to have a size?
size: Vector2;
+
+ @Entity_Store.Skip, Editor_Hidden
+ components: Map(type_expr, ^Component);
+}
+
+#inject Entity {
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 };
- };
-
- @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;
}
Entity_Schematic :: struct {
+ name: str;
+
+ // These will be filled out at runtime.
create: (^Scene) -> ^Entity;
- type := void; // This will be filled out at runtime.
}
Scene :: struct {
next_entity_id: Entity_ID;
width, height: f32;
+}
- 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;
+#inject Scene {
+ 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;
+ count_by_component :: scene_count_by_component
- query_by_component :: scene_query_by_component;
- create_component :: scene_create_component;
- modify_component :: scene_modify_component;
- first_component :: scene_first_component;
+ query_by_component :: scene_query_by_component
+ create_component :: scene_create_component
+ modify_component :: scene_modify_component
+ first_component :: scene_first_component
- create_from_schematic :: scene_create_from_schematic;
- duplicate :: scene_duplicate;
+ create_from_schematic :: scene_create_from_schematic
+ duplicate :: scene_duplicate
- load_from_file :: scene_load_from_file;
- save_to_file :: scene_save_to_file;
+ load_from_file :: scene_load_from_file
+ save_to_file :: scene_save_to_file
}
scene_create :: (width, height: f32) -> Scene {
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);
}
}
}
+
+ for get_procedures_with_tag(Entity_Schematic) {
+ schematic := it.tag;
+ schematic.create = *cast(^(^Scene) -> ^Entity) ^it.func;
+
+ schematics[schematic.name] = schematic;
+ debug_log(.Debug, "Discovered schematic: '{}'", schematic.name);
+ }
}
scene_add :: (use this: ^Scene, entity: ^Entity) -> Entity_ID {
if schematic == null do return null;
entity := schematic.create(this);
- entity.schematic = schematic.type;
+ entity.schematic = schematic_name;
return entity;
}
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;
+ e1_layer := e1_comp.layer if e1_comp else 0;
+ e2_layer := e2_comp.layer if e2_comp else 0;
return e1_layer - e2_layer;
});
for entities {
render_comp := it->get(RenderComponent);
- if render_comp != null {
+ if render_comp {
immediate_set_color(render_comp.color);
render_comp.func(it);
// This assuems that components cannot and will not be shared between entities.
for^ ent.components.entries {
- if it.value != null {
+ if it.value {
raw_free(entity_allocator, it.value);
}
}
pos: Vector2;
size: Vector2;
color: Color;
+}
+#inject Sprite {
render :: (use this: ^Sprite, r: Rect) {
texture, valid := texture_lookup(sheet);
// #local background_texture: Texture;
-@Entity_Schematic.{ Background.create }
-Background :: struct {
- create :: (scene) => {
- this := scene->make();
- this.pos = .{0, 0};
- this.size = .{0, 0};
+@Entity_Schematic.{ "Background" }
+(scene: ^Scene) => {
+ this := scene->make();
+ this.pos = .{0, 0};
+ this.size = .{0, 0};
- scene->modify_component(this, BackgroundComponent) {
- comp.texture_path = "./assets/images/background.png";
- }
-
- return this;
+ scene->modify_component(this, BackgroundComponent) {
+ comp.texture_path = "./assets/images/background.png";
}
+
+ return this;
}
use core
-@Entity_Schematic.{ Entryway.create }
-Entryway :: struct {
- create :: (scene) => {
- this := scene->make();
- this.size = .{16, 16};
+@Entity_Schematic.{ "Entryway" }
+(scene: ^Scene) => {
+ this := scene->make();
+ this.size = .{16, 16};
- scene->modify_component(this, SpriteRenderComponent) {
- comp.sprite.sheet = "./assets/images/spritesheet.png";
- comp.sprite.pos = .{0, 0};
- comp.sprite.size = .{16, 16};
- comp.sprite.color = .{1, 1, 1};
- }
-
- scene->modify_component(this, EntrywayComponent) {
- comp.schematic = "Patron";
- comp.spawned_size = .{16, 32};
- }
+ scene->modify_component(this, SpriteRenderComponent) {
+ comp.sprite.sheet = "./assets/images/spritesheet.png";
+ comp.sprite.pos = .{0, 0};
+ comp.sprite.size = .{16, 16};
+ comp.sprite.color = .{1, 1, 1};
+ }
- return this;
+ scene->modify_component(this, EntrywayComponent) {
+ comp.schematic = "Patron";
+ comp.spawned_size = .{16, 32};
}
+
+ return this;
}
use core
use ogre
-@Entity_Schematic.{
- (scene) => Furniture.create(scene, .{0, 0})
-}
-Furniture :: struct {
- create :: (scene: ^Scene, pos: Vector2) -> ^Entity {
- this := scene->make();
- this.pos = pos;
- this.size = .{16, 16};
- this.flags |= .Solid;
-
- scene->modify_component(this, FurnitureComponent) {}
+@Entity_Schematic.{ "Furniture" }
+(scene: ^Scene) -> ^Entity {
+ this := scene->make();
+ this.pos = .{0, 0};
+ this.size = .{16, 16};
+ this.flags |= .Solid;
- scene->modify_component(this, SpriteRenderComponent) {
- comp.sprite.sheet = "./assets/images/spritesheet.png";
- comp.sprite.pos = .{0, 32};
- comp.sprite.size = .{32, 32};
- comp.sprite.color = .{1, 1, 1};
- }
+ scene->modify_component(this, FurnitureComponent) {}
- return this;
+ scene->modify_component(this, SpriteRenderComponent) {
+ comp.sprite.sheet = "./assets/images/spritesheet.png";
+ comp.sprite.pos = .{0, 32};
+ comp.sprite.size = .{32, 32};
+ comp.sprite.color = .{1, 1, 1};
}
+
+ return this;
}
use core
use ogre
-@Entity_Schematic.{
- (scene: ^Scene) => Patron.create(scene, .{0,0})
-}
-Patron :: struct {
- create :: (scene: ^Scene, pos: Vector2) -> ^Entity {
- this := scene->make();
- this.pos = pos;
- this.size = .{32, 32};
- this.flags |= .Solid;
+@Entity_Schematic.{ "Patron" }
+(scene: ^Scene) -> ^Entity {
+ this := scene->make();
+ this.pos = .{0, 0};
+ this.size = .{32, 32};
+ this.flags |= .Solid;
- scene->modify_component(this, RenderComponent) {
- comp.func = render;
- comp.layer = 5;
- comp.color = .{1, 0, 0};
- }
+ scene->modify_component(this, RenderComponent) {
+ comp.func = patron_render;
+ comp.layer = 5;
+ comp.color = .{1, 0, 0};
+ }
- scene->modify_component(this, PatronComponent) {}
+ scene->modify_component(this, PatronComponent) {}
- return this;
- }
+ return this;
+}
- render :: (use this: ^Entity) {
- r := this->get_rect();
- immediate_subimage(^Spritesheet, r.x, r.y, r.w, r.h, 0*16, 4*16, 16, 16);
- }
+#local
+patron_render :: (use this: ^Entity) {
+ r := this->get_rect();
+ immediate_subimage(^Spritesheet, r.x, r.y, r.w, r.h, 0*16, 4*16, 16, 16);
}
}
-@Entity_Schematic.{
- (scene: ^Scene) => Player.create(scene, .{0,0})
-}
-Player :: struct {
- create :: (scene: ^Scene, pos: Vector2, controls := player_1_controls) -> ^Entity {
- this := scene->make();
- this.pos = pos;
- this.size = .{32, 32};
- this.flags |= .Solid;
-
- scene->modify_component(this, SizeComponent) {
- comp.func = (use this: ^Entity) => Rect.{pos.x - size.x / 2, pos.y, size.x, size.y / 2};
- }
+@Entity_Schematic.{ "Player" }
+(scene: ^Scene) -> ^Entity {
+ this := scene->make();
+ this.pos = .{0, 0};
+ this.size = .{32, 32};
+ this.flags |= .Solid;
- scene->modify_component(this, MovementComponent) {
- comp.controls = controls;
- }
-
- scene->modify_component(this, PlayerComponent) {
- comp.holding = Entity_Nothing;
- }
+ scene->modify_component(this, SizeComponent) {
+ comp.func = (use this: ^Entity) => Rect.{pos.x - size.x / 2, pos.y, size.x, size.y / 2};
+ }
- scene->modify_component(this, RenderComponent) {
- comp.func = PlayerComponent.render;
- comp.color = .{1,1,1};
- }
+ scene->modify_component(this, MovementComponent) {
+ comp.controls = player_1_controls;
+ }
- return this;
+ scene->modify_component(this, PlayerComponent) {
+ comp.holding = Entity_Nothing;
}
- #persist assets: struct {
- @"assets/images/player.png"
- @Texture_Wrap.Clamp
- texture: Texture;
+ scene->modify_component(this, RenderComponent) {
+ comp.func = PlayerComponent.render;
+ comp.color = .{1,1,1};
}
+
+ return this;
+}
+
+player_assets: struct {
+ @"assets/images/player.png"
+ @Texture_Wrap.Clamp
+ texture: Texture;
}
use ogre
-@Entity_Schematic.{
- (scene) => Tap.create(scene, .{0,0}, .{0,0})
-}
-Tap :: struct {
- create :: (scene: ^Scene, pos: Vector2, size: Vector2) -> ^Entity {
- this := scene->make();
- this.pos = pos;
- this.size = size;
- this.flags |= .Solid;
- this.flags |= .Interactable;
-
- scene->modify_component(this, SpriteRenderComponent) {
- comp.sprite.sheet = "./assets/images/spritesheet.png";
- comp.sprite.pos = .{ 0, 32 };
- comp.sprite.size = .{ 32, 32 };
- comp.sprite.color = .{ 1, 1, 1 };
- }
+@Entity_Schematic.{ "Tap" }
+(scene: ^Scene) -> ^Entity {
+ this := scene->make();
+ this.pos = .{0, 0};
+ this.size = .{0, 0};
+ this.flags |= .Solid;
+ this.flags |= .Interactable;
- scene->modify_component(this, DispenserComponent) {
- comp.item = "beer";
- }
+ scene->modify_component(this, SpriteRenderComponent) {
+ comp.sprite.sheet = "./assets/images/spritesheet.png";
+ comp.sprite.pos = .{ 0, 32 };
+ comp.sprite.size = .{ 32, 32 };
+ comp.sprite.color = .{ 1, 1, 1 };
+ }
- return this;
+ scene->modify_component(this, DispenserComponent) {
+ comp.item = "beer";
}
+
+ return this;
}
use runtime.info;
for entities {
- info := cast(^Type_Info_Struct) get_type_info(it.schematic);
- name := info.name;
- if name.count == 0 do name = "Custom";
+ name := it.schematic;
+ if !name do name = "Custom";
io.write_format(writer, "[{}]\n", name);
+
emit_struct_fields(any.{~~ it, Entity}, writer, "");
for^ it.components.entries {
if line.count <= 1 do continue;
if line[0] == #char "[" {
- if current_entity != null do this->add(current_entity);
+ if current_entity do this->add(current_entity);
current_component = null;
entity_kind := string.advance(line)
}
}
- if current_entity != null do this->add(current_entity);
+ if current_entity do this->add(current_entity);
}
out_texture := cast(^Texture) dest;
path_tag := array.first(tags, (x) => x.type == str);
- if path_tag != null {
+ if path_tag {
path := *cast(^str) path_tag.data;
if texture, success := texture_lookup(path); success {
- if wrap_tag := array.first(tags, (x) => x.type == Texture_Wrap); wrap_tag != null {
+ if wrap_tag := array.first(tags, (x) => x.type == Texture_Wrap); wrap_tag {
wrap := *cast(^Texture_Wrap) wrap_tag.data;
texture_wrap(^texture, wrap);
}