:beer
name="Beer"
texture_path="./assets/images/beer-1.png"
+texture_pos = 0 0
+texture_size = 16 16
[Wall]
id = 11
-flags = 2
+flags = 3
pos.x = 440.0000
pos.y = 160.0000
size.x = 16.0000
[Player]
id = 12
flags = 2
-pos.x = 452.6227
-pos.y = 356.0881
+pos.x = 544.3174
+pos.y = 236.6171
size.x = 32.0000
size.y = 32.0000
:MovementComponent
controls.right = 68
controls.interact = 70
controls.pick_up = 71
-facing = 1
+facing = 4
:PlayerComponent
holding = 0
:RenderComponent
:ItemComponent
item = "beer"
+[Item_Entity]
+id = 15
+flags = 4
+pos.x = 555.2645
+pos.y = 298.4719
+size.x = 16.0000
+size.y = 16.0000
+:RenderComponent
+color.r = 1.0000
+color.g = 1.0000
+color.b = 1.0000
+color.a = 1.0000
+:ItemComponent
+item = "beer"
+
+[Tap]
+id = 16
+flags = 3
+pos.x = 576.0000
+pos.y = 160.0000
+size.x = 32.0000
+size.y = 32.0000
+:RenderComponent
+color.r = 0.1000
+color.g = 0.1000
+color.b = 1.0000
+color.a = 1.0000
+:DispenserComponent
+item = "beer"
+max_timeout = 5.0000
+
#load "core/std"
-#load "config"
-#load "game"
-#load "main"
-
-#load "entity/editor"
-#load "entity/items"
-#load "entity/manager"
-#load "entity/player"
-#load "entity/store"
-
-#load "gfx/canvas"
-#load "gfx/font"
-#load "gfx/immediate"
-#load "gfx/mesh"
-#load "gfx/shader"
-#load "gfx/texture"
-#load "gfx/ui"
-
-#load "utils/any_utils"
-#load "utils/asset_loader"
-#load "utils/input"
-#load "utils/logger"
-#load "utils/vecmath"
+#load_all "./."
+
+#load_all "./entity"
+#load_all "./entity/components"
+#load_all "./entity/schematics"
+#load_all "./gfx"
+#load_all "./utils"
#load "stb_image"
#load "stb_truetype"
--- /dev/null
+
+use package core
+
+//
+// Currently, DispenserComponents only dispense Item_Entity's, and no
+// other entity type. I can't think of a reason at the moment that
+// you would need to dispense something else, but that is a limitation.
+
+DispenserComponent :: struct {
+ use base: Component;
+
+ item: str;
+ max_timeout := 2.0f;
+
+ #tag Entity_Store.Skip
+ timeout := 0.0f;
+
+ added :: (use this: ^DispenserComponent, entity: ^Entity) {
+ if entity->has(InteractableComponent) {
+ debug_log(.Error, "DispenserComponent expected entity to not have an InteractableComponent");
+ }
+
+ scene->create_and_add(entity, InteractableComponent) {
+ comp.interact = interact;
+ }
+ }
+
+ update :: (use this: ^DispenserComponent, entity: ^Entity, dt: f32) {
+ timeout -= dt;
+ if timeout < 0 do timeout = 0;
+ }
+
+ interact :: (this: ^Entity, entity: ^Entity) {
+ if entity->has(PlayerComponent) {
+ player_comp := entity->get(PlayerComponent);
+ if player_comp.holding != Entity_Nothing do return;
+
+ dispenser_comp := this->get(DispenserComponent);
+ if dispenser_comp.timeout != 0 do return;
+
+ item := scene->create_from_schematic("Item_Entity");
+ if item == null {
+ debug_log(.Error, "Bad schematic type.");
+ return;
+ }
+
+ // This should dynamic...
+ item.size = .{16, 16};
+ (item->get(ItemComponent)).item = dispenser_comp.item;
+
+ scene->add(item);
+ player_comp.holding = item.id;
+ dispenser_comp.timeout = dispenser_comp.max_timeout;
+ }
+ }
+
+ post_render :: (use this: ^DispenserComponent, entity: ^Entity) {
+ if timeout != 0 {
+ rect := entity->get_rect();
+
+ percent := (max_timeout - timeout) / max_timeout;
+ rect.y += (1 - percent) * rect.h;
+ rect.h *= percent;
+
+ immediate_set_color(.{0.4, 1, 0.4, 0.8});
+ immediate_rectangle(rect.x, rect.y, rect.w, rect.h);
+ }
+ }
+}
+
color := Color.{ 1, 1, 1 };
texture_path : str;
+ texture_pos := Vector2.{0, 0};
+ texture_size := Vector2.{1, 1};
}
Item_Store :: struct {
if !loaded {
immediate_rectangle(r.x, r.y, r.w, r.h);
} else {
- immediate_image(^texture, r.x, r.y, r.w, r.h);
+ tp := item_data.texture_pos;
+ ts := item_data.texture_size;
+ // immediate_image(^texture, r.x, r.y, r.w, r.h);
+ immediate_subimage(^texture, r.x, r.y, r.w, r.h,
+ tp.x, tp.y, ts.x, ts.y);
}
}
}
}
#local Component_Vtable :: struct {
- init : (rawptr) -> void = null_proc;
- update: (rawptr, ^Entity, f32) -> void = null_proc;
+ //
+ // '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
func : (e: ^Entity) -> void;
- color := Color.{1,1,1};
+ layer := 0;
+ color := Color.{1, 1, 1};
}
SizeComponent :: struct {
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_manager_draw :: (use this: ^Entity_Manager) {
// Entities should be sorted by z-order.
+
+
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);
+ }
+ }
}
}
}
player_assets: struct {
#tag "assets/images/player.png"
+ #tag Texture_Wrap.Clamp
texture: Texture;
}
--- /dev/null
+
+Tap :: struct {
+ #struct_tag Entity_Schematic.{
+ (scene) => Tap.create(scene, .{0,0}, .{0,0})
+ }
+
+ create :: (scene: ^Entity_Manager, pos: Vector2, size: Vector2) -> ^Entity {
+ this := scene->make();
+ this.pos = pos;
+ this.size = size;
+ this.flags |= .Solid;
+ this.flags |= .Interactable;
+
+ scene->create_and_add(this, RenderComponent) {
+ comp.func = render;
+ }
+
+ scene->create_and_add(this, DispenserComponent) {
+ comp.item = "beer";
+ }
+
+ return this;
+ }
+
+ render :: (use this: ^Entity) {
+ rect := this->get_rect();
+
+ immediate_rectangle(rect.x, rect.y, rect.w, rect.h);
+ }
+}
+
+tap_assets: struct {
+ #tag "./assets/"
+ texture: Texture;
+}
\ No newline at end of file
canvas_use(null);
immediate_clear(.{1, 1, 1});
+ immediate_set_color(.{1, 1, 1});
texture := canvas_to_texture(^scene_canvas);
view_rect: Rect;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + texture_binding);
glBindTexture(GL_TEXTURE_2D, texture);
}
+
+
+Texture_Wrap :: enum {
+ Clamp :: GL_CLAMP_TO_EDGE | 0;
+ Repeat :: GL_REPEAT | 0;
+ Mirrored_Repeat :: GL_MIRRORED_REPEAT | 0;
+}
+
+texture_wrap :: (use tex: ^Texture, wrap: Texture_Wrap) {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ~~ wrap);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ~~ wrap);
+}
\ No newline at end of file
}
main :: (args) => {
- debug_set_level(.Info);
+ debug_set_level(.Debug);
if !glfwInit() {
debug_log(.Critical, "Failed to initialize GLFW!");
os.exit(1);
for info.members {
if it.name == part_name {
member_info := get_type_info(it.type);
- if member_info.kind == .Struct {
+ if member_info.kind == .Struct && name != "" {
return get_any_for_member(any.{cast(^u8) base.data + it.offset, it.type}, name);
} else {
return any.{cast(^u8) base.data + it.offset, it.type};
if path_tag != null {
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 {
+ wrap := *cast(^Texture_Wrap) wrap_tag.data;
+ texture_wrap(^texture, wrap);
+ }
+
*out_texture = texture;
} else {
debug_log(.Error, "Failed to load texture '{}' for asset queued here: {}:{},{}.\n", path, location.file, location.line, location.column);
Zero :: Vector2.{0, 0}
#struct_tag conv.Custom_Format.{format_vector2}
+ #struct_tag conv.Custom_Parse.{parse_vector2}
}
Vector3i :: struct {
format_vector3i :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector3i) {
conv.format(output, "({}, {}, {})", v.x, v.y, v.z);
}
+
+ parse_vector2 :: (output: ^Vector2, line_: str, string_allocator: Allocator) -> bool {
+ string :: package core.string
+
+ line := line_;
+ xs := string.read_until(^line, #char " ");
+ string.advance(^line, 1);
+ ys := string.read_until(^line, #char " ");
+
+ if xs == "" || ys == "" do return false;
+
+ output.x = ~~ conv.str_to_f64(xs);
+ output.y = ~~ conv.str_to_f64(ys);
+ return true;
+ }
}