mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Update demo for both subtyping and union based Entity
This commit is contained in:
+100
-91
@@ -20,6 +20,7 @@ import (
|
|||||||
*/
|
*/
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
general_stuff :: proc() {
|
general_stuff :: proc() {
|
||||||
// Complex numbers
|
// Complex numbers
|
||||||
a := 3 + 4i;
|
a := 3 + 4i;
|
||||||
@@ -251,112 +252,120 @@ explicit_parametric_polymorphic_procedures :: proc() {
|
|||||||
a, b = b, a; // Or use this syntax for this silly example case
|
a, b = b, a; // Or use this syntax for this silly example case
|
||||||
|
|
||||||
|
|
||||||
// A more complicated example using subtyping
|
|
||||||
// Something like this could be used in a game
|
|
||||||
Vector2 :: struct {x, y: f32;};
|
Vector2 :: struct {x, y: f32;};
|
||||||
|
{
|
||||||
|
// A more complicated example using subtyping
|
||||||
|
// Something like this could be used in a game
|
||||||
|
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
using position: Vector2;
|
using position: Vector2;
|
||||||
flags: u64;
|
flags: u64;
|
||||||
id: u64;
|
id: u64;
|
||||||
batch_index: u32;
|
derived: any;
|
||||||
slot_index: u32;
|
|
||||||
portable_id: u32;
|
|
||||||
derived: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rock :: struct {
|
|
||||||
using entity: ^Entity;
|
|
||||||
heavy: bool;
|
|
||||||
}
|
|
||||||
Door :: struct {
|
|
||||||
using entity: ^Entity;
|
|
||||||
open: bool;
|
|
||||||
}
|
|
||||||
Monster :: struct {
|
|
||||||
using entity: ^Entity;
|
|
||||||
is_robot: bool;
|
|
||||||
is_zombie: bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityManager :: struct {
|
|
||||||
batches: [dynamic]^EntityBatch;
|
|
||||||
next_portable_id: u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENTITIES_PER_BATCH :: 16;
|
|
||||||
EntityBatch :: struct {
|
|
||||||
data: [ENTITIES_PER_BATCH]Entity;
|
|
||||||
occupied: [ENTITIES_PER_BATCH]bool;
|
|
||||||
batch_index: u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
use_empty_slot :: proc(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity {
|
|
||||||
for ok, i in batch.occupied {
|
|
||||||
if ok do continue;
|
|
||||||
batch.occupied[i] = true;
|
|
||||||
|
|
||||||
e := &batch.data[i];
|
|
||||||
e.batch_index = u32(batch.batch_index);
|
|
||||||
e.slot_index = u32(i);
|
|
||||||
e.portable_id = manager.next_portable_id;
|
|
||||||
manager.next_portable_id++;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_new_entity :: proc(manager: ^EntityManager) -> ^Entity {
|
|
||||||
for b in manager.batches {
|
|
||||||
e := use_empty_slot(manager, b);
|
|
||||||
if e != nil do return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_batch := new(EntityBatch);
|
Rock :: struct {
|
||||||
append(&manager.batches, new_batch);
|
using entity: Entity;
|
||||||
new_batch.batch_index = u32(len(manager.batches)-1);
|
heavy: bool;
|
||||||
|
}
|
||||||
|
Door :: struct {
|
||||||
|
using entity: Entity;
|
||||||
|
open: bool;
|
||||||
|
}
|
||||||
|
Monster :: struct {
|
||||||
|
using entity: Entity;
|
||||||
|
is_robot: bool;
|
||||||
|
is_zombie: bool;
|
||||||
|
}
|
||||||
|
|
||||||
return use_empty_slot(manager, new_batch);
|
new_entity :: proc(T: type, x, y: f32) -> ^T {
|
||||||
|
result := new(T);
|
||||||
|
result.derived = result^;
|
||||||
|
result.x = x;
|
||||||
|
result.y = y;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
entities: [dynamic]^Entity;
|
||||||
|
|
||||||
|
rock := new_entity(Rock, 3, 5);
|
||||||
|
|
||||||
|
// Named arguments work too!
|
||||||
|
door := new_entity(T = Door, x = 3, y = 6);
|
||||||
|
|
||||||
|
// And named arguments can be any order
|
||||||
|
monster := new_entity(
|
||||||
|
y = 1,
|
||||||
|
x = 2,
|
||||||
|
T = Monster,
|
||||||
|
);
|
||||||
|
|
||||||
|
append(&entities, rock, door, monster);
|
||||||
|
|
||||||
|
fmt.println("Subtyping");
|
||||||
|
for entity in entities {
|
||||||
|
match e in entity.derived {
|
||||||
|
case Rock: fmt.println("Rock", e.x, e.y);
|
||||||
|
case Door: fmt.println("Door", e.x, e.y);
|
||||||
|
case Monster: fmt.println("Monster", e.x, e.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Entity :: struct {
|
||||||
|
using position: Vector2;
|
||||||
|
flags: u64;
|
||||||
|
id: u64;
|
||||||
|
variant: union { Rock, Door, Monster };
|
||||||
|
}
|
||||||
|
|
||||||
|
Rock :: struct {
|
||||||
|
using entity: ^Entity;
|
||||||
|
heavy: bool;
|
||||||
|
}
|
||||||
|
Door :: struct {
|
||||||
|
using entity: ^Entity;
|
||||||
|
open: bool;
|
||||||
|
}
|
||||||
|
Monster :: struct {
|
||||||
|
using entity: ^Entity;
|
||||||
|
is_robot: bool;
|
||||||
|
is_zombie: bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_entity :: proc(T: type, x, y: f32) -> ^T {
|
||||||
|
result := new(Entity);
|
||||||
|
result.variant = T{entity = result};
|
||||||
|
result.x = x;
|
||||||
|
result.y = y;
|
||||||
|
|
||||||
new_entity :: proc(manager: ^EntityManager, T: type, x, y: f32) -> ^T {
|
return ^T(&result.variant);
|
||||||
result := new(T);
|
}
|
||||||
result.entity = gen_new_entity(manager);
|
|
||||||
result.derived.data = result;
|
|
||||||
result.derived.type_info = type_info(T);
|
|
||||||
|
|
||||||
result.position.x = x;
|
entities: [dynamic]^Entity;
|
||||||
result.position.y = y;
|
|
||||||
|
|
||||||
return result;
|
rock := new_entity(Rock, 3, 5);
|
||||||
}
|
|
||||||
|
|
||||||
manager: EntityManager;
|
// Named arguments work too!
|
||||||
entities: [dynamic]^Entity;
|
door := new_entity(T = Door, x = 3, y = 6);
|
||||||
|
|
||||||
rock := new_entity(&manager, Rock, 3, 5);
|
// And named arguments can be any order
|
||||||
|
monster := new_entity(
|
||||||
|
y = 1,
|
||||||
|
x = 2,
|
||||||
|
T = Monster,
|
||||||
|
);
|
||||||
|
|
||||||
// Named arguments work too!
|
append(&entities, rock, door, monster);
|
||||||
door := new_entity(manager = &manager, T = Door, x = 3, y = 6);
|
|
||||||
|
|
||||||
// And named arguments can be any order
|
fmt.println("Union");
|
||||||
monster := new_entity(
|
for entity in entities {
|
||||||
y = 1,
|
match e in entity.variant {
|
||||||
x = 2,
|
case Rock: fmt.println("Rock", e.x, e.y);
|
||||||
manager = &manager,
|
case Door: fmt.println("Door", e.x, e.y);
|
||||||
T = Monster,
|
case Monster: fmt.println("Monster", e.x, e.y);
|
||||||
);
|
}
|
||||||
|
|
||||||
append(&entities, rock, door, monster);
|
|
||||||
|
|
||||||
// An alternative to `union`s
|
|
||||||
for entity in entities {
|
|
||||||
match e in entity.derived {
|
|
||||||
case Rock: fmt.println("Rock", e.portable_id, e.x, e.y);
|
|
||||||
case Door: fmt.println("Door", e.portable_id, e.x, e.y);
|
|
||||||
case Monster: fmt.println("Monster", e.portable_id, e.x, e.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3338,6 +3338,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
|||||||
|
|
||||||
// Cast between pointers
|
// Cast between pointers
|
||||||
if (is_type_pointer(src) && is_type_pointer(dst)) {
|
if (is_type_pointer(src) && is_type_pointer(dst)) {
|
||||||
|
#if 0
|
||||||
Type *s = base_type(type_deref(src));
|
Type *s = base_type(type_deref(src));
|
||||||
if (is_type_union(s)) {
|
if (is_type_union(s)) {
|
||||||
// NOTE(bill): Should the error be here?!
|
// NOTE(bill): Should the error be here?!
|
||||||
@@ -3349,6 +3350,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
|||||||
gb_string_free(xs);
|
gb_string_free(xs);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user