读书人

三-A Basic Game Loop

发布时间: 2013-11-08 17:52:14 作者: rapoo

3-A Basic Game Loop
到目前为止,我们已经理解了游戏的结构。即使只是简单的知道了接收输入,更新内部状态,然后渲染到屏幕上,当然也会播放声音或者震动一下

让我们保持简单,看下面的图表

三-A Basic Game Loop

android上面任何事情都是发生在Activity内部,Activity会新建一个view,view是一切事情发生的地方,像触摸和最后的图片显示。把activity想成桌子,而view是一张白纸让我们画东西,我们用铅笔画图,化学反应都是在纸上的,产生了图片,同样也适用于Activity和View,像下图所示

三-A Basic Game Loop

让我们打开DroidzActivity.java,看这行代码

01 package net.obviam.droidz; 02 03 import android.content.Context; 04 import android.graphics.Canvas; 05 import android.view.MotionEvent; 06 import android.view.SurfaceHolder; 07 import android.view.SurfaceView; 08 09 public class MainGamePanel extends SurfaceView implements 10 SurfaceHolder.Callback { 11 12 public MainGamePanel(Context context) { 13 super(context); 14 // adding the callback (this) to the surface holder to intercept events 15 getHolder().addCallback(this); 16 // make the GamePanel focusable so it can handle events 17 setFocusable(true); 18 } 19 20 @Override 21 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 22 } 23 24 @Override 25 public void surfaceCreated(SurfaceHolder holder) { 26 } 27 28 @Override 29 public void surfaceDestroyed(SurfaceHolder holder) { 30 } 31 32 @Override 33 public boolean onTouchEvent(MotionEvent event) { 34 return super.onTouchEvent(event); 35 } 36 37 @Override 38 protected void onDraw(Canvas canvas) { 39 } 40 }

上面的代码只是重写了我们感兴趣的方法,除了15和17行,其他都没什么特别的

01 package net.obviam.droidz; 02 03 public class MainThread extends Thread { 04 05 // flag to hold game state 06 private boolean running; 07 public void setRunning(boolean running) { 08 this.running = running; 09 } 10 11 @Override 12 public void run() { 13 while (running) { 14 // update game state 15 // render state to the screen 16 } 17 } 18

你看到它没有做太多事情,重写了run方法,当running标识为true时,做了个无限循环

当前的进程没有实例化,当屏幕加载的时候,我们来让它运行

看一下修改过的MainGamePanel类

01 package net.obviam.droidz;  02    03 import android.content.Context;  04 import android.graphics.Canvas;  05 import android.view.MotionEvent;  06 import android.view.SurfaceHolder;  07 import android.view.SurfaceView;  08    09 public class MainGamePanel extends SurfaceView implements 10         SurfaceHolder.Callback {  11    12     private MainThread thread;  13    14     public MainGamePanel(Context context) {  15         super(context);  16         getHolder().addCallback(this);  17    18         // create the game loop thread  19         thread = new MainThread();  20    21         setFocusable(true);  22     }  23    24     @Override 25     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  26     }  27    28     @Override 29     public void surfaceCreated(SurfaceHolder holder) {  30         thread.setRunning(true);  31         thread.start();  32     }  33    34     @Override 35     public void surfaceDestroyed(SurfaceHolder holder) {  36         boolean retry = true;  37         while (retry) {  38             try {  39                 thread.join();  40                 retry = false;  41             } catch (InterruptedException e) {  42                 // try again shutting down the thread  43             }  44         }  45     }  46    47     @Override 48     public boolean onTouchEvent(MotionEvent event) {  49         return super.onTouchEvent(event);  50     }  51    52     @Override 53     protected void onDraw(Canvas canvas) {  54     }  55 } 

我们加入了下面代码行

12行声明了线程是私有的

01 public void surfaceDestroyed(SurfaceHolder holder) { 02 // tell the thread to shut down and wait for it to finish 03 // this is a clean shutdown 04 boolean retry = true; 05 while (retry) { 06 try { 07 thread.join(); 08 retry = false; 09 } catch (InterruptedException e) { 10 // try again shutting down the thread 11 } 12 } 13 }

这个方法在surface被销毁前被调用,这里不是设置running标识的地方,但是这里的代码保证了线程被干净的关闭了,我们只是阻塞线程,等待它的死亡

如果在模拟器运行,我们啥也看不这,但是我们可以打一些log来测试,不要担心,后面会告诉你是怎么回事的,更多的请参考Android site.

加入和屏幕的交互

我们会关闭程序当我们按屏幕下方的时候,如果我们点别的地方,我们只是记录坐标位置

在mainThread类中 我们加入如下行

1 private SurfaceHolder surfaceHolder;  2 private MainGamePanel gamePanel;  3 public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {  4     super();  5     this.surfaceHolder = surfaceHolder;  6     this.gamePanel = gamePanel;  7 } 

我们声明了变量gamepanel和surfaceHolder,在构造函数中实例化了他们

我们拥有他们是非常重要的,不仅仅是gamepanel,因为我们需要锁住surface来画图,而这个操作只能通过surfaceHolder

改变在构造函数中的方法

Now you should see the LogCat view. This is nothing more than a console where you can follow Android’s log. It’s a great tool as you can filter for logs containing a specific text or logs with a certain tag which is quite useful.

回到代码,MainThread.java现在是这样了

01 package net.obviam.droidz;  02  03 import android.util.Log;  04 import android.view.SurfaceHolder;  05  06 public class MainThread extends Thread {  07  08 private static final String TAG = MainThread.class.getSimpleName();  09  10 private SurfaceHolder surfaceHolder;  11 private MainGamePanel gamePanel;  12 private boolean running;  13 public void setRunning(boolean running) {  14 this.running = running;  15 }  16  17 public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {  18 super();  19 this.surfaceHolder = surfaceHolder;  20 this.gamePanel = gamePanel;  21 }  22  23 @Override 24 public void run() {  25 long tickCount = 0L;  26 Log.d(TAG, "Starting game loop");  27 while (running) {  28 tickCount++;  29 // update game state  30 // render state to the screen  31 }  32 Log.d(TAG, "Game loop executed " + tickCount + " times");  33 }  34 } 


在8行 我们定义了 log的tag

在run函数中我们定义tickcount,当游戏循环被执行,它会加1

让我们回到MainGamePanel.java类,我们修改OnTOuchEvent,来处理触摸消息

01 public boolean onTouchEvent(MotionEvent event) { 02 if (event.getAction() == MotionEvent.ACTION_DOWN) { 03 if (event.getY() > getHeight() - 50) { 04 thread.setRunning(false); 05 ((Activity)getContext()).finish(); 06 } else { 07 Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY()); 08 } 09 } 10 return super.onTouchEvent(event); 11 }

同样也修改了DroidzActivity

01 package net.obviam.droidz; 02 03 import android.app.Activity; 04 import android.os.Bundle; 05 import android.util.Log; 06 import android.view.Window; 07 import android.view.WindowManager; 08 09 public class DroidzActivity extends Activity { 10 /** Called when the activity is first created. */ 11 12 private static final String TAG = DroidzActivity.class.getSimpleName(); 13 14 @Override 15 public void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 // requesting to turn the title OFF 18 requestWindowFeature(Window.FEATURE_NO_TITLE); 19 // making it full screen 20 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 21 // set our MainGamePanel as the View 22 setContentView(new MainGamePanel(this)); 23 Log.d(TAG, "View added"); 24 } 25 26 @Override 27 protected void onDestroy() { 28 Log.d(TAG, "Destroying..."); 29 super.onDestroy(); 30 } 31 32 @Override 33 protected void onStop() { 34 Log.d(TAG, "Stopping..."); 35 super.onStop(); 36 } 37 }

运行程序,在程序上部点击几下,然后点击下部,程序应该退出

三-A Basic Game Loop

LogCat

目前做的事情

1 创建了一个全屏程序

2 有一个独立的线程控制程序

3 解析基本手势 例如触摸手势

4 优雅的关闭程序

代码大家可以去这里下载

读书人网 >移动开发

热点推荐