我正试图解决这个问题超过2天,并且变得非常绝望。
我想为Android写一个'Checkers-like'棋盘游戏。游戏引擎本身有点完整但我在更新视图方面遇到了问题。
我写了一个小例子来演示我的问题:
public class GameEngineView extends View {
private static final String TAG = GameEngineView.class.getSimpleName();
private int px;
private int py;
private int cx;
private int cy;
private boolean players_move;
private int clickx;
private int clicky;
Random rgen;
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
GameEngineView.this.update();
GameEngineView.this.invalidate();
Log.d(TAG, "invalidate()");
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public GameEngineView(Context context) {
super(context);
setFocusable(true);
players_move = true;
rgen = new Random();
}
public void update() {
updateGame();
Log.d(TAG, "update -> sleep handler");
mRedrawHandler.sleep(100);
}
public void updateGame() {
if(players_move) {
px = clickx;
py = clicky;
} else {
calcAIMove();
switchMove();
}
}
public void switchMove() {
players_move = !players_move;
}
public void calcAIMove() {
for(int i = 0; i < 20000; i++) {
cx = rgen.nextInt(getWidth());
cy = rgen.nextInt(getHeight());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "event");
int eventaction = event.getAction();
if(eventaction == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "action_down");
clickx = (int) event.getX();
clicky = (int) event.getY();
switchMove();
update();
}
return super.onTouchEvent(event);
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint green = new Paint();
green.setColor(Color.GREEN);
Paint red = new Paint();
red.setColor(Color.RED);
canvas.drawColor(Color.BLACK);
canvas.drawCircle(px, py, 25, green);
canvas.drawCircle(cx, cy, 25, red);
}
}
函数calcAIMove()只会耗费时间来模拟棋盘游戏中位置的真实评估。
现在我的问题是:如果玩家点击(移动),当ai移动计算完成时,首先绘制绿球。所以两个动作都是同时绘制的。
我想知道如何做到这一点: -Player点击 - 绿球被绘制 -AI计算 - 绘制的球 - 等等..
在搜索网页时,我发现了许多游戏循环示例,但它们都需要一个具有常量轮询的线程..如果没有这个,应该可以,因为整个程序按顺序运行..对吗?
希望得到建议。
感谢, 戴夫
答案 0 :(得分:2)
以下是您的游戏如何运作:
在这样的回合制游戏中不需要持续轮询。您应该睡觉的唯一地方是步骤4,因此您可以将其从其他区域移除(不需要旧的update()
方法,这只是对updateGame()
的延迟调用)。
实现此目的的一种方法是将calcAIMove()
和switchMove()
的呼叫推迟到Runnable
并使用Handler.postDelayed()
或类似内容。
我不知道在轮到CPU时你是如何禁用触摸事件的,如果switchMove()
和update()
仍被调用,可能会导致许多其他问题... < / p>
答案 1 :(得分:0)
在你的游戏循环中,你可以使用TimerTask的一个实例来确保greenBall和其他绘图任务之间的某些延迟。像Snake和LunarLander这样的游戏教程是关于何时以及是否需要使View无效的很好的参考。希望这有所帮助!
答案 2 :(得分:0)
好的,所以antonyt提供的答案帮助我解决了这个问题。我为其他感兴趣的人提供了更正的代码。
public class GameEngineView extends View {
private static final String TAG = GameEngineView.class.getSimpleName();
private int px;
private int py;
private int cx;
private int cy;
private boolean players_move;
private int clickx;
private int clicky;
Random rgen;
/**
* Create a simple handler that we can use to cause animation to happen. We
* set ourselves as a target and we can use the sleep()
* function to cause an update/invalidate to occur at a later date.
*/
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
GameEngineView.this.update();
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public GameEngineView(Context context) {
super(context);
setFocusable(true);
players_move = true;
rgen = new Random();
}
public void update() {
if(players_move) {
Log.d(TAG, "new player x");
px = clickx;
py = clicky;
GameEngineView.this.invalidate();
switchMove();
mRedrawHandler.sleep(100);
} else {
Log.d(TAG, "new ai x");
calcAIMove();
GameEngineView.this.invalidate();
switchMove();
}
Log.d(TAG, "update -> sleep handler");
}
public void switchMove() {
players_move = !players_move;
}
public void calcAIMove() {
for(int i = 0; i < 100000; i++) {
cx = rgen.nextInt(getWidth());
cy = rgen.nextInt(getHeight());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "event");
int eventaction = event.getAction();
if(players_move && eventaction == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "action_down");
clickx = (int) event.getX();
clicky = (int) event.getY();
update();
}
return super.onTouchEvent(event);
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
Paint green = new Paint();
green.setColor(Color.GREEN);
Paint red = new Paint();
red.setColor(Color.RED);
canvas.drawCircle(px, py, 25, green);
canvas.drawCircle(cx, cy, 25, red);
}
}