| name | fxgl-racing |
| description | Build a top-down racing game in FXGL — implement vehicle physics with forward thrust, steering, friction, and drift, create a circuit track with ordered checkpoint gates for lap counting, add AI opponents following a predefined racing line with waypoints, handle car-wall collisions with bounce-back, add power-up pickups on track (boost, shield, attack), track race position (1st/2nd/3rd), display lap timer and best lap, and implement a ghost replay system for time trials. Use this skill when building a top-down racer, kart racer, circuit racing game, or any vehicle-control game with lap-based competition.
|
| triggers | ["racing","top-down racing","car physics","lap counter","checkpoint","racing line","AI racer","drift","kart","circuit","ghost replay","race position"] |
| compatibility | Java 17+, FXGL 21.x
|
| category | fxgl/game-types |
| tags | ["fxgl","java","javafx","game-types","racing"] |
| metadata | {"author":"fxgl-skills","version":"1.0","fxgl-version":"21.1"} |
| allowed-tools | ["Read","Write","Edit","Bash"] |
FXGL Top-Down Racing
Vehicle Physics Component
public class VehicleComponent extends Component {
private PhysicsComponent physics;
private static final double ACCELERATION = 300.0;
private static final double MAX_SPEED = 350.0;
private static final double TURN_SPEED = 3.0;
private static final double FRICTION = 0.85;
private static final double DRIFT_FRICTION = 0.95;
private double speed = 0;
private ;
;
{
isHeld(KeyCode.W) || isHeld(KeyCode.UP);
isHeld(KeyCode.S) || isHeld(KeyCode.DOWN);
isHeld(KeyCode.A) || isHeld(KeyCode.LEFT);
isHeld(KeyCode.D) || isHeld(KeyCode.RIGHT);
drifting = isHeld(KeyCode.SHIFT) && Math.abs(speed) > ;
(throttle) speed = Math.min(MAX_SPEED, speed + ACCELERATION * tpf);
(brake) speed = Math.max(-MAX_SPEED * , speed - ACCELERATION * * tpf);
drifting ? DRIFT_FRICTION : FRICTION;
(!throttle && !brake) speed *= Math.pow(friction, tpf * );
(Math.abs(speed) > ) {
TURN_SPEED * tpf * (speed / MAX_SPEED);
(left) angle -= steerAmount;
(right) angle += steerAmount;
}
Math.cos(angle) * speed;
Math.sin(angle) * speed;
drifting ? : ;
physics.setVelocityX(vx * ( - lateralFriction) + physics.getVelocityX() * lateralFriction);
physics.setVelocityY(vy * ( - lateralFriction) + physics.getVelocityY() * lateralFriction);
entity.setRotation(Math.toDegrees(angle));
}
{
MAX_SPEED * ;
speed = boostSpeed;
runOnce(() -> {}, Duration.seconds(duration));
}
{
getInput().isHeld(key);
}
}