├── .gitignore ├── LICENSE ├── README.md └── simpleECS ├── Component.hx └── Entity.hx /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Guilherme Recchi Cardozo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simpleECS 2 | A Haxe Unity3D-like entity-component system. 3 | 4 | 5 | ## Usage 6 | * Add simpleECS to your classpaths. 7 | * That's it, quite simple. 8 | 9 | ### Wait, where is my GameObject/Actor class?! 10 | Well, I decided to call it Entity, after all you're not necessarily using this lib to make games. 11 | 12 | ### Code samples 13 | Your components should extend the Component class: 14 | ```haxe 15 | package; 16 | import simpleECS.Component; 17 | import simpleECS.Entity; 18 | 19 | class OneComponent extends Component 20 | { 21 | public function new(owner:Entity) 22 | { 23 | super(owner); 24 | } 25 | public function oneComponentMethod():Void 26 | { 27 | trace("This is oneComponentMethod."); 28 | } 29 | public function checkOtherComponent():Void 30 | { 31 | if (owner.getComponent(OtherComponent) != null) 32 | trace("Yay, we have OtherComponent!"); 33 | else 34 | trace("We don't have OtherComponent."); 35 | } 36 | /*ALWAYS override this method so you can properly destroy your components.*/ 37 | override public function destroy():Void 38 | { 39 | if (_isDestroyed) //preventing multiple destroy calls. 40 | return; 41 | 42 | _isDestroyed = true; 43 | //your component destruction code goes here... 44 | super.destroy(); 45 | trace("OneComponent destroyed."); 46 | } 47 | } 48 | 49 | class OtherComponent extends Component 50 | { 51 | public function new(owner:Entity) 52 | { 53 | super(owner); 54 | } 55 | public function otherComponentMethod():Void 56 | { 57 | trace("This is otherComponentMethod"); 58 | } 59 | /*ALWAYS override this method so you can properly destroy your components.*/ 60 | override public function destroy():Void 61 | { 62 | if (_isDestroyed) //preventing multiple destroy calls. 63 | return; 64 | 65 | _isDestroyed = true; 66 | //your component destruction code goes here... 67 | super.destroy(); 68 | trace("OtherComponent destroyed."); 69 | } 70 | } 71 | ``` 72 | 73 | Then, somewhere else you can build your entities: 74 | ```haxe 75 | var ent = new Entity(); 76 | ent.addComponent(new OneComponent(ent)).addComponent(new OtherComponent(ent)); 77 | 78 | var oneComp:OneComponent = ent.getComponent(OneComponent); 79 | oneComp.oneComponentMethod(); 80 | 81 | var otherComp:OtherComponent = ent.getComponent(OtherComponent); 82 | otherComp.otherComponentMethod(); 83 | 84 | ent.removeComponent(OtherComponent); 85 | trace("ent.numComponents: " + ent.numComponents + "\n"); //ent.numComponents: 1 86 | ``` 87 | -------------------------------------------------------------------------------- /simpleECS/Component.hx: -------------------------------------------------------------------------------- 1 | package simpleECS; 2 | 3 | /** 4 | * A simple Component with its owner. 5 | * A Component is a feature/functionality that can be added to an Entity. 6 | */ 7 | class Component 8 | { 9 | /** 10 | * The class type of this component. 11 | */ 12 | public var type(default, null):Class; 13 | /** 14 | * The owner of this component. 15 | */ 16 | public var owner(default, null):Entity; 17 | /** 18 | * Indicates whether or not this component was destroyed. 19 | */ 20 | private var _isDestroyed:Bool; 21 | /** 22 | * @param owner the Entity that owns this component. 23 | */ 24 | public function new(owner:Entity) 25 | { 26 | type = Type.getClass(this); 27 | this.owner = owner; 28 | _isDestroyed = false; 29 | } 30 | /** 31 | * A method to destroy this component. 32 | * When extending Component, you should always override this method so 33 | * it properly destroys your component. 34 | */ 35 | public function destroy():Void 36 | { 37 | owner = null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /simpleECS/Entity.hx: -------------------------------------------------------------------------------- 1 | package simpleECS; 2 | 3 | /** 4 | * Represents an Entity with its components. 5 | */ 6 | class Entity 7 | { 8 | /** 9 | * Array of components. 10 | */ 11 | private var _components:Array; 12 | /** 13 | * The current number of components. 14 | */ 15 | public var numComponents(get, null):Int; 16 | 17 | public function new() 18 | { 19 | _components = new Array(); 20 | } 21 | /** 22 | * numComponents getter. 23 | * @return the number of components in this Entity. 24 | */ 25 | private function get_numComponents():Int 26 | { 27 | return _components.length; 28 | } 29 | /** 30 | * Adds a component to the components array. 31 | * @param component to be added. 32 | * @return this Entity, so you can chain multiple calls. 33 | */ 34 | public function addComponent(component:Component):Entity 35 | { 36 | if (component != null) 37 | { 38 | if(getComponent(component.type) == null) 39 | _components.push(component); 40 | else 41 | { 42 | trace("Error: This Entity already has a component of type " + 43 | Type.getClassName(component.type) + ", you can call replaceComponent if you need."); 44 | } 45 | } 46 | else 47 | trace("Error: Entity.addComponent can't add a null component."); 48 | 49 | return this; 50 | } 51 | /** 52 | * Get the component's index. 53 | * @param classType the type of the component. 54 | * @return The component's index or -1 if it doesn't exist. 55 | */ 56 | private function getComponentIndex(classType:Class):Int 57 | { 58 | for (i in 0 ... _components.length) 59 | { 60 | if (_components[i].type == cast classType) 61 | return i; 62 | } 63 | return -1; 64 | } 65 | /** 66 | * Get the component you need. 67 | * @return 68 | * component:T, for example: 69 | * entity.getComponent(YourAwesomeComponent) 70 | * returns YourAwesomeComponent. 71 | */ 72 | public function getComponent(classType:Class):T 73 | { 74 | var compIndex = getComponentIndex(classType); 75 | return compIndex == -1 ? null : cast _components[compIndex]; 76 | } 77 | /** 78 | * Verifies if this Entity has a component. 79 | * @param classType the type of the component. 80 | * @return A boolean. 81 | */ 82 | public function hasComponent(classType:Class):Bool 83 | { 84 | return getComponentIndex(classType) != -1; 85 | } 86 | /** 87 | * Get all of the components. 88 | * @return the components array. 89 | */ 90 | public function getComponents():Array 91 | { 92 | return _components; 93 | } 94 | /** 95 | * Removes a component. 96 | * @param classType the type of the component. 97 | * @return this Entity, so you can chain multiple calls. 98 | */ 99 | public function removeComponent(classType:Class):Entity 100 | { 101 | var compIndex = getComponentIndex(classType); 102 | if (compIndex == -1) 103 | { 104 | trace("Error: Entity.removeComponent, there's no component of type " + 105 | Type.getClassName(classType) + " to be removed."); 106 | 107 | return this; 108 | } 109 | _components[compIndex].destroy(); 110 | _components.splice(compIndex, 1); 111 | return this; 112 | } 113 | /** 114 | * Removes all components. 115 | * Calls component.destroy() on each one. 116 | */ 117 | public function removeAllComponents():Void 118 | { 119 | for (c in _components) 120 | c.destroy(); 121 | 122 | _components.splice(0, _components.length); 123 | } 124 | /** 125 | * Replaces a component. 126 | * @param newComponent the new component that is 127 | * going to replace the old one. 128 | */ 129 | public function replaceComponent(newComponent:Component):Void 130 | { 131 | var compIndex = getComponentIndex(newComponent.type); 132 | if (compIndex == -1) 133 | { 134 | trace("Error: Entity.replaceComponent couldn't find a componenty of type " + 135 | Type.getClassName(newComponent.type)); 136 | 137 | return; 138 | } 139 | _components[compIndex].destroy(); 140 | _components[compIndex] = newComponent; 141 | } 142 | } 143 | --------------------------------------------------------------------------------