Skip to content

Commit

Permalink
Add facility to get an entity from the engine based on its name.
Browse files Browse the repository at this point in the history
  • Loading branch information
richardlord committed Mar 22, 2013
1 parent 0e2a1f4 commit cc94f55
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 7 deletions.
30 changes: 30 additions & 0 deletions src/ash/core/Engine.as
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package ash.core
*/
public class Engine
{
private var entityNames : Dictionary;
private var entityList : EntityList;
private var systemList : SystemList;
private var families : Dictionary;
Expand Down Expand Up @@ -37,6 +38,7 @@ package ash.core
public function Engine()
{
entityList = new EntityList();
entityNames = new Dictionary();
systemList = new SystemList();
families = new Dictionary();
updateComplete = new Signal0();
Expand All @@ -49,9 +51,15 @@ package ash.core
*/
public function addEntity( entity : Entity ) : void
{
if( entityNames[ entity.name ] )
{
throw new Error( "The entity name " + entity.name + " is already in use by another entity." );
}
entityList.add( entity );
entityNames[ entity.name ] = entity;
entity.componentAdded.add( componentAdded );
entity.componentRemoved.add( componentRemoved );
entity.nameChanged.add( entityNameChanged );
for each( var family : IFamily in families )
{
family.newEntity( entity );
Expand All @@ -67,13 +75,35 @@ package ash.core
{
entity.componentAdded.remove( componentAdded );
entity.componentRemoved.remove( componentRemoved );
entity.nameChanged.remove( entityNameChanged );
for each( var family : IFamily in families )
{
family.removeEntity( entity );
}
delete entityNames[ entity.name ];
entityList.remove( entity );
}

private function entityNameChanged( entity : Entity, oldName : String ) : void
{
if( entityNames[ oldName ] == entity )
{
delete entityNames[ oldName ];
entityNames[ entity.name ] = entity;
}
}

/**
* Get an entity based n its name.
*
* @param name The name of the entity
* @return The entity, or null if no entity with that name exists on the engine
*/
public function getEntityByName( name : String ) : Entity
{
return entityNames[ name ];
}

/**
* Remove all entities from the engine.
*/
Expand Down
43 changes: 41 additions & 2 deletions src/ash/core/Entity.as
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ash.core
{
import ash.signals.Signal2;

import flash.utils.Dictionary;

/**
Expand All @@ -23,10 +24,12 @@ package ash.core
*/
public class Entity
{
private static var nameCount : int = 0;

/**
* Optional, give the entity a name. This can help with debugging and with serialising the entity.
*/
public var name : String;
private var _name : String;
/**
* This signal is dispatched when a component is added to the entity.
*/
Expand All @@ -35,16 +38,52 @@ package ash.core
* This signal is dispatched when a component is removed from the entity.
*/
public var componentRemoved : Signal2;
/**
* Dispatched when the name of the entity changes. Used internally by the engine to track entities based on their names.
*/
internal var nameChanged : Signal2;

internal var previous : Entity;
internal var next : Entity;
internal var components : Dictionary;

public function Entity()
/**
* The constructor
*
* @param name The name for the entity. If left blank, a default name is assigned with the form _entityN where N is an integer.
*/
public function Entity( name : String = "" )
{
componentAdded = new Signal2( Entity, Class );
componentRemoved = new Signal2( Entity, Class );
nameChanged = new Signal2( Entity, String );
components = new Dictionary();
if( name )
{
_name = name;
}
else
{
_name = "_entity" + (++nameCount);
}
}

/**
* All entities have a name. If no name is set, a default name is used. Names are used to
* fetch specific entities from the engine, and can also help to identify an entity when debugging.
*/
public function get name() : String
{
return _name;
}
public function set name( value : String ) : void
{
if( _name != value )
{
var previous : String = _name;
_name = value;
nameChanged.dispatch( this, previous );
}
}

/**
Expand Down
44 changes: 42 additions & 2 deletions test/src/ash/core/EngineTests.as
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package ash.core
{
import flash.geom.Point;
import org.hamcrest.assertThat;
import org.hamcrest.collection.hasItems;
import org.hamcrest.object.equalTo;
import org.hamcrest.object.nullValue;
import org.hamcrest.object.sameInstance;

import flash.geom.Point;

public class EngineTests
{
Expand Down Expand Up @@ -119,13 +122,50 @@ package ash.core
engine.releaseNodeList( MockNode );
assertThat( MockFamily.instances[0].cleanUpCalls, equalTo( 1 ) );
}

[Test]
public function entityCanBeObtainedByName() : void
{
var entity : Entity = new Entity( "anything" );
engine.addEntity( entity );
var other : Entity = engine.getEntityByName( "anything" );
assertThat( other, sameInstance( entity ) );
}

[Test]
public function getEntityByInvalidNameReturnsNull() : void
{
var entity : Entity = engine.getEntityByName( "anything" );
assertThat( entity, nullValue() );
}

[Test]
public function entityCanBeObtainedByNameAfterRenaming() : void
{
var entity : Entity = new Entity( "anything" );
engine.addEntity( entity );
entity.name = "otherName";
var other : Entity = engine.getEntityByName( "otherName" );
assertThat( other, sameInstance( entity ) );
}

[Test]
public function entityCannotBeObtainedByOldNameAfterRenaming() : void
{
var entity : Entity = new Entity( "anything" );
engine.addEntity( entity );
entity.name = "otherName";
var other : Entity = engine.getEntityByName( "anything" );
assertThat( other, nullValue() );
}
}
}
import ash.core.Engine;
import ash.core.Entity;
import ash.core.IFamily;
import ash.core.Engine;
import ash.core.Node;
import ash.core.NodeList;

import flash.geom.Matrix;
import flash.geom.Point;

Expand Down
43 changes: 40 additions & 3 deletions test/src/ash/core/EntityTests.as
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package ash.core
{
import asunit.framework.IAsync;

import org.hamcrest.assertThat;
import org.hamcrest.collection.hasItems;
import org.hamcrest.number.greaterThan;
import org.hamcrest.object.equalTo;
import org.hamcrest.object.isFalse;
import org.hamcrest.object.isTrue;
import org.hamcrest.object.nullValue;
import org.hamcrest.object.sameInstance;




public class EntityTests
{
[Inject]
Expand Down Expand Up @@ -168,6 +167,44 @@ package ash.core
assertThat( signalEntity, sameInstance( entity ) );
assertThat( componentClass, sameInstance( MockComponent ) );
}

[Test]
public function testEntityHasNameByDefault() : void
{
entity = new Entity();
assertThat( entity.name.length, greaterThan( 0 ) );
}

[Test]
public function testEntityNameStoredAndReturned() : void
{
var name : String = "anything";
entity = new Entity( name );
assertThat( entity.name, equalTo( name ) );
}

[Test]
public function testEntityNameCanBeChanged() : void
{
entity = new Entity( "anything" );
entity.name = "otherThing";
assertThat( entity.name, equalTo( "otherThing" ) );
}

[Test]
public function testChangingEntityNameDispatchesSignal() : void
{
entity = new Entity( "anything" );
entity.nameChanged.add( async.add( testNameChangedSignal, 10 ) );
entity.name = "otherThing";
}

private function testNameChangedSignal( signalEntity : Entity, oldName : String ) : void
{
assertThat( signalEntity, sameInstance( entity ) );
assertThat( entity.name, equalTo( "otherThing" ) );
assertThat( oldName, equalTo( "anything" ) );
}
}
}

Expand Down

0 comments on commit cc94f55

Please sign in to comment.