Android - 为乒乓球游戏创建计时器循环 [英] Android - Creating a Timer loop for a pong game

查看:17
本文介绍了Android - 为乒乓球游戏创建计时器循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用 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:

如何在 Java 中从另一个线程暂停和恢复一个线程

有关游戏循环速度的一些讨论,请参阅这篇文章 ...

或许也可以看看这个讨论

这篇关于Android - 为乒乓球游戏创建计时器循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆