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