0

我正在为桌面制作一个飞扬的小鸟游戏作为一种学习体验,但不幸的是,出了点问题,我不知道如何解决。这是我的第一个滚动背景游戏,带有 fps 计算。

让我解释一下问题:

当我的游戏以 60 fps 运行时,这只鸟基本上看起来会随着背景快速地前后移动,如下所示:

(以 MP4 格式观看)

当我将我的游戏更改为 20 fps 时,它会飞得很好,但有时会向前小跳。

我不确定是我的电脑,还是我的渲染,或者我的游戏循环,还是我的小鸟运动系统。

什么可能导致这个问题?这是我的来源:

FlappyBird.java

public class FlappyBird extends Window {

    private static final long serialVersionUID = 1L;

    private Screen gameScreen;
    private boolean game = false;
    private Level level = new Level(this);
    private long lastLoop = System.nanoTime();
    private long lastFps = 0;
    private int fps = 0;

    private Bird myBird = new Bird(Constants.START_X, Constants.START_Y, this);

    public FlappyBird() {
        this.gameScreen = new Screen(this);
        this.level.generateLevel();
    }

    public void initialize() {
        super.setGameScreen(this.gameScreen);
        this.game = true;
        this.gameLoop();
    }

    public Bird getBird() {
        return this.myBird;
    }

    public Level getLevel() {
        return this.level;
    }

      private void gameLoop() {
            new Thread() {

                private long last;
                private long start;
                private int wait;

                public void run() {
                    long millisPerSecond = TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
                    long optimalDelay =  Math.round(millisPerSecond / Constants.OPTIMAL);
                    optimalDelay = TimeUnit.MILLISECONDS.toNanos(optimalDelay);              
                    long loop = System.nanoTime();
                    while (game) {
                        long now = System.nanoTime();
                        update(0);
                        render();
                        long timeTaken = System.nanoTime();
                        long delta = timeTaken - now;
                        long delay = optimalDelay - delta;
                        if (delay > 0) {
                            try {
                                delay = TimeUnit.NANOSECONDS.toMillis(delay);
                                Thread.sleep(delay);
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        }
                        long loopDelay = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - loop);
                        if (loopDelay >= 1) {

                            loop = System.nanoTime();
                            System.out.println("FPS = " + fps);
                            fps = 0;
                        } else {
                            fps++;
                        }
                    }
                }
            }.start();
        }

    private void update(double delta) {
        if (System.currentTimeMillis() - this.level.getTime() >= Constants.TRANSLATE_SPEED) {
            this.level.updateTranslate();
            this.getBird().move();
            this.level.setTime();
        }


    }

    private void render() {
        super.repaint();
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                FlappyBird bird = new FlappyBird();
                bird.initialize();
            }
        }).start();
    }
}

Window,你真的不需要,因为它只包含我的 JPanel,screen.java:

@SuppressWarnings("serial")
public class Screen extends JPanel {

    private FlappyBird game;
    private Background background;

    public Screen(FlappyBird bird) {
        this.game = bird;
        this.background = new Background(this.game);
        this.background.generateBackgrounds();
    }

    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;

        int translateAmount = this.game.getLevel().getTranslate();
        g.translate(-translateAmount, 0);
        this.background.render(g2d);    
        this.game.getLevel().renderLevel(g2d);
        this.game.getBird().render(g2d);

    }
}

Background.java(用于 bg 重复):

public class Background {

    private class RepeatedBackground {

        private int x;

        public RepeatedBackground(int x) {
            this.x = x;
        }

        public int getX() {
            return this.x;
        }

        public void render(Graphics2D g) {
            g.drawImage(new Sprite(Constants.BACKGROUND).getSprite(), x, 0, null);
        }
    }

    private FlappyBird game;
    private List<RepeatedBackground> repeats = new ArrayList<RepeatedBackground>();

    public Background(FlappyBird game) {
        this.game = game;
    }

    public void generateBackgrounds() {
        int x = 0;
        for (int i = 0; i < Constants.BACKGROUND_WORLD_SIZE; i++) {
            this.repeats.add(new RepeatedBackground(x));
            x += Constants.BACKGORUND_SPRITE_WIDTH;
        }
    }

    public void render(Graphics2D g) {
        Iterator<RepeatedBackground> itr = this.repeats.iterator();
        while (itr.hasNext()) {
            RepeatedBackground b = itr.next();
            if (this.game.getLevel().getTranslate() - b.getX() >= 300) {
                itr.remove();
                continue;
            }
            if (b.getX() - this.game.getLevel().getTranslate() < Constants.WIDTH) {
                b.render(g);
            }
        }
    }
}

常量.java:

public final class Constants {

    public static final String SPRITE_BASE = "Data/Sprites/";
    public static final String PILLAR = "pillar.png";
    public static final String END = "end.png";
    public static final String END_BOTTOM = "endBottom.png";    
    public static final String BACKGROUND = "background.png";

    public static final int WIDTH =700;
    public static final int HEIGHT = 512;

    public static final Random rand = new Random();

    public static final int LEVEL_AMOUNT = 25;
    public static final int BACKGROUND_WORLD_SIZE = 35;
    public static final int BACKGORUND_SPRITE_WIDTH = 288;
    public static final int BACKGROUNDS_PER_TIME = 4;

    public static final int TRANSLATE_SPEED = 35;
    public static final int TRANSLATE_SPEED_MOVE = 6;

    // GAME LOOP
    public static final long OPTIMAL = 60;

    // BIRD

    public static final int START_X = 450;
    public static final int START_Y = 250;
    public static final Sprite BIRD = new Sprite("bird.png");

    // Bird Physics constants

    public static final int MOVEMENT_SPEED = 6;
    public static final double MOVEMENT_TIME = 1;


}

级别.java:

public class Level {

    private FlappyBird instance;
    private List<Pillars> pillars = new ArrayList<Pillars>();
    private int translate = 0;
    private long lastMovementTime;

    public Level(FlappyBird bird) {
        this.instance = bird;
    }

    public void generateLevel() {
        this.pillars.clear();
        int x = 900;
        for (int i = 0; i < 25; i++) {
            int random = Constants.rand.nextInt(2);
            this.pillars.add(PillarsFactory.createPillars(x, this.intToEnum(random)));
            x += 275;
        }
    }

    public void renderLevel(Graphics2D g) {
        for (Pillars p : this.pillars) {
            p.renderPillars(g);
        }
    }

    public List<Pillars> getPillars() {
        return this.pillars;
    }

    public long getTime() {
        return this.lastMovementTime;
    }

    public int getTranslate() {
        return this.translate;
    }

    public void updateTranslate() {
        this.translate += Constants.TRANSLATE_SPEED_MOVE;
    }

    public void resetTranslate() {
        this.translate = 0;
    }

    public PillarType intToEnum(int i) {
        switch (i) {
            case 0:
                return PillarType.TOP;
            case 1:
                return PillarType.MIDDLE;
            case 2:
                return PillarType.BOTTOM;
        }
        return null;
    }

    public void setTime() {
        this.lastMovementTime = System.currentTimeMillis();
    }
}

鸟.java:

public class Bird {

    private int x;
    private int y;
    private Sprite bird = Constants.BIRD;
    private FlappyBird instance;
    private long lastMove;

    public Bird(int x, int y, FlappyBird instance) {
        this.x = x;
        this.y = y;
        this.instance = instance;
    }

    public Sprite getSprite() {
        return this.bird;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;
    }

    public void move() {
        this.x += Constants.MOVEMENT_SPEED;
        for (Pillars p : this.instance.getLevel().getPillars()) {
            Pillar a = p.getBottom();
            Pillar b = p.getBottom();
            if (this.x >= a.getX() && this.x <= a.getX() + a.getWidth() &&
                    this.y >= a.getY() && this.y <= a.getY() + a.getHeight()) {
                System.out.print("yes!");
            }
        }
    }

    public void render(Graphics2D g) {
        g.drawImage(this.bird.getSprite(), this.x, this.y, null);
    }
}

支柱包

是什么导致了这种奇怪的渲染?

4

0 回答 0