JavaFX小行星游戏克隆:在相互弹起小行星时遇到困难

JavaFX小行星游戏克隆:在相互弹起小行星时遇到困难,java,javafx,Java,Javafx,我正在尝试用JavaFX制作一个小行星游戏克隆。到目前为止,我已经能够在屏幕上画出飞船和小行星(现在,矩形代表它们)。我还实现了飞船的移动,以及小行星的随机移动 我很难实现将小行星相互弹起所需的代码。当前进行碰撞检查的方法(称为检查小行星碰撞)存在缺陷,因为所有小行星都开始在适当的位置发生口吃。它们不会移动,而是在原地快速来回摆动。如果不调用此方法,所有小行星都会开始正常运行,并按预期运行 相反,我希望每颗小行星都能自由移动,当与另一颗小行星接触时,像在实际的小行星游戏中那样相互反弹 MainA

我正在尝试用JavaFX制作一个小行星游戏克隆。到目前为止,我已经能够在屏幕上画出飞船和小行星(现在,矩形代表它们)。我还实现了飞船的移动,以及小行星的随机移动

我很难实现将小行星相互弹起所需的代码。当前进行碰撞检查的方法(称为
检查小行星碰撞
)存在缺陷,因为所有小行星都开始在适当的位置发生口吃。它们不会移动,而是在原地快速来回摆动。如果不调用此方法,所有小行星都会开始正常运行,并按预期运行

相反,我希望每颗小行星都能自由移动,当与另一颗小行星接触时,像在实际的小行星游戏中那样相互反弹

MainApp.java

    import java.util.ArrayList;
    import java.util.HashSet;

    import javafx.animation.AnimationTimer;
    import javafx.application.Application;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.canvas.Canvas;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.input.KeyEvent;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.stage.Stage;

    public class MainApp extends Application {
        private static final int WIDTH = 700;
        private static final int HEIGHT = 900;

        private static final int NUM_OF_ASTEROIDS = 12;
        private static final Color ASTEROID_COLOR = Color.GRAY;

        private static final Color PLAYER_COLOR = Color.BLUE;

        private Player player;
        private ArrayList<Entity> asteroids;

        long lastNanoTime; // For AnimationTimer

        HashSet<String> inputs; // For inputs

       private static final int MAX_SPEED = 150;
       private static final int SPEED = 10;
       private static final int ASTEROID_SPEED = 150;

private StackPane background;

/*
 * Generates a random number between min and max, inclusive.
 */
private float genRandom(int min, int max) {
    return (float) Math.floor(Math.random() * (max - min + 1) + min);
}

/*
 * Initializes the asteroids
 */
private void initAsteroids() {
    this.asteroids = new ArrayList<Entity>();
    for (int i = 0; i < NUM_OF_ASTEROIDS; i++) {
        Entity asteroid = new Entity(50, 50, ASTEROID_COLOR, EntityType.ASTEROID);
        float px = (float) genRandom(200, WIDTH - 50);
        float py = (float) genRandom(200, HEIGHT - 50);
        asteroid.setPos(px, py);

        // Keep recalculating position until there are no collisions
        while (asteroid.intersectsWith(this.asteroids)) {
            px = (float) genRandom(200, WIDTH - 50);
            py = (float) genRandom(200, HEIGHT - 50);
            asteroid.setPos(px, py);
        }

        // Randomly generate numbers to change velocity by
        float dx = this.genRandom(-ASTEROID_SPEED, ASTEROID_SPEED);
        float dy = this.genRandom(-ASTEROID_SPEED, ASTEROID_SPEED);
        asteroid.changeVelocity(dx, dy);

        this.asteroids.add(asteroid);
    }
}

/*
 * Initializes the player
 */
private void initPlayer() {
    this.player = new Player(30, 30, PLAYER_COLOR, EntityType.PLAYER);
    this.player.setPos(WIDTH / 2, 50);
}

/*
 * Checks collisions with screen boundaries
 */
private void checkOffScreenCollisions(Entity e) {
    if (e.getX() < -50)
        e.setX(WIDTH);
    if (e.getX() > WIDTH)
        e.setX(0);
    if (e.getY() < -50)
        e.setY(HEIGHT);
    if (e.getY() > HEIGHT)
        e.setY(0);
}

/*
 * Controls speed
 */
private void controlSpeed(Entity e) {
    if (e.getDx() < -MAX_SPEED)
        e.setDx(-MAX_SPEED);
    if (e.getDx() > MAX_SPEED)
        e.setDx(MAX_SPEED);
    if (e.getDy() < -MAX_SPEED)
        e.setDy(-MAX_SPEED);
    if (e.getDy() > MAX_SPEED)
        e.setDy(MAX_SPEED);
}

/*
 * Controls each asteroid's speed and collision off screen
 */
private void controlAsteroids(ArrayList<Entity> asteroids) {
    for (Entity asteroid : asteroids) {
        this.checkOffScreenCollisions(asteroid);
        this.controlSpeed(asteroid);
    }
}

/*
 * Checks an asteroid's collision with another asteroid
 */
private void checkAsteroidCollisions() {
    for (int i = 0; i < NUM_OF_ASTEROIDS; i++) {
        Entity asteroid = this.asteroids.get(i);
        if (asteroid.intersectsWith(this.asteroids)){
            float dx = (float) asteroid.getDx();
            float dy = (float) asteroid.getDy();
            asteroid.setDx(0);
            asteroid.setDy(0);
            asteroid.changeVelocity(-dx, -dy);
        }
    }
}

@Override
public void start(Stage primaryStage) throws Exception {
    primaryStage.setTitle("Hello World!");

    this.initAsteroids();
    this.initPlayer();

    background = new StackPane();
    background.setStyle("-fx-background-color: pink");

    this.inputs = new HashSet<String>();

    Group root = new Group();
    Scene scene = new Scene(root);
    primaryStage.setScene(scene);

    scene.setOnKeyPressed(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent e) {
            String code = e.getCode().toString();
            inputs.add(code);
        }

    });

    scene.setOnKeyReleased(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent e) {
            String code = e.getCode().toString();
            inputs.remove(code);
        }

    });

    Canvas canvas = new Canvas(WIDTH, HEIGHT);
    GraphicsContext gc = canvas.getGraphicsContext2D();

    background.getChildren().add(canvas);
    root.getChildren().add(background);

    lastNanoTime = System.nanoTime();

    new AnimationTimer() {
        @Override
        public void handle(long currentNanoTime) {
            float elapsedTime = (float) ((currentNanoTime - lastNanoTime) / 1000000000.0);
            lastNanoTime = currentNanoTime;

            /* PLAYER */
            // Game Logic
            if (inputs.contains("A"))
                player.changeVelocity(-SPEED, 0);
            if (inputs.contains("D"))
                player.changeVelocity(SPEED, 0);
            if (inputs.contains("W"))
                player.changeVelocity(0, -SPEED);
            if (inputs.contains("S"))
                player.changeVelocity(0, SPEED);
            // Collision with edge of map
            checkOffScreenCollisions(player);
            // Control speed
            controlSpeed(player);
            player.update(elapsedTime);

            /* ASTEROIDS */
            gc.setFill(ASTEROID_COLOR);

            for(int i = 0; i < NUM_OF_ASTEROIDS; i++) {
                checkAsteroidCollisions(i); // BUGGY CODE   
            }
            controlAsteroids(asteroids);

            gc.clearRect(0, 0, WIDTH, HEIGHT);

            for (Entity asteroid : asteroids) {
                asteroid.update(elapsedTime);
                asteroid.render(gc);
            }

            gc.setFill(PLAYER_COLOR);
            player.render(gc);
        }

    }.start();

    primaryStage.show();
}

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

}
import java.util.ArrayList;
导入java.util.HashSet;
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.event.EventHandler;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.canvas.canvas;
导入javafx.scene.canvas.GraphicsContext;
导入javafx.scene.input.KeyEvent;
导入javafx.scene.layout.StackPane;
导入javafx.scene.paint.Color;
导入javafx.stage.stage;
公共类MainApp扩展应用程序{
专用静态最终整数宽度=700;
专用静态最终内部高度=900;
私人静态最终小行星数=12;
私有静态最终颜色小行星颜色=Color.GRAY;
私有静态最终颜色播放器\u Color=Color.BLUE;
私人玩家;
私人ArrayList小行星;
long lastnotime;//用于AnimationTimer
HashSet输入;//用于输入
专用静态最终int最大速度=150;
专用静态最终积分速度=10;
私人静态最终int小行星_速度=150;
私人背景;
/*
*生成最小值和最大值之间的随机数(包括最小值和最大值)。
*/
专用浮点数genRandom(最小整数,最大整数){
return(float)Math.floor(Math.random()*(max-min+1)+min);
}
/*
*初始化小行星
*/
私人小行星(){
this.asteroids=新ArrayList();
对于(inti=0;i宽度)
e、 setX(0);
如果(如getY()<-50)
e、 赛蒂(身高);
如果(如getY()>高度)
e、 setY(0);
}
/*
*控制速度
*/
私有void controlSpeed(实体e){
如果(如getDx()<-最大速度)
e、 setDx(-MAX_速度);
如果(如getDx()>最大速度)
e、 setDx(最大速度);
如果(如getDy()<-最大速度)
e、 setDy(-MAX_速度);
如果(例如getDy()>最大速度)
e、 setDy(最大速度);
}
/*
*在屏幕外控制每个小行星的速度和碰撞
*/
私人空间控制小行星(ArrayList小行星){
对于(实体小行星:小行星){
这是。检查斜外碰撞(小行星);
控制速度(小行星);
}
}
/*
*检查一颗小行星与另一颗小行星的碰撞
*/
私有的void检查{
对于(inti=0;i    import java.util.ArrayList;

    import javafx.geometry.Rectangle2D;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.paint.Color;

    public class Entity {
        private Color color;
        private double x, y, width, height, dx, dy;
        private EntityType entityType; // ID of this Entity

public Entity(float width, float height, Color color, EntityType type) {
    this.x = this.dx = 0;
    this.y = this.dy = 0;
    this.width = width;
    this.height = height;
    this.color = color;
    this.entityType = type;
}

/*
 * Getters and setters
 */
public Color getColor() {
    return color;
}

public void setColor(Color color) {
    this.color = color;
}

public double getX() {
    return x;
}

public void setX(float x) {
    this.x = x;
}

public double getY() {
    return y;
}

public void setY(float y) {
    this.y = y;
}

public double getDx() {
    return dx;
}

public void setDx(float dx) {
    this.dx = dx;
}

public double getDy() {
    return dy;
}

public void setDy(float dy) {
    this.dy = dy;
}

public EntityType getEntityType() {
    return entityType;
}

/*
 * Adds to dx and dy (velocity)
 */
public void changeVelocity(float dx, float dy) {
    this.dx += dx;
    this.dy += dy;
}

/*
 * Sets position
 */
public void setPos(float x, float y) {
    this.setX(x);
    this.setY(y);
}

/*
 * Gets new position of the Entity based on velocity and time
 */
public void update(float time) {
    this.x += this.dx * time;
    this.y += this.dy * time;
}

/*
 * Used for collisions
 */
public Rectangle2D getBoundary() {
    return new Rectangle2D(this.x, this.y, this.width, this.height);
}

/*
 * Checks for intersections
 */
public boolean intersectsWith(Entity e) {
    return e.getBoundary().intersects(this.getBoundary());
}

/*
 * If any of the entities in the passed in ArrayList 
 * intersects with this, then return true;
 */
public boolean intersectsWith(ArrayList<Entity> entities) {
    for(Entity e : entities) {
        if(e.getBoundary().intersects(this.getBoundary()))
            return true;
    }
    return false;
}


/*
 * Draws the shape
 */
public void render(GraphicsContext gc) {
    gc.fillRoundRect(x, y, width, height, 10, 10);
}

@Override
public String toString() {
    return "Entity [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + ", entityType=" + entityType
            + "]";
}

}