summaryrefslogtreecommitdiff
path: root/core/src/test/java/coffee/liz/ecs
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/test/java/coffee/liz/ecs')
-rw-r--r--core/src/test/java/coffee/liz/ecs/DAGWorldTest.java54
-rw-r--r--core/src/test/java/coffee/liz/ecs/common/components/physics/BoundingBoxTest.java45
-rw-r--r--core/src/test/java/coffee/liz/ecs/common/systems/physics/CollisionGridTest.java50
-rw-r--r--core/src/test/java/coffee/liz/ecs/common/systems/physics/PhysicsSystemsTest.java78
4 files changed, 199 insertions, 28 deletions
diff --git a/core/src/test/java/coffee/liz/ecs/DAGWorldTest.java b/core/src/test/java/coffee/liz/ecs/DAGWorldTest.java
index 4825e36..7f3dc2f 100644
--- a/core/src/test/java/coffee/liz/ecs/DAGWorldTest.java
+++ b/core/src/test/java/coffee/liz/ecs/DAGWorldTest.java
@@ -17,7 +17,6 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
-import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -30,7 +29,7 @@ public class DAGWorldTest {
@ParameterizedTest
@MethodSource("queryScenarios")
public void queryResolvesExpectedEntities(final Query query, final Set<String> expectedEntityKeys) {
- final World<String> world = new DAGWorld<>();
+ final World world = new DAGWorld();
final Entity both = world.createEntity();
both.add(new PositionComponent());
both.add(new VelocityComponent());
@@ -40,7 +39,7 @@ public class DAGWorldTest {
velocityOnly.add(new VelocityComponent());
final Entity neither = world.createEntity();
- world.update("state", 0);
+ world.update(0);
final Map<String, Entity> entities = Map.of("both", both, "positionOnly", positionOnly, "velocityOnly",
velocityOnly, "neither", neither);
@@ -60,16 +59,16 @@ public class DAGWorldTest {
public void updateExecutesSystemsInTopologicalOrder() {
final CopyOnWriteArrayList<String> executionLog = new CopyOnWriteArrayList<>();
- final DAGWorld<String> world = new DAGWorld<>(new SystemC(executionLog), new SystemA(executionLog),
+ final DAGWorld world = new DAGWorld(new SystemC(executionLog), new SystemA(executionLog),
new SystemB(executionLog));
- world.update("state", 0);
+ world.update(0);
assertEquals(List.of("A", "B", "C"), executionLog);
}
@Test
public void cacheTracksComponentMutationsViaEntityEvents() {
- final DAGWorld<String> world = new DAGWorld<>();
+ final DAGWorld world = new DAGWorld();
final Entity subject = world.createEntity();
assertTrue(world.resolve(Query.allOf(PositionComponent.class)).isEmpty());
@@ -83,7 +82,7 @@ public class DAGWorldTest {
@Test
public void removedEntityNoLongerMutatesWorldCache() {
- final DAGWorld<String> world = new DAGWorld<>();
+ final DAGWorld world = new DAGWorld();
final Entity subject = world.createEntity();
subject.add(new PositionComponent());
@@ -100,13 +99,12 @@ public class DAGWorldTest {
public void queryFindsComponentsAddedByEarlierSystemInSameTick() {
final List<Set<Entity>> queryResults = new CopyOnWriteArrayList<>();
- final DAGWorld<String> world = new DAGWorld<>(new ComponentAdderSystem(),
- new ComponentReaderSystem(queryResults));
+ final DAGWorld world = new DAGWorld(new ComponentAdderSystem(), new ComponentReaderSystem(queryResults));
final Entity entity = world.createEntity();
entity.add(new PositionComponent());
- world.update("state", 0);
+ world.update(0);
assertEquals(1, queryResults.size());
assertEquals(Set.of(entity), queryResults.get(0));
@@ -114,7 +112,7 @@ public class DAGWorldTest {
@Test
public void circularDependencyDetectionThrowsIllegalStateException() {
- assertThrows(IllegalStateException.class, () -> new DAGWorld<>(new SystemCycleA(), new SystemCycleB()));
+ assertThrows(IllegalStateException.class, () -> new DAGWorld(new SystemCycleA(), new SystemCycleB()));
}
private static final class PositionComponent implements Component {
@@ -124,12 +122,12 @@ public class DAGWorldTest {
}
@RequiredArgsConstructor
- private abstract static class RecordingSystem implements System<String> {
+ private abstract static class RecordingSystem implements System {
private final List<String> log;
private final String label;
@Override
- public final void update(final World<String> world, final String state, final float deltaSeconds) {
+ public final void update(final World world, final float deltaSeconds) {
log.add(label);
}
}
@@ -140,7 +138,7 @@ public class DAGWorldTest {
}
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return List.of();
}
}
@@ -151,7 +149,7 @@ public class DAGWorldTest {
}
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return Set.of(SystemA.class);
}
}
@@ -162,56 +160,56 @@ public class DAGWorldTest {
}
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return Set.of(SystemB.class);
}
}
- private static final class SystemCycleA implements System<String> {
+ private static final class SystemCycleA implements System {
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return Set.of(SystemCycleB.class);
}
@Override
- public final void update(final World<String> world, final String state, final float deltaSeconds) {
+ public void update(final World world, final float deltaSeconds) {
}
}
- private static final class SystemCycleB implements System<String> {
+ private static final class SystemCycleB implements System {
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return Set.of(SystemCycleA.class);
}
@Override
- public final void update(final World<String> world, final String state, final float deltaSeconds) {
+ public void update(final World world, final float deltaSeconds) {
}
}
- private static final class ComponentAdderSystem implements System<String> {
+ private static final class ComponentAdderSystem implements System {
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return List.of();
}
@Override
- public final void update(final World<String> world, final String state, final float deltaSeconds) {
+ public void update(final World world, final float deltaSeconds) {
world.resolve(Query.allOf(PositionComponent.class)).forEach(e -> e.add(new VelocityComponent()));
}
}
@RequiredArgsConstructor
- private static final class ComponentReaderSystem implements System<String> {
+ private static final class ComponentReaderSystem implements System {
private final List<Set<Entity>> queryResults;
@Override
- public Collection<Class<? extends System<String>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return Set.of(ComponentAdderSystem.class);
}
@Override
- public final void update(final World<String> world, final String state, final float deltaSeconds) {
+ public void update(final World world, final float deltaSeconds) {
queryResults.add(world.resolve(Query.allOf(VelocityComponent.class, PositionComponent.class)));
}
}
diff --git a/core/src/test/java/coffee/liz/ecs/common/components/physics/BoundingBoxTest.java b/core/src/test/java/coffee/liz/ecs/common/components/physics/BoundingBoxTest.java
new file mode 100644
index 0000000..2372456
--- /dev/null
+++ b/core/src/test/java/coffee/liz/ecs/common/components/physics/BoundingBoxTest.java
@@ -0,0 +1,45 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.math.Vec2f;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class BoundingBoxTest {
+ @Test
+ public void isCollidingWith_overlapping() {
+ final BoundingBox a = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(2f, 2f));
+ final BoundingBox b = new BoundingBox(new Vec2f(1f, 1f), new Vec2f(2f, 2f));
+ assertTrue(a.isCollidingWith(b));
+ assertTrue(b.isCollidingWith(a));
+ }
+
+ @Test
+ public void isCollidingWith_notOverlapping() {
+ final BoundingBox a = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ final BoundingBox b = new BoundingBox(new Vec2f(2f, 2f), new Vec2f(1f, 1f));
+ assertFalse(a.isCollidingWith(b));
+ }
+
+ @Test
+ public void isCollidingWith_touching_isNotColliding() {
+ final BoundingBox a = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ final BoundingBox b = new BoundingBox(new Vec2f(1f, 0f), new Vec2f(1f, 1f));
+ assertFalse(a.isCollidingWith(b));
+ }
+
+ @Test
+ public void isAbove_returnsTrue_whenBottomAtOrAboveOtherTop() {
+ final BoundingBox a = new BoundingBox(new Vec2f(0f, 2f), new Vec2f(1f, 1f));
+ final BoundingBox b = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ assertTrue(a.isAbove(b));
+ }
+
+ @Test
+ public void isAbove_returnsFalse_whenOverlapping() {
+ final BoundingBox a = new BoundingBox(new Vec2f(0f, 0.5f), new Vec2f(1f, 1f));
+ final BoundingBox b = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ assertFalse(a.isAbove(b));
+ }
+}
diff --git a/core/src/test/java/coffee/liz/ecs/common/systems/physics/CollisionGridTest.java b/core/src/test/java/coffee/liz/ecs/common/systems/physics/CollisionGridTest.java
new file mode 100644
index 0000000..d5670aa
--- /dev/null
+++ b/core/src/test/java/coffee/liz/ecs/common/systems/physics/CollisionGridTest.java
@@ -0,0 +1,50 @@
+package coffee.liz.ecs.common.systems.physics;
+
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.math.Vec2f;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CollisionGridTest {
+ private final CollisionGrid grid = new CollisionGrid();
+
+ @BeforeEach
+ public void setup() {
+ grid.setOrigin(new Vec2f(0f, 0f));
+ grid.setCellSize(new Vec2f(32f, 32f));
+ }
+
+ @Test
+ public void insertedEntityIsFoundAsNeighbor() {
+ final BoundingBox bb = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ grid.insert(1, bb);
+ assertTrue(grid.getNeighborIds(bb).contains(1));
+ }
+
+ @Test
+ public void entityInDifferentCellIsNotNeighbor() {
+ final BoundingBox a = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ final BoundingBox b = new BoundingBox(new Vec2f(100f, 100f), new Vec2f(1f, 1f));
+ grid.insert(1, a);
+ assertFalse(grid.getNeighborIds(b).contains(1));
+ }
+
+ @Test
+ public void clearRemovesAllEntities() {
+ final BoundingBox bb = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(1f, 1f));
+ grid.insert(1, bb);
+ grid.clear();
+ assertTrue(grid.getNeighborIds(bb).isEmpty());
+ }
+
+ @Test
+ public void largeEntitySpanningMultipleCellsFoundByNeighborInAnyCell() {
+ final BoundingBox large = new BoundingBox(new Vec2f(0f, 0f), new Vec2f(64f, 64f));
+ final BoundingBox corner = new BoundingBox(new Vec2f(50f, 50f), new Vec2f(1f, 1f));
+ grid.insert(1, large);
+ assertTrue(grid.getNeighborIds(corner).contains(1));
+ }
+}
diff --git a/core/src/test/java/coffee/liz/ecs/common/systems/physics/PhysicsSystemsTest.java b/core/src/test/java/coffee/liz/ecs/common/systems/physics/PhysicsSystemsTest.java
new file mode 100644
index 0000000..13a4a1c
--- /dev/null
+++ b/core/src/test/java/coffee/liz/ecs/common/systems/physics/PhysicsSystemsTest.java
@@ -0,0 +1,78 @@
+package coffee.liz.ecs.common.systems.physics;
+
+import coffee.liz.ecs.DAGWorld;
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.common.components.physics.Collidable;
+import coffee.liz.ecs.common.components.physics.Force;
+import coffee.liz.ecs.common.components.physics.Forces;
+import coffee.liz.ecs.common.components.physics.Gravity;
+import coffee.liz.ecs.common.components.physics.Jump;
+import coffee.liz.ecs.common.components.physics.Mass;
+import coffee.liz.ecs.common.components.physics.TopCollidable;
+import coffee.liz.ecs.common.components.physics.Velocity;
+import coffee.liz.ecs.math.Vec2f;
+import coffee.liz.ecs.model.Entity;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class PhysicsSystemsTest {
+ private static final float GRAVITY = 9.8f;
+
+ @Test
+ public void gravityAcceleratesEntityDownwardOverTime() {
+ final DAGWorld world = new DAGWorld(new ForceReductionSystem(GRAVITY), new IntegrationSystem());
+ final Entity entity = world.createEntity();
+ entity.add(new Mass(1f));
+ entity.add(new Velocity(Vec2f.ZERO));
+ entity.add(new Forces());
+ entity.add(new Gravity(100f));
+ entity.add(new BoundingBox(new Vec2f(0f, 10f), new Vec2f(1f, 1f)));
+
+ world.update(1f);
+
+ assertTrue(entity.get(Velocity.class).getVelocity().getY() < 0f);
+ assertTrue(entity.get(BoundingBox.class).getPosition().getY() < 10f);
+ }
+
+ @Test
+ public void forcesAreClearedEachFrame() {
+ final DAGWorld world = new DAGWorld(new ForceReductionSystem(GRAVITY), new IntegrationSystem());
+ final Entity entity = world.createEntity();
+ entity.add(new Mass(1f));
+ entity.add(new Velocity(Vec2f.ZERO));
+ final Forces forces = new Forces();
+ forces.add(new Force(new Vec2f(0f, 100f)));
+ entity.add(forces);
+
+ world.update(1f);
+
+ assertTrue(entity.get(Forces.class).getForces().isEmpty());
+ }
+
+ @Test
+ public void entityLandsOnPlatformAndStops() {
+ final DAGWorld world = new DAGWorld(
+ new ForceReductionSystem(GRAVITY), new IntegrationSystem(), new CollisionSystem(GRAVITY, 32f));
+
+ final Entity player = world.createEntity();
+ player.add(new Mass(1f));
+ player.add(new Velocity(new Vec2f(0f, -5f)));
+ player.add(new Forces());
+ player.add(new Gravity(100f));
+ player.add(new Jump(false, 0L));
+ player.add(new BoundingBox(new Vec2f(0f, 1.1f), new Vec2f(1f, 1f)));
+ player.add(new Collidable());
+
+ final Entity floor = world.createEntity();
+ floor.add(new BoundingBox(new Vec2f(-5f, 0f), new Vec2f(10f, 1f)));
+ floor.add(new TopCollidable());
+
+ world.update(0.1f);
+
+ assertEquals(1f, player.get(BoundingBox.class).getPosition().getY(), 0.001f);
+ assertEquals(0f, player.get(Velocity.class).getVelocity().getY(), 0.001f);
+ assertTrue(player.get(Jump.class).isCanJump());
+ }
+}