Skip to content
Permalink
Browse files

Adds family filtering

  • Loading branch information
dsaltares committed Jun 27, 2014
1 parent b76c5e9 commit 9492d14a3e5cf4ad0d87305f8f7bb298bb8d687a
@@ -1,5 +1,7 @@
package com.badlogic.ashley.core;

import java.util.BitSet;

import com.badlogic.ashley.utils.ObjectMap;

/**
@@ -56,6 +58,21 @@ public static int getIndexFor(Class<? extends Component> componentType) {
return getTypeFor(componentType).getIndex();
}

/**
* @param componentTypes list of component types
* @return BitSet representing the collection of components for quick comparison and matching. See {@link Family#getFamilyFor(BitSet, BitSet, BitSet)}.
*/
public static BitSet getBitsFor(Class<? extends Component> ...componentTypes) {
BitSet bits = new BitSet();

int typesLength = componentTypes.length;
for(int i = 0; i < typesLength; i++){
bits.set(ComponentType.getIndexFor(componentTypes[i]));
}

return bits;
}

@Override
public int hashCode() {
final int prime = 31;
@@ -20,14 +20,20 @@
private static ObjectMap<String, Family> families = new ObjectMap<String, Family>();
private static int familyIndex = 0;

/** A bitset used for quick comparison between families & entities */
private final BitSet bits;
/** Must contain all the components in the set */
private final BitSet all;
/** Must contain at least one of the components in the set */
private final BitSet one;
/** Cannot contain any of the components in the set */
private final BitSet exclude;
/** Each family has a unique index, used for bitmasking */
private final int index;

/** Private constructor, use static method Family.getFamilyFor() */
private Family(BitSet bits){
this.bits = bits;
private Family(BitSet all, BitSet any, BitSet exclude){
this.all = all;
this.one = any;
this.exclude = exclude;
this.index = familyIndex++;
}

@@ -49,33 +55,46 @@ public boolean matches(Entity entity){
if(entityComponentBits.isEmpty())
return false;

for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i+1)){
for (int i = all.nextSetBit(0); i >= 0; i = all.nextSetBit(i+1)){
if(!entityComponentBits.get(i))
return false;
}

if (!one.isEmpty() && !one.intersects(entityComponentBits)) {
return false;
}

if (!exclude.isEmpty() && exclude.intersects(entityComponentBits)) {
return false;
}

return true;
}

/**
* Returns a family with the passed componentTypes as a descriptor. Each set of component types will
* always return the same Family instance.
* @param componentTypes The components to describe the family
* @param componentTypes The components to describe the family, entities must match all these components
* @return The family
*/
@SafeVarargs
public static Family getFamilyFor(Class<? extends Component> ...componentTypes){
BitSet bits = new BitSet();

int typesLength = componentTypes.length;
for(int i = 0; i < typesLength; i++){
bits.set(ComponentType.getIndexFor(componentTypes[i]));
}

String hash = bits.toString();
return getFamilyFor(ComponentType.getBitsFor(componentTypes), new BitSet(), new BitSet());
}

/**
* Returns a family with the passed componentTypes as a descriptor. Each set of component types will
* always return the same Family instance.
*
* @param componentTypes The components to describe the family, entities must match all these components. See {@link ComponentType#bitsFor(BitSet, BitSet, BitSet)}.
* @return The family
*/
@SafeVarargs
public static Family getFamilyFor(BitSet all, BitSet one, BitSet exclude){

This comment has been minimized.

Copy link
@xaguzman

xaguzman Jun 27, 2014

Contributor

this one seems to me to be very verbose for the constant use.

Family.getFamilyFor( ComponentType.getComponentBits(Component.class, Component1.class), ComponentType.getComponentBits(Component2.class), ComponentType.getComponentBits(Component3.class) ) is not very easy on the eye

String hash = getFamilyHash(all, one, exclude);
Family family = families.get(hash, null);
if(family == null){
family = new Family(bits);
family = new Family(all, one, exclude);
families.put(hash, family);
}

@@ -86,7 +105,9 @@ public static Family getFamilyFor(Class<? extends Component> ...componentTypes){
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bits == null) ? 0 : bits.hashCode());
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 + index;
return result;
}
@@ -100,11 +121,33 @@ public boolean equals(Object obj) {
if (!(obj instanceof Family))
return false;
Family other = (Family) obj;
if (bits == null) {
if (other.bits != null)
if (all == null) {
if (other.all != null)
return false;
} else if (!all.equals(other.all))
return false;
if (one == null) {
if (other.one != null)
return false;
} else if (!bits.equals(other.bits))
} else if (!one.equals(other.one))
return false;
return index == other.index;
}
if (exclude == null) {
if (other.exclude != null)
return false;
} else if (!exclude.equals(other.exclude))
return false;

return index == other.index;
}

private static String getFamilyHash(BitSet all, BitSet one, BitSet exclude) {
StringBuilder builder = new StringBuilder();
builder.append("all:");
builder.append(all.toString());
builder.append(",one:");
builder.append(one.toString());
builder.append(",exclude:");
builder.append(exclude.toString());
return builder.toString();
}
}
@@ -10,17 +10,12 @@

public class FamilyTests {

private static class ComponentA extends Component {

}

private static class ComponentB extends Component {

}

private static class ComponentC extends Component {

}
private static class ComponentA extends Component {}
private static class ComponentB extends Component {}
private static class ComponentC extends Component {}
private static class ComponentD extends Component {}
private static class ComponentE extends Component {}
private static class ComponentF extends Component {}

@Test
public void validFamily() {
@@ -34,6 +29,9 @@ public void validFamily() {
assertNotNull(Family.getFamilyFor(ComponentC.class, ComponentA.class));
assertNotNull(Family.getFamilyFor(ComponentC.class, ComponentB.class));
assertNotNull(Family.getFamilyFor(ComponentA.class, ComponentB.class, ComponentC.class));
assertNotNull(Family.getFamilyFor(ComponentType.getBitsFor(ComponentA.class, ComponentB.class),
ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class)));
}

@Test
@@ -44,17 +42,26 @@ public void sameFamily() {
Family family4 = Family.getFamilyFor(ComponentA.class, ComponentB.class);
Family family5 = Family.getFamilyFor(ComponentA.class, ComponentB.class, ComponentC.class);
Family family6 = Family.getFamilyFor(ComponentA.class, ComponentB.class, ComponentC.class);
Family family7 = Family.getFamilyFor(ComponentType.getBitsFor(ComponentA.class, ComponentB.class),
ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class));
Family family8 = Family.getFamilyFor(ComponentType.getBitsFor(ComponentA.class, ComponentB.class),
ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class));

assertTrue(family1.equals(family2));
assertTrue(family2.equals(family1));
assertTrue(family3.equals(family4));
assertTrue(family4.equals(family3));
assertTrue(family5.equals(family6));
assertTrue(family6.equals(family5));
assertTrue(family7.equals(family8));
assertTrue(family8.equals(family7));

assertEquals(family1.getFamilyIndex(), family2.getFamilyIndex());
assertEquals(family3.getFamilyIndex(), family4.getFamilyIndex());
assertEquals(family5.getFamilyIndex(), family6.getFamilyIndex());
assertEquals(family7.getFamilyIndex(), family8.getFamilyIndex());
}

@Test
@@ -69,6 +76,12 @@ public void differentFamily() {
Family family8 = Family.getFamilyFor(ComponentC.class, ComponentA.class);
Family family9 = Family.getFamilyFor(ComponentC.class, ComponentB.class);
Family family10 = Family.getFamilyFor(ComponentA.class, ComponentB.class, ComponentC.class);
Family family11 = Family.getFamilyFor(ComponentType.getBitsFor(ComponentA.class, ComponentB.class),
ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class));
Family family12 = Family.getFamilyFor(ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class),
ComponentType.getBitsFor(ComponentA.class, ComponentB.class));

assertFalse(family1.equals(family2));
assertFalse(family1.equals(family3));
@@ -79,6 +92,8 @@ public void differentFamily() {
assertFalse(family1.equals(family8));
assertFalse(family1.equals(family9));
assertFalse(family1.equals(family10));
assertFalse(family1.equals(family11));
assertFalse(family1.equals(family12));

assertFalse(family10.equals(family1));
assertFalse(family10.equals(family2));
@@ -89,6 +104,7 @@ public void differentFamily() {
assertFalse(family10.equals(family7));
assertFalse(family10.equals(family8));
assertFalse(family10.equals(family9));
assertFalse(family11.equals(family12));

assertNotEquals(family1.getFamilyIndex(), family2.getFamilyIndex());
assertNotEquals(family1.getFamilyIndex(), family3.getFamilyIndex());
@@ -99,6 +115,7 @@ public void differentFamily() {
assertNotEquals(family1.getFamilyIndex(), family8.getFamilyIndex());
assertNotEquals(family1.getFamilyIndex(), family9.getFamilyIndex());
assertNotEquals(family1.getFamilyIndex(), family10.getFamilyIndex());
assertNotEquals(family11.getFamilyIndex(), family12.getFamilyIndex());
}

@Test
@@ -160,4 +177,51 @@ public void entityMismatchThenMatch() {

assertTrue(family.matches(entity));
}

@Test
public void familyFiltering() {
Family family1 = Family.getFamilyFor(ComponentType.getBitsFor(ComponentA.class, ComponentB.class),
ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class));

Family family2 = Family.getFamilyFor(ComponentType.getBitsFor(ComponentC.class, ComponentD.class),
ComponentType.getBitsFor(ComponentA.class, ComponentB.class),
ComponentType.getBitsFor(ComponentE.class, ComponentF.class));

Entity entity = new Entity();

assertFalse(family1.matches(entity));
assertFalse(family2.matches(entity));

entity.add(new ComponentA());
entity.add(new ComponentB());

assertFalse(family1.matches(entity));
assertFalse(family2.matches(entity));

entity.add(new ComponentC());

assertTrue(family1.matches(entity));
assertFalse(family2.matches(entity));

entity.add(new ComponentD());

assertTrue(family1.matches(entity));
assertTrue(family2.matches(entity));

entity.add(new ComponentE());

assertFalse(family1.matches(entity));
assertFalse(family2.matches(entity));

entity.remove(ComponentE.class);

assertTrue(family1.matches(entity));
assertTrue(family2.matches(entity));

entity.remove(ComponentA.class);

assertFalse(family1.matches(entity));
assertTrue(family2.matches(entity));
}
}

0 comments on commit 9492d14

Please sign in to comment.
You can’t perform that action at this time.