View Invalidate() 和 Handler 的问题
我已经尝试解决这个问题超过两天了,并且已经变得非常绝望。
我想为 Android 编写一个“类似西洋跳棋”的棋盘游戏。游戏引擎本身有点完整,但我在更新视图时遇到问题。
我写了一个小示例类来演示我的问题:
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计算 - 红球被抽出 -等等..
在网上搜索时,我发现了很多游戏循环示例,但它们都需要一个不断轮询的线程..没有这个应该是可能的,因为整个程序是按顺序运行的..对吧?
希望得到建议。
谢谢, 戴夫
i'm trying to fix this problem for more than 2 days now and have become quite desperate.
I want to write a 'Checkers-like' board game for android. The game engine itself is kinda complete but i have problems with updating the views.
I wrote a little example class to demonstrate my problem:
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);
}
}
The function calcAIMove() just burns time to simulate a real evaluation of the position in a board game.
Now my Problem is: If the player clicks(makes a move) the green ball is first drawn when the ai move calculation has been complete. So both moves are drawn at the same time.
I wonder HOW to accomplish this:
-Player clicks
-green Ball is drawn
-AI calculates
-red ball is drawn
-and so on..
When searching the web i found a lot of game loop examples but they all need a Thread with constant polling.. it should be possible without this since the whole program runs sequentially .. right?
Hoping for advice.
thanks,
Dave
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的游戏的工作方式如下:
在这样的回合制游戏中不需要不断地轮询。唯一应该睡眠的地方是在步骤 4 中,因此您可以将其从其他区域中删除(不需要旧的
update()
方法,该方法只是延迟调用updateGame( )
)。实现此目的的一种方法是简单地延迟对
calcAIMove()
和switchMove()
的调用,方法是将其放入Runnable
并使用Handler.postDelayed()
或类似的。我不明白你如何在轮到 CPU 时禁用触摸事件,如果
switchMove()
和update()
被禁用,这可能会导致许多其他问题仍然被称为...Here is how your game could work:
There is no need for constant polling in a turn-based game like this. The only place you should have sleep is in step 4, so you can remove it from the other areas (no need for the old
update()
method which is just a delayed call toupdateGame()
).One way to implement this is to simply delay the call to
calcAIMove()
andswitchMove()
by putting it into aRunnable
and usingHandler.postDelayed()
or similar.I don't see how you are disabling touch events when it is the CPU's turn, which can lead to a host of other problems if
switchMove()
andupdate()
are still being called...在游戏循环中,您可以使用 TimerTask 的实例来确保 greenBall 和其他绘图任务之间存在一定的延迟。像 Snake 和 LunarLander 这样的游戏教程是关于何时以及是否需要使视图失效的很好的参考。希望这会有所帮助!
In your game loop you can use a instance of TimerTask to ensure certain delay between greenBall and some other drawing task. Game tutorials like Snake and LunarLander are great references on when and if you need to invalidate your View. Hope this helps a little!
好的,antonyt 提供的答案帮助我解决了这个问题。我为其他感兴趣的人提供了正确的代码。
}
ok so the answer provided by antonyt helped me solve this.. I provide the corrected code for other interested ones.
}