我正在尝试使用 JavaFX 2.2 编写Asteroids游戏,但是当我尝试移动游戏对象(即岩石,太空飞船和横梁)或检测到时,我遇到了问题他们之间的碰撞。
最初,我尝试使用 ScheduledThreadPoolExecutor 类的 scheduleAtFixedRate(Runnable,long,long,TimeUnit)方法从后台线程执行所有移动和碰撞检测,但是这导致了可怕的运行时异常甚至在我的代码中,因为我试图修改GUI形成后台线程。
我的下一个方法是使用 AnimationTimer 类从UI线程本身更新游戏对象。虽然这种方法解决了例外情况。问题,在UI线程上运行,导致严重滞后。
所以,我想知道是否有一种可行的方法来更新游戏对象而不会导致例外或滞后?
这是我的应用程序的Main类:
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);
}
}
}
}
}
为了简洁,我省略了SpaceShip,Beam和Rock课程。
答案 0 :(得分:0)
我发现了问题。我按照James_D的建议对我的代码进行了分析,发现所有滞后都是由 Shape.intersect(Shape,Shape)方法引起的,我用它进行更精确的碰撞检查。我用常规的Bounds检查方法替换它,现在它运行顺利。