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

标签 android surfaceview

我正在尝试使用 SurfaceView,但 lockCanvas(null) 令人困惑,并且当我退出 Activity 时应用程序会卡住。另外,即使我使用的教程运行得很好,也没有显示任何内容,而且我不明白我做错了什么。请帮忙。

最佳答案

解决方案可能是未调用 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;
        }
    }
}

表面本身并不真正想要回答它的宽度和高度是多少,因此如果我们从外部获取它的测量值,并从外部将其提供给我们的自定义 View ,会更容易:

//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;
}

现在我们可以从我们自己的线程中绘制到 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;

希望对你以后有帮助:)

关于android - 使用自定义SurfaceView和线程进行Android游戏编程(示例),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24890900/

相关文章:

java - MathTransform 在 Android 项目中不起作用 : "The type java.awt.geom.Point2D$Double cannot be resolved."

android - 即使时间过去了,也会重复调用警报

Android:如何在已经显示 Camara 预览的 Surfaceview 上绘图

android - 如何在 Surface/Gl View Camera 预览中进行实时模糊处理?

android - Android 4.3 纵向模式下的全屏相机预览

Android:使用 NDK 进行 OpenGL 渲染

android - Http 请求在 Flutter 中不返回任何内容,也不会抛出任何错误

android - 如何在圆角布局上添加波纹效果?

java - 多线程更新表面 View Canvas

android - 在透明 SurfaceView 之上添加 View ?