使用自定义SurfaceView和线程进行Android游戏编程(示例)

时间:2014-07-22 15:00:39

标签: android surfaceview

我正在尝试使用SurfaceView,但lockCanvas(null)令人困惑,当我退出活动时应用会冻结。此外,没有任何显示,即使我使用的教程工作得很好,我不明白我做错了什么。请帮忙。

1 个答案:

答案 0 :(得分:1)

解决方案可能是setWillNotDraw(false);未被调用。

因此,正常工作的参考实现如下:

public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback
{
    private SurfaceHolder holder;

    private MyThread myThread;

    private GameController gameController;

    private Paint paint;

    private int width;
    private int height;

    public GameSurfaceView(Context context, GameController gameController, int width, int height)
    {
        super(context);
        holder = getHolder(); 

        holder.addCallback(this);

        this.gameController = gameController;
        this.width = width;
        this.height = height;
        paint = new Paint();
        //initialize paint object parameters

        setWillNotDraw(false); //this line is very important!
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder)
    {
    }

    @Override
    // This is always called at least once, after surfaceCreated
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    {
        if (myThread == null)
        {
            myThread = new MyThread(holder, gameController);
            myThread.setRunning(true);
            myThread.start();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder)
    {
        boolean retry = true;
        myThread.setRunning(false);
        while (retry)
        {
            try
            {
                myThread.join();
                retry = false;
            }
            catch (InterruptedException e)
            {
                Log.d(getClass().getSimpleName(), "Interrupted Exception", e);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        System.out.println(event.getX() + " " + event.getY());
        gameController.onTouchEvent(event); //handle user interaction
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        canvas.drawText("Hello world!", width/20, 20, paint);
        gameController.draw(canvas);
    }

    public Thread getThread()
    {
        return thread;
    }

    public class MyThread extends Thread
    {
        private SurfaceHolder holder;
        private boolean running = false;

        private GameController gameController;

        public MyThread(SurfaceHolder holder, GameController gameController)
        {
            this.holder = holder;
            this.gameController = gameController;
        }

        @Override
        public void run()
        {
            Canvas canvas = null;
            while (running)
            {
                gameController.update(); //update the time between last update() call and now
                try
                {
                    canvas = holder.lockCanvas(null);
                    synchronized (holder)
                    {
                        postInvalidate();
                    }
                }
                finally
                {
                    if (canvas != null)
                    {
                        holder.unlockCanvasAndPost(canvas);
                    }
                }
            }

        }

        public void setRunning(boolean b)
        {
            running = b;
        }
    }
}

表面本身并不想回答它的宽度和高度,因此如果我们从外部获取测量结果,并从外部为我们的自定义视图提供它,则更容易:

//Fragment onCreateView()
    Display display = getActivity().getWindowManager().getDefaultDisplay();
    RelativeLayout rl = (RelativeLayout)view.findViewById(R.id.gameplay_container);
    rl.addView(new GameSurfaceView(this.getActivity().getApplicationContext(), gameController, display.getWidth(), display.getHeight()));
    return view;
}

现在我们可以从我们自己的Thread中绘制到SurfaceView,并且我们还能够在GameController中分离所有与游戏相关的逻辑。 GameController负责输入处理和游戏事件更新,如下所示:

    public void update()
    {
        long delta = getTimeManager().getDeltaTime(System.currentTimeMillis());
        long timeChunk;
        if (isGameOver == false)
        {
            for (long i = 0; i < delta; i += 20)
            {
                long iNext = i + 20;
                if (iNext > delta)
                {
                    timeChunk = delta - i;
                }
                else
                {
                    timeChunk = iNext - i;
                }
                // ...update game entities based on the miliseconds provided in timeChunk
    }

要获得增量时间(自上次更新以来经过的时间),请执行以下操作:

    long temp = currentTimeMillis - oldTime;
    this.oldTime = currentTimeMillis;
    return temp;

我希望以后会对你有所帮助:))