Skip to content

Gameplay Polish & Performance: delta-time loop, audio pooling, difficulty curve, CI + packaging #3

@hoangsonww

Description

@hoangsonww

Summary

Tighten gameplay feel and make builds frictionless. This issue bundles small, safe improvements:

  • Smooth, frame-rate-independent movement via delta-time.
  • No-stutter SFX with audio clip pooling.
  • Progressive difficulty curve + spawn scheduler.
  • Hitbox tuning + player i-frames after hit.
  • Remove local JavaFX SDK path by using javafx-maven-plugin.
  • Add CI (build + test) and packaging (jpackage) for one-click runs.

Scope & Tasks

1) Frame-rate independence

  • Replace fixed per-frame movement with delta time in AnimationTimer.
  • Cap dt (e.g., 0.033s) to avoid tunneling after GC pauses.

Sketch

new AnimationTimer() {
    private long lastNs = 0L;
    @Override public void handle(long now) {
        if (lastNs == 0L) { lastNs = now; return; }
        double dt = Math.min((now - lastNs) / 1_000_000_000.0, 0.033); // ~30 ms cap
        lastNs = now;

        player.update(dt);
        enemies.forEach(e -> e.update(dt));
        bullets.forEach(b -> b.update(dt));
        physics.update(dt);
        ui.render();
    }
}.start();

2) Audio stutter fix (pooling)

  • Pool AudioClip/MediaPlayer for repeated SFX (shoot/hit/power-up).
  • Volume & rate configurable via constants.

Sketch

class SfxPool {
    private final List<AudioClip> shots;
    private int i = 0;
    SfxPool(URL wavUrl, int size) {
        shots = IntStream.range(0, size)
            .mapToObj(n -> new AudioClip(wavUrl.toString()))
            .collect(Collectors.toList());
    }
    void playShot() {
        AudioClip c = shots.get(i++ % shots.size());
        c.stop(); c.play();
    }
}

3) Difficulty curve & spawns

  • Spawn rate & enemy speed scale with score/time.
  • Boss every N points with telegraphed warning.
  • Power-up weighting increases when player is low on lives.

Sketch

double difficulty = 1.0 + (score / 250.0) + elapsedMinutes * 0.25;
spawner.setSpawnIntervalSeconds(Math.max(0.25, 1.5 / difficulty));
enemyBaseSpeed = 120 * difficulty;

4) Hitboxes & i-frames

  • Slightly shrink collision bounds (feel > math).
  • Add 1.0s invulnerability after hit (blink sprite).

Sketch

boolean collides(Node a, Node b) {
    Bounds A = a.getBoundsInParent(); Bounds B = b.getBoundsInParent();
    double pad = 6; // shrink by 6px
    return A.getMaxX()-pad > B.getMinX()+pad &&
           A.getMinX()+pad < B.getMaxX()-pad &&
           A.getMaxY()-pad > B.getMinY()+pad &&
           A.getMinY()+pad < B.getMaxY()-pad;
}

5) Input polish

  • Key repeat & “diagonal feels right”: normalize vector, clamp speed.
  • Add Pause (P) and Mute (M).

6) Build: remove SDK path; add packaging

  • Switch to org.openjfx:javafx-maven-plugin so no local SDK path is needed.
  • Add jpackage profile to produce platform installers.
  • Embed assets in src/main/resources and load via getResource.

POM snippet

<plugin>
  <groupId>org.openjfx</groupId>
  <artifactId>javafx-maven-plugin</artifactId>
  <version>0.0.8</version>
  <configuration>
    <mainClass>com.yourgame.SpaceShooter</mainClass>
    <launcher>SpaceShooter</launcher>
    <stripNativeCommands>true</stripNativeCommands>
    <jlinkZip>true</jlinkZip>
    <modules>
      <module>javafx.controls</module>
      <module>javafx.media</module>
    </modules>
  </configuration>
</plugin>

7) CI & Tests

  • GitHub Actions: mvn -B -ntp -DskipTests=false verify.
  • Headless smoke tests (logic only; no Stage) for spawn math & collisions.
  • Optional: TestFX stage tests behind -Dtestfx.headless=true.

Acceptance Criteria

  • ✅ Player speed & projectile speed are consistent at 60fps and 120fps (simulate by throttling) with <5% variance.
  • ✅ No audible stutter on rapid fire (≥8 shots/sec).
  • ✅ Spawn rate & enemy speed visibly scale with score/time; boss appears on schedule.
  • ✅ Post-hit i-frames prevent immediate double damage; player sprite blinks.
  • mvn javafx:run works without editing a local JavaFX SDK path.
  • ✅ CI workflow passes on Ubuntu runner; a packaged artifact is produced via mvn -Ppackage.

Nice-to-have (future)

  • Quadtree for broad-phase collision when entities > 400.
  • Screen-space shaders (flash on boss entry).
  • Save best score (Preferences API) + simple settings modal.

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededquestionFurther information is requested

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions