| name | fxgl-shmup |
| description | Build a shoot 'em up (shmup) in FXGL — implement auto-scrolling background for vertical or horizontal scrollers, spawn enemy formations with timer-based waves, fire player bullets toward the scroll direction, script enemy bullet fan/ring/aimed patterns with ProjectileComponent, add power-up collectibles that upgrade weapons (spread shot, laser, shield), implement a lives-and-respawn system, build multi-phase boss fights, track score with chain multipliers, and despawn off-screen entities efficiently. Use this skill when building a space shooter, bullet shooter, vertical shmup, horizontal shmup, forced-scroll shooter, or any game in the shoot 'em up genre.
|
| triggers | ["shmup","shoot em up","space shooter","vertical shooter","horizontal shooter","scrolling shooter","formation","wave spawner","bullet pattern","power-up weapon","lives system","boss fight phases","score multiplier"] |
| compatibility | Java 17+, FXGL 21.x
|
| category | fxgl/game-types |
| tags | ["fxgl","java","javafx","game-types","shmup"] |
| metadata | {"author":"fxgl-skills","version":"1.0","fxgl-version":"21.1"} |
| allowed-tools | ["Read","Write","Edit","Bash"] |
FXGL Shoot 'em Up (Shmup)
Scrolling Background (Vertical Shmup)
private Entity bg1, bg2;
private static final double SCROLL_SPEED = 120;
@Override
protected void initGame() {
Image bgImage = getAssetLoader().loadImage("bg_space.png");
double bgH = bgImage.getHeight();
bg1 = entityBuilder().at(0, 0)
.view(new ImageView(bgImage)).zIndex(-1).buildAndAttach();
bg2 = entityBuilder().at(0, -bgH)
.view(new ImageView(bgImage)).zIndex(-1).buildAndAttach();
}
@Override
protected void onUpdate(double tpf) {
bg1.translateY(SCROLL_SPEED * tpf);
bg2.translateY(SCROLL_SPEED * tpf);
double bgH = bg1.getHeight();
if (bg1.getY() >= getAppHeight()) bg1.setY(bg2.getY() - bgH);
if (bg2.getY() >= getAppHeight()) bg2.setY(bg1.getY() - bgH);
}
Player Ship
@Spawns("player")
public Entity {
entityBuilder(data)
.type(EntityType.PLAYER)
.view()
.bbox(BoundingShape.box(, ))
.with( ())
.with( ())
.build();
}
{
;
;
;
{
entity.setX(Math.max(, Math.min(getAppWidth() - , entity.getX())));
entity.setY(Math.max(, Math.min(getAppHeight() - , entity.getY())));
fireTimer += tpf;
(fireTimer >= FIRE_RATE) {
fireTimer = ;
fire();
}
}
{
(weaponLevel) {
-> spawnBullet(entity.getCenter(), (, -));
-> {
spawnBullet(entity.getCenter().add(-, ), (-, -).normalize());
spawnBullet(entity.getCenter().add(, ), (, -).normalize());
}
-> {
spawnBullet(entity.getCenter(), (, -));
spawnBullet(entity.getCenter().add(-, ), (-, -).normalize());
spawnBullet(entity.getCenter().add(, ), (, -).normalize());
}
}
play();
}
{
spawn(, (pos.getX(), pos.getY()).put(, dir));
}
}