java游戏如何构造定时效果/定距效果?

标签 java javafx timer game-physics 2d-games

我正在用 javafx 编写一个 java 游戏,但我认为这个问题的解决方案并不是 javafx 独有的......

我有一个实体类和一堆它的子类,如导弹、激光等。 但是,当导弹和激光是由游戏中的角色创建时,它们总是会一直运行,直到它们碰到 Canvas 的矩形边界或当它们击中一个角色并消失。

但是,我预计导弹/激光还有许多其他行为:

  • 导弹可以继续飞行,直到 4 秒后消失
  • 导弹飞行600像素后可以继续飞行直到消失(这个和上一个类似)
  • 激光可以存在于矩形区域中或与角色一起移动,直到它在 4 秒后消失。

  • 问题是,我们如何才能达到这种定时效果? (也许是 propertyChangeListener?)或者我应该向实体本身添加内容,还是应该考虑更改我的 Controller 类?
    这是我拥有的代码:
    public abstract class Entity implements Collidable{
    
    private double x;
    private double y;
    private int z;
    private double velocityX;
    private double velocityY;
    private Image img;
    private boolean ally;
    protected double width;
    protected double height;
    
        public Entity(int x,int y,int z,boolean b,Image hihi)
        {
         setX(x);
         setY(y);
         setZ(z);
          ally=b;
         setVelocityX(0);
         setVelocityY(0);
         img= hihi;
        }
        public void move()
        {       
            x+=getVelocityX();
            y+=getVelocityY();
        }
    
      ...
      ...
    }
    
    public class Controller {
    
    private List<BattleShip> bs;
    private List<Missile> m;
    private Rectangle2D rect;
    
    
    public Controller()
    {
        bs= new ArrayList<BattleShip>();
        m= new ArrayList<Missile>();
        rect= new Rectangle2D(-300, -300, 1300, 1050);
    }
    public void update()
    {
    
        for(int i = bs.size() - 1; i >= 0; i --) {
            bs.get(i).move();
            if (!rect.contains(bs.get(i).getRect())) {
            bs.remove(i);
                  }
            }
        for(int i = m.size() - 1; i >= 0; i --) {
            m.get(i).move();
              if (!rect.contains(m.get(i).getRect())) {
                m.remove(i);
              }
            }
        collide();
    }
    

    更新[看起来不错:)]:

    enter image description here

    最佳答案

    好吧,我不是游戏行业的专家,但这是我的建议:

  • 有一个变量( boolean 值)显示对象的状态。
  • private volatile boolean isDestroyed = false ;

  • 注意 : volatile 是必要的!
  • 如果游戏对象有时间限制(自毁),那么在它的构造函数(或通常在它的类中)创建时,启动一个在你想要的持续时间内 hibernate 的任务,并在任务结束时将 isDestroyed 变量更新为 true。

  • 注意 :您还可以在 Task 中放置销毁游戏对象的动画。
  • 在执行所有渲染操作的主要 update() 中,您可以忽略渲染游戏对象或将其从列表中删除(小心避免 ConcurrentModificationException )

  • 编辑 :
    所以让我们尝试一个例子..下面的代码不是绘制/移动形状的最佳方式,它只是为了展示我的解决方案。

    主类
    import java.util.ArrayList;
    import java.util.Random;
    import javafx.animation.AnimationTimer;
    import javafx.application.Application;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.canvas.Canvas;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.stage.Stage;
    
    public class TestApp extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage stage) throws Exception {
    
            Group root = new Group();
            Scene theScene = new Scene(root);
            stage.setScene(theScene);
    
            Canvas canvas = new Canvas(512, 820);
            root.getChildren().add(canvas);
    
            GraphicsContext gc = canvas.getGraphicsContext2D();
    
            ArrayList<Lasser> allLassers = new ArrayList<>();
    
            Random randGen = new Random();
    
            for (int i = 0; i < 10; i++) {
                // create 10 lessers with different self-destruction time
                // on random places
                allLassers.add(new Lasser(randGen.nextInt(500) + 10, 800, i * 1000));
            }
    
            new AnimationTimer() {
                public void handle(long currentNanoTime) {
                    // Clear the canvas
                    gc.clearRect(0, 0, 512, 820);
    
                    for (Lasser l : allLassers) {
                        // if the current object is still ok
                        if (!l.isDestroyed()) {
                            // draw it
                            gc.fillRect(l.getxPos(), l.getyPos(), l.getWidth(), l.getHeight());
                        }
                    }
    
                    // remove all destroyed object
                    for (int i = allLassers.size() - 1; i >= 0; i--) {
                        if (allLassers.get(i).isDestroyed()) {
                            allLassers.remove(i);
                        }
                    }
                }
            }.start();
    
            stage.show();
        }
    }
    

    小类
    import javafx.concurrent.Task;
    import javafx.scene.shape.Rectangle;
    
    public class Lasser extends Rectangle {
    
        private volatile boolean isDestroyed = false;
    
        private double xPos;
        private double yPos;
    
        public Lasser(double x, double y, long time) {
            super(x, y, 5, 20);
            this.xPos = x;
            this.yPos = y;
            startSelfDestruct(time);
        }
    
        private void startSelfDestruct(long time) {
    
            Task<Void> task = new Task<Void>() {
                @Override
                protected Void call() {
                    try {
                        Thread.sleep(time);
                    } catch (InterruptedException e) {
                    }
                    return null;
                }
            };
    
            task.setOnSucceeded(e -> {
                isDestroyed = true;
            });
    
            new Thread(task).start();
        }
    
        public void move(double x, double y) {
            this.xPos = x;
            this.yPos = y;
        }
    
        public boolean isDestroyed() {
            return isDestroyed;
        }
    
        public double getxPos() {
            return xPos;
        }
    
        public double getyPos() {
            this.yPos -= 1;
            return yPos;
        }
    
    }
    

    关于java游戏如何构造定时效果/定距效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46760004/

    相关文章:

    java - 文本区域未随按钮操作执行事件更新

    wpf - 在不丢失单元格焦点的情况下刷新 WPF DataGrid

    java - 如何根据按钮单击在新屏幕上的 webview 中打开 url

    java - 让 log4j 以 UTC 时间登录

    java - 为什么我看不到项目中的更改,但在 fxml 文件中看到它们?

    javafx - JavaFX 中的 AutoScalePane 与 layoutChildren()

    android - 如何在不执行任何操作的情况下在 Activity 开始时启动倒数计时器?

    ios - 如何使 ViewDidLoad 之外的计时器无效

    java - 在netty中的单例类中使用threadlocal

    java - 如何从 JavaFX 应用程序读取 X11 剪贴板?