Teil 3: Kollisionen

FXGL Tutorial: Kollisionen hinzufügen mit JavaFX

Almas Baimagambetov

©  Shutterstock / pixeldreams.eu

Willkommen zum dritten Teil unseres FXGL-11-Tutorials! Nachdem wir unser Spiel mit Grafiken und Soundeffekten ausgestattet haben, werden wir uns in diesem Teil dem Hinzufügen von Kollisionen widmen. Hier können Sie den zweiten Teil des Tutorials nachholen, falls Sie das noch nicht gemacht haben sollten. Wie zuvor gilt, dass dieses Tutorial auf FXGL 11.0+ und Java 11+ ausgelegt ist.

Legen wir los – dieses Mal haben wir zwei Aufgaben zu erledigen. Wir werden zunächst eine weitere Entität hinzufügen. Anschließend werden wir einen Handler erstellen, der sich zwischen der Spielfigur und der neuen Entität befinden wird. Damit sehen unsere Aufgaben wie folgt aus:

  1. Hinzufügen der Münzen-Entität
  2. Hinzufügen des Collision Handlers, der die Interaktion zwischen Spielfigur und Münze verwaltet

Zum Schluss dieses Tutorials sollten Sie folgendes erhalten:

Quelle: <a href="https://github.com/AlmasB/FXGL/wiki/Adding-Collisions-%28FXGL-11%29">GitHub</a>

Quelle: GitHub

Vorbereitung

Damit unsere Kollisionen auch funktionieren können, müssen wir zuerst FXGL darüber informieren, was für Typen von Entitäten vorhanden sind. Im Falle unseres Spiels wären das die Entitäten der Spielfigur und der Münze. Hier empfiehlt es sich, den Typ durch ein enum (enumerated Type; Aufzählungstyp) darzustellen. Also machen wir uns daran, den Aufzählungstyp EntityType zu erstellen.

public enum EntityType {
    PLAYER, COIN
}	

Aufgabe 1: Hinzufügen der Münzen-Entität

Jetzt werden wir eine brandneue Entität hinzufügen – die Münze. Das machen wir in initGame():

FXGL.entityBuilder()
        .type(EntityType.COIN)
        .at(500, 200)
        .viewWithBBox(new Circle(15, Color.YELLOW))
        .with(new CollidableComponent(true))
        .buildAndAttach();

Wir können den Typ der Entität durch einen Aufruf von .type() festlegen. Danach verwenden wir viewWithBBox(), damit FXGL die Entity Bounding Box aus deren Ansicht erstellen kann, bei der es sich um einen gelben Kreis handelt. Und schließlich fügen wir CollidableComponent hinzu, um die Entität so zu markieren, dass sie an der Kollisionserkennung und -behandlung teilnehmen können.

Aufgabe 2: Hinzufügen des Collision Handlers

Jetzt werden wir unsere Spielfigur-Entität leicht modifizieren. Mittlerweile sollte genug Wissen vorhanden sein, um die folgenden Methodenaufrufe zu verstehen.

player = Entities.builder()
        .type(EntityType.PLAYER)
        .at(300, 300)
        .viewFromTextureWithBBox("brick.png")
        .with(new CollidableComponent(true))
        .buildAndAttach(getGameWorld());

Nun sind die Spielfigur und die Münze dazu bereit, an der Kollisionserkennung teilzunehmen. Zum Schluss müssen wir noch den eigentlichen Handler hinzufügen, d. h. den Code, der ausgeführt wird, wenn Spielfigur und Münze miteinander kollidieren.

@Override
protected void initPhysics() {
    FXGL.getPhysicsWorld().addCollisionHandler(new CollisionHandler(EntityType.PLAYER, EntityType.COIN) {

        // order of types is the same as passed into the constructor
        @Override
        protected void onCollisionBegin(Entity player, Entity coin) {
            coin.removeFromWorld();
        }
    });
}

Wir fügen den Handler an die physics-Komponente an (Vergesst nicht, import com.almasb.fxgl.physics.CollisionHandler; auszuführen). Der Handler-Konstruktor nimmt zwei Entitätstypen: Wir haben zuerst PLAYER übergeben und dann COIN. Demzufolge wird die Reihenfolge der Entitäten in onCollisionBegin() dem gleichen Schema folgen, also zuerst player und dann coin. In diesem Beispiel rufen wir lediglich coin.removeFromWorld() auf, das die Münzen-Entität aus der Spielwelt entfernt.

Jetzt wissen wir, wie man zwei Entitäten miteinander kollidieren lassen kann und wie man nach deren Kollision-Events Ausschau halten kann. Gut gemacht!

Der vollständige Quellcode ist, wie immer, unten aufgeführt:

package tutorial;

import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.components.CollidableComponent;
import com.almasb.fxgl.input.Input;
import com.almasb.fxgl.input.UserAction;
import com.almasb.fxgl.physics.CollisionHandler;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
import java.util.Map;

/**
 * @author Almas Baimagambetov (almaslvl@gmail.com)
 */
public class BasicGameApp extends GameApplication {
    @Override
    protected void initSettings(GameSettings settings) {
        settings.setWidth(600);
        settings.setHeight(600);
        settings.setTitle("Basic Game App");
        settings.setVersion("0.1");
    }

    public enum EntityType {
        PLAYER, COIN
    }

    @Override
    protected void initInput() {
        Input input = FXGL.getInput();

        input.addAction(new UserAction("Move Right") {
            @Override
            protected void onAction() {
                player.translateX(5); // move right 5 pixels
                FXGL.getGameState().increment("pixelsMoved", +5);
            }
        }, KeyCode.D);

        input.addAction(new UserAction("Move Left") {
            @Override
            protected void onAction() {
                player.translateX(-5); // move left 5 pixels
                FXGL.getGameState().increment("pixelsMoved", +5);
            }
        }, KeyCode.A);

        input.addAction(new UserAction("Move Up") {
            @Override
            protected void onAction() {
                player.translateY(-5); // move up 5 pixels
                FXGL.getGameState().increment("pixelsMoved", +5);
            }
        }, KeyCode.W);

        input.addAction(new UserAction("Move Down") {
            @Override
            protected void onAction() {
                player.translateY(5); // move down 5 pixels
                FXGL.getGameState().increment("pixelsMoved", +5);
            }
        }, KeyCode.S);

        input.addAction(new UserAction("Play Sound") {
            @Override
            protected void onActionBegin() {
                FXGL.play("drop.wav");
            }
        }, KeyCode.F);
    }

    @Override
    protected void initGameVars(Map<String, Object> vars) {
        vars.put("pixelsMoved", 0);
    }

    private Entity player;

    @Override
    protected void initGame() {
        player = FXGL.entityBuilder()
                .type(EntityType.PLAYER)
                .at(300, 300)
                .viewWithBBox("brick.png")
                .with(new CollidableComponent(true))
                .buildAndAttach();

        FXGL.entityBuilder()
                .type(EntityType.COIN)
                .at(500, 200)
                .viewWithBBox(new Circle(15, Color.YELLOW))
                .with(new CollidableComponent(true))
                .buildAndAttach();
    }

    @Override
    protected void initPhysics() {
        FXGL.getPhysicsWorld().addCollisionHandler(new CollisionHandler(EntityType.PLAYER, EntityType.COIN) {

            // order of types is the same as passed into the constructor
            @Override
            protected void onCollisionBegin(Entity player, Entity coin) {
                coin.removeFromWorld();
            }
        });
    }

    @Override
    protected void initUI() {
        Text textPixels = new Text();
        textPixels.setTranslateX(50); // x = 50
        textPixels.setTranslateY(100); // y = 100

        textPixels.textProperty().bind(FXGL.getGameState().intProperty("pixelsMoved").asString());

        FXGL.getGameScene().addUINode(textPixels); // add to the scene graph

        var brickTexture = FXGL.getAssetLoader().loadTexture("brick.png");
        brickTexture.setTranslateX(50);
        brickTexture.setTranslateY(450);

        FXGL.getGameScene().addUINode(brickTexture);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Stay tuned! Wer mehr über die Kernfunktionen wissen oder vorgefertigten Spielen experimentieren will, findet dazu alles auf GitHub.

Verwandte Themen:

Geschrieben von
Almas Baimagambetov
Almas Baimagambetov
Almas is engaged with research in the field of Automated Diagram Generation. He also teaches Computer Science. In his spare time, he enjoys playing video games as well as designing and developing them.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: