Exemple #1
0
    void when_created()
    {
        it["increments creationIndex"] = () => {
            _pool.CreateEntity().creationIndex.should_be(0);
            _pool.CreateEntity().creationIndex.should_be(1);
        };

        it["starts with given creationIndex"] = () => {
            new Pool(CID.NumComponents, 42).CreateEntity().creationIndex.should_be(42);
        };

        it["has no entities when no entities were created"] = () => {
            _pool.GetEntities().should_be_empty();
        };

        it["creates entity"] = () => {
            var e = _pool.CreateEntity();
            e.should_not_be_null();
            e.GetType().should_be(typeof(Entity));
        };

        it["gets total entity count"] = () => {
            _pool.CreateEntity();
            _pool.Count.should_be(1);
        };

        it["doesn't have entites that were not created with CreateEntity()"] = () => {
            _pool.HasEntity(this.CreateEntity()).should_be_false();
        };

        it["has entites that were created with CreateEntity()"] = () => {
            _pool.HasEntity(_pool.CreateEntity()).should_be_true();
        };

        it["returns all created entities"] = () => {
            var e1       = _pool.CreateEntity();
            var e2       = _pool.CreateEntity();
            var entities = _pool.GetEntities();
            entities.should_contain(e1);
            entities.should_contain(e2);
            entities.Length.should_be(2);
        };

        it["destroys entity and removes it"] = () => {
            var e = _pool.CreateEntity();
            _pool.DestroyEntity(e);
            _pool.HasEntity(e).should_be_false();
        };

        it["destroys an entity and removes all its components"] = () => {
            var e = _pool.CreateEntity();
            e.AddComponentA();
            _pool.DestroyEntity(e);
            e.GetComponents().should_be_empty();
        };

        it["destroys all entites"] = () => {
            var e = _pool.CreateEntity();
            e.AddComponentA();
            _pool.CreateEntity();
            _pool.DestroyAllEntities();
            _pool.GetEntities().should_be_empty();
            e.GetComponents().should_be_empty();
        };

        it["caches entities"] = () => {
            _pool.CreateEntity();
            var entities1 = _pool.GetEntities();
            var entities2 = _pool.GetEntities();
            entities1.should_be_same(entities2);
            _pool.DestroyEntity(_pool.CreateEntity());
            _pool.GetEntities().should_not_be_same(entities1);
        };

        context["events"] = () => {
            it["dispatches OnEntityCreated when creating a new entity"] = () => {
                Pool   eventPool   = null;
                Entity eventEntity = null;
                _pool.OnEntityCreated += (pool, entity) => {
                    eventPool   = pool;
                    eventEntity = entity;
                };

                var e = _pool.CreateEntity();
                eventPool.should_be_same(_pool);
                eventEntity.should_be_same(e);
            };

            it["dispatches OnEntityWillBeDestroyed when destroying a new entity"] = () => {
                var e = _pool.CreateEntity();
                e.AddComponentA();
                Pool   eventPool   = null;
                Entity eventEntity = null;
                _pool.OnEntityWillBeDestroyed += (pool, entity) => {
                    eventPool   = pool;
                    eventEntity = entity;
                    entity.HasComponentA().should_be_true();
                };
                _pool.DestroyEntity(e);
                eventPool.should_be_same(_pool);
                eventEntity.should_be_same(e);
            };

            it["dispatches OnEntityDestroyed when destroying a new entity"] = () => {
                var    e           = _pool.CreateEntity();
                Pool   eventPool   = null;
                Entity eventEntity = null;
                _pool.OnEntityDestroyed += (pool, entity) => {
                    eventPool   = pool;
                    eventEntity = entity;
                    entity.HasComponentA().should_be_false();
                };
                _pool.DestroyEntity(e);
                eventPool.should_be_same(_pool);
                eventEntity.should_be_same(e);
            };

            it["dispatches OnGroupCreated when creating a new group"] = () => {
                Pool  eventPool  = null;
                Group eventGroup = null;
                _pool.OnGroupCreated += (pool, g) => {
                    eventPool  = pool;
                    eventGroup = g;
                };
                var group = _pool.GetGroup(Matcher.AllOf(0));
                eventPool.should_be_same(_pool);
                eventGroup.should_be_same(group);
            };

            it["doesn't dispatch OnGroupCreeated when group alredy exists"] = () => {
                _pool.GetGroup(Matcher.AllOf(0));
                _pool.OnGroupCreated += (pool, g) => this.Fail();
                _pool.GetGroup(Matcher.AllOf(0));
            };
        };

        context["entity pool"] = () => {
            it["gets entity from object pool"] = () => {
                var e = _pool.CreateEntity();
                e.should_not_be_null();
                e.GetType().should_be(typeof(Entity));
            };

            it["destroys entity when pushing back to object pool"] = () => {
                var e = _pool.CreateEntity();
                e.AddComponentA();
                _pool.DestroyEntity(e);
                e.HasComponent(CID.ComponentA).should_be_false();
            };

            it["returns pushed entity"] = () => {
                var e = _pool.CreateEntity();
                e.AddComponentA();
                _pool.DestroyEntity(e);
                var entity = _pool.CreateEntity();
                entity.HasComponent(CID.ComponentA).should_be_false();
                entity.should_be_same(e);
            };

            it["returns new entity"] = () => {
                var e = _pool.CreateEntity();
                e.AddComponentA();
                _pool.DestroyEntity(e);
                _pool.CreateEntity();
                var entityFromPool = _pool.CreateEntity();
                entityFromPool.HasComponent(CID.ComponentA).should_be_false();
                entityFromPool.should_not_be_same(e);
            };

            it["sets up entity from pool"] = () => {
                _pool.DestroyEntity(_pool.CreateEntity());
                var g = _pool.GetGroup(Matcher.AllOf(new [] { CID.ComponentA }));
                var e = _pool.CreateEntity();
                e.AddComponentA();
                g.GetEntities().should_contain(e);
            };
        };

        context["get entities"] = () => {
            it["gets empty group for matcher when no entities were created"] = () => {
                var g = _pool.GetGroup(Matcher.AllOf(new [] { CID.ComponentA }));
                g.should_not_be_null();
                g.GetEntities().should_be_empty();
            };

            context["when entities created"] = () => {
                Entity eAB1 = null;
                Entity eAB2 = null;
                Entity eA   = null;

                IMatcher matcher = Matcher.AllOf(new [] {
                    CID.ComponentA,
                    CID.ComponentB
                });

                before = () => {
                    eAB1 = _pool.CreateEntity();
                    eAB1.AddComponentA();
                    eAB1.AddComponentB();
                    eAB2 = _pool.CreateEntity();
                    eAB2.AddComponentA();
                    eAB2.AddComponentB();
                    eA = _pool.CreateEntity();
                    eA.AddComponentA();
                };

                it["gets group with matching entities"] = () => {
                    var g = _pool.GetGroup(matcher).GetEntities();
                    g.Length.should_be(2);
                    g.should_contain(eAB1);
                    g.should_contain(eAB2);
                };

                it["gets cached group"] = () => {
                    _pool.GetGroup(matcher).should_be_same(_pool.GetGroup(matcher));
                };

                it["cached group contains newly created matching entity"] = () => {
                    var g = _pool.GetGroup(matcher);
                    eA.AddComponentB();
                    g.GetEntities().should_contain(eA);
                };

                it["cached group doesn't contain entity which are not matching anymore"] = () => {
                    var g = _pool.GetGroup(matcher);
                    eAB1.RemoveComponentA();
                    g.GetEntities().should_not_contain(eAB1);
                };

                it["removes destroyed entity"] = () => {
                    var g = _pool.GetGroup(matcher);
                    _pool.DestroyEntity(eAB1);
                    g.GetEntities().should_not_contain(eAB1);
                };

                it["ignores adding components to destroyed entity"] = () => {
                    var g = _pool.GetGroup(matcher);
                    _pool.DestroyEntity(eA);
                    eA.AddComponentA();
                    eA.AddComponentB();
                    g.GetEntities().should_not_contain(eA);
                };

                it["throws when destroying an entity the pool doesn't contain"] = expect <PoolDoesNotContainEntityException>(() => {
                    var e = _pool.CreateEntity();
                    _pool.DestroyEntity(e);
                    _pool.DestroyEntity(e);
                });

                it["group dispatches OnEntityRemoved and OnEntityAdded when replacing components"] = () => {
                    var g = _pool.GetGroup(matcher);
                    var didDispatchRemoved = 0;
                    var didDispatchAdded   = 0;
                    var componentA         = new ComponentA();
                    g.OnEntityRemoved += (group, entity, index, component) => {
                        group.should_be_same(g);
                        entity.should_be_same(eAB1);
                        index.should_be(CID.ComponentA);
                        component.should_be_same(Component.A);
                        didDispatchRemoved++;
                    };
                    g.OnEntityAdded += (group, entity, index, component) => {
                        group.should_be_same(g);
                        entity.should_be_same(eAB1);
                        index.should_be(CID.ComponentA);
                        component.should_be_same(componentA);
                        didDispatchAdded++;
                    };
                    eAB1.ReplaceComponentA(componentA);

                    didDispatchRemoved.should_be(1);
                    didDispatchAdded.should_be(1);
                };

                it["group dispatches OnEntityUpdated with previous and current component when replacing a component"] = () => {
                    var updated  = 0;
                    var prevComp = eA.GetComponent(CID.ComponentA);
                    var newComp  = new ComponentA();
                    var g        = _pool.GetGroup(Matcher.AllOf(new [] { CID.ComponentA }));
                    g.OnEntityUpdated += (group, entity, index, previousComponent, newComponent) => {
                        updated += 1;
                        group.should_be_same(g);
                        entity.should_be_same(eA);
                        index.should_be(CID.ComponentA);
                        previousComponent.should_be_same(prevComp);
                        newComponent.should_be_same(newComp);
                    };

                    eA.ReplaceComponent(CID.ComponentA, newComp);

                    updated.should_be(1);
                };
            };
        };

        context["getGroup"] = () => {
            context["AnyOfCompoundMatcher"] = () => {
                AllOfMatcher         allOfA   = null;
                AllOfMatcher         allOfB   = null;
                AnyOfCompoundMatcher compound = null;
                Group  group = null;
                Entity e     = null;
                before = () => {
                    allOfA   = Matcher.AllOf(CID.ComponentA);
                    allOfB   = Matcher.AllOf(CID.ComponentB);
                    compound = Matcher.AnyOf(allOfA, allOfB);
                    group    = _pool.GetGroup(compound);
                    e        = _pool.CreateEntity();
                };

                it["adds entity when matching"] = () => {
                    e.AddComponentA();
                    compound.Matches(e).should_be_true();
                    group.Count.should_be(1);
                };

                it["doesn't add entity when not matching"] = () => {
                    e.AddComponentC();
                    compound.Matches(e).should_be_false();
                    group.Count.should_be(0);
                };

                it["removes entity when not matching anymore"] = () => {
                    e.AddComponentA();
                    e.RemoveComponentA();
                    group.Count.should_be(0);
                };

                it["doesn't remove entity when still matching"] = () => {
                    e.AddComponentA();
                    e.AddComponentB();
                    e.RemoveComponentB();
                    group.Count.should_be(1);
                };
            };

            context["AllOfOfCompoundMatcher containing a NoneOfMatcher"] = () => {
                AllOfMatcher         allOfAB  = null;
                NoneOfMatcher        noneOfC  = null;
                AllOfCompoundMatcher compound = null;
                Group  group = null;
                Entity e     = null;
                before = () => {
                    allOfAB  = Matcher.AllOf(CID.ComponentA, CID.ComponentB);
                    noneOfC  = Matcher.NoneOf(CID.ComponentC);
                    compound = Matcher.AllOf(allOfAB, noneOfC);
                    group    = _pool.GetGroup(compound);
                    e        = _pool.CreateEntity();
                };

                it["adds entity when matching"] = () => {
                    e.AddComponentA();
                    e.AddComponentB();
                    compound.Matches(e).should_be_true();
                    group.Count.should_be(1);
                };

                it["doesn't add entity when not matching"] = () => {
                    e.AddComponentA();
                    e.AddComponentB();
                    e.AddComponentC();
                    compound.Matches(e).should_be_false();
                    group.Count.should_be(0);
                };

                it["removes entity when not matching anymore"] = () => {
                    e.AddComponentA();
                    e.AddComponentB();
                    e.RemoveComponentB();
                    group.Count.should_be(0);
                };

                it["doesn't remove entity when still matching"] = () => {
                    e.AddComponentA();
                    e.AddComponentB();
                    e.AddComponentC();
                    e.RemoveComponentC();
                    group.Count.should_be(1);
                };
            };
        };
    }
    void when_compounding_matchers()
    {
        context["allOf"] = () => {
            AllOfMatcher         allAB    = null;
            AllOfMatcher         allBC    = null;
            AnyOfMatcher         anyAB    = null;
            AnyOfMatcher         anyBC    = null;
            AllOfCompoundMatcher compound = null;
            before = () => {
                allAB = Matcher.AllOf(new[] {
                    CID.ComponentB,
                    CID.ComponentA
                });
                allBC = Matcher.AllOf(new[] {
                    CID.ComponentC,
                    CID.ComponentB
                });
                anyAB = Matcher.AnyOf(new[] {
                    CID.ComponentB,
                    CID.ComponentA
                });
                anyBC = Matcher.AnyOf(new[] {
                    CID.ComponentC,
                    CID.ComponentB
                });
            };

            it["has all indices in order"] = () => {
                compound = Matcher.AllOf(allAB, allBC);
                compound.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC
                });
            };

            it["has all indices in order (mixed)"] = () => {
                compound = Matcher.AllOf(allAB, anyBC);
                compound.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC
                });
            };

            it["matches"] = () => {
                compound = Matcher.AllOf(allAB, allBC);
                var e = this.CreateEntity();
                e.AddComponentA();
                e.AddComponentB();
                e.AddComponentC();
                compound.Matches(e).should_be_true();
            };

            it["matches (mixed)"] = () => {
                compound = Matcher.AllOf(allAB, anyBC);
                var e = this.CreateEntity();
                e.AddComponentA();
                e.AddComponentB();
                compound.Matches(e).should_be_true();
            };

            it["doesn't match"] = () => {
                compound = Matcher.AllOf(allAB, allBC);
                var e = this.CreateEntity();
                e.AddComponentB();
                e.AddComponentC();
                compound.Matches(e).should_be_false();
            };

            it["doesn't match (mixed)"] = () => {
                compound = Matcher.AllOf(anyAB, anyBC);
                var e = this.CreateEntity();
                e.AddComponentC();
                compound.Matches(e).should_be_false();
            };
        };

        context["anyOf"] = () => {
            AllOfMatcher         allAB    = null;
            AllOfMatcher         allBC    = null;
            AnyOfMatcher         anyBC    = null;
            AnyOfCompoundMatcher compound = null;
            before = () => {
                allAB = Matcher.AllOf(new[] {
                    CID.ComponentB,
                    CID.ComponentA
                });
                allBC = Matcher.AllOf(new[] {
                    CID.ComponentC,
                    CID.ComponentB
                });
                anyBC = Matcher.AnyOf(new[] {
                    CID.ComponentC,
                    CID.ComponentB
                });
            };

            it["has all indices in order"] = () => {
                compound = Matcher.AnyOf(allAB, allBC);
                compound.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC
                });
            };

            it["has all indices in order (mixed)"] = () => {
                compound = Matcher.AnyOf(allAB, anyBC);
                compound.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC
                });
            };

            it["matches"] = () => {
                compound = Matcher.AnyOf(allBC, allAB);
                var e = this.CreateEntity();
                e.AddComponentB();
                e.AddComponentC();
                compound.Matches(e).should_be_true();
            };

            it["matches (mixed)"] = () => {
                compound = Matcher.AnyOf(allAB, anyBC);
                var e = this.CreateEntity();
                e.AddComponentC();
                compound.Matches(e).should_be_true();
            };

            it["doesn't match"] = () => {
                compound = Matcher.AnyOf(allAB, allBC);
                var e = this.CreateEntity();
                e.AddComponentA();
                e.AddComponentC();
                compound.Matches(e).should_be_false();
            };
        };

        context["noneOf"] = () => {
            AllOfMatcher          allAB    = null;
            AllOfMatcher          allBC    = null;
            AllOfMatcher          allAC    = null;
            AnyOfMatcher          anyBC    = null;
            NoneOfCompoundMatcher compound = null;
            before = () => {
                allAB = Matcher.AllOf(new[] {
                    CID.ComponentB,
                    CID.ComponentA
                });
                allBC = Matcher.AllOf(new[] {
                    CID.ComponentC,
                    CID.ComponentB
                });
                allAC = Matcher.AllOf(new[] {
                    CID.ComponentC,
                    CID.ComponentA
                });
                anyBC = Matcher.AnyOf(new[] {
                    CID.ComponentC,
                    CID.ComponentB
                });
            };

            it["has all indices in order"] = () => {
                compound = Matcher.NoneOf(allAB, allBC);
                compound.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC
                });
            };

            it["matches"] = () => {
                compound = Matcher.NoneOf(allAB, allAC);
                var e = this.CreateEntity();
                e.AddComponentB();
                e.AddComponentC();
                compound.Matches(e).should_be_true();
            };

            it["matches (mixed)"] = () => {
                compound = Matcher.NoneOf(allAB, anyBC);
                var e = this.CreateEntity();
                e.AddComponentA();
                compound.Matches(e).should_be_true();
            };

            it["doesn't match"] = () => {
                compound = Matcher.NoneOf(allAB, anyBC);
                var e = this.CreateEntity();
                e.AddComponentC();
                compound.Matches(e).should_be_false();
            };
        };

        context["equals"] = () => {
            it["doesn't equal when only indices are same"] = () => {
                var all1 = Matcher.AllOf(0, 1);
                var all2 = Matcher.AllOf(2, 3);
                var c1   = Matcher.AllOf(all1, all2);

                var any1 = Matcher.AnyOf(0, 1);
                var any2 = Matcher.AnyOf(2, 3);
                var c2   = Matcher.AllOf(any1, any2);

                c1.Equals(c2).should_be_false();
            };

            it["doesn't equal when not same type"] = () => {
                var all1 = Matcher.AllOf(0, 1);
                var all2 = Matcher.AllOf(2, 3);
                var c1   = Matcher.AllOf(all1, all2);
                var c2   = Matcher.AnyOf(all1, all2);

                c1.Equals(c2).should_be_false();
            };

            it["equals when equal"] = () => {
                var all1 = Matcher.AllOf(0, 1);
                var all2 = Matcher.AllOf(2, 3);
                var c1   = Matcher.AllOf(all1, all2);

                var all3 = Matcher.AllOf(0, 1);
                var all4 = Matcher.AllOf(2, 3);
                var c2   = Matcher.AllOf(all3, all4);

                c1.Equals(c2).should_be_true();
            };
        };

        context["nested"] = () => {
            it["works like a charme"] = () => {
                var allAB = Matcher.AllOf(CID.ComponentA, CID.ComponentB);
                var allCD = Matcher.AllOf(CID.ComponentC, CID.ComponentD);
                var allEF = Matcher.AllOf(CID.ComponentE, CID.ComponentF);
                var anyEF = Matcher.AnyOf(CID.ComponentE, CID.ComponentF);

                var c1 = Matcher.AllOf(allAB, allCD, anyEF);
                var c2 = Matcher.AllOf(allAB, allCD, allEF);
                var c3 = Matcher.AnyOf(allAB, allCD, allEF);

                var e = this.CreateEntity();
                e.AddComponentA();
                e.AddComponentB();
                e.AddComponentC();
                e.AddComponentD();
                e.AddComponentE();

                c1.Matches(e).should_be_true();
                c2.Matches(e).should_be_false();
                c3.Matches(e).should_be_true();

                var nested1 = Matcher.AllOf(c1, c2);
                var nested2 = Matcher.AnyOf(c1, c2);
                nested1.Matches(e).should_be_false();
                nested2.Matches(e).should_be_true();

                nested1.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC,
                    CID.ComponentD,
                    CID.ComponentE,
                    CID.ComponentF
                });
                nested2.indices.should_be(new [] {
                    CID.ComponentA,
                    CID.ComponentB,
                    CID.ComponentC,
                    CID.ComponentD,
                    CID.ComponentE,
                    CID.ComponentF
                });

                var nestedAll = Matcher.AllOf(nested1, nested2);
                var nestedAny = Matcher.AnyOf(nested1, nested2);
                nestedAll.Matches(e).should_be_false();
                nestedAny.Matches(e).should_be_true();

                Matcher.NoneOf(nestedAll, nestedAny).Matches(e).should_be_false();
            };
        };

        context["can ToString"] = () => {
            AllOfMatcher  allOf  = null;
            AnyOfMatcher  anyOf  = null;
            NoneOfMatcher noneOf = null;
            before = () => {
                allOf  = Matcher.AllOf(CID.ComponentA, CID.ComponentB);
                anyOf  = Matcher.AnyOf(CID.ComponentC, CID.ComponentD);
                noneOf = Matcher.NoneOf(CID.ComponentE, CID.ComponentF);
            };

            it["AllOfCompoundMatcher"] = () => {
                var m = Matcher.AllOf(allOf, anyOf, noneOf);
                m.ToString().should_be("AllOf(AllOf(1, 2), AnyOf(3, 4), NoneOf(5, 6))");
            };

            it["AnyOfCompoundMatcher"] = () => {
                var m = Matcher.AnyOf(allOf, anyOf, noneOf);
                m.ToString().should_be("AnyOf(AllOf(1, 2), AnyOf(3, 4), NoneOf(5, 6))");
            };

            it["NoneOfCompoundMatcher"] = () => {
                var m = Matcher.NoneOf(allOf, anyOf, noneOf);
                m.ToString().should_be("NoneOf(AllOf(1, 2), AnyOf(3, 4), NoneOf(5, 6))");
            };
        };
    }