Skip to content

Commit

Permalink
Add late-behavior initialization (fastjengine#201)
Browse files Browse the repository at this point in the history
- (fastjengine#172) add mid-game init calls
  • Loading branch information
lucasstarsz authored May 7, 2022
1 parent b8b7984 commit 60dc5a1
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ private void newWave() {
enemyCount = calculateEnemyCount(wave);
for (int i = 0; i < enemyCount; i++) {
Model2D enemy = createEnemy();
enemy.initBehaviors();
enemies.put(enemy.getID(), enemy);
}

Expand All @@ -183,7 +182,7 @@ private Model2D createEnemy() {
);

Model2D enemy = Model2D.fromPolygons(ModelUtil.loadModel(Path.of(FilePaths.PathToResources + "enemy.psdf")));
enemy.addBehavior(new EnemyMovement(this), this);
enemy.addLateBehavior(new EnemyMovement(this), this);
enemy.setTranslation(randomPosition);
drawableManager.addGameObject(enemy);
return enemy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ private void createBullet(GameObject player) {

Polygon2D bullet = (Polygon2D) Polygon2D.fromPoints(bulletMesh)
.setFill(Color.red)
.addBehavior(bulletMovementScript, gameScene)
.addLateBehavior(bulletMovementScript, gameScene)
.<GameObject>addTag(Tags.Bullet, gameScene);

gameScene.drawableManager.addGameObject(bullet);
bullet.initBehaviors();

bulletCount++;
}

Expand Down
9 changes: 4 additions & 5 deletions src/main/java/tech/fastj/engine/FastJEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -654,17 +654,16 @@ private static void initEngine() {
/** Runs the game loop -- the heart of the engine. */
private static void gameLoop() {
float elapsedTime;
float elapsedFixedTime;
float accumulator = 0f;
float updateInterval = 1f / targetUPS;

while (display.getWindow().isVisible()) {
elapsedTime = deltaTimer.evalDeltaTime();
FastJEngine.log("Delta: {}", FastJEngine.getDeltaTime());
accumulator += elapsedTime;

while (accumulator >= updateInterval) {
fixedDeltaTimer.evalDeltaTime();
FastJEngine.log("Fixed Delta: {}", FastJEngine.getFixedDeltaTime());
elapsedFixedTime = fixedDeltaTimer.evalDeltaTime();
gameManager.fixedUpdate(canvas);
gameManager.updateBehaviors();

Expand All @@ -677,7 +676,7 @@ private static void gameLoop() {
AfterUpdateList.clear();
}

accumulator -= updateInterval;
accumulator -= elapsedFixedTime;
}

gameManager.processInputEvents();
Expand Down Expand Up @@ -712,7 +711,7 @@ private static void gameLoop() {
private static void sync() {
final float loopSlot = 1f / targetFPS;
final double endTime = deltaTimer.getLastTimestamp() + loopSlot;
final double currentTime = deltaTimer.getTime();
final double currentTime = deltaTimer.getCurrentTime();
if (currentTime < endTime) {
try {
TimeUnit.MILLISECONDS.sleep((long) ((endTime - currentTime) * 1000L));
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/tech/fastj/engine/internals/Timer.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package tech.fastj.engine.internals;

/**
* Timer that accurately specifies time.
* Timekeeping class, primarily used to track the time between the previous and current game frames.
* <p>
* This class is based on Antonio Hernández Bejarano's Timer class: https://ahbejarano.gitbook.io/lwjglgamedev/
* This class is based on Antonio Hernández Bejarano's Timer class:
* <a href="https://ahbejarano.gitbook.io/lwjglgamedev/">https://ahbejarano.gitbook.io/lwjglgamedev/</a>
* <p>
* Didn't make too many changes.
*
Expand All @@ -17,7 +18,7 @@ public class Timer {

/** Initializes the Timer. */
public void init() {
lastTimestamp = getTime();
lastTimestamp = getCurrentTime();
deltaTime = 0f;
}

Expand All @@ -26,7 +27,7 @@ public void init() {
*
* @return The current time (nanoseconds) as a double.
*/
public double getTime() {
public double getCurrentTime() {
return System.nanoTime() / 1_000_000_000d;
}

Expand All @@ -36,7 +37,7 @@ public double getTime() {
* @return The time elapsed since the last time evaluation.
*/
public float evalDeltaTime() {
double time = getTime();
double time = getCurrentTime();
deltaTime = (float) (time - lastTimestamp);
lastTimestamp = time;
return deltaTime;
Expand Down
27 changes: 23 additions & 4 deletions src/main/java/tech/fastj/graphics/game/GameObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,31 @@ public GameObject addBehavior(Behavior behavior, BehaviorHandler behaviorHandler
return this;
}

/**
* Adds the specified {@link Behavior} to the {@code GameObject}'s list of {@code Behavior}s, and initializes it.
* <p>
* This does not check to make sure the game is running -- it only initializes the given behavior.
* <p>
* {@code Behavior}s can be added as many times as needed.
*
* @param behavior {@code Behavior} parameter to be added.
* @param behaviorHandler Handler that the {@code GameObject} will be added to, as a behavior listener.
* @return the {@code GameObject} is returned for method chaining.
*/
public GameObject addLateBehavior(Behavior behavior, BehaviorHandler behaviorHandler) {
behaviors.add(behavior);
behaviorHandler.addBehaviorListener(this);
behavior.init(this);

return this;
}

/**
* Removes the specified {@link Behavior} from the {@code GameObject}'s list of {@code Behavior}s.
*
* @param behavior {@code Behavior} parameter to be removed from.
* @param behaviorHandler Handler that, if the {@code GameObject} no longer has any Behaviors, the {@code
* GameObject} will be removed from as a behavior listener.
* @param behaviorHandler Handler that, if the {@code GameObject} no longer has any Behaviors, the
* {@code GameObject} will be removed from as a behavior listener.
* @return the {@code GameObject} is returned for method chaining.
*/
public GameObject removeBehavior(Behavior behavior, BehaviorHandler behaviorHandler) {
Expand Down Expand Up @@ -127,8 +146,8 @@ protected void destroyTheRest(Scene origin) {
}

/**
* Destroys all references of the {@code GameObject}'s behaviors and removes its references from the {@code
* SimpleManager}.
* Destroys all references of the {@code GameObject}'s behaviors and removes its references from the
* {@code SimpleManager}.
*
* @param origin {@code SimpleManager} parameter that will have all references to this {@code GameObject} removed.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,47 @@ void checkDestroyBehaviors_shouldMakePointfNull() {
assertNull(mockBehavior.getPointf(), "After destroying the GameObject's behaviors, the Pointf should be null.");
}

@Test
void checkInitBehavior_withAddLateBehavior_shouldInitializePointf() {
GameObject gameObject = new MockGameObject();
MockBehavior mockBehavior = new MockBehavior();
Scene mockScene = new MockEmptyScene();

gameObject.addLateBehavior(mockBehavior, mockScene);

assertNotNull(mockBehavior.getPointf(), "After initializing the GameObject's behaviors, its Pointf should not be null.");
}

@Test
void checkUpdateBehavior_withAddLateBehavior_shouldIncrementPointf() {
GameObject gameObject = new MockGameObject();
MockBehavior mockBehavior = new MockBehavior();
Scene mockScene = new MockEmptyScene();

gameObject.addLateBehavior(mockBehavior, mockScene);

int expectedIncrement = 15;
for (int i = 0; i < expectedIncrement; i++) {
gameObject.updateBehaviors();
}

boolean condition = Maths.floatEquals(expectedIncrement, mockBehavior.getPointf().x) && Maths.floatEquals(expectedIncrement, mockBehavior.getPointf().y);
assertTrue(condition, "After updating, the behavior's Pointf should have incremented.");
}

@Test
void checkDestroyBehavior_withAddLateBehavior_shouldMakePointfNull() {
GameObject gameObject = new MockGameObject();
MockBehavior mockBehavior = new MockBehavior();
Scene mockScene = new MockEmptyScene();

gameObject.addLateBehavior(mockBehavior, mockScene); // pointf is not null here
assertNotNull(mockBehavior.getPointf());

gameObject.destroyAllBehaviors(); // pointf is null here
assertNull(mockBehavior.getPointf(), "After destroying the GameObject's behaviors, the Pointf should be null.");
}

@Test
void tryUpdateBehaviorWithoutInitializing_shouldThrowNullPointerException() {
GameObject gameObject = new MockGameObject();
Expand Down

0 comments on commit 60dc5a1

Please sign in to comment.