Ich versuche, das Asteroids-Spiel mit JavaFX 2.2 zu schreiben, aber ich habe Probleme, wenn ich versuche, die Spielobjekte zu bewegen (d. H. Die Felsen, Raumschiff und Balken) oder Kollisionen zwischen ihnen zu erkennen.Wie kann man die GUI einer JavaFX-Anwendung von einem Hintergrund-Thread sicher aktualisieren?
Anfangs habe ich versucht, alle beweglichen und Kollisionserkennung von einem Hintergrund-Thread mit dem scheduleAtFixedRate (Runnable, lang, lang, Timeunit) Methode der ScheduledThreadPoolExecutor Klasse zu tun, aber diese Ausnahmen allerdings nicht der Laufzeit verursacht wurde, die wasn nicht einmal in meinem Code, weil ich versucht habe, die GUI als Hintergrund-Thread zu modifizieren.
Meine nächste Vorgehensweise bestand darin, die Spielobjekte von einem UI-Thread selbst zu aktualisieren, indem die AnimationTimer Klasse verwendet wurde. Während mit diesem Ansatz das Problem der Ausnahmen behoben wurde, das auf dem UI-Thread ausgeführt wird, verursacht es erhebliche Verzögerungen.
Also, ich möchte wissen, ob es eine machbare Möglichkeit gibt, die Spielobjekte zu aktualisieren, ohne Ausnahmen oder Verzögerungen zu verursachen?
Hier ist die Hauptklasse meiner Anwendung:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.media.AudioClip;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import java.util.ArrayList;
public class Main extends Application {
private ArrayList<Rock> rocks = new ArrayList<>();
private ArrayList<Beam> beams = new ArrayList<>();
private SpaceShip spaceShip = null;
private Group group;
private final int SCENE_WIDTH = 900, SCENE_HEIGHT = 600;
private final int ROCK_COUNT = 20;
private boolean upKeyPressed, upKeyReleased, zKeyPressed, leftKeyPressed, rightKeyPressed;
private int bulletsFired = 0, skipCount = 10;
private AudioClip explosion = new AudioClip(Main.class.getResource("explosion.wav").toString());
private AudioClip destroy = new AudioClip(Main.class.getResource("destroy.mp3").toString());
public static void main(String args[]) {
launch();
}
@Override
public void start(Stage primaryStage) throws Exception {
ImageView spaceBackground = new ImageView("space.jpg");
spaceBackground.setFitHeight(SCENE_HEIGHT);
spaceBackground.setFitWidth(SCENE_WIDTH);
group = new Group(spaceBackground);
Scene scene = new Scene(group, SCENE_WIDTH, SCENE_HEIGHT);
initializeGameObjects();
// add event listeners for the spaceShip controls
scene.setOnKeyPressed((keyEvent) -> {
switch(keyEvent.getCode()) {
case UP:
upKeyPressed = true;
break;
case Z:
zKeyPressed = true;
break;
case LEFT:
leftKeyPressed = true;
break;
case RIGHT:
rightKeyPressed = true;
}
});
scene.setOnKeyReleased((keyEvent) -> {
switch(keyEvent.getCode()) {
case UP:
upKeyPressed = false;
upKeyReleased = true;
break;
case Z:
zKeyPressed = false;
break;
case LEFT:
leftKeyPressed = false;
break;
case RIGHT:
rightKeyPressed = false;
}
});
AnimationTimer updater = new AnimationTimer() {
@Override
public void handle(long now) {
updateGameObjects();
}
};
primaryStage.setScene(scene);
primaryStage.setTitle("Asteroids");
primaryStage.setResizable(false);
primaryStage.getIcons().add(new Image(Main.class.getResource("icon.png").toString()));
primaryStage.show();
updater.start();
}
private void initializeGameObjects() {
// initialize the Rock ArrayList
for(int i=0; i<ROCK_COUNT; i++) {
Rock rock = new Rock();
rocks.add(rock);
group.getChildren().add(rock);
}
// add the space ship to the center
spaceShip = new SpaceShip();
group.getChildren().add(spaceShip);
}
private void updateGameObjects() {
// move the rocks
for(Rock rock: rocks) {
rock.move(rocks);
}
// check for collision among rocks
for(int i=0; i<rocks.size(); i++) {
for(int j=i+1; j<rocks.size(); j++) {
Rock rock1 = rocks.get(i), rock2 = rocks.get(j);
// if two rocks collide, interchange their speeds
if(rock1.getBoundsInParent().intersects(rock2.getBoundsInParent())) {
int tmpSpeedX = rock1.getSpeedX();
int tmpSpeedY = rock1.getSpeedY();
rock1.setSpeedX(rock2.getSpeedX());
rock1.setSpeedY(rock2.getSpeedY());
rock2.setSpeedX(tmpSpeedX);
rock2.setSpeedY(tmpSpeedY);
}
}
}
// control the spaceShip
if(upKeyPressed) {
spaceShip.accelerate();
//System.out.println(spaceShip.getSpeed());
}
else if(upKeyReleased) {
if(spaceShip.getSpeed() > 0)
spaceShip.decelerate();
else {
spaceShip.nullifySpeed();
upKeyReleased = false;
}
//System.out.println(spaceShip.getSpeed());
}
if(leftKeyPressed)
spaceShip.rotateLeft();
if(rightKeyPressed)
spaceShip.rotateRight();
if(zKeyPressed) {
if(bulletsFired < 4) {
beams = spaceShip.fire(group);
bulletsFired++;
skipCount = 15;
} else {
skipCount--;
if(skipCount == 0)
bulletsFired = 0;
}
}
// move the beams
for(int i=0; i<beams.size(); i++) {
Beam beam = beams.get(i);
if(!beam.isAlive()) {
beams.remove(beam);
continue;
}
beam.move();
}
// check if the ship hits a rock
for(int i=0; i<rocks.size(); i++) {
Rock rock = rocks.get(i);
if(Shape.intersect(spaceShip, rock).getLayoutBounds().getWidth() > 0) {
rock.setVisible(false);
rocks.remove(rock);
explosion.play(0.04, 0, 1.5, 0, 1);
}
}
// check if a beam hits a rock
for(int i=0; i<beams.size(); i++) {
for(int j=0; j<rocks.size(); j++) {
Beam beam = beams.get(i);
Rock rock = rocks.get(j);
if(Shape.intersect(beam, rock).getLayoutBounds().getWidth() > 1) {
rock.setVisible(false);
rocks.remove(rock);
beam.setVisible(false);
beams.remove(beam);
destroy.play(0.04, 0, 1.5, 0, 1);
}
}
}
}
}
ich das Raumschiff, Beam und Rock-Klassen für die der Kürze halber weggelassen.
Schauen Sie sich 'JavaFX's [' AnimatinTimer'] an (https://docs.oracle.com/javase/8/javafx/api/javafx/animation/AnimationTimer.html). Gehen Sie durch dieses Tutorial: https://gamedevelopment.tutsplus.com/tutorials/introduction-to-javafx-for-game-development--cms-23835 – Sedrick
Wie ich in meiner Frage erwähnt habe, verwende ich derzeit AnimationTimer. –
Das Tutorial erklärt, wie man es richtig benutzt. Ich habe nicht bemerkt, dass du es bereits benutzt hast. – Sedrick