Example #1
0
        public unsafe void PoolCapacity(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var       pool         = new ParticlePool(0, maxParticles, policy);

            const bool forceCreation = true;

            pool.FieldExists(ParticleFields.Position, forceCreation);
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation);
            pool.FieldExists(ParticleFields.Velocity, forceCreation);
            pool.FieldExists(ParticleFields.Size, forceCreation);

            var testPos  = new Vector3(1, 2, 3);
            var testVel  = new Vector3(5, 6, 7);
            var testLife = 5f;
            var testSize = 4f;

            // Spawn all particles
            for (int i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }


            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                foreach (var particle in pool)
                {
                    *((Vector3 *)particle[positionField]) = testPos;

                    *((float *)particle[lifetimeField]) = testLife;

                    *((Vector3 *)particle[velocityField]) = testVel;

                    *((float *)particle[sizeField]) = testSize;
                }
            }

            // Double the pool capacity and assert that the first half of particles still have the same fields
            pool.SetCapacity(2 * maxParticles);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                var sorter     = new ParticleSorterLiving(pool);
                var sortedList = sorter.GetSortedList(new Vector3(0, 0, -1));

                var i = 0;
                foreach (var particle in sortedList)
                {
                    Assert.Equal(testPos, *((Vector3 *)particle[positionField]));

                    Assert.Equal(testLife, *((float *)particle[lifetimeField]));

                    Assert.Equal(testVel, *((Vector3 *)particle[velocityField]));

                    Assert.Equal(testSize, *((float *)particle[sizeField]));

                    i++;
                }

                sorter.FreeSortedList(ref sortedList);

                // Assert that the number of living particles is still maxParticles, not maxParticles x2
                Assert.Equal(maxParticles, i);
            }

            // Halve the pool capacity from its original size. Now all the particles should still have the same fields
            pool.SetCapacity(maxParticles / 2);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                var sorter     = new ParticleSorterLiving(pool);
                var sortedList = sorter.GetSortedList(new Vector3(0, 0, -1));

                var i = 0;
                foreach (var particle in sortedList)
                {
                    Assert.Equal(testPos, *((Vector3 *)particle[positionField]));

                    Assert.Equal(testLife, *((float *)particle[lifetimeField]));

                    Assert.Equal(testVel, *((Vector3 *)particle[velocityField]));

                    Assert.Equal(testSize, *((float *)particle[sizeField]));

                    i++;
                }

                sorter.FreeSortedList(ref sortedList);

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.Equal(maxParticles / 2, i);
            }
        }
Example #2
0
        public unsafe void ParticleGetSet(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var       pool         = new ParticlePool(0, maxParticles, policy);

            // Spawn all particles
            for (var i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }

            const bool forceCreation = true;

            pool.FieldExists(ParticleFields.Position, forceCreation);
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation);
            pool.FieldExists(ParticleFields.Velocity, forceCreation);
            pool.FieldExists(ParticleFields.Size, forceCreation);

            var positionField = pool.GetField(ParticleFields.Position);
            var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
            var velocityField = pool.GetField(ParticleFields.Velocity);
            var sizeField     = pool.GetField(ParticleFields.Size);

            var vectorToSet = new Vector3(0, 0, 0);
            var scalarToSet = 0f;

            foreach (var particle in pool)
            {
                vectorToSet.Y = scalarToSet;

                *((Vector3 *)particle[positionField]) = vectorToSet;

                *((float *)particle[lifetimeField]) = scalarToSet;

                *((Vector3 *)particle[velocityField]) = vectorToSet;

                *((float *)particle[sizeField]) = scalarToSet;

                scalarToSet++;
            }

            // Assert the values are the same
            scalarToSet = 0f;
            foreach (var particle in pool)
            {
                Assert.Equal(new Vector3(0, scalarToSet, 0), *((Vector3 *)particle[positionField]));

                Assert.Equal(scalarToSet, *((float *)particle[lifetimeField]));

                Assert.Equal(new Vector3(0, scalarToSet, 0), *((Vector3 *)particle[velocityField]));

                Assert.Equal(scalarToSet, *((float *)particle[sizeField]));

                scalarToSet++;
            }

            // "Update" the values with delta time
            var dt = 0.033333f;

            foreach (var particle in pool)
            {
                var pos = ((Vector3 *)particle[positionField]);
                var vel = ((Vector3 *)particle[velocityField]);

                *pos += *vel * dt;

                *((float *)particle[lifetimeField]) += 1;
            }

            scalarToSet = 0f;
            foreach (var particle in pool)
            {
                Assert.Equal(*((Vector3 *)particle[positionField]), new Vector3(0, scalarToSet, 0) + *((Vector3 *)particle[velocityField]) * dt);

                Assert.Equal(scalarToSet + 1, *((float *)particle[lifetimeField]));

                scalarToSet++;
            }
        }
        public unsafe void PoolFields(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var       pool         = new ParticlePool(0, maxParticles, policy);

            // Spawn all particles
            for (int i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }

            const bool forceCreation = true;

            // Position
            pool.FieldExists(ParticleFields.Position, forceCreation);
            var testPos = new Vector3(1, 2, 3);

            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField = pool.GetField(ParticleFields.Position);

                foreach (var particle in pool)
                {
                    *((Vector3 *)particle[positionField]) = testPos;
                }
            }

            // Life
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation);
            var testLife = 5f;

            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                foreach (var particle in pool)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    *((float *)particle[lifetimeField]) = testLife;
                }
            }


            // Velocity
            pool.FieldExists(ParticleFields.Velocity, forceCreation);
            var testVel = new Vector3(5, 6, 7);

            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);

                foreach (var particle in pool)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    *((Vector3 *)particle[velocityField]) = testVel;
                }
            }

            // Size
            pool.FieldExists(ParticleFields.Size, forceCreation);
            var testSize = 4f;

            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                foreach (var particle in pool)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    Assert.That(*((Vector3 *)particle[velocityField]), Is.EqualTo(testVel));

                    *((float *)particle[sizeField]) = testSize;
                }
            }

            // II. Change the capacity and assert that fields are still accessible
            pool.SetCapacity(2 * maxParticles);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    Assert.That(*((Vector3 *)particle[velocityField]), Is.EqualTo(testVel));

                    Assert.That(*((float *)particle[sizeField]), Is.EqualTo(testSize));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles));
            }

            // Halve the pool capacity from its original size. Now all the particles should still have the same fields
            pool.SetCapacity(maxParticles / 2);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    Assert.That(*((Vector3 *)particle[velocityField]), Is.EqualTo(testVel));

                    Assert.That(*((float *)particle[sizeField]), Is.EqualTo(testSize));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles / 2));
            }

            // III. Remove fields and assert the remaining fields are unchanged

            // Remove velocity
            pool.RemoveField(ParticleFields.Velocity);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                Assert.That(velocityField.IsValid(), Is.EqualTo(false));

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    Assert.That(*((float *)particle[sizeField]), Is.EqualTo(testSize));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles / 2));
            }

            // Remove size
            pool.RemoveField(ParticleFields.Size);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                Assert.That(velocityField.IsValid(), Is.EqualTo(false));
                Assert.That(sizeField.IsValid(), Is.EqualTo(false));

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((Vector3 *)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles / 2));
            }

            // Remove position
            pool.RemoveField(ParticleFields.Position);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                Assert.That(velocityField.IsValid(), Is.EqualTo(false));
                Assert.That(sizeField.IsValid(), Is.EqualTo(false));
                Assert.That(positionField.IsValid(), Is.EqualTo(false));

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((float *)particle[lifetimeField]), Is.EqualTo(testLife));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles / 2));
            }
        }