summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-02-28 17:23:42 -0800
committerElizabeth Alexander Hunt <me@liz.coffee>2026-02-28 17:23:42 -0800
commitc491b5cb08972ffc041fa0b968810373b9ed79a3 (patch)
tree962a41f50fab58a026ab7c2c3e034fcda0733dfd
parent2bc1cb77dfe8edf29ccb4064be23078cdd06038b (diff)
downloaddyl-c491b5cb08972ffc041fa0b968810373b9ed79a3.tar.gz
dyl-c491b5cb08972ffc041fa0b968810373b9ed79a3.zip
Removing parameterization from World since it was getting complicated.
-rw-r--r--build.gradle7
-rw-r--r--core/src/main/java/coffee/liz/dyl/FrameState.java16
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/BoundingBox.java21
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/graphic/Graphic.java4
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/graphic/TextureGraphic.java6
-rw-r--r--core/src/main/java/coffee/liz/dyl/config/KeyBinds.java21
-rw-r--r--core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java12
-rw-r--r--core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java26
-rw-r--r--core/src/main/java/coffee/liz/dyl/screen/GameScreen.java9
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/InputSystem.java69
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/IntegrationSystem.java32
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/RenderSystem.java14
-rw-r--r--core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java25
-rw-r--r--core/src/main/java/coffee/liz/ecs/DAGWorld.java74
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/BoundingBox.java34
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Collidable.java6
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Force.java12
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Forces.java20
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Gravity.java11
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Jump.java14
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Mass.java11
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/TopCollidable.java6
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/components/physics/Velocity.java (renamed from core/src/main/java/coffee/liz/dyl/components/Velocity.java)7
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionGrid.java65
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionSystem.java107
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/systems/physics/ForceReductionSystem.java55
-rw-r--r--core/src/main/java/coffee/liz/ecs/common/systems/physics/IntegrationSystem.java25
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/QueryBuilder.java4
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/System.java25
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/World.java56
-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
-rw-r--r--gradle.properties2
-rw-r--r--lwjgl3/build.gradle28
36 files changed, 741 insertions, 310 deletions
diff --git a/build.gradle b/build.gradle
index 79053e4..2cf224f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -27,8 +27,11 @@ allprojects {
configure(subprojects) {
apply plugin: 'java-library'
- java.sourceCompatibility = JavaVersion.VERSION_24
- java.targetCompatibility = JavaVersion.VERSION_24
+ java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(25)
+ }
+ }
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.42'
diff --git a/core/src/main/java/coffee/liz/dyl/FrameState.java b/core/src/main/java/coffee/liz/dyl/FrameState.java
deleted file mode 100644
index 7d70cde..0000000
--- a/core/src/main/java/coffee/liz/dyl/FrameState.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package coffee.liz.dyl;
-
-import coffee.liz.dyl.config.Settings;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.function.Predicate;
-
-@Builder
-@Getter
-@RequiredArgsConstructor
-public class FrameState {
- private final Settings settings;
- private final Predicate<Integer> isKeyPressed;
-}
diff --git a/core/src/main/java/coffee/liz/dyl/components/BoundingBox.java b/core/src/main/java/coffee/liz/dyl/components/BoundingBox.java
deleted file mode 100644
index 481e91e..0000000
--- a/core/src/main/java/coffee/liz/dyl/components/BoundingBox.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package coffee.liz.dyl.components;
-
-import coffee.liz.ecs.math.Vec2;
-import coffee.liz.ecs.model.Component;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.Setter;
-
-@AllArgsConstructor
-@Getter
-@Setter
-public class BoundingBox implements Component, Comparable<BoundingBox> {
- private Vec2<Float> position;
- private Vec2<Integer> dimensions;
- private int z;
-
- @Override
- public int compareTo(final BoundingBox other) {
- return Integer.compare(z, other.getZ());
- }
-}
diff --git a/core/src/main/java/coffee/liz/dyl/components/graphic/Graphic.java b/core/src/main/java/coffee/liz/dyl/components/graphic/Graphic.java
index c70b382..7075755 100644
--- a/core/src/main/java/coffee/liz/dyl/components/graphic/Graphic.java
+++ b/core/src/main/java/coffee/liz/dyl/components/graphic/Graphic.java
@@ -1,6 +1,6 @@
package coffee.liz.dyl.components.graphic;
-import coffee.liz.dyl.components.BoundingBox;
+import coffee.liz.ecs.common.components.physics.BoundingBox;
import coffee.liz.ecs.model.Component;
import com.badlogic.gdx.graphics.g2d.Batch;
@@ -9,5 +9,7 @@ public interface Graphic extends Component {
return Graphic.class;
}
+ int getZ();
+
void draw(final Batch batch, final BoundingBox boundingBox);
}
diff --git a/core/src/main/java/coffee/liz/dyl/components/graphic/TextureGraphic.java b/core/src/main/java/coffee/liz/dyl/components/graphic/TextureGraphic.java
index 6f29759..c2718b5 100644
--- a/core/src/main/java/coffee/liz/dyl/components/graphic/TextureGraphic.java
+++ b/core/src/main/java/coffee/liz/dyl/components/graphic/TextureGraphic.java
@@ -1,6 +1,6 @@
package coffee.liz.dyl.components.graphic;
-import coffee.liz.dyl.components.BoundingBox;
+import coffee.liz.ecs.common.components.physics.BoundingBox;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
@@ -10,6 +10,7 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public class TextureGraphic implements Graphic {
+ private int z;
private Color color;
private Texture texture;
@@ -18,8 +19,7 @@ public class TextureGraphic implements Graphic {
batch.setColor(color);
batch.draw(texture,
boundingBox.getPosition().getX(), boundingBox.getPosition().getY(),
- 0, 0,
- boundingBox.getDimensions().getX(), boundingBox.getDimensions().getY()
+ boundingBox.getSize().getX(), boundingBox.getSize().getY()
);
}
}
diff --git a/core/src/main/java/coffee/liz/dyl/config/KeyBinds.java b/core/src/main/java/coffee/liz/dyl/config/KeyBinds.java
index 762dc48..0b33b26 100644
--- a/core/src/main/java/coffee/liz/dyl/config/KeyBinds.java
+++ b/core/src/main/java/coffee/liz/dyl/config/KeyBinds.java
@@ -1,4 +1,5 @@
package coffee.liz.dyl.config;
+
import com.badlogic.gdx.Input;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -16,26 +17,24 @@ import java.util.function.Predicate;
@Getter
public class KeyBinds {
@Builder.Default
- private Set<Integer> moveUpKeys = Set.of(Input.Keys.K, Input.Keys.UP, Input.Keys.W);
- @Builder.Default
- private Set<Integer> moveDownKeys = Set.of(Input.Keys.J, Input.Keys.DOWN, Input.Keys.S);
- @Builder.Default
private Set<Integer> moveLeftKeys = Set.of(Input.Keys.H, Input.Keys.LEFT, Input.Keys.A);
@Builder.Default
private Set<Integer> moveRightKeys = Set.of(Input.Keys.L, Input.Keys.RIGHT, Input.Keys.D);
+ @Builder.Default
+ private Set<Integer> jumpKeys = Set.of(Input.Keys.W, Input.Keys.UP, Input.Keys.SPACE);
public Set<Action> filterActiveActions(final Predicate<Integer> isDown) {
final Set<Action> actions = new HashSet<>();
- Map.of(moveUpKeys, Action.MOVE_UP, moveDownKeys, Action.MOVE_DOWN, moveRightKeys, Action.MOVE_RIGHT,
- moveLeftKeys, Action.MOVE_LEFT).forEach((keys, action) -> {
- if (keys.stream().anyMatch(isDown)) {
- actions.add(action);
- }
- });
+ Map.of(moveLeftKeys, Action.MOVE_LEFT, moveRightKeys, Action.MOVE_RIGHT, jumpKeys, Action.JUMP)
+ .forEach((keys, action) -> {
+ if (keys.stream().anyMatch(isDown)) {
+ actions.add(action);
+ }
+ });
return actions;
}
public enum Action {
- MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT;
+ MOVE_LEFT, MOVE_RIGHT, JUMP;
}
}
diff --git a/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java b/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java
new file mode 100644
index 0000000..b0b1a31
--- /dev/null
+++ b/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java
@@ -0,0 +1,12 @@
+package coffee.liz.dyl.config;
+
+public final class PhysicsConstants {
+ public static final float GRAVITY = 9.8f;
+ public static final float MOVE_SPEED = 5.0f;
+ public static final float JUMP_INITIAL_VEL = 8.0f;
+ public static final float JUMP_ACC = 15.0f;
+ public static final long MAX_JUMP_MS = 150L;
+
+ private PhysicsConstants() {
+ }
+}
diff --git a/core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java b/core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java
index 54c5df7..a982bb9 100644
--- a/core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java
+++ b/core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java
@@ -1,8 +1,15 @@
package coffee.liz.dyl.entities;
import coffee.liz.dyl.components.Controllable;
-import coffee.liz.dyl.components.Velocity;
import coffee.liz.dyl.components.graphic.TextureGraphic;
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.common.components.physics.Collidable;
+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.Velocity;
+import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.model.Entity;
import coffee.liz.ecs.model.World;
import com.badlogic.gdx.Gdx;
@@ -15,16 +22,23 @@ public class PlayerFactory {
private static final int PENGUIN_FRAMES_Y = 4;
private static final int PENGUIN_FRAMES_X = 8;
private static final FileHandle FILE = Gdx.files.internal("player.png");
- private static Texture texture = new Texture(FILE);;
+ private static Texture texture = new Texture(FILE);
- public static Entity addTo(final World<?> world) {
+ public static Entity addTo(final World world) {
final TextureRegion[][] tmp = TextureRegion.split(texture, texture.getWidth() / PENGUIN_FRAMES_X,
texture.getHeight() / PENGUIN_FRAMES_Y);
return world.createEntity()
- .add(new TextureGraphic(Color.PINK, tmp[0][0].getTexture()))
+ .add(new TextureGraphic(0, Color.PINK, tmp[0][0].getTexture()))
.add(new Controllable())
- .add(new Velocity());
+ .add(new BoundingBox(new Vec2f(2f, 2f), new Vec2f(1f, 1f)))
+ .add(new Velocity(Vec2f.ZERO))
+ .add(new Mass(1f))
+ .add(new Forces())
+ .add(new Gravity(20f))
+ .add(new Jump(false, 0L))
+ .add(new Collidable());
}
- private PlayerFactory() { }
+ private PlayerFactory() {
+ }
}
diff --git a/core/src/main/java/coffee/liz/dyl/screen/GameScreen.java b/core/src/main/java/coffee/liz/dyl/screen/GameScreen.java
index 39017c5..0797e3e 100644
--- a/core/src/main/java/coffee/liz/dyl/screen/GameScreen.java
+++ b/core/src/main/java/coffee/liz/dyl/screen/GameScreen.java
@@ -1,9 +1,7 @@
package coffee.liz.dyl.screen;
import coffee.liz.dyl.DylGame;
-import coffee.liz.dyl.FrameState;
import coffee.liz.dyl.world.DylGameWorld;
-import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import lombok.RequiredArgsConstructor;
@@ -13,20 +11,15 @@ public class GameScreen implements Screen {
private final DylGame game;
private DylGameWorld dylGameWorld;
- private FrameState frameState;
@Override
public void show() {
dylGameWorld = new DylGameWorld(game);
- frameState = FrameState.builder()
- .settings(game.getSettings())
- .isKeyPressed(Gdx.input::isKeyPressed)
- .build();
}
@Override
public void render(final float delta) {
- dylGameWorld.update(frameState, Math.min(delta, MAX_DELTA_SECONDS));
+ dylGameWorld.update(Math.min(delta, MAX_DELTA_SECONDS));
}
@Override
diff --git a/core/src/main/java/coffee/liz/dyl/systems/InputSystem.java b/core/src/main/java/coffee/liz/dyl/systems/InputSystem.java
index 1519b3e..d5acbaf 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/InputSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/InputSystem.java
@@ -1,42 +1,65 @@
package coffee.liz.dyl.systems;
-import coffee.liz.dyl.FrameState;
-import coffee.liz.dyl.components.BoundingBox;
-import coffee.liz.dyl.components.Velocity;
+import coffee.liz.dyl.components.Controllable;
import coffee.liz.dyl.config.KeyBinds;
-import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.common.components.physics.Force;
+import coffee.liz.ecs.common.components.physics.Forces;
+import coffee.liz.ecs.common.components.physics.Jump;
+import coffee.liz.ecs.common.components.physics.Mass;
+import coffee.liz.ecs.common.components.physics.Velocity;
import coffee.liz.ecs.math.Vec2f;
-import coffee.liz.ecs.math.Vec2i;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
+import lombok.RequiredArgsConstructor;
+import java.time.Instant;
import java.util.Collection;
-import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
+
+import static coffee.liz.dyl.config.PhysicsConstants.JUMP_ACC;
+import static coffee.liz.dyl.config.PhysicsConstants.JUMP_INITIAL_VEL;
+import static coffee.liz.dyl.config.PhysicsConstants.MAX_JUMP_MS;
+import static coffee.liz.dyl.config.PhysicsConstants.MOVE_SPEED;
+
+@RequiredArgsConstructor
+public class InputSystem implements System {
+ private final Supplier<Set<KeyBinds.Action>> activeActions;
-public class InputSystem implements System<FrameState> {
@Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
+ public Collection<Class<? extends System>> getDependencies() {
return Set.of();
}
@Override
- public void update(final World<FrameState> world, final FrameState state, final float deltaSeconds) {
- final Set<KeyBinds.Action> currentlyActive = state.getSettings().getKeyBinds()
- .filterActiveActions(state.getIsKeyPressed());
+ public void update(final World world, final float deltaSeconds) {
+ final Set<KeyBinds.Action> actions = activeActions.get();
- final Vec2<Float> momentum = currentlyActive.stream().map(movementVectors::get)
- .reduce(Vec2::plus)
- .orElse(Vec2f.ZERO);
+ world.queryable().allOf(Controllable.class, Velocity.class).forEach(entity -> {
+ final Velocity velocity = entity.get(Velocity.class);
- world.queryable().allOf(Velocity.class, BoundingBox.class)
- .forEach(e -> e.get(Velocity.class).setVelocity(momentum));
- }
+ float dx = 0f;
+ if (actions.contains(KeyBinds.Action.MOVE_LEFT)) dx = -MOVE_SPEED;
+ if (actions.contains(KeyBinds.Action.MOVE_RIGHT)) dx = MOVE_SPEED;
+
+ float newDy = velocity.getVelocity().getY();
- private static Map<KeyBinds.Action, Vec2<Float>> movementVectors = Map.of(
- KeyBinds.Action.MOVE_UP, Vec2i.NORTH.floatValue(),
- KeyBinds.Action.MOVE_DOWN, Vec2i.SOUTH.floatValue(),
- KeyBinds.Action.MOVE_LEFT, Vec2i.WEST.floatValue(),
- KeyBinds.Action.MOVE_RIGHT, Vec2i.EAST.floatValue()
- );
+ if (entity.has(Jump.class) && entity.has(Mass.class) && entity.has(Forces.class)) {
+ final Jump jump = entity.get(Jump.class);
+ final Mass mass = entity.get(Mass.class);
+
+ if (actions.contains(KeyBinds.Action.JUMP)) {
+ if (jump.isCanJump()) {
+ newDy = JUMP_INITIAL_VEL;
+ jump.setCanJump(false);
+ jump.setJumpStartMs(Instant.now().toEpochMilli());
+ } else if (Instant.now().toEpochMilli() - jump.getJumpStartMs() < MAX_JUMP_MS) {
+ entity.get(Forces.class).add(new Force(new Vec2f(0f, mass.getMass() * JUMP_ACC)));
+ }
+ }
+ }
+
+ velocity.setVelocity(new Vec2f(dx, newDy));
+ });
+ }
}
diff --git a/core/src/main/java/coffee/liz/dyl/systems/IntegrationSystem.java b/core/src/main/java/coffee/liz/dyl/systems/IntegrationSystem.java
deleted file mode 100644
index cd7d7b1..0000000
--- a/core/src/main/java/coffee/liz/dyl/systems/IntegrationSystem.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package coffee.liz.dyl.systems;
-
-import coffee.liz.dyl.FrameState;
-import coffee.liz.dyl.components.BoundingBox;
-import coffee.liz.dyl.components.Velocity;
-import coffee.liz.ecs.math.Vec2;
-import coffee.liz.ecs.model.System;
-import coffee.liz.ecs.model.World;
-import lombok.extern.log4j.Log4j2;
-
-import java.util.Collection;
-import java.util.List;
-
-@Log4j2
-public class IntegrationSystem implements System<FrameState> {
- @Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
- return List.of(InputSystem.class);
- }
-
- @Override
- public void update(final World<FrameState> world, final FrameState state, final float deltaSeconds) {
- world.queryable().allOf(Velocity.class, BoundingBox.class)
- .forEach(e -> {
- final Vec2<Float> velocity = e.get(Velocity.class).getVelocity();
- final BoundingBox box = e.get(BoundingBox.class);
- final Vec2<Float> position = box.getPosition()
- .plus(velocity.scale(deltaSeconds, deltaSeconds));
- box.setPosition(position);
- });
- }
-}
diff --git a/core/src/main/java/coffee/liz/dyl/systems/RenderSystem.java b/core/src/main/java/coffee/liz/dyl/systems/RenderSystem.java
index 86c18fd..15e1f30 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/RenderSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/RenderSystem.java
@@ -1,8 +1,8 @@
package coffee.liz.dyl.systems;
-import coffee.liz.dyl.FrameState;
import coffee.liz.dyl.components.graphic.Graphic;
-import coffee.liz.dyl.components.BoundingBox;
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.common.systems.physics.CollisionSystem;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
import com.badlogic.gdx.graphics.Color;
@@ -14,7 +14,7 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.Set;
-public class RenderSystem implements System<FrameState> {
+public class RenderSystem implements System {
private final Batch batch;
private final OrthographicCamera camera;
private final Viewport viewport;
@@ -26,12 +26,12 @@ public class RenderSystem implements System<FrameState> {
}
@Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
- return Set.of(IntegrationSystem.class);
+ public Collection<Class<? extends System>> getDependencies() {
+ return Set.of(CollisionSystem.class);
}
@Override
- public void update(final World<FrameState> world, final FrameState state, final float deltaSeconds) {
+ public void update(final World world, final float deltaSeconds) {
viewport.apply();
camera.update();
@@ -40,7 +40,7 @@ public class RenderSystem implements System<FrameState> {
batch.setColor(Color.WHITE);
world.queryable().allOf(BoundingBox.class, Graphic.class).stream()
- .sorted(Comparator.comparing(e -> e.get(BoundingBox.class)))
+ .sorted(Comparator.comparingDouble(e -> e.get(Graphic.class).getZ()))
.forEach(e -> {
final BoundingBox boundingBox = e.get(BoundingBox.class);
final Graphic graphic = e.get(Graphic.class);
diff --git a/core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java b/core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java
index a52ea0f..7f1cb62 100644
--- a/core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java
+++ b/core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java
@@ -1,26 +1,31 @@
package coffee.liz.dyl.world;
import coffee.liz.dyl.DylGame;
-import coffee.liz.dyl.FrameState;
-import coffee.liz.dyl.components.BoundingBox;
+import coffee.liz.dyl.config.PhysicsConstants;
import coffee.liz.dyl.entities.PlayerFactory;
import coffee.liz.dyl.systems.InputSystem;
-import coffee.liz.dyl.systems.IntegrationSystem;
import coffee.liz.dyl.systems.RenderSystem;
import coffee.liz.ecs.DAGWorld;
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.common.components.physics.TopCollidable;
+import coffee.liz.ecs.common.systems.physics.CollisionSystem;
+import coffee.liz.ecs.common.systems.physics.ForceReductionSystem;
+import coffee.liz.ecs.common.systems.physics.IntegrationSystem;
import coffee.liz.ecs.math.Vec2f;
-import coffee.liz.ecs.math.Vec2i;
+import com.badlogic.gdx.Gdx;
-public class DylGameWorld extends DAGWorld<FrameState> {
+public class DylGameWorld extends DAGWorld {
public DylGameWorld(final DylGame game) {
super(
- new InputSystem(),
+ new InputSystem(() -> game.getSettings().getKeyBinds().filterActiveActions(Gdx.input::isKeyPressed)),
+ new ForceReductionSystem(PhysicsConstants.GRAVITY),
new IntegrationSystem(),
+ new CollisionSystem(PhysicsConstants.GRAVITY),
new RenderSystem(game.getBatch(), game.getViewport())
);
- for (int i = 0; i < 2_000; i++) {
- PlayerFactory.addTo(this)
- .add(new BoundingBox(new Vec2f(i / 200f, i/ 200f), new Vec2i(1, 1), 1));
- }
+ PlayerFactory.addTo(this);
+ createEntity()
+ .add(new BoundingBox(new Vec2f(-50f, -1f), new Vec2f(200f, 1f)))
+ .add(new TopCollidable());
}
}
diff --git a/core/src/main/java/coffee/liz/ecs/DAGWorld.java b/core/src/main/java/coffee/liz/ecs/DAGWorld.java
index 0cc7d5d..f941dba 100644
--- a/core/src/main/java/coffee/liz/ecs/DAGWorld.java
+++ b/core/src/main/java/coffee/liz/ecs/DAGWorld.java
@@ -8,7 +8,6 @@ import coffee.liz.ecs.model.QueryBuilder;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
-import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import java.util.ArrayList;
@@ -26,20 +25,17 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;
-/** World that updates in {@link System#getDependencies()} topological order. */
@Log4j2
-@RequiredArgsConstructor
-public class DAGWorld<T> implements World<T> {
+public class DAGWorld implements World {
private final Set<Entity> entities = Collections.synchronizedSet(new HashSet<>());
private final ComponentCache componentCache = new ComponentCache();
private final Consumer<EntityEvent> entityEventConsumer = componentCache::onEntityEvent;
private final AtomicInteger nextEntityId = new AtomicInteger(0);
- protected final Map<Class<? extends System<T>>, System<T>> systems;
- private final List<System<T>> systemExecutionOrder;
- private final QueryBuilder<T> queryBuilder = new QueryBuilder<>(this);
+ protected final Map<Class<? extends System>, System> systems;
+ private final List<System> systemExecutionOrder;
+ private final QueryBuilder queryBuilder = new QueryBuilder(this);
- @SafeVarargs
- public DAGWorld(final System<T>... systems) {
+ public DAGWorld(final System... systems) {
this.systems = singletonClazzMap(systems);
this.systemExecutionOrder = buildExecutionOrder(Arrays.asList(systems));
log.info("Executing in order: {}", systemExecutionOrder);
@@ -72,18 +68,18 @@ public class DAGWorld<T> implements World<T> {
}
@Override
- public QueryBuilder<T> queryable() {
+ public QueryBuilder queryable() {
return queryBuilder;
}
@Override
- public void update(final T state, final float deltaSeconds) {
- systemExecutionOrder.forEach(system -> system.update(this, state, deltaSeconds));
+ public void update(final float deltaSeconds) {
+ systemExecutionOrder.forEach(system -> system.update(this, deltaSeconds));
}
@SuppressWarnings("unchecked")
@Override
- public <S extends System<T>> S getSystem(final Class<S> system) {
+ public <S extends System> S getSystem(final Class<S> system) {
return (S) systems.get(system);
}
@@ -98,7 +94,6 @@ public class DAGWorld<T> implements World<T> {
if (components.isEmpty()) {
return Collections.emptySet();
}
-
final Set<Entity> matches = new HashSet<>();
components.forEach(componentType -> matches.addAll(componentCache.entitiesWith(componentType)));
return matches;
@@ -108,10 +103,8 @@ public class DAGWorld<T> implements World<T> {
if (components.isEmpty()) {
return entities;
}
-
final Set<Entity> excluded = new HashSet<>();
components.forEach(componentType -> excluded.addAll(componentCache.entitiesWith(componentType)));
-
final Set<Entity> result = new HashSet<>();
entities.forEach(entity -> {
if (!excluded.contains(entity)) {
@@ -121,41 +114,35 @@ public class DAGWorld<T> implements World<T> {
return result;
}
- private List<System<T>> buildExecutionOrder(final Collection<System<T>> systems) {
+ private List<System> buildExecutionOrder(final Collection<System> systems) {
if (systems.isEmpty()) {
return Collections.emptyList();
}
- final Map<Class<?>, System<T>> systemMap = systems.stream()
+ final Map<Class<?>, System> systemMap = systems.stream()
.collect(Collectors.toMap(System::getClass, system -> system, (_sys, b) -> b, LinkedHashMap::new));
final Map<Class<?>, Integer> inDegree = new LinkedHashMap<>();
final Map<Class<?>, Set<Class<?>>> adjacencyList = new LinkedHashMap<>();
systems.forEach(system -> {
- final Class<?> systemClass = system.getClass();
- inDegree.put(systemClass, 0);
- adjacencyList.put(systemClass, new HashSet<>());
- });
-
- systems.forEach(system -> {
- system.getDependencies().forEach(dependency -> {
- if (systemMap.containsKey(dependency)) {
- adjacencyList.get(dependency).add(system.getClass());
- inDegree.merge(system.getClass(), 1, Integer::sum);
- }
- });
+ inDegree.put(system.getClass(), 0);
+ adjacencyList.put(system.getClass(), new HashSet<>());
});
- // Kahn's algorithm
- final List<System<T>> result = new ArrayList<>();
+ systems.forEach(system -> system.getDependencies().forEach(dependency -> {
+ if (systemMap.containsKey(dependency)) {
+ adjacencyList.get(dependency).add(system.getClass());
+ inDegree.merge(system.getClass(), 1, Integer::sum);
+ }
+ }));
+ final List<System> result = new ArrayList<>();
final Queue<Class<?>> queue = new LinkedList<>(
- inDegree.entrySet().stream().filter(entry -> entry.getValue() == 0).map(Map.Entry::getKey).toList());
+ inDegree.entrySet().stream().filter(e -> e.getValue() == 0).map(Map.Entry::getKey).toList());
while (!queue.isEmpty()) {
final Class<?> currentClass = queue.poll();
result.add(systemMap.get(currentClass));
-
adjacencyList.getOrDefault(currentClass, Collections.emptySet()).forEach(dependent -> {
final int newInDegree = inDegree.get(dependent) - 1;
inDegree.put(dependent, newInDegree);
@@ -174,23 +161,24 @@ public class DAGWorld<T> implements World<T> {
@Override
public void dispose() {
- for (final System<T> system : systemExecutionOrder) {
- system.dispose();
- }
+ systemExecutionOrder.forEach(System::dispose);
entities.forEach(entity -> entity.unsubscribe(entityEventConsumer));
componentCache.clear();
entities.clear();
}
@SuppressWarnings("unchecked")
- private static <T> Map<Class<? extends T>, T> singletonClazzMap(final T... singletons) {
- final boolean areSingletons = Arrays.stream(singletons).map(t -> (Class<? extends System<T>>) t.getClass())
- .distinct().count() == singletons.length;
+ private static Map<Class<? extends System>, System> singletonClazzMap(final System... singletons) {
+ final boolean areSingletons = Arrays.stream(singletons)
+ .map(Object::getClass)
+ .distinct()
+ .count() == singletons.length;
if (!areSingletons) {
throw new IllegalArgumentException("Only one instance may be used per clazz");
}
-
- return Arrays.stream(singletons).map(t -> Map.entry((Class<? extends T>) t.getClass(), t))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ return Arrays.stream(singletons)
+ .collect(Collectors.toMap(
+ s -> (Class<? extends System>) s.getClass(),
+ s -> s));
}
}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/BoundingBox.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/BoundingBox.java
new file mode 100644
index 0000000..7a31cae
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/BoundingBox.java
@@ -0,0 +1,34 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.model.Component;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@AllArgsConstructor
+@Getter
+@Setter
+public class BoundingBox implements Component {
+ private Vec2<Float> position;
+ private Vec2<Float> size;
+
+ public float getTop() {
+ return position.getY() + size.getY();
+ }
+
+ public float getRight() {
+ return position.getX() + size.getX();
+ }
+
+ public boolean isCollidingWith(final BoundingBox other) {
+ return getRight() > other.getPosition().getX()
+ && position.getX() < other.getRight()
+ && getTop() > other.getPosition().getY()
+ && position.getY() < other.getTop();
+ }
+
+ public boolean isAbove(final BoundingBox other) {
+ return position.getY() >= other.getTop();
+ }
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/Collidable.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Collidable.java
new file mode 100644
index 0000000..166428a
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Collidable.java
@@ -0,0 +1,6 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.model.Component;
+
+public class Collidable implements Component {
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/Force.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Force.java
new file mode 100644
index 0000000..7d5dab1
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Force.java
@@ -0,0 +1,12 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.model.Component;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class Force implements Component {
+ private final Vec2<Float> force;
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/Forces.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Forces.java
new file mode 100644
index 0000000..f6c9ee8
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Forces.java
@@ -0,0 +1,20 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.model.Component;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+public class Forces implements Component {
+ private final List<Force> forces = new ArrayList<>();
+
+ public void add(final Force force) {
+ forces.add(force);
+ }
+
+ public void clear() {
+ forces.clear();
+ }
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/Gravity.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Gravity.java
new file mode 100644
index 0000000..44d5caf
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Gravity.java
@@ -0,0 +1,11 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.model.Component;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class Gravity implements Component {
+ private final float terminalVelocity;
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/Jump.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Jump.java
new file mode 100644
index 0000000..5224b32
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Jump.java
@@ -0,0 +1,14 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.model.Component;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@AllArgsConstructor
+@Getter
+@Setter
+public class Jump implements Component {
+ private boolean canJump;
+ private long jumpStartMs;
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/Mass.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Mass.java
new file mode 100644
index 0000000..f38ccc0
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Mass.java
@@ -0,0 +1,11 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.model.Component;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class Mass implements Component {
+ private final float mass;
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/components/physics/TopCollidable.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/TopCollidable.java
new file mode 100644
index 0000000..76185bd
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/TopCollidable.java
@@ -0,0 +1,6 @@
+package coffee.liz.ecs.common.components.physics;
+
+import coffee.liz.ecs.model.Component;
+
+public class TopCollidable implements Component {
+}
diff --git a/core/src/main/java/coffee/liz/dyl/components/Velocity.java b/core/src/main/java/coffee/liz/ecs/common/components/physics/Velocity.java
index f31e861..9b6a36b 100644
--- a/core/src/main/java/coffee/liz/dyl/components/Velocity.java
+++ b/core/src/main/java/coffee/liz/ecs/common/components/physics/Velocity.java
@@ -1,17 +1,14 @@
-package coffee.liz.dyl.components;
+package coffee.liz.ecs.common.components.physics;
import coffee.liz.ecs.math.Vec2;
-import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.model.Component;
import lombok.AllArgsConstructor;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.Setter;
@AllArgsConstructor
-@NoArgsConstructor
@Getter
@Setter
public class Velocity implements Component {
- private Vec2<Float> velocity = Vec2f.ZERO;
+ private Vec2<Float> velocity;
}
diff --git a/core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionGrid.java b/core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionGrid.java
new file mode 100644
index 0000000..94202b4
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionGrid.java
@@ -0,0 +1,65 @@
+package coffee.liz.ecs.common.systems.physics;
+
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.math.Vec2i;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class CollisionGrid {
+ private final Map<Vec2i, Set<Integer>> cells = new HashMap<>();
+ private Vec2<Float> origin;
+ private Vec2<Float> cellSize;
+
+ public void setOrigin(final Vec2<Float> origin) {
+ this.origin = origin;
+ }
+
+ public void setCellSize(final Vec2<Float> cellSize) {
+ this.cellSize = cellSize;
+ }
+
+ public void clear() {
+ cells.clear();
+ }
+
+ public void insert(final int entityId, final BoundingBox bb) {
+ final int minCx = cellX(bb.getPosition().getX());
+ final int minCy = cellY(bb.getPosition().getY());
+ final int maxCx = cellX(bb.getRight());
+ final int maxCy = cellY(bb.getTop());
+ for (int cx = minCx; cx <= maxCx; cx++) {
+ for (int cy = minCy; cy <= maxCy; cy++) {
+ cells.computeIfAbsent(new Vec2i(cx, cy), _ -> new HashSet<>()).add(entityId);
+ }
+ }
+ }
+
+ public Set<Integer> getNeighborIds(final BoundingBox bb) {
+ final Set<Integer> neighbors = new HashSet<>();
+ final int minCx = cellX(bb.getPosition().getX());
+ final int minCy = cellY(bb.getPosition().getY());
+ final int maxCx = cellX(bb.getRight());
+ final int maxCy = cellY(bb.getTop());
+ for (int cx = minCx; cx <= maxCx; cx++) {
+ for (int cy = minCy; cy <= maxCy; cy++) {
+ final Set<Integer> cell = cells.get(new Vec2i(cx, cy));
+ if (cell != null) {
+ neighbors.addAll(cell);
+ }
+ }
+ }
+ return neighbors;
+ }
+
+ private int cellX(final float x) {
+ return (int) Math.floor((x - origin.getX()) / cellSize.getX());
+ }
+
+ private int cellY(final float y) {
+ return (int) Math.floor((y - origin.getY()) / cellSize.getY());
+ }
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionSystem.java b/core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionSystem.java
new file mode 100644
index 0000000..14f0a2b
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/systems/physics/CollisionSystem.java
@@ -0,0 +1,107 @@
+package coffee.liz.ecs.common.systems.physics;
+
+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.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.System;
+import coffee.liz.ecs.model.World;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+@RequiredArgsConstructor
+@AllArgsConstructor
+public class CollisionSystem implements System {
+ private final float gravity;
+ private float cellSize = 64f;
+ private final CollisionGrid grid = new CollisionGrid();
+
+ @Override
+ public Collection<Class<? extends System>> getDependencies() {
+ return Set.of(IntegrationSystem.class);
+ }
+
+ @Override
+ public void update(final World world, final float deltaSeconds) {
+ final Set<Entity> collidableEntities = world.queryable().allOf(BoundingBox.class, Collidable.class);
+ final Set<Entity> surfaceEntities = world.queryable().allOf(BoundingBox.class, TopCollidable.class);
+
+ if (collidableEntities.isEmpty() || surfaceEntities.isEmpty()) {
+ return;
+ }
+
+ final Map<Integer, Entity> entityMap = new HashMap<>();
+ collidableEntities.forEach(e -> entityMap.put(e.getId(), e));
+ surfaceEntities.forEach(e -> entityMap.put(e.getId(), e));
+
+ float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE;
+ for (final Entity e : entityMap.values()) {
+ final BoundingBox bb = e.get(BoundingBox.class);
+ minX = Math.min(minX, bb.getPosition().getX());
+ minY = Math.min(minY, bb.getPosition().getY());
+ }
+
+ grid.clear();
+ grid.setOrigin(new Vec2f(minX, minY));
+ grid.setCellSize(new Vec2f(cellSize, cellSize));
+ entityMap.forEach((id, e) -> grid.insert(id, e.get(BoundingBox.class)));
+
+ final Set<Vec2i> checkedPairs = new HashSet<>();
+
+ for (final Entity entityA : collidableEntities) {
+ if (!entityA.has(Velocity.class)) {
+ continue;
+ }
+ final BoundingBox bbA = entityA.get(BoundingBox.class);
+ final Velocity velocity = entityA.get(Velocity.class);
+
+ for (final int idB : grid.getNeighborIds(bbA)) {
+ final int idA = entityA.getId();
+ if (idB == idA) {
+ continue;
+ }
+ if (!checkedPairs.add(new Vec2i(Math.min(idA, idB), Math.max(idA, idB)))) {
+ continue;
+ }
+
+ final Entity entityB = entityMap.get(idB);
+ if (entityB == null || !entityB.has(TopCollidable.class)) {
+ continue;
+ }
+
+ final BoundingBox bbB = entityB.get(BoundingBox.class);
+ if (!bbA.isCollidingWith(bbB)) {
+ continue;
+ }
+ if (velocity.getVelocity().getY() > 0 || bbA.isAbove(bbB)) {
+ continue;
+ }
+
+ bbA.setPosition(new Vec2f(bbA.getPosition().getX(), bbB.getTop()));
+ velocity.setVelocity(new Vec2f(velocity.getVelocity().getX(), 0f));
+
+ if (entityA.has(Jump.class)) {
+ entityA.get(Jump.class).setCanJump(true);
+ }
+ if (entityA.has(Gravity.class) && entityA.has(Forces.class) && entityA.has(Mass.class)) {
+ entityA.get(Forces.class).add(new Force(new Vec2f(0f, entityA.get(Mass.class).getMass() * gravity)));
+ }
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/systems/physics/ForceReductionSystem.java b/core/src/main/java/coffee/liz/ecs/common/systems/physics/ForceReductionSystem.java
new file mode 100644
index 0000000..4a51ba8
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/systems/physics/ForceReductionSystem.java
@@ -0,0 +1,55 @@
+package coffee.liz.ecs.common.systems.physics;
+
+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.Velocity;
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.math.Vec2f;
+import coffee.liz.ecs.model.System;
+import coffee.liz.ecs.model.World;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Collection;
+import java.util.Set;
+
+@RequiredArgsConstructor
+public class ForceReductionSystem implements System {
+ private final float gravity;
+
+ @Override
+ public Collection<Class<? extends System>> getDependencies() {
+ return Set.of();
+ }
+
+ @Override
+ public void update(final World world, final float deltaSeconds) {
+ world.queryable().allOf(Forces.class, Mass.class, Velocity.class).forEach(entity -> {
+ final Forces forces = entity.get(Forces.class);
+ final Mass mass = entity.get(Mass.class);
+ final Velocity velocity = entity.get(Velocity.class);
+
+ if (entity.has(Gravity.class)) {
+ final Gravity gravityComponent = entity.get(Gravity.class);
+ if (velocity.getVelocity().getY() > -gravityComponent.getTerminalVelocity()) {
+ forces.add(new Force(new Vec2f(0f, -mass.getMass() * gravity)));
+ }
+ }
+
+ Vec2<Float> netForce = Vec2f.ZERO;
+ for (final Force f : forces.getForces()) {
+ netForce = netForce.plus(f.getForce());
+ }
+ forces.clear();
+
+ final Vec2<Float> acceleration = netForce.scale(1f / mass.getMass(), 1f / mass.getMass());
+ velocity.setVelocity(velocity.getVelocity().plus(acceleration.scale(deltaSeconds, deltaSeconds)));
+
+ if (entity.has(Jump.class) && acceleration.getY() < 0) {
+ entity.get(Jump.class).setCanJump(false);
+ }
+ });
+ }
+}
diff --git a/core/src/main/java/coffee/liz/ecs/common/systems/physics/IntegrationSystem.java b/core/src/main/java/coffee/liz/ecs/common/systems/physics/IntegrationSystem.java
new file mode 100644
index 0000000..ba38b70
--- /dev/null
+++ b/core/src/main/java/coffee/liz/ecs/common/systems/physics/IntegrationSystem.java
@@ -0,0 +1,25 @@
+package coffee.liz.ecs.common.systems.physics;
+
+import coffee.liz.ecs.common.components.physics.BoundingBox;
+import coffee.liz.ecs.common.components.physics.Velocity;
+import coffee.liz.ecs.model.System;
+import coffee.liz.ecs.model.World;
+
+import java.util.Collection;
+import java.util.Set;
+
+public class IntegrationSystem implements System {
+ @Override
+ public Collection<Class<? extends System>> getDependencies() {
+ return Set.of(ForceReductionSystem.class);
+ }
+
+ @Override
+ public void update(final World world, final float deltaSeconds) {
+ world.queryable().allOf(Velocity.class, BoundingBox.class).forEach(entity -> {
+ final BoundingBox bb = entity.get(BoundingBox.class);
+ final Velocity velocity = entity.get(Velocity.class);
+ bb.setPosition(bb.getPosition().plus(velocity.getVelocity().scale(deltaSeconds, deltaSeconds)));
+ });
+ }
+}
diff --git a/core/src/main/java/coffee/liz/ecs/model/QueryBuilder.java b/core/src/main/java/coffee/liz/ecs/model/QueryBuilder.java
index eba5021..bc7c4f7 100644
--- a/core/src/main/java/coffee/liz/ecs/model/QueryBuilder.java
+++ b/core/src/main/java/coffee/liz/ecs/model/QueryBuilder.java
@@ -5,8 +5,8 @@ import lombok.RequiredArgsConstructor;
import java.util.Set;
@RequiredArgsConstructor
-public class QueryBuilder<T> {
- private final World<T> world;
+public class QueryBuilder {
+ private final World world;
@SafeVarargs
public final Set<Entity> allOf(final Class<? extends Component>... components) {
diff --git a/core/src/main/java/coffee/liz/ecs/model/System.java b/core/src/main/java/coffee/liz/ecs/model/System.java
index f16cdba..e9e0729 100644
--- a/core/src/main/java/coffee/liz/ecs/model/System.java
+++ b/core/src/main/java/coffee/liz/ecs/model/System.java
@@ -2,29 +2,10 @@ package coffee.liz.ecs.model;
import java.util.Collection;
-/**
- * Updates the {@link World} state.
- *
- * @param <T>
- * is the state of the stuff outside the {@link World}.
- */
-public interface System<T> {
- /**
- * {@link System} clazzes that must run before this system.
- *
- * @return {@link Collection} of dependencies.
- */
- Collection<Class<? extends System<T>>> getDependencies();
+public interface System {
+ Collection<Class<? extends System>> getDependencies();
- /**
- * @param world
- * Is the {@link World}.
- * @param state
- * Is the {@link T} state outside the {@param world}.
- * @param deltaSeconds
- * Is the timestamp.
- */
- void update(final World<T> world, final T state, final float deltaSeconds);
+ void update(World world, float deltaSeconds);
default void dispose() {
}
diff --git a/core/src/main/java/coffee/liz/ecs/model/World.java b/core/src/main/java/coffee/liz/ecs/model/World.java
index 82e01a7..63335c8 100644
--- a/core/src/main/java/coffee/liz/ecs/model/World.java
+++ b/core/src/main/java/coffee/liz/ecs/model/World.java
@@ -1,63 +1,21 @@
package coffee.liz.ecs.model;
-import java.time.Duration;
import java.util.Set;
-/**
- * The game world.
- *
- * @param <T>
- * is the state of the stuff outside the world.
- */
-public interface World<T> {
- /**
- * Create unique {@link Entity} in the {@link World}.
- *
- * @return created {@link Entity}.
- */
+public interface World {
Entity createEntity();
- /**
- * Remove an entity from the {@link World}.
- *
- * @param entity
- * to remove.
- */
- void removeEntity(final Entity entity);
+ void removeEntity(Entity entity);
- /**
- * Get entities with {@link Component}s.
- *
- * @param query
- * to query.
- * @return All entities satisfying {@param query}.
- */
- Set<Entity> resolve(final Query query);
+ Set<Entity> resolve(Query query);
- default QueryBuilder<T> queryable() {
- return new QueryBuilder<>(this);
+ default QueryBuilder queryable() {
+ return new QueryBuilder(this);
}
- /**
- * Integrate the {@link World}.
- *
- * @param state
- * Is the state outside the world.
- * @param deltaSeconds
- * Is the time step.
- */
- void update(T state, float deltaSeconds);
+ void update(float deltaSeconds);
- /**
- * Get world {@link System}.
- *
- * @param system
- * is the Clazz.
- * @param <S>
- * is the {@link System} type.
- * @return {@link System} instance of {@param system}.
- */
- <S extends System<T>> S getSystem(final Class<S> system);
+ <S extends System> S getSystem(Class<S> system);
default void dispose() {
}
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());
+ }
+}
diff --git a/gradle.properties b/gradle.properties
index 15acc17..8ffde07 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -13,8 +13,6 @@ org.gradle.configureondemand=false
# the link to the scan won't get shown at all.
# Documented at: https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_logging
org.gradle.logging.level=lifecycle
-aiVersion=1.8.2
-ashleyVersion=1.7.4
box2dlightsVersion=1.5
graalHelperVersion=2.0.1
enableGraalNative=false
diff --git a/lwjgl3/build.gradle b/lwjgl3/build.gradle
index 76f521b..33f6d9b 100644
--- a/lwjgl3/build.gradle
+++ b/lwjgl3/build.gradle
@@ -21,12 +21,8 @@ import io.github.fourlastor.construo.Target
sourceSets.main.resources.srcDirs += [ rootProject.file('assets').path ]
application.mainClass = 'coffee.liz.dyl.lwjgl3.Lwjgl3Launcher'
application.applicationName = appName
+application.applicationDefaultJvmArgs = ['-XX:+UseZGC', '-XX:+UseCompactObjectHeaders']
eclipse.project.name = appName + '-lwjgl3'
-java.sourceCompatibility = JavaVersion.VERSION_24
-java.targetCompatibility = JavaVersion.VERSION_24
-if (JavaVersion.current().isJava9Compatible()) {
- compileJava.options.release.set(24)
-}
dependencies {
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
@@ -119,40 +115,34 @@ tasks.register("jarWin") {
}
construo {
- // name of the executable
name.set(appName)
- // human-readable name, used for example in the `.app` name for macOS
humanName.set(appName)
+ roast {
+ vmArgs.addAll('-XX:+UseCompactObjectHeaders')
+ }
+
targets.configure {
register("linuxX64", Target.Linux) {
architecture.set(Target.Architecture.X86_64)
- jdkUrl.set("https://api.adoptium.net/v3/binary/latest/24/ga/linux/x64/jdk/hotspot/normal/eclipse")
- // Linux does not currently have a way to set the icon on the executable
+ jdkUrl.set("https://api.adoptium.net/v3/binary/latest/25/ga/linux/x64/jdk/hotspot/normal/eclipse")
}
register("macM1", Target.MacOs) {
architecture.set(Target.Architecture.AARCH64)
- jdkUrl.set("https://api.adoptium.net/v3/binary/latest/24/ga/mac/aarch64/jdk/hotspot/normal/eclipse")
- // macOS needs an identifier
+ jdkUrl.set("https://api.adoptium.net/v3/binary/latest/25/ga/mac/aarch64/jdk/hotspot/normal/eclipse")
identifier.set("coffee.liz.dyl." + appName)
- // Optional: icon for macOS, as an ICNS file
macIcon.set(project.file("icons/logo.icns"))
}
register("macX64", Target.MacOs) {
architecture.set(Target.Architecture.X86_64)
- jdkUrl.set("https://api.adoptium.net/v3/binary/latest/24/ga/mac/x64/jdk/hotspot/normal/eclipse")
- // macOS needs an identifier
+ jdkUrl.set("https://api.adoptium.net/v3/binary/latest/25/ga/mac/x64/jdk/hotspot/normal/eclipse")
identifier.set("coffee.liz.dyl." + appName)
- // Optional: icon for macOS, as an ICNS file
macIcon.set(project.file("icons/logo.icns"))
}
register("winX64", Target.Windows) {
architecture.set(Target.Architecture.X86_64)
- // Optional: icon for Windows, as a PNG
icon.set(project.file("icons/logo.png"))
- jdkUrl.set("https://api.adoptium.net/v3/binary/latest/24/ga/windows/x64/jdk/hotspot/normal/eclipse")
- // Uncomment the next line to show a console when the game runs, to print messages.
- //useConsole.set(true)
+ jdkUrl.set("https://api.adoptium.net/v3/binary/latest/25/ga/windows/x64/jdk/hotspot/normal/eclipse")
}
}
}