1 module re.ecs.entity; 2 3 import std.array; 4 import std.conv; 5 import std.algorithm.iteration; 6 import std.algorithm.searching; 7 import re.ng.scene; 8 import re.ecs.manager; 9 import re.ecs.component; 10 import re.ecs.storage; 11 import re.math; 12 13 /// a container for components 14 class Entity { 15 /// the unique id of this entity 16 public size_t id; 17 /// whether this entity is alive 18 public bool alive; 19 /// the scene that this entity is part of 20 public Scene scene; 21 /// world transform of entity 22 public Transform transform; 23 /// friendly name 24 public string name; 25 /// ecs manager 26 public EntityManager manager; 27 /// list of component references 28 public ComponentId[] components; 29 30 /// create entity given the ecs 31 this(EntityManager manager) { 32 this.manager = manager; 33 } 34 35 /// prepare the instance as a fresh entity 36 public void initialize() { 37 alive = true; 38 transform = Transform(); 39 name = string.init; 40 components = []; 41 } 42 43 /// release all resources and deinitialize 44 public void destroy() { 45 alive = false; 46 manager.storage.destroy_all(this); // destroy all components 47 name = string.init; 48 } 49 50 /// add an instance of a component given the type 51 public T add_component(T)() { 52 return add_component(new T()); 53 } 54 55 /// add a component 56 public T add_component(T)(T component) { 57 auto id = manager.storage.insert(this, component); 58 components ~= id; 59 component.entity = this; 60 component.setup(); 61 return component; 62 } 63 64 /// remove a matching component given a type 65 public void remove_component(T)() { 66 auto component = get_component!T(); 67 remove_component(component); 68 } 69 70 /// remove a specific component 71 public void remove_component(T)(T component) { 72 manager.storage.remove(this, component); 73 } 74 75 /// checks whether this entity contains a matching component 76 public bool has_component(T)() { 77 return manager.storage.has_component!T(this); 78 } 79 80 /// gets a matching component given a type 81 public T get_component(T)() { 82 return cast(T) manager.storage.get!T(this); 83 84 } 85 86 /// gets all matching components given a type 87 public T[] get_components(T)() { 88 return manager.storage.get_all!T(this); 89 } 90 91 /// gets all components attached to this entity 92 public Component[] get_all_components() { 93 return manager.storage.get_all(this); 94 } 95 96 // - transform 97 98 /// forwards to transform 99 @property Vector2 position2() { 100 return transform.position2; 101 } 102 103 /// forwards to transform 104 @property Vector2 position2(Vector2 value) { 105 return transform.position2 = value; 106 } 107 108 /// forwards to transform 109 @property ref Vector3 position() { 110 return transform.position; 111 } 112 113 /// forwards to transform 114 @property Vector3 position(Vector3 value) { 115 return transform.position = value; 116 } 117 118 public override string toString() const { 119 import std.string : format; 120 121 return format("Entity[%d, %s]", id, name); 122 } 123 } 124 125 @("ecs-entity-basic") 126 unittest { 127 import std.string : format; 128 import re.ecs.renderable; 129 import re.ecs.updatable; 130 131 static class Thing1 : Component { 132 } 133 134 static class Thing2 : Component, Updatable { 135 void update() { 136 } 137 } 138 139 auto ecs = new EntityManager(); 140 auto nt = ecs.create_entity(); 141 142 // try adding stuff 143 // insert 6 thing1, and 4 thing2 144 auto thing11 = nt.add_component(new Thing1()); 145 auto thing12 = nt.add_component(new Thing1()); 146 auto thing13 = nt.add_component(new Thing1()); 147 auto thing14 = nt.add_component(new Thing1()); 148 auto thing15 = nt.add_component(new Thing1()); 149 auto thing16 = nt.add_component(new Thing1()); 150 auto thing21 = nt.add_component(new Thing2()); 151 auto thing22 = nt.add_component(new Thing2()); 152 auto thing23 = nt.add_component(new Thing2()); 153 auto thing24 = nt.add_component(new Thing2()); 154 155 // check that we have the right number of components 156 auto thing1s = nt.get_components!Thing1(); 157 assert(thing1s.length == 6, format("expected 6 thing1s, got %d", thing1s.length)); 158 159 auto thing2s = nt.get_components!Thing2(); 160 assert(thing2s.length == 4, format("expected 4 thing2s, got %d", thing2s.length)); 161 162 // try removing random stuff 163 nt.remove_component(thing13); 164 thing1s = nt.get_components!Thing1(); 165 assert(thing1s.length == 5, format("expected 5 thing1s, got %d", thing1s.length)); 166 nt.remove_component(thing11); 167 thing1s = nt.get_components!Thing1(); 168 assert(thing1s.length == 4, format("expected 4 thing1s, got %d", thing1s.length)); 169 170 nt.remove_component(thing22); 171 thing2s = nt.get_components!Thing2(); 172 assert(thing2s.length == 3, format("expected 3 thing2s, got %d", thing2s.length)); 173 }