我正在创建一个动画,基本上一个球在屏幕上移动。但是,我遇到了口吃,使游戏不那么可玩。请看一下我的代码,非常欢迎任何指向正确的方向!
GameActivity.java - >启动游戏循环,并处理更新。
Thread gameThread = new Thread(this);
public boolean running = true;
private final static int MAX_FPS = 60;
private final static int MAX_FRAME_SKIPS = 5;
private final static int FRAME_PERIOD = 1000000000/MAX_FPS;
private final static int FPS_COUNTER_REPORTTIME = 1000000000;
long lastFPSReport;
int UPS; //updates per second
public static int DPS; //draws per second
public SurfaceView gameView;
public void init() {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point screenDim = new Point();
display.getRealSize(screenDim);
width = screenDim.x;
height = screenDim.y;
initGame();
gameThread.start();
}
public void initGame() {
fingerX = (width / 2);
fingerY = height * 0.90f;
GamePlatform platform = new GamePlatform(fingerX, fingerY, width * 0.3f, height * 0.025f, 0, 0);
GameBall ball = new GameBall(fingerX - 50, height * 0.8f - 50, 100, 100, 20, 20);
}
@Override
public void run() {
Canvas canvas = null;
Log.d("testlog", "Starting game loop");
lastFPSReport = System.nanoTime();
while(running) {
beginTime = System.nanoTime();
framesSkipped = 0;
try{
canvas = gameView.getHolder().lockCanvas();
update();
synchronized (gameView.getHolder()) {
gameView.postInvalidate();
}
timeDiff = System.nanoTime() - beginTime;
sleeptime = (int)(FRAME_PERIOD - timeDiff);
long sleeptimeMillis = (long) (Math.floor(sleeptime / 1000000));
int sleeptimeNanos = (int)(sleeptime - (sleeptimeMillis * 1000000));
if(sleeptime > 0) {
try{
Thread.sleep(sleeptimeMillis, sleeptimeNanos);
}catch(InterruptedException e) {}
}
while (sleeptime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
//only update
update();
sleeptime += FRAME_PERIOD;
framesSkipped++;
}
}finally {
if(canvas != null) {
gameView.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
public void update() {
UPS++;
//FPS counter
if(System.nanoTime() - lastFPSReport > FPS_COUNTER_REPORTTIME) {
Log.d("testlog", "UPS: " + UPS + " | DPS: " + DPS);
lastFPSReport = System.nanoTime();
UPS = 0;
DPS = 0;
}
//Entities
GameEntity.updateAllEntities();
}
GameBall.java - &gt;处理更新和绘制球,扩展GameEntity.java(见下文)
public class GameBall extends GameEntity {
public GameBall(float x, float y, float width, float height, float dx, float dy) {
super(x, y, width, height, dx, dy, "ballMain");
}
@Override
public void update() {
ArrayList<GameEntity> entityList = getEntityList();
//Collision
for(int i = 0; i < entityList.size(); i++) {
GameEntity entity = entityList.get(i);
if(entity.getType() != "ballMain") {
if(this.getX() < entity.getX() + entity.getWidth() && this.getX() + this.getWidth() > entity.getX() && this.getY() < entity.getY() + entity.getHeight() && this.getY() + this.getHeight() > entity.getY()) {
if(Math.abs(this.getDx()) < Math.abs(entity.getDx())) this.setDx(entity.getDx());
if(Math.abs(this.getDy()) < Math.abs(entity.getDy())) this.setDy(entity.getDy());
if(this.getDx() > 20) entity.setDx(20);
else if(this.getDx() < -20) entity.setDx(-20);
if(this.getDy() > 20) entity.setDy(20);
else if(this.getDy() < -20) entity.setDy(-20);
}
}
}
this.setX(this.getX() + this.getDx());
this.setY(this.getY() + this.getDy());
//walls
if(this.getX() + this.getWidth() >= GameActivity.width || this.getX() <= 0) {
this.setDx(-this.getDx());
}
if(this.getY() <= 0) {
this.setDy(-this.getDy());
}else if(this.getY() + this.getHeight() >= GameActivity.height) {
Log.d("testlog", "game over");
this.setDy(-this.getDy());
}
}
@Override
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawOval(new RectF(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight()), paint);
}
}
GameEntity.java:
public abstract class GameEntity {
float x = 0, y = 0, width = 0, height = 0;
float dx = 0, dy = 0;
String type;
static ArrayList<GameEntity> entityList = new ArrayList();
public GameEntity(float x, float y, float width, float height, float dx, float dy, String type) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.dx = dx;
this.dy = dy;
this.type = type;
entityList.add(this);
}
public static void updateAllEntities() {
for(int i = 0; i < entityList.size(); i++) {
entityList.get(i).update();
}
}
public void update() {
this.x += this.dx;
this.y += this.dy;
}
public static void drawAllEntities(Canvas canvas) {
for(int i = 0; i < entityList.size(); i++) {
entityList.get(i).draw(canvas);
}
}
public abstract void draw(Canvas canvas);
//Getters and Setters
public ArrayList<GameEntity> getEntityList() {
return entityList;
}
public float getX() {
return this.x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return this.y;
}
public void setY(float y) {
this.y = y;
}
public float getWidth() {
return this.width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return this.height;
}
public void setHeight(float height) {
this.height = height;
}
public Point getAbsCenter() {
return new Point((int)(this.x + (this.width / 2)), (int)(this.y + (height / 2)));
}
public Point getSurfaceCenter() {
return new Point((int)(this.x + (this.width / 2)), (int)(this.y));
}
public float getDx() {
return this.dx;
}
public void setDx(float speed) {
this.dx = speed;
}
public float getDy() {
return this.dy;
}
public void setDy(float speed) {
this.dy = speed;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
}
FPS计数器日志示例:
06-24 16:40:43.304 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 51 | DPS: 46
06-24 16:40:44.308 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 55 | DPS: 55
06-24 16:40:44.786 30689-30793/com.zenodhaene.keepitup D/testlog: game over
06-24 16:40:45.324 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 49 | DPS: 49
06-24 16:40:46.330 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 53 | DPS: 53
06-24 16:40:46.566 30689-30793/com.zenodhaene.keepitup D/testlog: game over
06-24 16:40:47.345 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 54 | DPS: 54
06-24 16:40:48.344 30689-30793/com.zenodhaene.keepitup D/testlog: game over
06-24 16:40:48.363 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 56 | DPS: 56
06-24 16:40:49.490 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 50 | DPS: 19
06-24 16:40:50.213 30689-30793/com.zenodhaene.keepitup D/testlog: game over
06-24 16:40:50.514 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 60 | DPS: 0
06-24 16:40:51.516 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 63 | DPS: 1
06-24 16:40:51.855 30689-30793/com.zenodhaene.keepitup D/testlog: game over
06-24 16:40:52.522 30689-30793/com.zenodhaene.keepitup D/testlog: UPS: 62 | DPS: 44
答案 0 :(得分:1)
在视频游戏中使用的解决方案是将每个移动因子乘以最后一帧(也称为增量时间)之间的时间,您应该尝试去看看这个
答案 1 :(得分:1)
根据经验,您绝对应该避免在onDraw()
中分配/取消分配内存。
您正在使用它来创建Paint
对象。由于onDraw()
每秒最多被调用60次,因此创建方法的性能受到巨大影响。只需将Paint
对象移动到类的字段并初始化一次即可。这将为初学者提供一个很好的保存。
Yan绝对是关于更新的。使用某种插值将为您提供更流畅的动画。有一个很棒的article你可以看看优化你的游戏线程。