使用LGame开发游戏的摸索历程之一:sample们是怎么跑起来的

	使用LGame开发游戏,一开始都会把CP大神(http://blog.csdn.net/cping1982)的sample拿来跑一下,看看示例代码。不过对我们这种菜鸟来说,第一个疑问就是:这玩意是怎么跑起来的?本文就来摸索这个问题。说的不准确的地方,希望有人前来丢砖~~(当然前提是有人来看)。

我们先从Main类的onMain()方法开始。一个典型的onMain()是这样的:

publicvoid onMain() {           
              this.maxScreen(480,320);
              this.initialization(true,LMode.Fill);
             
this.setScreen(new MyScreen());      
              this.setShowFPS(true);
              this.showScreen();         
       }

我们知道LGame中,Main是继承自LGameAndroid2DActivity,LGameAndroid2DActivity继承自Activity;android应用来说,我们看到的内容都是在view中绘制的,通过Activity类的setContentView(View view)方法来把view加载到Activity中。(为什么要加载到Activity中?这个嘛,去google一下android入门知识咯~)LGame分两种实现方案,一种是canvas,一种是openGL es。目前大部分机型都已经支持openGL ES硬件加速,所以我们使用openGL ES方案。这里补充一下必要的背景知识,androidopenGL ES的绘制方案是通过指定一个渲染器Renderer,实现GLSurfaceView.RendereronDrawFrame方法进行。这个待会再仔细说。

现在就来找View。注意onMain()方法中的this.initialization(true,LMode.Fill)这句。往下挖一层,到LGameAndroid2DActivity,调用几次重载的initialization方法后,我们看到这么一句代码:this.gameView = newLGameAndroid2DView(LGameAndroid2DActivity.this,mode, fullScreen, landscape);

同时在这个类中我们找到下面这个方法:

publicvoid showScreen() {
             
setContentView(frameLayout);
             
...... //不需要关心的东东我就不贴出来了
      
}

是的,这是我们在上面的onMain当中看到的那个this.showScreen()所调用的东东。注意到setContentView方法中的参数frameLayout这个frameLayout就是我们所要找的那个绘制屏幕的view(好吧,其实它是一个ViewGroup,不过绘制操作是调用内部每一个View的绘制....有点晕的话,还是老办法,google一下入门知识~~<真不厚道>)。它通过addView方法把gameView添加到内部。于是我们目光转向gameview.LGameAndroid2DView的构造方法中我们看到:

this.surfaceView= createGLSurfaceView(activity);

挖掘下去,createGLSurfaceView方法内部我们看到:

LGameTools.Playview = new LGameTools.Play(activity);

......

view.setRenderer(this);
surfaceView = view;

 LGameTools.Playfinal static class Play extendsGLSurfaceView,额,原来它所定义的view就是我们要找的GLSurfaceView下面的就好理解了,view.setRenderer(this)因为LGameAndroid2DView实现了Renderer接口,所以LGameAndroid2DView实际上就是上面提到的渲染器。我们在做游戏开发时的绘制操作,就是在这个渲染器中进行的。在setRenderer方法调用的时候,系统将新建一个线程,该线程每帧调用一次渲染器中的onDrawFrame方法,持续地绘制我们看到的东西~好吧,看下代码就不晕了。

我们挖一下view.setRenderer(this)的源码(额,这个要用git去下载android的源码,具体怎么下载,那个嘛你懂得,google~~在这里我会把关键的部分贴出来)

GLSurfaceView类中的setRenderer方法是这样的:

 public void setRenderer(Renderer renderer){
       ......//
闲杂人等我就不贴出来了
     
  mGLThread = new GLThread(renderer);
       
 mGLThread.start();
    }

好了我没骗你吧,蓝色的那句代码就新建了一个线程用于渲染。来,接着挖一下它,这个GLThread是个线程,是GLSurfaceView里面定义的一个内部类(内部类就是,,敢说不懂你就shi定了)

 class GLThread extends Thread {
        ......

        public void run() {
         ......         
          guardedRun();
         ......
        }

闲杂人等我都没贴出来,用了省略号代替。线程的run方法中我们关心的只有一句: guardedRun();

是的,再挖下去:

private void guardedRun() throwsInterruptedException {

  mRenderer.onDrawFrame(gl);

}

mRenderer的定义

private Renderer mRenderer;

好了,到这里豁然开朗了,一切神奇的起源,就在这个onDrawFrame方法里面。马不停蹄赶回LGameAndroid2DView.java,直接看onDrawFrame方法。这个方法还是比较复杂,我们暂时先关注其中的两句:

public voidonDrawFrame(javax.microedition.khronos.opengles.GL10 gl10) {

......

process.runTimer(timerContext);

......

process.draw(gl);

......

}

先挖process.runTimer(timerContext)打开LProcess(这个类以后再议)类的runTimer方法,里面有一句

currentControl.runTimer(context);这个currentControl其实就是当前的screen(好吧,回头去看一下最开始的onMain方法,有一句setScreen里面的参***screen就是我们所实现的screen,也就是这里我们看到的currentControl),再挖下去,点开screen类的runTimer方法:

public void runTimer(final LTimerContext timer) {
             
......
              if (fristPaintFlag) {
                     fristOrder.update(timer);
              }
              if (secondPaintFlag) {
                     secondOrder.update(timer);
              }
              if (lastPaintFlag) {
                     lastOrder.update(timer);
              }
              ......
       }

看到这几个update方法,我们已经接近真相了。点进去看:

void update(LTimerContext c) {
                    
switch (type) {
                     case DRAW_USER:
                            screen.alter(c);
                           
break;
                     case DRAW_SPRITE:
                            spriteRun = (sprites != null && sprites.size()> 0);
                            if (spriteRun) {
                                   sprites.update(c.timeSinceLastUpdate);
                           
}
                            break;
                     case DRAW_DESKTOP:
                            desktopRun = (desktop != null && desktop.size()> 0);
                            if (desktopRun) {
                                   desktop.update(c.timeSinceLastUpdate);
                           
}
                            break;
                     }
              }

screen.alter(c) :这里调用的就是screenalert方法,主要用来执行整个游戏的逻辑操作。

sprites.update(c.timeSinceLastUpdate):这个很明显了,更新精灵的状态。

desktop.update(c.timeSinceLastUpdate):这个作用是更新屏幕上的各种组件的状态,比如按钮、进度条等等。

上面的三个操作并不进行绘制。LGame的绘制和逻辑的执行是分开在不同的方法的,这样游戏逻辑和绘制操作可以得到最大限度的分离。下面我们来讲绘制的部分。

       我们在一条分岔路口走的好远了,现在回到上面那句红色的process.draw(gl);(终于知道为什么把它弄成红色了吧,怕你找不到)

还是老套剧情,挖下去,打开LProcess类的draw方法,看到里面有一句currentControl.createUI(g).刚才说了,currentControl就是当前screen,这里就是调用了screencreateUI,再打开这个方法,我把重点部分贴出来:

public synchronized void createUI(GLEx g) {
      
......
              if (fristPaintFlag) {
                     fristOrder.paint(g);
              }
              if (secondPaintFlag) {
                     secondOrder.paint(g);
              }
              if (lastPaintFlag) {
                     lastOrder.paint(g);
              }
              ......
       }

这里有三个PaintOrder对象,分别调用各自的paint方法。PaintOrderscreen类的一个内部类(好纠结),paint方法当中进行对屏幕的绘制。我们打开这个方法看看(次要部分我先把它们省略号代替~):

void paint(GLEx g) {
                    
switch (type) {
                     case DRAW_USER:
                            screen.draw(g);
                            break;
                     case DRAW_SPRITE:
                            if (spriteRun) {
                                   sprites.createUI(g);                       ......

                            break;
                    
case DRAW_DESKTOP:
                            ......
                                   desktop.createUI(g);
                            ......
                     }
              }

真相就出来了,所谓的paint,其实就是调用了screendraw方法绘制屏幕;调用spritedesktopcreateUI方法绘制精灵和其他组件。这三个方法和上面提到的三个update遥相呼应~~一个处理逻辑,一个处理绘制。

好了,这么长的帖子看的头晕。总结一下,基于LGame的游戏要怎么跑起来?开发者需要实现自己的MyScreen,一般继承自screen类就可以了。实现的时候把逻辑执行语句写在alert方法中,把绘制语句写在draw方法中。调用的来龙去脉:LGameAndroid2DView.java中的onDrawFrame-->LProcess类的runTimer方法和draw方法-->你的Screen类中的alert方法和draw方法。

好了,现在打开CP大神的那些sample,你该知道要怎么去下手去依葫芦画瓢了吧(不过CP的有些sample直接把逻辑都放在draw方法当中,比如那个ACT_OpenGLES,,汗,估计是为了快速发出来~大家还是尽量不要在draw里面写逻辑~)。

第一篇博文,写的有点啰嗦,内容有不对的地方请各位赏脸丢个砖头~~~下次见。

 

你可能感兴趣的:(LGame,游戏)