Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为Android游戏编程使用自定义SurfaceView和线程(示例)_Android_Surfaceview - Fatal编程技术网

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

为Android游戏编程使用自定义SurfaceView和线程(示例),android,surfaceview,Android,Surfaceview,我正在尝试使用SurfaceView,但是lockCanvas(null)令人困惑,当我退出活动时,应用程序会冻结。此外,没有显示任何内容,即使我使用的教程运行得非常好,我也不明白我做错了什么。请帮助。解决方案可能是setWillNotDraw(false)未被调用 因此,正常工作的参考实现如下所示: public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private S

我正在尝试使用SurfaceView,但是
lockCanvas(null)
令人困惑,当我退出活动时,应用程序会冻结。此外,没有显示任何内容,即使我使用的教程运行得非常好,我也不明白我做错了什么。请帮助。

解决方案可能是
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;
        }
    }
}
    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;
曲面本身并不想回答其宽度和高度,因此,如果我们从外部获取其测量值,并从外部为我们的自定义视图提供测量值,则会更容易:

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

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

请同时查看,特别是关于游戏循环的附录A和关于SurfaceView生命周期的附录B。我参加聚会有点晚,但我有一个问题。使用HandlerThread而不是用自己的循环实现简单线程不是更好吗?我实际上不确定。表面新闻很奇怪。我很高兴我的例子奏效了,这就是我不久前在这里发布它的原因。