为Android游戏编程使用自定义SurfaceView和线程(示例)
我正在尝试使用SurfaceView,但是为Android游戏编程使用自定义SurfaceView和线程(示例),android,surfaceview,Android,Surfaceview,我正在尝试使用SurfaceView,但是lockCanvas(null)令人困惑,当我退出活动时,应用程序会冻结。此外,没有显示任何内容,即使我使用的教程运行得非常好,我也不明白我做错了什么。请帮助。解决方案可能是setWillNotDraw(false)未被调用 因此,正常工作的参考实现如下所示: public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private S
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而不是用自己的循环实现简单线程不是更好吗?我实际上不确定。表面新闻很奇怪。我很高兴我的例子奏效了,这就是我不久前在这里发布它的原因。