Skip to content

Commit

Permalink
Family Builder Pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
Lusito committed Oct 29, 2014
1 parent ad99d23 commit 974f12f
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 120 deletions.
102 changes: 95 additions & 7 deletions ashley/src/com/badlogic/ashley/core/Family.java
Expand Up @@ -24,17 +24,20 @@
* Represents a group of {@link Component}s. It is used to describe what {@link Entity} objects an
* {@link EntitySystem} should process.
*
* Example: {@code Family.getFor(PositionComponent.class, VelocityComponent.class)}
* Example: {@code Family.all(PositionComponent.class, VelocityComponent.class).get()}
*
* Families can't be instantiate directly but must be accessed via {@code Family.getFor()}, this is
* to avoid duplicate families that describe the same components.
* Families can't be instantiated directly but must be accessed via a builder ( start with
* {@code Family.all()}, {@code Family.one()} or {@code Family.exclude()}), this is to avoid
* duplicate families that describe the same components.
*
* @author Stefan Bachmann
*/
public class Family {
/** The hashmap holding all families */
private static ObjectMap<String, Family> families = new ObjectMap<String, Family>();
private static int familyIndex = 0;
private static final Builder builder = new Builder();
private static final Bits zeroBits = new Bits();

/** Must contain all the components in the set */
private final Bits all;
Expand Down Expand Up @@ -88,10 +91,12 @@ public boolean matches(Entity entity){
/**
* @return The family matching the specified {@link Component} classes as a descriptor. Each set of component types will
* always return the same Family instance.
* @deprecated Use builder functionality instead ({@link Family#all}, {@link Family#one}, {@link Family#exclude})
*/
@SafeVarargs
@Deprecated
public static Family getFor(Class<? extends Component> ...componentTypes){
return getFor(ComponentType.getBitsFor(componentTypes), new Bits(), new Bits());
return getFor(ComponentType.getBitsFor(componentTypes), zeroBits, zeroBits);
}

/**
Expand All @@ -102,7 +107,9 @@ public static Family getFor(Class<? extends Component> ...componentTypes){
* @param one entities will have to contain at least one of the components in the set.See {@link ComponentType#getBitsFor(Class<? extends Component> ...)}.
* @param exclude entities cannot contain any of the components in the set. See {@link ComponentType#getBitsFor(Class<? extends Component> ...)}.
* @return The family
* @deprecated Use builder functionality instead ({@link Family#all}, {@link Family#one}, {@link Family#exclude})
*/
@Deprecated
public static Family getFor(Bits all, Bits one, Bits exclude){
String hash = getFamilyHash(all, one, exclude);
Family family = families.get(hash, null);
Expand All @@ -114,13 +121,94 @@ public static Family getFor(Bits all, Bits one, Bits exclude){
return family;
}

/**
* @param componentTypes entities will have to contain all of the specified components.
* @return A Builder singleton instance to get a family
*/
public static Builder all(Class<? extends Component> ...componentTypes) {
return builder.reset().all(componentTypes);
}

/**
* @param componentTypes entities will have to contain at least one of the specified components.
* @return A Builder singleton instance to get a family
*/
public static Builder one(Class<? extends Component> ...componentTypes) {
return builder.reset().one(componentTypes);
}

/**
* @param componentTypes entities cannot contain any of the specified components.
* @return A Builder singleton instance to get a family
*/
public static Builder exclude(Class<? extends Component> ...componentTypes) {
return builder.reset().exclude(componentTypes);
}

public static class Builder {
private Bits all = zeroBits;
private Bits one = zeroBits;
private Bits exclude = zeroBits;

/**
* Resets the builder instance
* @return A Builder singleton instance to get a family
*/
public Builder reset() {
all = zeroBits;
one = zeroBits;
exclude = zeroBits;
return this;
}

/**
* @param componentTypes entities will have to contain all of the specified components.
* @return A Builder singleton instance to get a family
*/
public Builder all(Class<? extends Component> ...componentTypes) {
all = ComponentType.getBitsFor(componentTypes);
return this;
}

/**
* @param componentTypes entities will have to contain at least one of the specified components.
* @return A Builder singleton instance to get a family
*/
public Builder one(Class<? extends Component> ...componentTypes) {
one = ComponentType.getBitsFor(componentTypes);
return this;
}

/**
* @param componentTypes entities cannot contain any of the specified components.
* @return A Builder singleton instance to get a family
*/
public Builder exclude(Class<? extends Component> ...componentTypes) {
exclude = ComponentType.getBitsFor(componentTypes);
return this;
}

/**
* @return A family for the configured component types
*/
public Family get() {
String hash = getFamilyHash(all, one, exclude);
Family family = families.get(hash, null);
if(family == null){
family = new Family(all, one, exclude);
families.put(hash, family);
}
return family;
}
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((all == null) ? 0 : all.hashCode());
result = prime * result + ((one == null) ? 0 : one.hashCode());
result = prime * result + ((exclude == null) ? 0 : exclude.hashCode());
result = prime * result + all.hashCode();
result = prime * result + one.hashCode();
result = prime * result + exclude.hashCode();
result = prime * result + index;
return result;
}
Expand Down
22 changes: 10 additions & 12 deletions ashley/tests/com/badlogic/ashley/core/EngineTests.java
Expand Up @@ -128,7 +128,7 @@ private static class CounterSystem extends EntitySystem {
@Override
public void addedToEngine(Engine engine) {
this.engine = engine;
entities = engine.getEntitiesFor(Family.getFor(CounterComponent.class));
entities = engine.getEntitiesFor(Family.all(CounterComponent.class).get());
}

@Override
Expand Down Expand Up @@ -294,7 +294,7 @@ public void ignoreSystem() {
public void entitiesForFamily() {
Engine engine = new Engine();

Family family = Family.getFor(ComponentA.class, ComponentB.class);
Family family = Family.all(ComponentA.class, ComponentB.class).get();
ImmutableArray<Entity> familyEntities = engine.getEntitiesFor(family);

assertEquals(0, familyEntities.size());
Expand Down Expand Up @@ -340,7 +340,7 @@ public void entityForFamilyWithRemoval() {

engine.addEntity(entity);

ImmutableArray<Entity> entities = engine.getEntitiesFor(Family.getFor(ComponentA.class));
ImmutableArray<Entity> entities = engine.getEntitiesFor(Family.all(ComponentA.class).get());

assertEquals(1, entities.size());
assertTrue(entities.contains(entity, true));
Expand All @@ -355,7 +355,7 @@ public void entityForFamilyWithRemoval() {
public void entitiesForFamilyAfter() {
Engine engine = new Engine();

Family family = Family.getFor(ComponentA.class, ComponentB.class);
Family family = Family.all(ComponentA.class, ComponentB.class).get();
ImmutableArray<Entity> familyEntities = engine.getEntitiesFor(family);

assertEquals(0, familyEntities.size());
Expand Down Expand Up @@ -395,7 +395,7 @@ public void entitiesForFamilyAfter() {
public void entitiesForFamilyWithRemoval() {
Engine engine = new Engine();

Family family = Family.getFor(ComponentA.class, ComponentB.class);
Family family = Family.all(ComponentA.class, ComponentB.class).get();
ImmutableArray<Entity> familyEntities = engine.getEntitiesFor(family);

Entity entity1 = new Entity();
Expand Down Expand Up @@ -443,11 +443,9 @@ public void entitiesForFamilyWithRemovalAndFiltering() {
Engine engine = new Engine();


ImmutableArray<Entity> entitiesWithComponentAOnly = engine.getEntitiesFor(Family.getFor(ComponentType.getBitsFor(ComponentA.class),
new Bits(),
ComponentType.getBitsFor(ComponentB.class)));
ImmutableArray<Entity> entitiesWithComponentAOnly = engine.getEntitiesFor(Family.all(ComponentA.class).exclude(ComponentB.class).get());

ImmutableArray<Entity> entitiesWithComponentB = engine.getEntitiesFor(Family.getFor(ComponentB.class));
ImmutableArray<Entity> entitiesWithComponentB = engine.getEntitiesFor(Family.all(ComponentB.class).get());

Entity entity1 = new Entity();
Entity entity2 = new Entity();
Expand Down Expand Up @@ -481,7 +479,7 @@ public void entitySystemRemovalWhileIterating() {
engine.addEntity(entity);
}

ImmutableArray<Entity> entities = engine.getEntitiesFor(Family.getFor(CounterComponent.class));
ImmutableArray<Entity> entities = engine.getEntitiesFor(Family.all(CounterComponent.class).get());

for (int i = 0; i < entities.size(); ++i) {
assertEquals(0, entities.get(i).getComponent(CounterComponent.class).counter);
Expand All @@ -501,8 +499,8 @@ public void familyListener() {
EntityListenerMock listenerA = new EntityListenerMock();
EntityListenerMock listenerB = new EntityListenerMock();

Family familyA = Family.getFor(ComponentA.class);
Family familyB = Family.getFor(ComponentB.class);
Family familyA = Family.all(ComponentA.class).get();
Family familyB = Family.all(ComponentB.class).get();

engine.addEntityListener(familyA, listenerA);
engine.addEntityListener(familyB, listenerB);
Expand Down
Expand Up @@ -13,7 +13,7 @@ public void addEntityListenerFamilyRemove() {
engine.addEntity(e);

@SuppressWarnings("unchecked")
Family family = Family.getFor(PositionComponent.class);
Family family = Family.all(PositionComponent.class).get();
engine.addEntityListener(family, new EntityListener() {

public void entityRemoved(Entity entity) {
Expand All @@ -36,7 +36,7 @@ public void addEntityListenerFamilyAdd() {
e.add(new PositionComponent());

@SuppressWarnings("unchecked")
Family family = Family.getFor(PositionComponent.class);
Family family = Family.all(PositionComponent.class).get();
engine.addEntityListener(family, new EntityListener() {

public void entityRemoved(Entity entity) {
Expand All @@ -60,7 +60,7 @@ public void addEntityListenerNoFamilyRemove() {
engine.addEntity(e);

@SuppressWarnings("unchecked")
final Family family = Family.getFor(PositionComponent.class);
final Family family = Family.all(PositionComponent.class).get();
engine.addEntityListener(new EntityListener() {

public void entityRemoved(Entity entity) {
Expand All @@ -84,7 +84,7 @@ public void addEntityListenerNoFamilyAdd() {
e.add(new PositionComponent());

@SuppressWarnings("unchecked")
final Family family = Family.getFor(PositionComponent.class);
final Family family = Family.all(PositionComponent.class).get();
engine.addEntityListener(new EntityListener() {

public void entityRemoved(Entity entity) {
Expand Down

0 comments on commit 974f12f

Please sign in to comment.