summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-03-07 08:21:41 -0800
committerElizabeth Alexander Hunt <me@liz.coffee>2026-03-07 08:21:41 -0800
commitf2135acc9accdc938035d753ee6e79c865fd44e2 (patch)
tree1016a19e087ce7666c3e2b20a07143bb063bd9c9
parent19385bdee0972edcedf2a719fc5130aa32134029 (diff)
downloaddyl-f2135acc9accdc938035d753ee6e79c865fd44e2.tar.gz
dyl-f2135acc9accdc938035d753ee6e79c865fd44e2.zip
Some refactoring work
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/graphic/TextureGraphic.java4
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/physics/CollisionContacts.java19
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/physics/Jump.java8
-rw-r--r--core/src/main/java/coffee/liz/dyl/components/physics/Jumpable.java16
-rw-r--r--core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java10
-rw-r--r--core/src/main/java/coffee/liz/dyl/entities/FloorFactory.java34
-rw-r--r--core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java39
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/AnimationSystem.java3
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/InputSystem.java51
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/JumpSystem.java43
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/physics/AccelerationSystem.java (renamed from core/src/main/java/coffee/liz/dyl/systems/physics/ForceReductionSystem.java)24
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/physics/CollisionSystem.java14
-rw-r--r--core/src/main/java/coffee/liz/dyl/systems/physics/MovementSystem.java (renamed from core/src/main/java/coffee/liz/dyl/systems/physics/IntegrationSystem.java)4
-rw-r--r--core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java14
-rw-r--r--core/src/test/java/coffee/liz/dyl/systems/physics/PhysicsSystemsTest.java6
-rw-r--r--design/bugs.txt3
-rw-r--r--design/design.txt4
-rw-r--r--design/todo.txt8
18 files changed, 220 insertions, 84 deletions
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 8cca8ac..24e5109 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
@@ -3,8 +3,8 @@ package coffee.liz.dyl.components.graphic;
import coffee.liz.dyl.components.physics.BoundingBox;
import coffee.liz.ecs.math.Vec2;
import com.badlogic.gdx.graphics.Color;
-import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.TextureRegion;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -13,7 +13,7 @@ import lombok.RequiredArgsConstructor;
public class TextureGraphic implements Graphic {
private final int z;
private final Color color;
- private final Texture texture;
+ private final TextureRegion texture;
private boolean facingLeft = false;
@Override
diff --git a/core/src/main/java/coffee/liz/dyl/components/physics/CollisionContacts.java b/core/src/main/java/coffee/liz/dyl/components/physics/CollisionContacts.java
index b709751..49ab7f6 100644
--- a/core/src/main/java/coffee/liz/dyl/components/physics/CollisionContacts.java
+++ b/core/src/main/java/coffee/liz/dyl/components/physics/CollisionContacts.java
@@ -1,20 +1,27 @@
package coffee.liz.dyl.components.physics;
+import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.model.Component;
import coffee.liz.ecs.model.Entity;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+@Getter
public class CollisionContacts implements Component {
- private final List<Entity> contacts = new ArrayList<>();
-
- public void add(final Entity entity) {
- contacts.add(entity);
+ @Getter
+ @RequiredArgsConstructor
+ public class Contact {
+ private final Entity contactEntity;
+ private final Vec2<Float> penetrationVector;
}
- public List<Entity> getAll() {
- return Collections.unmodifiableList(contacts);
+ private final List<Contact> contacts = new ArrayList<>();
+
+ public void add(final Entity entity, final Vec2<Float> penetrationVector) {
+ contacts.add(new Contact(entity, penetrationVector));
}
}
diff --git a/core/src/main/java/coffee/liz/dyl/components/physics/Jump.java b/core/src/main/java/coffee/liz/dyl/components/physics/Jump.java
index c49d6e1..79d2f78 100644
--- a/core/src/main/java/coffee/liz/dyl/components/physics/Jump.java
+++ b/core/src/main/java/coffee/liz/dyl/components/physics/Jump.java
@@ -3,12 +3,16 @@ package coffee.liz.dyl.components.physics;
import coffee.liz.ecs.model.Component;
import lombok.AllArgsConstructor;
import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
import lombok.Setter;
+import java.time.Instant;
+
+@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Jump implements Component {
- private boolean canJump;
- private long jumpStartMs;
+ private Instant jumpStart;
}
diff --git a/core/src/main/java/coffee/liz/dyl/components/physics/Jumpable.java b/core/src/main/java/coffee/liz/dyl/components/physics/Jumpable.java
new file mode 100644
index 0000000..d35464a
--- /dev/null
+++ b/core/src/main/java/coffee/liz/dyl/components/physics/Jumpable.java
@@ -0,0 +1,16 @@
+package coffee.liz.dyl.components.physics;
+
+import coffee.liz.ecs.model.Component;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.Instant;
+
+@AllArgsConstructor
+@Getter
+@Setter
+public class Jumpable implements Component {
+ private boolean canPhysicallyJump = false;
+ private Instant jumpRequestTime;
+}
diff --git a/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java b/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java
index 6339a34..3019160 100644
--- a/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java
+++ b/core/src/main/java/coffee/liz/dyl/config/PhysicsConstants.java
@@ -1,11 +1,15 @@
package coffee.liz.dyl.config;
+import java.time.Duration;
+
public final class PhysicsConstants {
public static final float GRAVITY = 40f;
+ public static final float ADDITIONAL_JUMP_OVER_GRAVITY = 1.05f;
public static final float MOVE_SPEED = 8.0f;
- public static final float JUMP_INITIAL_VEL = 7.0f;
- public static final float JUMP_ACC = 30.0f;
- public static final long MAX_JUMP_MS = 200L;
+ public static final float JUMP_INITIAL_VEL = 10.0f;
+ public static final Duration MAX_JUMP = Duration.ofMillis(100);
+ public static final Duration JUMP_BUFFER = Duration.ofMillis(400);
+ public static final float JUMP_CUT_FACTOR = 0.5f;
public static final float DAMAGE_TIME = 0.25f;
private PhysicsConstants() { }
diff --git a/core/src/main/java/coffee/liz/dyl/entities/FloorFactory.java b/core/src/main/java/coffee/liz/dyl/entities/FloorFactory.java
new file mode 100644
index 0000000..e6c5591
--- /dev/null
+++ b/core/src/main/java/coffee/liz/dyl/entities/FloorFactory.java
@@ -0,0 +1,34 @@
+package coffee.liz.dyl.entities;
+
+import coffee.liz.dyl.components.graphic.TextureGraphic;
+import coffee.liz.dyl.components.physics.BoundingBox;
+import coffee.liz.dyl.components.physics.Solid;
+import coffee.liz.ecs.math.Vec2f;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.World;
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.files.FileHandle;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.TextureRegion;
+
+public class FloorFactory {
+ private static final FloorAssets ASSETS = new FloorAssets();
+ public static Entity addTo(final World world) {
+ return world.createEntity()
+ .add(new TextureGraphic(0, Color.WHITE, ASSETS.textureRegion))
+ .add(new Solid())
+ .add(new BoundingBox(new Vec2f(5f, 0.25f), new Vec2f(1f, 0.5f)));
+ }
+
+ private static class FloorAssets {
+ private static final FileHandle FILE = Gdx.files.internal("noir/Underground.png");
+ final Texture texture;
+ final TextureRegion textureRegion;
+
+ public FloorAssets() {
+ texture = new Texture(FILE);
+ textureRegion = new TextureRegion(texture, 4, 12, 8, 4);
+ }
+ }
+}
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 c857d02..ffd55f6 100644
--- a/core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java
+++ b/core/src/main/java/coffee/liz/dyl/entities/PlayerFactory.java
@@ -4,6 +4,7 @@ import coffee.liz.dyl.components.AnimationState;
import coffee.liz.dyl.components.Controllable;
import coffee.liz.dyl.components.FacingDirection;
import coffee.liz.dyl.components.graphic.AnimationGraphic;
+import coffee.liz.dyl.components.physics.Jumpable;
import coffee.liz.dyl.config.PhysicsConstants;
import coffee.liz.dyl.components.physics.BoundingBox;
import coffee.liz.dyl.components.physics.Forces;
@@ -14,6 +15,7 @@ import coffee.liz.dyl.components.physics.Velocity;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
import coffee.liz.ecs.model.World;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
@@ -27,57 +29,58 @@ import java.util.Map;
public class PlayerFactory {
private static final PlayerAssets ASSETS = new PlayerAssets();
- public static void addTo(final World world) {
+ public static Entity addTo(final World world) {
final var animationState = new AnimationState(
Map.of(
AnimationState.State.JUMP, new AnimationGraphic(Color.WHITE, ASSETS.jumping, 0),
AnimationState.State.DAMAGE, new AnimationGraphic(Color.valueOf("#0000000a"), ASSETS.damaged, 0),
AnimationState.State.IDLE, new AnimationGraphic(Color.WHITE, ASSETS.idling, 0),
AnimationState.State.RUN, new AnimationGraphic(Color.WHITE, ASSETS.running, 0)));
- world.createEntity()
+ return world.createEntity()
.add(animationState)
.add(animationState.getAnimationStates().get(AnimationState.State.IDLE))
.add(new Controllable())
- .add(new BoundingBox(new Vec2f(1f, 1f), new Vec2f(1f, 1f)))
+ .add(new BoundingBox(new Vec2f(1f, 1f), PlayerAssets.PLAYER_DIMS.floatValue().scale(1/6f, 1/6f)))
.add(new Velocity(Vec2f.ZERO))
.add(new Mass(0.8f))
.add(new Forces())
.add(new FacingDirection(Vec2f.ZERO))
- .add(new Gravity(20f))
- .add(new Jump(false, 0L));
+ .add(new Gravity(-20f))
+ .add(new Jumpable(false, null));
}
private static class PlayerAssets {
private static final Vec2<Integer> DIMS = new Vec2i(14, 8);
- private static final FileHandle FILE = Gdx.files.internal("noir/hero.png");
+ public static final Vec2<Integer> PLAYER_DIMS = new Vec2i(6, 7); // six sevennnnn
+ private static final FileHandle FILE = Gdx.files.internal("noir/Hero.png");
final Texture texture;
- final TextureRegion[][] region;
+// final TextureRegion[][] region;
final Animation<TextureRegion> idling;
final Animation<TextureRegion> damaged;
final Animation<TextureRegion> jumping;
final Animation<TextureRegion> running;
public PlayerAssets() {
texture = new Texture(FILE);
- region = TextureRegion.split(texture,
- texture.getWidth() / DIMS.getX(),
- texture.getHeight() / DIMS.getY()
- );
+ final int dy = texture.getHeight() / DIMS.getY();
+ final int dx = texture.getWidth() / DIMS.getX();
+ final int ddx = 0;// dx - PLAYER_DIMS.getX();
+ final int ddy = dy - PLAYER_DIMS.getY();
final TextureRegion[] idlingTextureRegion = new TextureRegion[2];
- idlingTextureRegion[0] = region[5][0];
- idlingTextureRegion[1] = region[5][1];
+ idlingTextureRegion[0] = new TextureRegion(texture, 0 * dx + ddx, 5 * dy + ddy, PLAYER_DIMS.getX(), PLAYER_DIMS.getY());
+ idlingTextureRegion[1] = new TextureRegion(texture, 1 * dx + ddx, 5 * dy + ddy, PLAYER_DIMS.getX(), PLAYER_DIMS.getY());
final TextureRegion[] runningTextureRegion = new TextureRegion[2];
- runningTextureRegion[0] = region[0][0];
- runningTextureRegion[1] = region[0][1];
+ runningTextureRegion[0] = new TextureRegion(texture, 0 * dx + ddx, 0 * dy + ddy, PLAYER_DIMS.getX(), PLAYER_DIMS.getY());
+ runningTextureRegion[1] = new TextureRegion(texture, 1 * dx + ddx, 0 * dy + ddy, PLAYER_DIMS.getX(), PLAYER_DIMS.getY());
final TextureRegion[] damagedTextureRegion = new TextureRegion[1];
- damagedTextureRegion[0] = region[6][0];
+ damagedTextureRegion[0] = new TextureRegion(texture, 0 * dx + ddx, 6 * dy + ddy, PLAYER_DIMS.getX(), PLAYER_DIMS.getY());
final TextureRegion[] jump = new TextureRegion[1];
- jump[0] = region[1][0];
+ jump[0] = new TextureRegion(texture, 0 * dx + ddx, 1 * dy + ddy, PLAYER_DIMS.getX(), PLAYER_DIMS.getY());
- running = new Animation<>(0.20f, runningTextureRegion);
+ running = new Animation<>(0.18f, runningTextureRegion);
idling = new Animation<>(0.75f, idlingTextureRegion);
damaged = new Animation<>(PhysicsConstants.DAMAGE_TIME, damagedTextureRegion);
jumping = new Animation<>(0.75f, jump);
diff --git a/core/src/main/java/coffee/liz/dyl/systems/AnimationSystem.java b/core/src/main/java/coffee/liz/dyl/systems/AnimationSystem.java
index 8c0d595..a932eea 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/AnimationSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/AnimationSystem.java
@@ -24,9 +24,8 @@ public class AnimationSystem implements System {
world.queryable().allOf(AnimationState.class, Velocity.class).forEach(entity -> {
final AnimationState animationState = entity.get(AnimationState.class);
final Velocity velocity = entity.get(Velocity.class);
- final Jump jump = entity.get(Jump.class);
- if (!jump.isCanJump()) {
+ if (entity.has(Jump.class)) {
animationState.setTransition(AnimationState.State.JUMP);
return;
}
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 1938a50..ea0e574 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/InputSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/InputSystem.java
@@ -2,26 +2,22 @@ package coffee.liz.dyl.systems;
import coffee.liz.dyl.components.Controllable;
import coffee.liz.dyl.components.FacingDirection;
+import coffee.liz.dyl.components.physics.Jumpable;
import coffee.liz.dyl.config.KeyBinds;
-import coffee.liz.dyl.components.physics.Force;
-import coffee.liz.dyl.components.physics.Forces;
import coffee.liz.dyl.components.physics.Jump;
-import coffee.liz.dyl.components.physics.Mass;
import coffee.liz.dyl.components.physics.Velocity;
import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
import lombok.RequiredArgsConstructor;
+import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
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;
+import static coffee.liz.dyl.config.PhysicsConstants.*;
@RequiredArgsConstructor
public class InputSystem implements System {
@@ -36,7 +32,7 @@ public class InputSystem implements System {
public void update(final World world, final float deltaSeconds) {
final Set<KeyBinds.Action> actions = activeActions.get();
- world.queryable().allOf(Forces.class, Controllable.class, Velocity.class).forEach(entity -> {
+ world.queryable().allOf(Controllable.class, Velocity.class).forEach(entity -> {
final Velocity velocity = entity.get(Velocity.class);
float dx = 0f;
@@ -46,23 +42,38 @@ public class InputSystem implements System {
entity.add(new FacingDirection(new Vec2f(dx / MOVE_SPEED, 0f)));
}
- float newDy = velocity.getVelocity().getY();
+ final Instant now = Instant.now();
+ final Jumpable jumpable = entity.get(Jumpable.class);
+ final boolean canRequestJump = jumpable.getJumpRequestTime() == null;
+ final boolean jumpRequested = actions.contains(KeyBinds.Action.JUMP);
+ final boolean hasCurrentJump = entity.has(Jump.class);
- final Jump jump = entity.get(Jump.class);
- final Mass mass = entity.get(Mass.class);
+ float dy = velocity.getVelocity().getY();
- if (actions.contains(KeyBinds.Action.JUMP)) {
- final boolean applyForce = Instant.now().toEpochMilli() - jump.getJumpStartMs() < MAX_JUMP_MS;
- if (jump.isCanJump()) {
- newDy = JUMP_INITIAL_VEL;
- jump.setCanJump(false);
- jump.setJumpStartMs(Instant.now().toEpochMilli());
- } else if (applyForce) {
- entity.get(Forces.class).add(new Force(new Vec2f(0f, mass.getMass() * JUMP_ACC)));
+ // buffer only fires on a released press — holding never re-triggers
+ final boolean withinBuffer = !canRequestJump && !jumpRequested
+ && Duration.between(jumpable.getJumpRequestTime(), now).compareTo(JUMP_BUFFER) <= 0;
+ if (jumpable.isCanPhysicallyJump() && !hasCurrentJump && (canRequestJump && jumpRequested || withinBuffer)) {
+ entity.add(new Jump(now));
+ dy = JUMP_INITIAL_VEL;
+ jumpable.setJumpRequestTime(now); // mark consumed; keeps canRequestJump false while held
+ } else if (!jumpRequested && hasCurrentJump && dy > 0) {
+ dy *= JUMP_CUT_FACTOR;
+ }
+
+ // record an aerial press for buffering (ground presses are recorded above on initiation)
+ if (!jumpable.isCanPhysicallyJump() && canRequestJump && jumpRequested && !entity.has(Jump.class)) {
+ jumpable.setJumpRequestTime(now);
+ } else if (!jumpRequested && !entity.has(Jump.class)) {
+ if (jumpable.isCanPhysicallyJump()) {
+ jumpable.setJumpRequestTime(null); // released on ground — ready for next press
+ } else if (!canRequestJump
+ && Duration.between(jumpable.getJumpRequestTime(), now).compareTo(JUMP_BUFFER) > 0) {
+ jumpable.setJumpRequestTime(null); // aerial, buffer expired
}
}
- velocity.setVelocity(new Vec2f(dx, newDy));
+ velocity.setVelocity(new Vec2f(dx, dy));
});
}
}
diff --git a/core/src/main/java/coffee/liz/dyl/systems/JumpSystem.java b/core/src/main/java/coffee/liz/dyl/systems/JumpSystem.java
new file mode 100644
index 0000000..d1552f5
--- /dev/null
+++ b/core/src/main/java/coffee/liz/dyl/systems/JumpSystem.java
@@ -0,0 +1,43 @@
+package coffee.liz.dyl.systems;
+
+import coffee.liz.dyl.components.physics.CollisionContacts;
+import coffee.liz.dyl.components.physics.Jump;
+import coffee.liz.dyl.components.physics.Jumpable;
+import coffee.liz.dyl.components.physics.Velocity;
+import coffee.liz.dyl.systems.physics.CollisionSystem;
+import coffee.liz.ecs.model.System;
+import coffee.liz.ecs.model.World;
+
+import java.util.Collection;
+import java.util.List;
+
+public class JumpSystem implements System {
+ @Override
+ public Collection<Class<? extends System>> getDependencies() {
+ return List.of(CollisionSystem.class);
+ }
+
+ @Override
+ public void update(final World world, final float deltaSeconds) {
+ world.queryable().allOf(Jumpable.class).forEach(entity -> {
+ entity.get(Jumpable.class).setCanPhysicallyJump(false);
+ });
+ world.queryable().allOf(Jumpable.class, CollisionContacts.class).forEach(entity -> {
+ final CollisionContacts contacts = entity.get(CollisionContacts.class);
+ final Jumpable jumpable = entity.get(Jumpable.class);
+ contacts.getContacts().forEach(contact -> {
+ final boolean solidUnderUs = contact.getPenetrationVector().getY() <= 0;
+ if (!solidUnderUs) {
+ return;
+ }
+ jumpable.setCanPhysicallyJump(true);
+
+ final boolean currentJumpOver = entity.has(Jump.class) && entity.has(Velocity.class)
+ && entity.get(Velocity.class).getVelocity().getY() <= 0;
+ if (currentJumpOver) {
+ entity.remove(Jump.class);
+ }
+ });
+ });
+ }
+}
diff --git a/core/src/main/java/coffee/liz/dyl/systems/physics/ForceReductionSystem.java b/core/src/main/java/coffee/liz/dyl/systems/physics/AccelerationSystem.java
index 944ad2b..519cc3f 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/physics/ForceReductionSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/physics/AccelerationSystem.java
@@ -6,6 +6,7 @@ import coffee.liz.dyl.components.physics.Gravity;
import coffee.liz.dyl.components.physics.Jump;
import coffee.liz.dyl.components.physics.Mass;
import coffee.liz.dyl.components.physics.Velocity;
+import coffee.liz.dyl.config.PhysicsConstants;
import coffee.liz.dyl.systems.InputSystem;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2f;
@@ -17,7 +18,7 @@ import java.util.Collection;
import java.util.Set;
@RequiredArgsConstructor
-public class ForceReductionSystem implements System {
+public class AccelerationSystem implements System {
private final float gravity;
@Override
@@ -33,10 +34,10 @@ public class ForceReductionSystem implements System {
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)));
- }
+ final float gravityMult = entity.has(Jump.class) && velocity.getVelocity().getY() < 0
+ ? 1f + PhysicsConstants.ADDITIONAL_JUMP_OVER_GRAVITY
+ : 1f;
+ forces.add(new Force(new Vec2f(0f, -mass.getMass() * gravity * gravityMult)));
}
Vec2<Float> netForce = Vec2f.ZERO;
@@ -45,12 +46,13 @@ public class ForceReductionSystem implements System {
}
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);
- }
+ final Vec2<Float> dv = netForce.scale(deltaSeconds / mass.getMass(), deltaSeconds / mass.getMass());
+ velocity.setVelocity(velocity.getVelocity().plus(dv).transform(x -> x, y -> {
+ if (entity.has(Gravity.class)) {
+ return Math.max(entity.get(Gravity.class).getTerminalVelocity(), y);
+ }
+ return y;
+ }));
});
}
}
diff --git a/core/src/main/java/coffee/liz/dyl/systems/physics/CollisionSystem.java b/core/src/main/java/coffee/liz/dyl/systems/physics/CollisionSystem.java
index 8cf7a59..fb98151 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/physics/CollisionSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/physics/CollisionSystem.java
@@ -2,9 +2,9 @@ package coffee.liz.dyl.systems.physics;
import coffee.liz.dyl.components.physics.BoundingBox;
import coffee.liz.dyl.components.physics.CollisionContacts;
-import coffee.liz.dyl.components.physics.Jump;
import coffee.liz.dyl.components.physics.Solid;
import coffee.liz.dyl.components.physics.Velocity;
+import coffee.liz.dyl.systems.InputSystem;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.model.Entity;
@@ -22,7 +22,7 @@ public class CollisionSystem implements System {
@Override
public Collection<Class<? extends System>> getDependencies() {
- return Set.of(IntegrationSystem.class);
+ return Set.of(MovementSystem.class);
}
@Override
@@ -55,9 +55,6 @@ public class CollisionSystem implements System {
continue;
}
- contacts(me).add(them);
- contacts(them).add(me);
-
if (them.has(Solid.class)) {
resolveCollision(me, them);
}
@@ -70,6 +67,8 @@ public class CollisionSystem implements System {
final BoundingBox themBox = them.get(BoundingBox.class);
final Vec2<Float> mtv = getPenetrationVector(meBox, themBox);
+ contacts(me).add(them, getPenetrationVector(themBox, meBox));
+ contacts(them).add(me, mtv);
meBox.setPosition(meBox.getPosition().plus(mtv));
// Cancel the velocity component pressing into the solid (normal impulse)
@@ -85,11 +84,6 @@ public class CollisionSystem implements System {
vel.getY() + ny * velIntoWall
));
}
-
- // Landing on top of a solid restores jump ability
- if (me.has(Jump.class) && ny > 0f) {
- me.get(Jump.class).setCanJump(true);
- }
}
private Vec2<Float> getPenetrationVector(final BoundingBox meBox, final BoundingBox themBox) {
diff --git a/core/src/main/java/coffee/liz/dyl/systems/physics/IntegrationSystem.java b/core/src/main/java/coffee/liz/dyl/systems/physics/MovementSystem.java
index 4de4dd7..77a9b9c 100644
--- a/core/src/main/java/coffee/liz/dyl/systems/physics/IntegrationSystem.java
+++ b/core/src/main/java/coffee/liz/dyl/systems/physics/MovementSystem.java
@@ -8,10 +8,10 @@ import coffee.liz.ecs.model.World;
import java.util.Collection;
import java.util.Set;
-public class IntegrationSystem implements System {
+public class MovementSystem implements System {
@Override
public Collection<Class<? extends System>> getDependencies() {
- return Set.of(ForceReductionSystem.class);
+ return Set.of(AccelerationSystem.class);
}
@Override
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 b1376df..fd8e282 100644
--- a/core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java
+++ b/core/src/main/java/coffee/liz/dyl/world/DylGameWorld.java
@@ -2,17 +2,19 @@ package coffee.liz.dyl.world;
import coffee.liz.dyl.DylGame;
import coffee.liz.dyl.config.PhysicsConstants;
+import coffee.liz.dyl.entities.FloorFactory;
import coffee.liz.dyl.entities.PlayerFactory;
import coffee.liz.dyl.systems.AnimationSystem;
import coffee.liz.dyl.systems.DamageSystem;
import coffee.liz.dyl.systems.InputSystem;
+import coffee.liz.dyl.systems.JumpSystem;
import coffee.liz.dyl.systems.RenderSystem;
import coffee.liz.ecs.DAGWorld;
import coffee.liz.dyl.components.physics.BoundingBox;
import coffee.liz.dyl.components.physics.Solid;
import coffee.liz.dyl.systems.physics.CollisionSystem;
-import coffee.liz.dyl.systems.physics.ForceReductionSystem;
-import coffee.liz.dyl.systems.physics.IntegrationSystem;
+import coffee.liz.dyl.systems.physics.AccelerationSystem;
+import coffee.liz.dyl.systems.physics.MovementSystem;
import coffee.liz.ecs.math.Vec2f;
import com.badlogic.gdx.Gdx;
@@ -20,14 +22,16 @@ public class DylGameWorld extends DAGWorld {
public DylGameWorld(final DylGame game) {
super(
new InputSystem(() -> game.getSettings().getKeyBinds().filterActiveActions(Gdx.input::isKeyPressed)),
- new ForceReductionSystem(PhysicsConstants.GRAVITY),
- new IntegrationSystem(),
+ new AccelerationSystem(PhysicsConstants.GRAVITY),
+ new MovementSystem(),
new CollisionSystem(),
new DamageSystem(),
new AnimationSystem(),
- new RenderSystem(game.getBatch(), game.getViewport())
+ new RenderSystem(game.getBatch(), game.getViewport()),
+ new JumpSystem()
);
PlayerFactory.addTo(this);
+ FloorFactory.addTo(this);
createEntity()
.add(new BoundingBox(new Vec2f(-50f, -1f), new Vec2f(200f, 1f)))
.add(new Solid());
diff --git a/core/src/test/java/coffee/liz/dyl/systems/physics/PhysicsSystemsTest.java b/core/src/test/java/coffee/liz/dyl/systems/physics/PhysicsSystemsTest.java
index 4c285fb..885c112 100644
--- a/core/src/test/java/coffee/liz/dyl/systems/physics/PhysicsSystemsTest.java
+++ b/core/src/test/java/coffee/liz/dyl/systems/physics/PhysicsSystemsTest.java
@@ -21,7 +21,7 @@ class PhysicsSystemsTest {
@Test
public void gravityAcceleratesEntityDownwardOverTime() {
- final DAGWorld world = new DAGWorld(new ForceReductionSystem(GRAVITY), new IntegrationSystem());
+ final DAGWorld world = new DAGWorld(new AccelerationSystem(GRAVITY), new MovementSystem());
final Entity entity = world.createEntity();
entity.add(new Mass(1f));
entity.add(new Velocity(Vec2f.ZERO));
@@ -37,7 +37,7 @@ class PhysicsSystemsTest {
@Test
public void forcesAreClearedEachFrame() {
- final DAGWorld world = new DAGWorld(new ForceReductionSystem(GRAVITY), new IntegrationSystem());
+ final DAGWorld world = new DAGWorld(new AccelerationSystem(GRAVITY), new MovementSystem());
final Entity entity = world.createEntity();
entity.add(new Mass(1f));
entity.add(new Velocity(Vec2f.ZERO));
@@ -53,7 +53,7 @@ class PhysicsSystemsTest {
@Test
public void entityLandsOnPlatformAndStops() {
final DAGWorld world = new DAGWorld(
- new ForceReductionSystem(GRAVITY), new IntegrationSystem(), new CollisionSystem());
+ new AccelerationSystem(GRAVITY), new MovementSystem(), new CollisionSystem());
final Entity player = world.createEntity();
player.add(new Mass(1f));
diff --git a/design/bugs.txt b/design/bugs.txt
new file mode 100644
index 0000000..e65b3ca
--- /dev/null
+++ b/design/bugs.txt
@@ -0,0 +1,3 @@
+Clipping into a solid gives double height:
+
+Jumping into a solid from the side has weird interactions. First, I can hold the direction where the vector goes into the solid and jump, and I'll get a "double jump", probably because the jump resets immediately on top collision. ~/Desktop/dyl-bugs/jump-into-solid.mov.
diff --git a/design/design.txt b/design/design.txt
index df8842c..74c720d 100644
--- a/design/design.txt
+++ b/design/design.txt
@@ -78,3 +78,7 @@ This gives the world a little bit of "depth".
---------S | (height difference is two screens' worth
\ |
\_______
+
+Something I still need to decide on is how the camera will work. Is every chunk of the game a
+room like mega man? Or is it like Terraria where the camera centers on the player and chunks
+feel seemless? The former is probably easier generation-wise etc.
diff --git a/design/todo.txt b/design/todo.txt
new file mode 100644
index 0000000..023868e
--- /dev/null
+++ b/design/todo.txt
@@ -0,0 +1,8 @@
+Terrain:
+- [ ] Basic platforming
+- [ ] First dungeon
+- [ ] First overworld attempt
+
+Combat:
+- [ ] Basic enemy
+- [ ] Separate solid collision bounding box and damageable collision bounding box. Perhaps even different systems?