我有一个乒乓球比赛,我用Java写的,我想将它移植到Android。 (这是我的第一个Android游戏)。
在Java我使用的Timer
,其基本上更新了游戏的值(球/桨位置),然后重画屏幕对象。
我想实现的Android相同的功能,但我得到了一些错误。
我的程序由一个的PongView
类,这是游戏的视觉部分,和PongDriverActivity
它使用类PongView
其观点。 如果我有一个循环的线程无效PongView
我得到一个错误,因为线程不能碰观点产生了另一个线程。
我想我需要做某种AsyncTask
,但我不知道如何环路。
什么任何建议将是实现这一目标的最佳方式是什么?
有很多方法可以做到这一点。 Android提供支持普通的Java Thread
对象,你可以使用这些。 您可以搜索(SO)的android game loop
,并可能会发现很多例子。 但是,如果你想尝试AsyncTask
,这里有一个简单的实现:
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,一个内部类):
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工作。
此代码假定桨通过搜索栏,你会做你的控制Activity
的变化侦听。 其他很多方式做到这一点,太。
我只是实现了一个原油游戏停止机制,你可以钩到一个按钮。 如果你想允许用户暂停和恢复,你可以搜索到的实现暂停/恢复线程,这应该是适用在这里也。 例如:
如何暂停,并从另一个线程恢复Java中的一个线程
更多阅读...
看到这个书面记录的游戏循环的速度进行了一些讨论 ...
也许看看这个讨论,也