我正在为桌面制作一个飞扬的小鸟游戏作为一种学习体验,但不幸的是,出了点问题,我不知道如何解决。这是我的第一个滚动背景游戏,带有 fps 计算。
让我解释一下问题:
当我的游戏以 60 fps 运行时,这只鸟基本上看起来会随着背景快速地前后移动,如下所示:
当我将我的游戏更改为 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);
}
}
支柱包。
是什么导致了这种奇怪的渲染?