Android - 为乒乓球游戏创建计时器循环 [英] Android - Creating a Timer loop for a pong game
问题描述
我有一个用 Java 编写的 Pong 游戏,我正在尝试将其移植到 Android.(这是我的第一个 Android 游戏;).
I have a Pong game that I wrote in Java and I'm trying to port it to Android. (It's my first Android game ;).
在 Java 中,我使用了一个 Timer
对象,它基本上更新了游戏值(球/球拍位置),然后重新绘制了屏幕.
In Java I used a Timer
object which basically updated the Game values (ball/paddles position) and then redrew the screen.
我正在尝试在 Android 中实现相同的功能,但出现了许多错误.
I'm trying to implement the same functionality in Android but I'm getting a number of errors.
我的程序包含一个 PongView
类,它是游戏的视觉部分,以及一个 PongDriverActivity
类,它使用 PongView
作为其视图.如果我有一个使 PongView
无效的循环线程,我会收到一个错误,因为该线程无法触摸在另一个线程上生成的视图.
My program consists of a PongView
class which is the visual part of the game, and a PongDriverActivity
class which uses PongView
for its view. If I have a looping thread invalidating PongView
I get an error because the thread can't touch a view spawned on another thread.
我假设我需要执行某种AsyncTask
,但我不确定如何循环.
I assume I need to do some sort of AsyncTask
, but I'm not sure how to loop that.
关于实现此目标的最佳方法有什么建议吗?
Any suggestions on what would be the best way to implement this?
推荐答案
有很多方法可以做到这一点.Android 确实支持普通的 Java Thread
对象,您可以使用它们.您可以搜索 (SO) for android game loop
并可能找到很多示例.但是,如果您想尝试 AsyncTask
,这里有一个示例实现:
There's many ways to do this. Android does support normal Java Thread
objects, and you can use those. You can search (SO) for android game loop
and probably find lots of examples. But, if you'd like to try AsyncTask
, here's a sample implementation:
public class PongView extends View {
public PongView(Context context) {
super(context);
}
public void setBallPosition(int x, int y) {
// relocate the ball graphic
}
}
然后,您的活动:
public class PongDriverActivity extends Activity implements OnSeekBarChangeListener {
private enum GameSpeed { SLOW, MEDIUM, FAST };
private PongView mGameView;
private PongDriverTask mWorker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGameView = new PongView(this);
mWorker = new PongDriverTask(GameSpeed.MEDIUM);
// if you need to pass some data to the worker:
mWorker.execute("one", "two", "three");
// else, declare the AsyncTask's first generic param as Void, and do:
//mWorker.execute();
setContentView(mGameView);
}
// you would connect this up to a button, to allow the user to stop
public void onStopClicked(View sender) {
if (mWorker.isRunning()) {
mWorker.stopRunning();
}
}
// you could connect this up to a slider, to allow the user to control the paddle
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// you may need to convert progress to a y-coordinate
mWorker.setPaddlePosition(progress);
}
然后(可能在 PongDriverActivity.java 内部,一个内部类):
And, then (maybe inside PongDriverActivity.java, an inner class):
private class PongDriverTask extends AsyncTask<String, Integer, Integer> {
private int mDelay;
private boolean mRunning = true;
private int mPaddleY = 0;
public PongDriverTask(GameSpeed speed) {
if (speed == GameSpeed.SLOW) {
mDelay = 100;
} else if (speed == GameSpeed.MEDIUM) {
mDelay = 50;
} else if (speed == GameSpeed.FAST) {
mDelay = 10;
}
}
public synchronized boolean isRunning() {
return mRunning;
}
public synchronized void stopRunning() {
mRunning = false;
}
public synchronized void setPaddlePosition(int y) {
mPaddleY = 0;
}
private synchronized int getPaddlePosition() {
return mPaddleY;
}
@Override
protected void onPostExecute(Integer score) {
super.onPostExecute(score);
// here you could show a UI that shows the final score
}
@Override
protected void onPreExecute() {
super.onPreExecute();
mGameView.setBallPosition(0, 0);
// here you could throw up some UI that shows just
// before the game really starts
}
@Override
protected void onProgressUpdate(Integer... params) {
super.onProgressUpdate(params);
// retrieve updated game coordinates from params
mGameView.setBallPosition(params[0], params[1]); // x,y
}
@Override
protected Integer doInBackground(String... args) {
// If you have some information to pass to the background worker,
// it would be passed in args[0], args[1], etc.
// It doesn't have to be String data. you could change the generic
// to take something other than String as the first param, in which
// case, doInBackground() would take a variable length list of that
// other data type.
int ballX = 0;
int ballY = 0;
int score = 0;
while (isRunning()) {
// use your game engine to recalculate the ball position
// on this background thread
int paddleY = getPaddlePosition();
ballX += 1;
ballY += 2;
score++;
// now, update the UI, which must happen on the UI thread
publishProgress(ballX, ballY);
try {
Thread.sleep(mDelay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return score;
}
}
任务的 doInBackground()
方法将在后台线程上运行,因此您不能直接从那里修改 UI.但是,我上面覆盖的所有其他 AsyncTask
方法都是在 UI 线程上调用的,因此在其中任何一个中执行 UI 工作都是安全的.
The task's doInBackground()
method will be run on a background thread, so you must not directly modify the UI from there. But, all the other AsyncTask
methods I override above are called on the UI thread, so it's safe to perform UI work in any of them.
此代码假定拨片由搜索栏控制,您可以将 Activity
设为更改侦听器.还有很多其他方法可以做到这一点.
This code assumes the paddle is controlled by a seek bar, which you'd make your Activity
a change listener for. Lots of other ways to do it, too.
我刚刚实现了一个粗略的游戏停止机制,您可以将其连接到一个按钮上.如果你想允许用户暂停和恢复,你可以搜索暂停/恢复线程的实现,这也应该适用于这里.例如:
I just implemented a crude game stop mechanism, which you could hook up to a button. If you want to allow the user to pause and resume, you can search for implementations to pause/resume threads, which should be applicable here, too. For example:
这篇关于Android - 为乒乓球游戏创建计时器循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!