public void Behavior_Initialization_Method_Called_When_Trigger_Returns_A_Positive_Number() { const int newParticleCount = 5; var trigger = MockTrigger(); var initializer = MockInitializer(); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, Initializers = { initializer.Object }, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); trigger.Setup(x => x.DetermineNumberOfParticlesToCreate(emitter, 0.16f)) .Returns(newParticleCount); emitter.Update(0.16f); initializer.Verify(x => x.InitializeParticles( emitter, It.IsAny <ParticleCollection>(), It.Is <IReadOnlyList <int> >(y => y.Count == newParticleCount)), Times.Once); }
public void Tracked_Distance_Reset_After_Emission() { var trigger = new DistanceBasedTrigger(new Random()) { DistanceBetweenEmissions = 1.0f, MinParticlesToEmit = 5, MaxParticlesToEmit = 10, }; var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); emitter.WorldCoordinates = Vector2.Zero; trigger.DetermineNumberOfParticlesToCreate(emitter, 0.16f).ShouldBe(0); emitter.WorldCoordinates = new Vector2(0.5f, 0.5f); trigger.DetermineNumberOfParticlesToCreate(emitter, 0.16f).ShouldBe(0); emitter.WorldCoordinates = new Vector2(1, 1); trigger.DetermineNumberOfParticlesToCreate(emitter, 0.16f).ShouldBeInRange(5, 10); emitter.WorldCoordinates = new Vector2(1, 1.5f); trigger.DetermineNumberOfParticlesToCreate(emitter, 0.16f).ShouldBe(0); }
public void Emitter_Capacity_Expanded_If_Not_Enough_Dead_Particles_Exist() { const int newParticleCount = 3; var trigger = MockTrigger(); trigger.Setup(x => x.DetermineNumberOfParticlesToCreate(It.IsAny <ParticleEmitter>(), 0.16f)) .Returns(newParticleCount); var initializer = MockInitializer(); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, Initializers = { initializer.Object }, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); var values = emitter.Reservation.GetPropertyValues <bool>(StandardParmeProperties.IsAlive.Name); for (var x = 0; x <= 10 - newParticleCount; x++) { values[x] = true; } emitter.Update(0.16f); emitter.Reservation.Length.ShouldBeGreaterThan(10); }
public void Property_Values_Remain_After_Expansion() { var allocator = new ParticleAllocator(5); allocator.RegisterProperty(typeof(float), "Something"); var first = allocator.Reserve(3); { var values = first.GetPropertyValues <float>("Something"); values[0] = 1.1f; values[1] = 2.2f; values[2] = 3.3f; } allocator.Reserve(3); allocator.Capacity.ShouldBeGreaterThan(5, "Expected capacity to grow"); var newValues = first.GetPropertyValues <float>("Something"); newValues[0].ShouldBe(1.1f); newValues[1].ShouldBe(2.2f); newValues[2].ShouldBe(3.3f); }
public void KeyNotFoundException_When_Property_Is_Not_Registered() { var allocator = new ParticleAllocator(10); var reservation = allocator.Reserve(5); Assert.Throws <KeyNotFoundException>(() => reservation.GetPropertyValues <float>("Something")); }
public void Can_Reserve_Block_Under_Capacity() { var allocator = new ParticleAllocator(10); var reservation = allocator.Reserve(7); reservation.Length.ShouldBe(7); reservation.StartIndex.ShouldBe(0); reservation.LastUsedIndex.ShouldBe(6); }
public void KeyNotFoundException_When_Property_Registered_For_Different_Type() { var allocator = new ParticleAllocator(10); var reservation = allocator.Reserve(5); allocator.RegisterProperty(typeof(float), "Something"); Assert.Throws <KeyNotFoundException>(() => reservation.GetPropertyValues <bool>("Something")); }
public void Can_Reserve_Block_Over_Capacity() { var allocator = new ParticleAllocator(10); var reservation = allocator.Reserve(11); allocator.Capacity.ShouldBeGreaterThan(10); reservation.Length.ShouldBe(11); reservation.StartIndex.ShouldBe(0); reservation.LastUsedIndex.ShouldBe(10); }
public void Properties_Of_Different_Types_Can_Have_The_Same_Name() { var allocator = new ParticleAllocator(10); var reservation = allocator.Reserve(5); allocator.RegisterProperty(typeof(bool), "Something"); allocator.RegisterProperty(typeof(float), "Something"); var boolValues = reservation.GetPropertyValues <bool>("Something"); var floatValues = reservation.GetPropertyValues <float>("Something"); }
public void Can_Expand_When_Not_Enough_Free_Space_Exists() { var allocator = new ParticleAllocator(10); allocator.Reserve(3); var reservation = allocator.Reserve(5); reservation.Expand(10); reservation.Length.ShouldBe(15); }
public void Can_Expand_Reservation_When_Its_The_Only_Reservation() { var allocator = new ParticleAllocator(10); var reservation = allocator.Reserve(5); reservation.Expand(3); reservation.Length.ShouldBe(8); reservation.StartIndex.ShouldBe(0); reservation.LastUsedIndex.ShouldBe(7); }
public void Can_Reserve_When_Not_Enough_Free_Space_Exists() { var allocator = new ParticleAllocator(10); allocator.Reserve(3); allocator.Reserve(2); allocator.Reserve(3); var fourth = allocator.Reserve(3); fourth.Length.ShouldBe(3); allocator.Capacity.ShouldBeGreaterThan(10); }
public void Can_Expand_When_Free_Space_Exists_But_No_Big_Enough_Gaps() { var allocator = new ParticleAllocator(10); var first = allocator.Reserve(3); var second = allocator.Reserve(2); allocator.Reserve(3); second.Dispose(); first.Expand(3); first.Length.ShouldBe(6); }
public void Particles_For_Initialization_Are_Marked_As_Alive() { const int newParticleCount = 3; var trigger = MockTrigger(); trigger.Setup(x => x.DetermineNumberOfParticlesToCreate(It.IsAny <ParticleEmitter>(), 0.16f)) .Returns(newParticleCount); var initializer = MockInitializer(); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, Initializers = { initializer.Object }, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); { var values = emitter.Reservation.GetPropertyValues <bool>(StandardParmeProperties.IsAlive.Name); values[1] = true; values[3] = true; values[5] = true; values[7] = true; values[9] = true; } IReadOnlyList <int>?newParticleIndices = null; initializer.Setup(x => x.InitializeParticles( It.IsAny <ParticleEmitter>(), It.IsAny <ParticleCollection>(), It.IsAny <IReadOnlyList <int> >())) .Callback <ParticleEmitter, ParticleCollection, IReadOnlyList <int> >((_, _, indices) => newParticleIndices = indices); emitter.Update(0.16f); newParticleIndices.ShouldNotBeNull(); newParticleIndices.Count.ShouldBe(3); { var values = emitter.Reservation.GetPropertyValues <bool>(StandardParmeProperties.IsAlive.Name); values[newParticleIndices[0]].ShouldBeTrue(); values[newParticleIndices[1]].ShouldBeTrue(); values[newParticleIndices[2]].ShouldBeTrue(); } }
public void Two_Consecutive_Reservations_Are_Adjacent() { var allocator = new ParticleAllocator(10); var first = allocator.Reserve(5); var second = allocator.Reserve(3); first.Length.ShouldBe(5); first.StartIndex.ShouldBe(0); first.LastUsedIndex.ShouldBe(4); second.Length.ShouldBe(3); second.StartIndex.ShouldBe(5); second.LastUsedIndex.ShouldBe(7); }
public void Can_Expand_Reservation_Into_Disposed_Gap() { var allocator = new ParticleAllocator(10); var first = allocator.Reserve(5); var second = allocator.Reserve(3); allocator.Reserve(2); second.Dispose(); first.Expand(3); first.Length.ShouldBe(8); first.StartIndex.ShouldBe(0); first.LastUsedIndex.ShouldBe(7); }
public void Can_Reserve_When_Free_Space_Exists_But_No_Wide_Enough_Gaps() { var allocator = new ParticleAllocator(10); allocator.Reserve(3); var second = allocator.Reserve(1); allocator.Reserve(3); second.Dispose(); var fourth = allocator.Reserve(3); fourth.Length.ShouldBe(3); }
public void Disposing_Reservation_Allows_Indices_To_Be_Reused() { var allocator = new ParticleAllocator(10); using (var first = allocator.Reserve(5)) { first.Length.ShouldBe(5); first.StartIndex.ShouldBe(0); first.LastUsedIndex.ShouldBe(4); } var second = allocator.Reserve(5); second.StartIndex.ShouldBe(0); second.LastUsedIndex.ShouldBe(4); }
public void Cannot_Get_Property_Not_In_Valid_Readable_Hash_Set() { var property1 = new ParticleProperty(typeof(bool), "Something"); var property2 = new ParticleProperty(typeof(bool), "Something2"); var allocator = new ParticleAllocator(10); allocator.RegisterProperty(property1.Type, property1.Name); allocator.RegisterProperty(property2.Type, property2.Name); var reservation = allocator.Reserve(5); var collection = new ParticleCollection(reservation) { ValidPropertiesToSet = new HashSet <ParticleProperty>(new[] { property1 }) }; Assert.ThrowsAny <Exception>(() => collection.GetReadOnlyPropertyValues <bool>(property2.Name)); }
public void Properties_Marked_As_Valid_For_Reading_Can_Be_Retrieved_As_Read_Only() { var property = new ParticleProperty(typeof(bool), "Something"); var allocator = new ParticleAllocator(10); allocator.RegisterProperty(property.Type, property.Name); var reservation = allocator.Reserve(5); var collection = new ParticleCollection(reservation) { ValidPropertiesToRead = new HashSet <ParticleProperty>(new[] { property }) }; var result = collection.GetReadOnlyPropertyValues <bool>(property.Name); result.Length.ShouldBe(reservation.Length); }
public void Modifier_Method_Called() { var trigger = MockTrigger(); var modifier = MockModifier(); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, Modifiers = { modifier.Object }, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); emitter.Update(0.16f); modifier.Verify(x => x.Update(emitter, It.IsAny <ParticleCollection>(), 0.16f), Times.Once); }
public void Defrag_Occurs_When_2x_Free_Space_Exists_But_No_Wide_Enough_Gaps() { var allocator = new ParticleAllocator(15); var first = allocator.Reserve(3); var second = allocator.Reserve(2); var third = allocator.Reserve(3); var fourth = allocator.Reserve(2); var fifth = allocator.Reserve(3); second.Dispose(); fourth.Dispose(); var sixth = allocator.Reserve(3); allocator.Capacity.ShouldBe(15); // No increase in capacity in a defrag VerifyAllAreConsecutive(first, third, fifth, sixth); }
public void Multiple_Reservations_Have_Distinct_Property_Values() { var allocator = new ParticleAllocator(8); allocator.RegisterProperty(typeof(float), "Something"); var first = allocator.Reserve(3); var second = allocator.Reserve(2); var third = allocator.Reserve(3); allocator.Capacity.ShouldBe(8, "Allocator capacity shouldn't have changed yet"); { var values = first.GetPropertyValues <float>("Something"); values[0] = 1.1f; values[1] = 2.2f; values[2] = 3.3f; } { var values = third.GetPropertyValues <float>("Something"); values[0] = 4.4f; values[1] = 5.5f; values[2] = 6.6f; } second.Dispose(); allocator.Reserve(3); // cause defrag or expansion, don't care which for this test { var values = first.GetPropertyValues <float>("Something"); values[0].ShouldBe(1.1f); values[1].ShouldBe(2.2f); values[2].ShouldBe(3.3f); } { var values = third.GetPropertyValues <float>("Something"); values[0].ShouldBe(4.4f); values[1].ShouldBe(5.5f); values[2].ShouldBe(6.6f); } }
public void Trigger_Not_Called_If_Emitter_Is_Not_Active() { var trigger = MockTrigger(); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config) { IsEmittingNewParticles = false, }; emitter.Update(0.16f); trigger.Verify(x => x.DetermineNumberOfParticlesToCreate(emitter, 0.16f), Times.Never); }
public void Initializer_Properties_Are_Registered() { var trigger = MockTrigger(); var initializer = MockInitializer(); initializer.Setup(x => x.PropertiesISet) .Returns(new HashSet <ParticleProperty>(new[] { new ParticleProperty(typeof(bool), "Test1") })); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, Initializers = { initializer.Object }, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); emitter.Reservation.GetPropertyValues <bool>("Test1"); }
public void Only_One_Set_Of_Particles_Emitted_If_Multiples_Of_Time_Elapses() { var trigger = new TimeBasedTrigger(new Random()) { SecondsBetweenEmissions = 1.0f, MinParticlesToEmit = 5, MaxParticlesToEmit = 5, }; var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); trigger.DetermineNumberOfParticlesToCreate(emitter, 5.0f).ShouldBe(5); }
protected static (ParticleCollection collection, int[] newIndices) RunInitializer(IParticleInitializer initializer) { var config = new EmitterConfig { Initializers = { initializer }, Trigger = MockTrigger().Object, InitialCapacity = 10, }; var allocator = new ParticleAllocator(100); var emitter = new ParticleEmitter(allocator, config); var collection = new ParticleCollection(emitter.Reservation) { ValidPropertiesToSet = initializer.PropertiesISet, }; var newIndices = new[] { 1, 3, 5, 7 }; initializer.InitializeParticles(emitter, collection, newIndices); return(collection, newIndices); }
public void Timer_Reset_After_Particles_Emitted() { var trigger = new TimeBasedTrigger(new Random()) { SecondsBetweenEmissions = 1.0f, MinParticlesToEmit = 5, MaxParticlesToEmit = 10, }; var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); trigger.DetermineNumberOfParticlesToCreate(emitter, 1.05f).ShouldBeInRange(5, 10); trigger.DetermineNumberOfParticlesToCreate(emitter, 0.16f).ShouldBe(0); }
public void Mandatory_Properties_Are_Automatically_Registered() { var trigger = MockTrigger(); var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger.Object, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); var reservation = emitter.Reservation; reservation.GetPropertyValues <bool>(StandardParmeProperties.IsAlive.Name); reservation.GetPropertyValues <float>(StandardParmeProperties.PositionX.Name); reservation.GetPropertyValues <float>(StandardParmeProperties.PositionY.Name); reservation.GetPropertyValues <float>(StandardParmeProperties.TimeAlive.Name); reservation.GetPropertyValues <float>(StandardParmeProperties.CurrentWidth.Name); reservation.GetPropertyValues <float>(StandardParmeProperties.CurrentHeight.Name); }
public void Returns_Value_Between_Min_And_Max_On_Invocation() { const int seed = 1; var trigger = new OneShotTrigger(new Random(seed)) { MinParticlesToEmit = 5, MaxParticlesToEmit = 10, }; var allocator = new ParticleAllocator(10); var config = new EmitterConfig { Trigger = trigger, InitialCapacity = 10, }; var emitter = new ParticleEmitter(allocator, config); var result = trigger.DetermineNumberOfParticlesToCreate(emitter, 0.16f); result.ShouldBe(new Random(seed).Next(trigger.MinParticlesToEmit, trigger.MaxParticlesToEmit + 1)); }