<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[/无间落叶]]></title>
  <link href="http://blog.leafsoar.com/atom.xml" rel="self"/>
  <link href="http://blog.leafsoar.com/"/>
  <updated>2014-10-25T22:20:41+08:00</updated>
  <id>http://blog.leafsoar.com/</id>
  <author>
    <name><![CDATA[一叶]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[如何优雅的管理游戏资源]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/11-27.html"/>
    <updated>2013-11-27T20:56:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/res-mgr</id>
    <content type="html"><![CDATA[<p>在游戏的开发过程中，<strong>前期的规划 往往比 后期的“优化”更为重要！</strong>比如多分辨率适配，如果前期没有规划好，可能导致的情况是，画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配，可以使在合适的机型使用对应的图片资源，避免在高清屏幕使用低质量的图片，在低分辨率屏幕因为图片太大而浪费硬件资源。机制与策略分离，可以让你设计出简单有效的接口。模块化的设计可以让你组织好各种逻辑流程，条理分明 ~ 前期的规划工作可以有很多，一叶也在摸索之中，以使游戏的开发尽量变的简单灵活且可控。最简单的也是最容易忽略的地方，跟我们打交道最多的要数精灵了，从图片创建一个精灵，很简单的开端，将以此展开行动 ~</p>

<p>本文使用 Cocos2d-3.0alpha1 版本，创建了一个 C++ 项目，介绍在 C++ 中，如何处理资源相关的内容，如果读者使用脚本，也可以参考本文中资源管理理念而忽略语言特性，你可以在 Github<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> 上面看到本文所有源码。</p>

<!-- more -->


<h2>名字系统</h2>

<p>也许你可称之为“命名规范”，但显然它无法表达我所想说的内容，很多人在创建精灵的时候喜欢直接使用资源名称，而没有任何定义，这是一个不好的习惯，如果游戏资源不存在，缺少，或者修改名字，如此你需要在多出引用的地方一一修改。游戏开发中的变数总是无法预料，合理的“名字系统”可以节省很多人力。</p>

<p>我们设定一个文件，这里名为 “Resources.h” 的文件，在其中定义所有的资源名称，在游戏开发中，<strong>尽量只</strong> 使用此处的名称，如图片名称，字体名称，声音资源等。这样做有以下好处，只是简单说几点：</p>

<ul>
<li>如果对资源做出修改，我们可以修改此处定义，以保证同步，避免缺失，命名错误，错误引用等问题</li>
<li>在图片名定义修改时，编译器会编译出错，并自动帮助我们 “找” 出引用的地方，方便修改</li>
<li>由于有常量定义的缘故，我们的 IDE 会自动补全所有以定义变量名称，减少出错的可能，提高效率</li>
<li>这个文件列表显然可以写一个如 python 脚本自动生成</li>
</ul>


<p>使用脚本来自动生成文件常量定义显然是个行之有效的途径，这种机械式的操作交给脚本就行了，它总能出色的完成任务，首先来看看项目的 Resources 目录内容：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="o">[</span>Resources<span class="o">]</span>~ ./tree
</span><span class='line'>├── CloseNormal.png
</span><span class='line'>├── CloseSelected.png
</span><span class='line'>├── HelloWorld.png
</span><span class='line'>├── file_list.json
</span><span class='line'>├── fonts
</span><span class='line'>│   └── Marker<span class="se">\ </span>Felt.ttf
</span><span class='line'>└── images
</span><span class='line'>    ├── JungleLeft.png
</span><span class='line'>    ├── ghosts.plist
</span><span class='line'>    ├── ghosts.png
</span><span class='line'>    ├── grossini_family.plist
</span><span class='line'>    └── grossini_family.png
</span></code></pre></td></tr></table></div></figure>


<p>以上是资源文件，那么通过脚本所生成的 “Resources.h” 文件又是什么样子的呢，脚本在 Github 仓库中可以找到(<strong>注意：资源名中最好不要有空格，以免留下“隐患”</strong>)：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="cp">#ifndef _AUTO_RESOURCES_H_</span>
</span><span class='line'><span class="cp">#define _AUTO_RESOURCES_H_</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// search paths</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">searchPaths</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="s">&quot;fonts&quot;</span><span class="p">,</span>
</span><span class='line'>  <span class="s">&quot;images&quot;</span><span class="p">,</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// files</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_CloseNormal</span><span class="p">[]</span>         <span class="o">=</span> <span class="s">&quot;CloseNormal.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_CloseSelected</span><span class="p">[]</span>       <span class="o">=</span> <span class="s">&quot;CloseSelected.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">sjs_file_list</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;file_list.json&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_HelloWorld</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;HelloWorld.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">st_MarkerFelt</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;Marker Felt.ttf&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">sp_ghosts</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;ghosts.plist&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_ghosts</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;ghosts.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">sp_grossini_family</span><span class="p">[]</span>         <span class="o">=</span> <span class="s">&quot;grossini_family.plist&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_grossini_family</span><span class="p">[]</span>         <span class="o">=</span> <span class="s">&quot;grossini_family.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_JungleLeft</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;JungleLeft.png&quot;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#endif </span><span class="c1">// _AUTO_RESOURCES_H_</span>
</span></code></pre></td></tr></table></div></figure>


<p>看到通过脚本，我们生成了所有文件的常量定义，这让得我们可以在游戏中任意使用，但是请注意，这里生成的文件名称是没有包含路径的，所以在定义文件之前，也自动生成了目录列表 <strong>searchPaths</strong>，顾名思义，设定了一个目录列表，以便找寻资源，我们可以在程序的开始处使用 <code>FileUtils::getInstance()-&gt;setSearchPaths(searchPaths);</code> 来设定游戏的资源目录列表，这样我们就可以不用关心资源所在的目录了，你甚至可以根据需要合理的调整资源目录。</p>

<p><strong>注意</strong>：通过设置 searchPaths 可以让我们不用关系资源的路径所在，那么意味着资源名称必须唯一，否则可能会出现引用问题。其次，是如果使用了多套资源方案，请注意 searchPaths 的先后顺序关系。本文暂不考虑多套资源。关于忽略资源目录的做法，如果有不同看法者，欢迎留言讨论，对我来说，忽略路径是利大于弊的 ~</p>

<p>以上通过脚本自动生成了文件列表，但是这显然不够，我们看到资源当中有两张 <strong>打包</strong> 资源图片（可以使用 TexturePacker 对图片资源进行打包，具有占用更小空间，优化运行效率等诸多好处，后面还会介绍此点） plist 文件。我们当然也是需要使用打包中资源的，所以脚本需要能够自动解析 plist 文件，并提取出 TexturePacker 打包的资源名称，请看如下定义，同样是自动生成在 “Resources.h” 文件之中：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">////// texture //////</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// ghosts.plist</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_child1</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;child1.gif&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_father</span><span class="p">[]</span>      <span class="o">=</span> <span class="s">&quot;father.gif&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_sister1</span><span class="p">[]</span>         <span class="o">=</span> <span class="s">&quot;sister1.gif&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_sister2</span><span class="p">[]</span>         <span class="o">=</span> <span class="s">&quot;sister2.gif&quot;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// grossini_family.plist</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_grossini</span><span class="p">[]</span>        <span class="o">=</span> <span class="s">&quot;grossini.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_grossinis_sister1</span><span class="p">[]</span>       <span class="o">=</span> <span class="s">&quot;grossinis_sister1.png&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">si_grossinis_sister2</span><span class="p">[]</span>       <span class="o">=</span> <span class="s">&quot;grossinis_sister2.png&quot;</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<p>此时我们就能用以下代码来创建精灵了，都引用了资源名称定义，并且使用两种方式创建了精灵：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 直接由图片创建精灵</span>
</span><span class='line'><span class="k">auto</span> <span class="n">hello</span> <span class="o">=</span> <span class="n">Sprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">si_HelloWorld</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 从打包资源创建精灵</span>
</span><span class='line'><span class="n">SpriteFrameCache</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addSpriteFramesWithFile</span><span class="p">(</span><span class="n">sp_grossini_family</span><span class="p">,</span> <span class="n">si_grossini_family</span><span class="p">);</span>
</span><span class='line'><span class="k">auto</span> <span class="n">sister</span> <span class="o">=</span> <span class="n">Sprite</span><span class="o">::</span><span class="n">createWithSpriteFrameName</span><span class="p">(</span><span class="n">si_grossinis_sister1</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>上面我们使用两种方式创建精灵，为什么会有两种方式？也许你可以看看 <a href="http://blog.zilongshanren.com/">『子龙山人』</a> 翻译的文章 <a href="http://www.cnblogs.com/zilongshanren/archive/2011/03/18/1988097.html">『在cocos2d里面如何使用Texture Packer和像素格式来优化spritesheet』</a>
其中详细的介绍了图片资源打包优化的相关细节问题，一个游戏最多的就是图片资源，优化空间最大的也是图片资源，里面详细的介绍了优化图片资源占用空间 50％ 以上，如何使游戏运行内存占用优化近 50％，以 cocos2d 为例，但 cocos2d-x 同样能够适用，而且能通过脚本自动打包。 所以合理的对图片资源进行打包优化是非常有必要的。但如何处理这个流程确实不好定夺，<strong>因为不同资源的使用方式不同，因为这两种方式的存在，导致我们编写代码的逻辑不同，这需要提前预定好，</strong>所以我们考虑如下开发流程：</p>

<p>在游戏开发前，对所有资源打包后提供给 编写游戏人员，也就是说在写程序之前，游戏资源就已确定，那些以打包，哪些未打包都已经知道，如前面一样，通过两种方式创建精灵。但是这样的结果是，前期规定好了的，后期就无法改动，或者说很难改动，牵一发而动全身啊 ~ 这就需要加大 <strong>前期的规划</strong> 力度，以确保后期不会出现太大太多事与愿违的情形。这种情况下的 <strong>后期优化</strong> 将会非常蹩脚。况且加大前期规划的力度，可能会对整个项目的进程有所影响，如比编写人员的动工会稍缓，人力资源分配不合理。</p>

<h3>透明</h3>

<p>前文提到，我们使用了 searchPaths 变量，以用忽略资源的路径，一个存在的东西，看起来好像不存在一样，我们称之为 “透明”，”透明” 在软件领域中也是重要的概念，它也强调着封装的重要性，隐藏细节的必要性。这里的资源路径就是如此，我们可以说 <strong>对于资源的使用来说，它的路径是透明的，</strong> 有没有路径，路径为何？那不重要，重要的是你能通过资源名称获取想要的资源。</p>

<p>也许你已经发现了，我想说的不是路径问题，而是图片资源问题。<strong>对于图片资源的使用来说，它’是否是打包资源’ 应该是透明的。</strong>也既是在使用图片资源的时候，你不应该关心它是不是打包后的资源，是也好，不是也罢，这不应该影响你对资源的请求和使用。”打包” 这个过程对你来说，<strong>不存 ~</strong></p>

<h2>图片资源类型的 “透明化” 处理</h2>

<p>先来段代码，看看没有 “透明化” 处理时的一般使用方式：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 方式一  文件资源</span>
</span><span class='line'><span class="k">auto</span> <span class="n">jungle</span> <span class="o">=</span> <span class="n">Sprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">si_JungleLeft</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 方式二  打包资源</span>
</span><span class='line'><span class="n">SpriteFrameCache</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addSpriteFramesWithFile</span><span class="p">(</span><span class="n">sp_grossini_family</span><span class="p">,</span> <span class="n">si_grossini_family</span><span class="p">);</span>
</span><span class='line'><span class="k">auto</span> <span class="n">sister</span> <span class="o">=</span> <span class="n">Sprite</span><span class="o">::</span><span class="n">createWithSpriteFrameName</span><span class="p">(</span><span class="n">si_grossinis_sister1</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>以上我们看到，同样是创建精灵， <code>si_JungleLeft</code> 是普通的 <strong>文件资源</strong>，而 <code>si_grossinis_sister1</code> 是 <strong>打包资源</strong>，这决定着两者的使用方式不同，那么怎么 “透明化” 处理呢：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 不论图片属于 文件资源 还是 打包资源 使用方法相同</span>
</span><span class='line'><span class="k">auto</span> <span class="n">jungle</span> <span class="o">=</span> <span class="n">AssetLoader</span><span class="o">::</span><span class="n">createSprite</span><span class="p">(</span><span class="n">si_JungleLeft</span><span class="p">);</span>
</span><span class='line'><span class="k">auto</span> <span class="n">jungle</span> <span class="o">=</span> <span class="n">AssetLoader</span><span class="o">::</span><span class="n">createSprite</span><span class="p">(</span><span class="n">si_grossinis_sister1</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>我们提供了一个类 <code>AssetLoader</code>，它有一个方法 <code>createSprite(const std::string&amp; name)</code>。不论我们是不是打包资源，我们都通过这个方法来创建精灵，显然它的内部工作原理是根据图片的实际类型，动态判断并创建，之后返回，要实现这样一个功能是可行的，并且没有多复杂，实现以后。我们在使用图片资源的使用就再也用关心它是什么类型的资源了。</p>

<p><strong>这也意味着你可以以一个理想的方式来管理开发流程</strong>。 图片资源可以和游戏编写同时进行，不停的添加图片资源，不停的编写游戏逻辑，而不用考虑图片是否已经优化的问题了，此时可以提供一些零散的图片，以供使用（图片命名最好还是固定），当然也可以提前把关联性比较强的图片提前打包处理，这并不影响使用，因为对程序来说，<strong>它是透明的</strong>，”不存在”的。在后期，我们可以集中的在后期对游戏资源优化，打包处理等（关于此点，文章后面也会给出相对合理的处理流程）。</p>

<h3>功能的实现方案与流程</h3>

<p>在开始之前，一叶通常会将其流程在心中演算一遍，使其不会出现太大的纰漏，对于不合理的所在，可以重新拟定方案。然后实现之 ~ 要使得 <strong>AssetLoader</strong> 的 <strong>createSprite</strong> 方法完成其功能，那么它需要知道，当前请求的 <strong>图片资源</strong> 是否是 <strong>文件资源</strong>（以 <strong>文件资源</strong> 和 <strong>打包资源</strong> 区分两者），如果是，直接由前文 <strong>方式一</strong> 创建精灵返回，如果不是，则从 打包资源 里面找寻，找到就通过 <strong>方式二</strong> 创建精灵并返回，如果还没找到，就返回空指针喽 ~ 由此我们知道 AssetLoader 它内部需要完成以下功能：</p>

<ul>
<li>能够判断一个资源是否是文件资源</li>
<li>能够根据打包资源图片名称返回实际的 plist 文件（打包资源描述文件）和 图片文件</li>
</ul>


<p>要完成以上功能，那就需要让 AssetLoader 知道有哪些文件资源，还要知道有哪些打包资源，我们可以在 AssetLoader 里面定义几个字典用以保存这些数据：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">class</span> <span class="nc">AssetLoader</span><span class="o">:</span> <span class="k">public</span> <span class="n">Object</span><span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>    <span class="k">static</span> <span class="n">Sprite</span><span class="o">*</span> <span class="n">createSprite</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>    <span class="k">static</span> <span class="n">AssetLoader</span><span class="o">*</span> <span class="n">getInstance</span><span class="p">();</span>
</span><span class='line'>    <span class="kt">bool</span> <span class="n">init</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kt">bool</span> <span class="n">fileExists</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">filename</span><span class="p">);</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">getTexturePlist</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">);</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">getTextureImage</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>    <span class="n">Dictionary</span><span class="o">*</span> <span class="n">_fileDict</span><span class="p">;</span>              <span class="c1">// 文件列表</span>
</span><span class='line'>    <span class="n">Dictionary</span><span class="o">*</span> <span class="n">_texturePlistDict</span><span class="p">;</span>           <span class="c1">// 打包资源到文件的映射</span>
</span><span class='line'>    <span class="n">Dictionary</span><span class="o">*</span> <span class="n">_textureImageDict</span><span class="p">;</span>       <span class="c1">// 打包资源plist 到图片的映射</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p>如以上的定义实现，它有三个字典， <code>_fileDict</code> 的 <strong>key</strong> 保存着所有文件资源，<strong>value</strong> 保存文件资源的 编号 ，这样我们就能够随时判断一个图片是否是文件资源了。<code>_texturePlistDict</code> 的 key 保存着打包资源的名称，value 保存打包资源所在 Plist 文件的编号，通过它我们能通过打包资源获取到它 Plist 所在的文件。 <code>_textureImageDict</code> 也是类似，key 保存打包资源名称，value 保存打包资源所在的真实 图片文件的引用。</p>

<p>功能已经定义完毕，现在的问题是我们如何去为这几个字典填充数据？显然程序初始化手动填充不靠谱，前文的文件名等信息都已经是自动定义了，此处我们当然也希望有一个方案 <strong>自动填充</strong> 了。这里的做法是，在使用 <strong>python</strong> 生成资源定义的时候，同时生成一个 json 文件，这个文件里面包含了所有此处字典中所需要的数据，然后 <strong>AssetLoader</strong> 初始化的时候读取这个 json 文件，以完成自动填充数据的功能。先来看看自动生成的 json 文件长什么样纸：</p>

<p>题外话：使用 json 来存储这样一个中转的数据格式是最后定下来的方案，设计之初考虑过几种方案，比如想到可以用一个 sqlite 数据来保存各种数据，这样数据的操作就非常统一，对后期的数据统计分析也会非常方便，曾与朋友 子龙山人 讨论过这之间的详细细节，以及各种实现方案的利弊分析。使用 sqlite 的好处是更为灵活，后期扩展功能会非常方便，适合稍微大点的项目，但是如果一个项目本身没有使用 sqlite 数据库，如果为这里的方案而硬添加一个扩展库实现 sqlite，可能就会非常的不友好，不通用。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="s">&quot;file_name&quot;</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>    <span class="s">&quot;CloseNormal.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;CloseSelected.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;file_list.json&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;HelloWorld.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;Marker Felt.ttf&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;ghosts.plist&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;ghosts.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;grossini_family.plist&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;grossini_family.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;JungleLeft.png&quot;</span>
</span><span class='line'>  <span class="p">],</span>
</span><span class='line'>  <span class="s">&quot;file_index&quot;</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>      <span class="s">&quot;1&quot;</span><span class="p">,</span> <span class="s">&quot;2&quot;</span><span class="p">,</span> <span class="s">&quot;3&quot;</span><span class="p">,</span> <span class="s">&quot;4&quot;</span><span class="p">,</span> <span class="s">&quot;5&quot;</span><span class="p">,</span> <span class="s">&quot;6&quot;</span><span class="p">,</span> <span class="s">&quot;7&quot;</span><span class="p">,</span> <span class="s">&quot;8&quot;</span><span class="p">,</span> <span class="s">&quot;9&quot;</span><span class="p">,</span> <span class="s">&quot;10&quot;</span>
</span><span class='line'>  <span class="p">],</span>
</span><span class='line'>  <span class="s">&quot;texture_name&quot;</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>    <span class="s">&quot;child1.gif&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;father.gif&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;sister1.gif&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;sister2.gif&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;grossini.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;grossinis_sister1.png&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="s">&quot;grossinis_sister2.png&quot;</span>
</span><span class='line'>  <span class="p">],</span>
</span><span class='line'>  <span class="s">&quot;texture_plist&quot;</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>    <span class="s">&quot;6&quot;</span><span class="p">,</span> <span class="s">&quot;6&quot;</span><span class="p">,</span> <span class="s">&quot;6&quot;</span><span class="p">,</span> <span class="s">&quot;6&quot;</span><span class="p">,</span> <span class="s">&quot;8&quot;</span><span class="p">,</span> <span class="s">&quot;8&quot;</span><span class="p">,</span> <span class="s">&quot;8&quot;</span>
</span><span class='line'>  <span class="p">],</span>
</span><span class='line'>  <span class="s">&quot;texture_image&quot;</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>    <span class="s">&quot;7&quot;</span><span class="p">,</span> <span class="s">&quot;7&quot;</span><span class="p">,</span> <span class="s">&quot;7&quot;</span><span class="p">,</span> <span class="s">&quot;7&quot;</span><span class="p">,</span> <span class="s">&quot;9&quot;</span><span class="p">,</span> <span class="s">&quot;9&quot;</span><span class="p">,</span> <span class="s">&quot;9&quot;</span>
</span><span class='line'>  <span class="p">]</span>
</span><span class='line'> <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>以上是自动生成的 json 数据文件内容，为了在这里展示，做了点格式化和缩进，更为友好一点。通过 <strong>file_name</strong> 和 <strong>file_index</strong> 可以创建文件资源列表字典，通过 texture_name 和 texture_plist 可以创建打包资源和文件资源之间的映射， texture_image 也是同样。 file_name 包含了所有文件资源，file_index 为文件资源做了编号，这两个数据项的个数是相同的。 texture_name 定义了所有打包资源的定义，texture_plist 和 texture_image 则保存了 打包资源所在的 plist 文件和图片文件的引用，它们的数据项个数也是相同的。只要保证这里生成的内容没有错误，那么我们就正确的将其填充到 AssetLoader 的字典里面，以实现想要的功能。</p>

<p>为什么数据会长这个样子？一叶本来的设计 json 文件，多层嵌套更具描述性（各种对象，各种属性，一目了然），但是发现 解析的时候稍显麻烦，在 新版 cocos2d-x 的 gui 库中，已经封装好了一些常用的 json 解析功能，本着 拿来注意（尽可能的寻找可用的资源来简化自身的流程） 的思想，为使解析过程简单，所以数据格式就定义成那个样子了 － ＝。现在只是用了五个数组（更平面化的数据组织，像是数据库表），保存所有数据。只能说，这样做是为了迎合代码的编写，让本来复杂的 json 解析过程变得更为简单。现在看来，但到也简单清晰，看看填充字典的关键代码实现（如果有其它更好的方式，修改也不麻烦，修改生成的数据格式，再修改代码中数据的填充方法就行了）：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">JsonDictionary</span> <span class="o">*</span><span class="n">jsonDict</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JsonDictionary</span><span class="p">();</span>
</span><span class='line'><span class="n">String</span><span class="o">*</span> <span class="n">fileContent</span> <span class="o">=</span> <span class="n">String</span><span class="o">::</span><span class="n">createWithContentsOfFile</span><span class="p">(</span><span class="n">sjs_file_list</span><span class="p">);</span>
</span><span class='line'><span class="n">jsonDict</span><span class="o">-&gt;</span><span class="n">initWithDescription</span><span class="p">(</span><span class="n">fileContent</span><span class="o">-&gt;</span><span class="n">getCString</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'><span class="n">DictionaryHelper</span><span class="o">*</span> <span class="n">dicHelper</span> <span class="o">=</span> <span class="n">DICTOOL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="n">_fileDict</span> <span class="o">=</span> <span class="n">Dictionary</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="kt">int</span> <span class="n">file_idx</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getArrayCount_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">file_name</span><span class="p">);</span>
</span><span class='line'><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">file_idx</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getStringValueFromArray_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">file_name</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">index</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getStringValueFromArray_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">file_index</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="n">_fileDict</span><span class="o">-&gt;</span><span class="n">setObject</span><span class="p">(</span><span class="n">String</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">index</span><span class="p">),</span> <span class="n">name</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="n">log</span><span class="p">(</span><span class="s">&quot;file count: %d&quot;</span><span class="p">,</span> <span class="n">file_idx</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">_texturePlistDict</span> <span class="o">=</span> <span class="n">Dictionary</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="kt">int</span> <span class="n">texture_idx</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getArrayCount_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">texture_name</span><span class="p">);</span>
</span><span class='line'><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">texture_idx</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getStringValueFromArray_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">texture_name</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">plist</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getStringValueFromArray_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">texture_plist</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="n">_texturePlistDict</span><span class="o">-&gt;</span><span class="n">setObject</span><span class="p">(</span><span class="n">String</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">plist</span><span class="p">),</span> <span class="n">name</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="n">log</span><span class="p">(</span><span class="s">&quot;texture count: %d&quot;</span><span class="p">,</span> <span class="n">texture_idx</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">_textureImageDict</span> <span class="o">=</span> <span class="n">Dictionary</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">texture_idx</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getStringValueFromArray_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">texture_name</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">image</span> <span class="o">=</span> <span class="n">dicHelper</span><span class="o">-&gt;</span><span class="n">getStringValueFromArray_json</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">,</span> <span class="n">texture_image</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="n">_textureImageDict</span><span class="o">-&gt;</span><span class="n">setObject</span><span class="p">(</span><span class="n">String</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">image</span><span class="p">),</span> <span class="n">name</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">CC_SAFE_DELETE</span><span class="p">(</span><span class="n">jsonDict</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>这里能看到一些陌生的内容 <code>JsonDictionary</code>、<code>DictionaryHelper</code> 类型和其操作方式，这里的使用方法不是本文的重点，有兴趣的朋友看看源码实现。以很简洁的方式，填充了我们需要的字典数据内容。有了这些字典数据，我们就很容易的判断一个图片是否是文件资源了，如果是打包资源，也能够很容易找出打包资源所在的 Plist 文件和 图片文件，最后看一下 <code>createSprite</code> 方法的实现：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">Sprite</span><span class="o">*</span> <span class="n">AssetLoader</span><span class="o">::</span><span class="n">createSprite</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">){</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">AssetLoader</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">fileExists</span><span class="p">(</span><span class="n">name</span><span class="p">)){</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">Sprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="n">log</span><span class="p">(</span><span class="s">&quot;create sprite: %s&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">plistfile</span> <span class="o">=</span> <span class="n">AssetLoader</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getTexturePlist</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">imagefile</span> <span class="o">=</span> <span class="n">AssetLoader</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getTextureImage</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
</span><span class='line'>    <span class="n">log</span><span class="p">(</span><span class="s">&quot;plist: %s, image: %s&quot;</span><span class="p">,</span> <span class="n">plistfile</span><span class="p">.</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">imagefile</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">plistfile</span> <span class="o">!=</span> <span class="s">&quot;&quot;</span> <span class="o">&amp;&amp;</span> <span class="n">imagefile</span> <span class="o">!=</span> <span class="s">&quot;&quot;</span><span class="p">){</span>
</span><span class='line'>        <span class="n">SpriteFrameCache</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addSpriteFramesWithFile</span><span class="p">(</span><span class="n">plistfile</span><span class="p">,</span> <span class="n">imagefile</span><span class="p">);</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">Sprite</span><span class="o">::</span><span class="n">createWithSpriteFrameName</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">nullptr</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>至此我们便完成了 <strong>图片资源类型的 “透明化” 处理</strong> 。这样一个解决方案，很好的解决了在开发过程中图片资源的管理过程，后期优化，都不冲突。能够通过此提供一个较为合理的开发流程。 本文所使用的源码，脚本等都可以在 Github 上面找到 <a href="https://github.com/leafsoar/resource-manager">『https://github.com/leafsoar/resource-manager』</a>，但是要清楚，我这里提供的只是按照我这种流程下来的一种实现而已，对于程序本身而言，也还有很多可以改进的所在 ~ 思路同样，每个人实现的具体细节可能不一样，不论你使用 C++ 还是脚本语言，都不影响你 “透明化” 图片资源类型。</p>

<h2>如何优雅的管理游戏资源</h2>

<p>我们解决了一些问题，提供了一些解决方案，但总有更多的问题等着我们去解决，更多的优秀解决方案，好的工作模式，处理流程。我们会把开发中一些 <strong>变动</strong> 的所在找寻出来，对它灵活的处理，使它能够适应各种不同的 <strong>险恶环境</strong>。哪些是不变的，哪些是容易变动的，尽量做到 <strong>以不变应万变</strong>。现在新的问题和需求又来了，哈 ~</p>

<p>继续前文内容，我们可以使用 AssetLoader 来加载图片资源，创建精灵，实现游戏玩法逻辑等。但是我们通常会在一个场景进入时就预先缓存所有图片资源（声音资源亦是同样），甚至在游戏开始时，预先加载所有的图片资源，以 <strong>保证游戏画面的流畅性</strong>。如果没有预先缓存图片资源，那么在游戏中用到的时候，实时加载可能 <strong>会使游戏画面卡顿</strong>，这不是我们想看到的结果。如果一个游戏不大，资源总和也没多少，那么可以直接在游戏开始时全部加载完毕，这种情况处理起来比较简单，直接把所有资源加载就可以了。但是如今的游戏动辄几十兆，几百兆，显然游戏资源一次性加载是不科学的，这时我们可以分场景，在加载一个场景的时候，清空前一个场景所使用的图片缓存资源，然后预先加载当前场景的游戏资源，以达到最优的内存占用。</p>

<p>通常我们都是人为的，定义了一个方法在开始场景前做一些准备工作，清空缓存，预加载游戏资源，如这里有一个需要预加载的资源列表，而前文我们提到，在游戏开发的过程中，我们的图片资源可能会有所改动，这就需要我们去 <strong>人为的同步去手动维护这个列表</strong>，而这样的工作费时费力，还容易出现很多错误，如果我们能够把这一步的操作自动化，根据实际情况生成其列表，并且 <strong>列表资源的加载顺序也是做过优化的</strong>(根据文件大小，或者分辨率大小，优先加载大的资源，使游戏减少因占用内存过多而崩溃的可能性)，那将使我们能有 更多的精力花在更值得的地方。如果结合到本文之前的实现方案就是，在开始一个场景时，我们对 AssetLoader 做一个标记，在这个标记之后所请求的图片资源都是当前场景的资源，我们可以在内部将其记录下来，以任何方式都行，这样我们就能够非常容易的收集并生成当前场景所使用的图片资源了。如果我们将这个列表做成动态可维护的，自动记录以便下次运行时预先加载，这样一种实现从逻辑上来说时可行。如何优雅得管理游戏资源？但是实现比 优雅 更重要，在实现的过程中，尽量使开发变得简单，流程变得清晰，也是一叶努力的方向 ～</p>

<p>以上只是对预加载资源列表的动态维护，提供了一个简单的思路，其中还有很多细节值得推敲。但我想实现这样一种流程对游戏的开发是非常有帮助的，对于这个部分的内容，一叶还没有给出一个具体的实现方案，但将继续之前的流程往下实现，并分享在 Github 上面，同时你也可以参与进来。也算是在这里集思广益，如果你有什么好的想法，对本文实现有什么改进，都可以一起交流。如果你遇到了相同的问题，也可以说说你是怎么处理这些问题的，欢迎分享 ~</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>本文源码 Github 仓库地址：<a href="https://github.com/leafsoar/resource-manager/tree/v1.0">https://github.com/leafsoar/resource-manager/tree/v1.0</a><a href="#fnref:1" rev="footnote">&#8617;</a></p></li>
</ol>
</div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[玩转 Cocos2d-x 脚本引擎]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/11-10.html"/>
    <updated>2013-11-10T20:56:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/script-engin</id>
    <content type="html"><![CDATA[<p>在 Unix 文化中，有这样一种理念，Happy Hacking！使用 Cocos2d-x/C++ 写过一些游戏，其绑定的脚本语言，用的也不少，脚本语言的一个好处就是快速开发，你无需明白它之运行机理，便可容易的完成所想要的效果，三天上手，五天就能写出像样的程序来，C++ 则不然，其各种语言细节特性，各种开发技巧，内存管理等细枝末叶 ~</p>

<p>计算机不会魔法，在一叶看来其内容，只有 <strong>“知、或者不知”</strong> ，没有 <strong>“懂、或者不懂”</strong>，“知或者不知”来自于你的学习历程与经验，至于“不懂”么，我还没接触到的领域内容，我都不懂，哈 ~ Cocos2d-x 脚本引擎也用过一段时间了，但其运行机理还不明白，就使用而言也无需明白，不过于在意细节的实现，可能更好的从宏观角度把握整体。过去只是对其“存疑”（对于这里的“不懂”，一叶通常美其名曰：<strong>要学会存疑</strong> :p ），而现在想要对其运行机制多了解一些，那就只有一步步去探究喽，要了解到什么程度，那就随意了～</p>

<p>对 Cocos2d-x 的运行机制只是略懂一二，C++ 的场景由 C++ 运行，脚本呢，先开启脚本引擎，让后将控制权交由脚本代码执行，在这过程中发生了什么，由脚本所控制的元素和 C++ 有什么不同，或者说它的本质是什么！这之前一叶一直说的是脚本引擎，而非具体那种脚本引擎，lua 或者 js (jsvascript)的引擎实现！凭着对已有知识的了解和直觉，很多疑问和可能性随之而来，它所支持的脚本语言有两种，此两种的共同之处是什么，其使用了脚本绑定技术，<strong>什么是绑定</strong> ？各种对象在内存中如何分布，如何配合在一起工作。</p>

<p>为了增加探究过程的趣味性，所以一叶试想着能不能让 Cocos2d-x 现今所支持的<strong>两种脚本引擎同时运行</strong> (lua and js)，然后确定是否能在三者之间（C++, js, lua）访问同一个内存元素，如果行，便弄出来，即便不能做到，那也无所谓，这其中的过程比结果更有意思，不是吗 ~</p>

<!-- more -->


<h2>两种脚本引擎同时运行</h2>

<p>这里使用了 cocos2d-x-3.0alpha0-pre 版本，原因有二。一者：这是最新版本，反正是折腾，顺便了解一下 3.0 的新特性和 代码 style ，其二：3.0 对 三大开发平台(windows, linux ,mac)，两大运行平台(android, ios)的支持更好更全一些，比如，lua 可以跑在 mac 上面，这一点最新的 2.2 版本不行（lua ）。这样的选择，可以让我在当前系统（Mac OS X） 系统下，直接运行看效果，而不用开模拟器或者虚拟机，使过程更为方便。（过去使用 Linux 作为开发环境，也很方便，一叶的博客也有其具体的开发环境搭建配置等）而 windows 系统，几年前就几乎不怎么用了，各种不顺手。</p>

<p>3.0 中去除了使用项目模板来构建项目，而改为使用脚本创建，支持的平台如下(这个脚本是 github 上最新的版本)，观其关键代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="c"># [Cocos2d-x]/tools/project-creator/create_project.py</span>
</span><span class='line'><span class="n">PLATFORMS</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="s">&quot;cpp&quot;</span> <span class="p">:</span> <span class="p">[</span><span class="s">&quot;ios_mac&quot;</span><span class="p">,</span> <span class="s">&quot;android&quot;</span><span class="p">,</span> <span class="s">&quot;win32&quot;</span><span class="p">,</span> <span class="s">&quot;linux&quot;</span><span class="p">],</span>
</span><span class='line'>  <span class="s">&quot;lua&quot;</span> <span class="p">:</span> <span class="p">[</span><span class="s">&quot;ios_mac&quot;</span><span class="p">,</span> <span class="s">&quot;android&quot;</span><span class="p">,</span> <span class="s">&quot;win32&quot;</span><span class="p">,</span> <span class="s">&quot;linux&quot;</span><span class="p">],</span>
</span><span class='line'>  <span class="s">&quot;javascript&quot;</span> <span class="p">:</span> <span class="p">[</span><span class="s">&quot;ios_mac&quot;</span><span class="p">,</span> <span class="s">&quot;android&quot;</span><span class="p">,</span> <span class="s">&quot;win32&quot;</span><span class="p">]</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>从这里脚本看出 cpp 和 lua ，对五个平台已经全面支持，javascript 对 linux 还没有支持（脚本上是这样），相比 -x 2.x 版本支持更好，更全面，其代码也经过重构，更模块化，还有很多 C++ 11 的新特性，这里同样也期待 3.0 早日成熟，达到实用阶段 :p</p>

<p>为了简化操作步骤，一叶尽量利用现有的环境内容，使用 XCode打开 samples 项目，这里包含了所有项目内容，起初一叶打算基于 HelloCpp 项目做扩展，添加脚本支持，来实现自己的功能，也许是我对 XCode 环境了解不够，通过手动配置，让它能够支持 lua 扩展，但是 js 扩展却没能跑起来（没理由 lua 可以 js 却不行，知道一定是哪里配置有误），此时看来，在已有的项目中添加 lua 比 js 成功几率要大，固转而使用 HelloLua 项目添加 js 扩展支持，以达到项目组织上能够独立运行 js 引擎 或者 lua 引擎。（注：使用 HelloCpp 作为扩展，主要想看看怎么配置方便，如果都好配置，就基于 Cpp ，如果其中一个配置难，或者没通过，就基于没有通过配置的已有实现，扩展它。比如，这里 lua 通过 js 却没有，那就基于已有的 HelloLua 扩展支持 js，更为节省精力，这是策略问题 :p）</p>

<p>以上只是让项目同时支持 js <strong>或者</strong> lua 的运行，比如只跑 lua，或者只跑 js，但是 两者却不能同时跑，如果在代码中，同时用到了 lua 和 js 的支持库，在编译时会报错。这是因为在绑定的时候，两种脚本引擎分别实现了自己的 GLNode 。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// [Cocos2d-x]/scripting/javascript/bindings/js_bindings_opengl.h</span>
</span><span class='line'><span class="cp">#include &quot;cocos2d.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;ScriptingCore.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;cocos2d_specifics.hpp&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">GLNode</span> <span class="o">:</span> <span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">Node</span> <span class="p">{</span>
</span><span class='line'> <span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="kt">void</span> <span class="n">draw</span><span class="p">();</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">js_register_cocos2dx_GLNode</span><span class="p">(</span><span class="n">JSContext</span> <span class="o">*</span><span class="n">cx</span><span class="p">,</span> <span class="n">JSObject</span> <span class="o">*</span><span class="n">global</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// [Cocos2d-x]/scripting/lua/cocos2dx_support/LuaOpengl.h</span>
</span><span class='line'><span class="cp">#ifndef __LUA_OPENGL_H__</span>
</span><span class='line'><span class="cp">#define __LUA_OPENGL_H__</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#ifdef __cplusplus</span>
</span><span class='line'><span class="k">extern</span> <span class="s">&quot;C&quot;</span> <span class="p">{</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'><span class="cp">#include &quot;tolua++.h&quot;</span>
</span><span class='line'><span class="cp">#ifdef __cplusplus</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &quot;base_nodes/CCNode.h&quot;</span>
</span><span class='line'><span class="k">class</span> <span class="nc">GLNode</span><span class="o">:</span><span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">Node</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">virtual</span> <span class="kt">void</span> <span class="n">draw</span><span class="p">();</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="n">TOLUA_API</span> <span class="kt">int</span> <span class="n">tolua_Cocos2d_CCDrawNode_drawPolygon00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">TOLUA_API</span> <span class="kt">int</span> <span class="n">tolua_opengl_open</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#endif </span><span class="c1">//__LUA_OPENGL_H__</span>
</span></code></pre></td></tr></table></div></figure>


<p>同时使用两种引擎，就意味着同时用到两者的库依赖，而重复的类型定义导致编译通不过，所以只能根据需要 hack 源码了，如果修改，二者修改其一，看修改哪个方便，引用的地方少。如下是使用 Emacs 的 find-grep 命令，在 scripting 目录搜索 &ldquo;GLNode&rdquo; 关键字的结果。（Emacs 是一叶的必备工具，这里搜索出的结果可以快速定位代码位置）</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="o">-*-</span> <span class="nl">mode:</span> <span class="n">grep</span><span class="p">;</span> <span class="k">default</span><span class="o">-</span><span class="nl">directory:</span> <span class="s">&quot;~/Tools/cocos2d-x/cocos2d-x-3.0alpha0-pre/scripting/&quot;</span> <span class="o">-*-</span>
</span><span class='line'><span class="n">Grep</span> <span class="n">started</span> <span class="n">at</span> <span class="n">Mon</span> <span class="n">Nov</span> <span class="mi">11</span> <span class="mi">13</span><span class="o">:</span><span class="mi">55</span><span class="o">:</span><span class="mo">04</span>
</span><span class='line'>
</span><span class='line'><span class="n">find</span> <span class="p">.</span> <span class="o">-</span><span class="n">type</span> <span class="n">f</span> <span class="o">-</span><span class="n">exec</span> <span class="n">grep</span> <span class="o">-</span><span class="n">nH</span> <span class="o">-</span><span class="n">e</span> <span class="n">GLNode</span> <span class="p">{}</span> <span class="o">+</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js</span><span class="o">/</span><span class="n">jsb_cocos2d_extension</span><span class="p">.</span><span class="nl">js:</span><span class="mi">167</span><span class="o">:</span><span class="n">cc</span><span class="p">.</span><span class="n">GLNode</span><span class="p">.</span><span class="n">extend</span> <span class="o">=</span> <span class="n">cc</span><span class="p">.</span><span class="n">Class</span><span class="p">.</span><span class="n">extend</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">3</span><span class="o">:</span><span class="kt">void</span> <span class="n">GLNode</span><span class="o">::</span><span class="n">draw</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">27</span><span class="o">:</span><span class="n">JSClass</span>  <span class="o">*</span><span class="n">js_cocos2dx_GLNode_class</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">28</span><span class="o">:</span><span class="n">JSObject</span> <span class="o">*</span><span class="n">js_cocos2dx_GLNode_prototype</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">30</span><span class="o">:</span><span class="n">JSBool</span> <span class="n">js_cocos2dx_GLNode_constructor</span><span class="p">(</span><span class="n">JSContext</span> <span class="o">*</span><span class="n">cx</span><span class="p">,</span> <span class="n">uint32_t</span> <span class="n">argc</span><span class="p">,</span> <span class="n">jsval</span> <span class="o">*</span><span class="n">vp</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">34</span><span class="o">:</span>    <span class="n">GLNode</span><span class="o">*</span> <span class="n">cobj</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GLNode</span><span class="p">();</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">41</span><span class="o">:</span>    <span class="n">TypeTest</span><span class="o">&lt;</span><span class="n">GLNode</span><span class="o">&gt;</span> <span class="n">t</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">51</span><span class="o">:</span>    <span class="n">JS_AddNamedObjectRoot</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">obj</span><span class="p">,</span> <span class="s">&quot;cocos2d::GLNode&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">59</span><span class="o">:</span><span class="kt">void</span> <span class="n">js_cocos2dx_GLNode_finalize</span><span class="p">(</span><span class="n">JSFreeOp</span> <span class="o">*</span><span class="n">fop</span><span class="p">,</span> <span class="n">JSObject</span> <span class="o">*</span><span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">62</span><span class="o">:</span><span class="k">static</span> <span class="n">JSBool</span> <span class="n">js_cocos2dx_GLNode_ctor</span><span class="p">(</span><span class="n">JSContext</span> <span class="o">*</span><span class="n">cx</span><span class="p">,</span> <span class="n">uint32_t</span> <span class="n">argc</span><span class="p">,</span> <span class="n">jsval</span> <span class="o">*</span><span class="n">vp</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">65</span><span class="o">:</span>    <span class="n">GLNode</span> <span class="o">*</span><span class="n">nobj</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GLNode</span><span class="p">();</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">68</span><span class="o">:</span>    <span class="n">JS_AddNamedObjectRoot</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">obj</span><span class="p">,</span> <span class="s">&quot;GLNode&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">73</span><span class="o">:</span><span class="n">JSBool</span> <span class="n">js_cocos2dx_GLNode_create</span><span class="p">(</span><span class="n">JSContext</span> <span class="o">*</span><span class="n">cx</span><span class="p">,</span> <span class="n">uint32_t</span> <span class="n">argc</span><span class="p">,</span> <span class="n">jsval</span> <span class="o">*</span><span class="n">vp</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">75</span><span class="o">:</span>  <span class="n">GLNode</span><span class="o">*</span> <span class="n">ret</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GLNode</span><span class="p">();</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">79</span><span class="o">:</span>      <span class="n">js_proxy_t</span> <span class="o">*</span><span class="n">proxy</span> <span class="o">=</span> <span class="n">js_get_or_create_proxy</span><span class="o">&lt;</span><span class="n">GLNode</span><span class="o">&gt;</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">ret</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">91</span><span class="o">:</span><span class="kt">void</span> <span class="n">js_register_cocos2dx_GLNode</span><span class="p">(</span><span class="n">JSContext</span> <span class="o">*</span><span class="n">cx</span><span class="p">,</span> <span class="n">JSObject</span> <span class="o">*</span><span class="n">global</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">92</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span> <span class="o">=</span> <span class="p">(</span><span class="n">JSClass</span> <span class="o">*</span><span class="p">)</span><span class="n">calloc</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">JSClass</span><span class="p">));</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">93</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;GLNode&quot;</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">94</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">addProperty</span> <span class="o">=</span> <span class="n">JS_PropertyStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">95</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">delProperty</span> <span class="o">=</span> <span class="n">JS_PropertyStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">96</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">getProperty</span> <span class="o">=</span> <span class="n">JS_PropertyStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">97</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">setProperty</span> <span class="o">=</span> <span class="n">JS_StrictPropertyStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">98</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">enumerate</span> <span class="o">=</span> <span class="n">JS_EnumerateStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">99</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">resolve</span> <span class="o">=</span> <span class="n">JS_ResolveStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">100</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">convert</span> <span class="o">=</span> <span class="n">JS_ConvertStub</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">101</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">finalize</span> <span class="o">=</span> <span class="n">js_cocos2dx_GLNode_finalize</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">102</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_class</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">=</span> <span class="n">JSCLASS_HAS_RESERVED_SLOTS</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">109</span><span class="o">:</span>      <span class="n">JS_FN</span><span class="p">(</span><span class="s">&quot;ctor&quot;</span><span class="p">,</span> <span class="n">js_cocos2dx_GLNode_ctor</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">JSPROP_PERMANENT</span> <span class="o">|</span> <span class="n">JSPROP_ENUMERATE</span><span class="p">),</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">114</span><span class="o">:</span>    <span class="n">JS_FN</span><span class="p">(</span><span class="s">&quot;create&quot;</span><span class="p">,</span> <span class="n">js_cocos2dx_GLNode_create</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">JSPROP_PERMANENT</span> <span class="o">|</span> <span class="n">JSPROP_ENUMERATE</span><span class="p">),</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">118</span><span class="o">:</span>  <span class="n">js_cocos2dx_GLNode_prototype</span> <span class="o">=</span> <span class="n">JS_InitClass</span><span class="p">(</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">121</span><span class="o">:</span>                         <span class="n">js_cocos2dx_GLNode_class</span><span class="p">,</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">122</span><span class="o">:</span>                         <span class="n">js_cocos2dx_GLNode_constructor</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="c1">// constructor</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">129</span><span class="o">:</span>  <span class="n">JS_SetPropertyAttributes</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">global</span><span class="p">,</span> <span class="s">&quot;GLNode&quot;</span><span class="p">,</span> <span class="n">JSPROP_ENUMERATE</span> <span class="o">|</span> <span class="n">JSPROP_READONLY</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">found</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">132</span><span class="o">:</span>  <span class="n">TypeTest</span><span class="o">&lt;</span><span class="n">GLNode</span><span class="o">&gt;</span> <span class="n">t</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">139</span><span class="o">:</span>    <span class="n">p</span><span class="o">-&gt;</span><span class="n">jsclass</span> <span class="o">=</span> <span class="n">js_cocos2dx_GLNode_class</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">140</span><span class="o">:</span>    <span class="n">p</span><span class="o">-&gt;</span><span class="n">proto</span> <span class="o">=</span> <span class="n">js_cocos2dx_GLNode_prototype</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">h:</span><span class="mi">5</span><span class="o">:</span><span class="k">class</span> <span class="nc">GLNode</span> <span class="o">:</span> <span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">Node</span> <span class="p">{</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">js_bindings_opengl</span><span class="p">.</span><span class="nl">h:</span><span class="mi">10</span><span class="o">:</span><span class="kt">void</span> <span class="n">js_register_cocos2dx_GLNode</span><span class="p">(</span><span class="n">JSContext</span> <span class="o">*</span><span class="n">cx</span><span class="p">,</span> <span class="n">JSObject</span> <span class="o">*</span><span class="n">global</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">jsb_opengl_registration</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">56</span><span class="o">:</span>    <span class="n">js_register_cocos2dx_GLNode</span><span class="p">(</span><span class="n">_cx</span><span class="p">,</span> <span class="n">ccns</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">javascript</span><span class="o">/</span><span class="n">bindings</span><span class="o">/</span><span class="n">obfuscate</span><span class="o">/</span><span class="n">obfuscate_exclude_cocos2d</span><span class="p">.</span><span class="nl">js:</span><span class="mi">3049</span><span class="o">:</span><span class="n">CSSProperties</span><span class="p">.</span><span class="n">prototype</span><span class="p">.</span><span class="n">GLNode</span><span class="p">;</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">CCLuaEngine</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">615</span><span class="o">:</span>    <span class="n">extendGLNode</span><span class="p">(</span><span class="n">lua_S</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">CCLuaEngine</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">726</span><span class="o">:</span><span class="kt">void</span> <span class="n">LuaEngine</span><span class="o">::</span><span class="n">extendGLNode</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">lua_S</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">CCLuaEngine</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">731</span><span class="o">:</span>    <span class="n">lua_pushstring</span><span class="p">(</span><span class="n">lua_S</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">CCLuaEngine</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">736</span><span class="o">:</span>        <span class="n">lua_pushcfunction</span><span class="p">(</span><span class="n">lua_S</span><span class="p">,</span><span class="n">tolua_Cocos2d_GLNode_registerScriptDrawHandler00</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">CCLuaEngine</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">739</span><span class="o">:</span>        <span class="n">lua_pushcfunction</span><span class="p">(</span><span class="n">lua_S</span><span class="p">,</span><span class="n">tolua_Cocos2d_GLNode_unregisterScriptDrawHandler00</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">CCLuaEngine</span><span class="p">.</span><span class="nl">h:</span><span class="mi">146</span><span class="o">:</span>    <span class="kt">void</span> <span class="n">extendGLNode</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">lua_S</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">24</span><span class="o">:</span><span class="kt">void</span> <span class="n">GLNode</span><span class="o">::</span><span class="n">draw</span><span class="p">()</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">26</span><span class="o">:</span>    <span class="kt">int</span> <span class="n">handler</span> <span class="o">=</span> <span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getObjectHandler</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="k">this</span><span class="p">,</span> <span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">kGLNodeDrawHandler</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">38</span><span class="o">:</span>    <span class="n">tolua_usertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span> <span class="s">&quot;GLNode&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">42</span><span class="o">:</span><span class="k">static</span> <span class="kt">int</span> <span class="n">tolua_collect_GLNode</span> <span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">44</span><span class="o">:</span>    <span class="n">GLNode</span> <span class="o">*</span><span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">GLNode</span><span class="o">*</span><span class="p">)</span> <span class="n">tolua_tousertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">63</span><span class="o">:</span><span class="cm">/* method: create of class  GLNode */</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">64</span><span class="o">:</span><span class="err">#</span><span class="n">ifndef</span> <span class="n">TOLUA_DISABLE_tolua_Cocos2d_GLNode_create00</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">65</span><span class="o">:</span><span class="k">static</span> <span class="kt">int</span> <span class="n">tolua_Cocos2d_GLNode_create00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">70</span><span class="o">:</span>        <span class="o">!</span><span class="n">tolua_isusertable</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="o">&amp;</span><span class="n">tolua_err</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">77</span><span class="o">:</span>        <span class="n">GLNode</span> <span class="o">*</span><span class="n">glNode</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GLNode</span><span class="p">();</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">83</span><span class="o">:</span>            <span class="n">toluafix_pushusertype_ccobject</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span> <span class="n">nID</span><span class="p">,</span> <span class="n">pLuaID</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">glNode</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">100</span><span class="o">:</span><span class="cm">/* method: setShaderProgram of class  GLNode */</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">101</span><span class="o">:</span><span class="err">#</span><span class="n">ifndef</span> <span class="n">TOLUA_DISABLE_tolua_Cocos2d_GLNode_setShaderProgram00</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">102</span><span class="o">:</span><span class="k">static</span> <span class="kt">int</span> <span class="n">tolua_Cocos2d_GLNode_setShaderProgram00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">107</span><span class="o">:</span>        <span class="o">!</span><span class="n">tolua_isusertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="o">&amp;</span><span class="n">tolua_err</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">115</span><span class="o">:</span>        <span class="n">GLNode</span><span class="o">*</span> <span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">GLNode</span><span class="o">*</span><span class="p">)</span>  <span class="n">tolua_tousertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">292</span><span class="o">:</span><span class="cm">/* method: glBindFramebuffer of class  GLNode */</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">300</span><span class="o">:</span>        <span class="o">!</span><span class="n">tolua_isusertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="o">&amp;</span><span class="n">tolua_err</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">6386</span><span class="o">:</span>      <span class="n">tolua_cclass</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="s">&quot;CCNode&quot;</span><span class="p">,</span><span class="n">tolua_collect_GLNode</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">6387</span><span class="o">:</span>        <span class="n">tolua_beginmodule</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">6388</span><span class="o">:</span>            <span class="n">tolua_function</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span> <span class="s">&quot;create&quot;</span><span class="p">,</span> <span class="n">tolua_Cocos2d_GLNode_create00</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">6389</span><span class="o">:</span>            <span class="n">tolua_function</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span> <span class="s">&quot;setShaderProgram&quot;</span><span class="p">,</span> <span class="n">tolua_Cocos2d_GLNode_setShaderProgram00</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaOpengl</span><span class="p">.</span><span class="nl">h:</span><span class="mi">13</span><span class="o">:</span><span class="k">class</span> <span class="nc">GLNode</span><span class="o">:</span><span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">Node</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">584</span><span class="o">:</span><span class="kt">int</span> <span class="n">tolua_Cocos2d_GLNode_registerScriptDrawHandler00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">588</span><span class="o">:</span>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">tolua_isusertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="o">&amp;</span><span class="n">tolua_err</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">595</span><span class="o">:</span>        <span class="n">GLNode</span><span class="o">*</span> <span class="n">glNode</span> <span class="o">=</span> <span class="p">(</span><span class="n">GLNode</span><span class="o">*</span><span class="p">)</span>  <span class="n">tolua_tousertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">597</span><span class="o">:</span>        <span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addObjectHandler</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">glNode</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">kGLNodeDrawHandler</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">608</span><span class="o">:</span><span class="kt">int</span> <span class="n">tolua_Cocos2d_GLNode_unregisterScriptDrawHandler00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">)</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">612</span><span class="o">:</span>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">tolua_isusertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="s">&quot;GLNode&quot;</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="o">&amp;</span><span class="n">tolua_err</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">618</span><span class="o">:</span>        <span class="n">GLNode</span><span class="o">*</span> <span class="n">glNode</span> <span class="o">=</span> <span class="p">(</span><span class="n">GLNode</span><span class="o">*</span><span class="p">)</span><span class="n">tolua_tousertype</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">619</span><span class="o">:</span>        <span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">removeObjectHandler</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">glNode</span><span class="p">,</span><span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">kGLNodeDrawHandler</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">cpp:</span><span class="mi">779</span><span class="o">:</span>        <span class="n">tolua_constant</span><span class="p">(</span><span class="n">tolua_S</span><span class="p">,</span><span class="s">&quot;kGLNodeDrawHandler&quot;</span><span class="p">,</span><span class="n">ScriptHandlerMgr</span><span class="o">::</span><span class="n">kGLNodeDrawHandler</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">h:</span><span class="mi">99</span><span class="o">:</span>       <span class="n">kGLNodeDrawHandler</span><span class="p">,</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">h:</span><span class="mi">137</span><span class="o">:</span><span class="n">TOLUA_API</span> <span class="kt">int</span> <span class="n">tolua_Cocos2d_GLNode_registerScriptDrawHandler00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">cocos2dx_support</span><span class="o">/</span><span class="n">LuaScriptHandlerMgr</span><span class="p">.</span><span class="nl">h:</span><span class="mi">138</span><span class="o">:</span><span class="n">TOLUA_API</span> <span class="kt">int</span> <span class="n">tolua_Cocos2d_GLNode_unregisterScriptDrawHandler00</span><span class="p">(</span><span class="n">lua_State</span><span class="o">*</span> <span class="n">tolua_S</span><span class="p">);</span>
</span><span class='line'><span class="p">.</span><span class="o">/</span><span class="n">lua</span><span class="o">/</span><span class="n">script</span><span class="o">/</span><span class="n">Opengl</span><span class="p">.</span><span class="nl">lua:</span><span class="mi">297</span><span class="o">:</span>    <span class="k">return</span> <span class="nl">GLNode:</span><span class="n">create</span><span class="p">()</span>
</span><span class='line'><span class="n">Grep</span> <span class="n">finished</span> <span class="p">(</span><span class="n">matches</span> <span class="n">found</span><span class="p">)</span> <span class="n">at</span> <span class="n">Mon</span> <span class="n">Nov</span> <span class="mi">11</span> <span class="mi">13</span><span class="o">:</span><span class="mi">55</span><span class="o">:</span><span class="mo">07</span>
</span></code></pre></td></tr></table></div></figure>


<p>目测感觉两者差不多，而且代码量也不多，所以修改其中之一的 GLNode 类名称是可行的，总共八十多行结果，修改一种就四十行左右，而且其中出现的 &ldquo;GLNode&rdquo; 关键字，并不是都需要修改，有的是绑定到脚本引擎内部的，我们只需要修改其 C++ 端绑定的类型就 OK 了，一叶修改了 lua 绑定中的 GLNode 名字为 LuaGLNode，然后定位到 LuaOpengl 和相关文件（两个文件左右），查找并替换其中一部分 &ldquo;GLNode&rdquo; 关键字代码，这里借助 Emacs ，递进式的关键字查询替换，通过匹配规则，一个个过滤，手动选择是替换还是不替换，最后替换了所有 C++ 中 Lua 端的 GLNode 类名实现（替换的内容很少，比我想象中要少）。</p>

<p>到这里就已经完成能够让两种脚本引擎同时运行的方法。并且一叶修改了入口函数，在 AppDelegate 入口处，添加修改：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="kt">bool</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">applicationDidFinishLaunching</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="c1">// initialize director</span>
</span><span class='line'>    <span class="n">Director</span> <span class="o">*</span><span class="n">pDirector</span> <span class="o">=</span> <span class="n">Director</span><span class="o">::</span><span class="n">getInstance</span><span class="p">();</span>
</span><span class='line'>    <span class="n">pDirector</span><span class="o">-&gt;</span><span class="n">setOpenGLView</span><span class="p">(</span><span class="n">EGLView</span><span class="o">::</span><span class="n">getInstance</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">EGLView</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setDesignResolutionSize</span><span class="p">(</span><span class="mi">480</span><span class="p">,</span> <span class="mi">320</span><span class="p">,</span> <span class="n">ResolutionPolicy</span><span class="o">::</span><span class="n">NO_BORDER</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// turn on display FPS</span>
</span><span class='line'>    <span class="n">pDirector</span><span class="o">-&gt;</span><span class="n">setDisplayStats</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// set FPS. the default value is 1.0/60 if you don&#39;t call this</span>
</span><span class='line'>    <span class="n">pDirector</span><span class="o">-&gt;</span><span class="n">setAnimationInterval</span><span class="p">(</span><span class="mf">1.0</span> <span class="o">/</span> <span class="mi">60</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">//    runLua();</span>
</span><span class='line'>    <span class="n">runCpp</span><span class="p">();</span>
</span><span class='line'><span class="c1">//    runJsb();</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">runCpp</span><span class="p">(){</span>
</span><span class='line'>    <span class="k">auto</span> <span class="n">scene</span> <span class="o">=</span> <span class="n">HelloLeafsoar</span><span class="o">::</span><span class="n">scene</span><span class="p">();</span>
</span><span class='line'>    <span class="n">Director</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">runWithScene</span><span class="p">(</span><span class="n">scene</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">runJsb</span><span class="p">(){</span>
</span><span class='line'>    <span class="n">ScriptingCore</span><span class="o">*</span> <span class="n">sc</span> <span class="o">=</span> <span class="n">ScriptingCore</span><span class="o">::</span><span class="n">getInstance</span><span class="p">();</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">register_all_cocos2dx</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">register_all_cocos2dx_extension</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">register_cocos2dx_js_extensions</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">jsb_register_chipmunk</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">register_all_cocos2dx_extension_manual</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">register_CCBuilderReader</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">jsb_register_system</span><span class="p">);</span>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">addRegisterCallback</span><span class="p">(</span><span class="n">JSB_register_opengl</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">sc</span><span class="o">-&gt;</span><span class="n">start</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">ScriptEngineProtocol</span> <span class="o">*</span><span class="n">pEngine</span> <span class="o">=</span> <span class="n">ScriptingCore</span><span class="o">::</span><span class="n">getInstance</span><span class="p">();</span>
</span><span class='line'>    <span class="n">ScriptEngineManager</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setScriptEngine</span><span class="p">(</span><span class="n">pEngine</span><span class="p">);</span>
</span><span class='line'>    <span class="n">ScriptingCore</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">runScript</span><span class="p">(</span><span class="s">&quot;main.js&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">runLua</span><span class="p">(){</span>
</span><span class='line'>    <span class="n">LuaEngine</span><span class="o">*</span> <span class="n">luaEngine</span> <span class="o">=</span> <span class="n">LuaEngine</span><span class="o">::</span><span class="n">getInstance</span><span class="p">();</span>
</span><span class='line'>    <span class="n">ScriptEngineManager</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setScriptEngine</span><span class="p">(</span><span class="n">luaEngine</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">path</span> <span class="o">=</span> <span class="n">FileUtils</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">fullPathForFilename</span><span class="p">(</span><span class="s">&quot;hello.lua&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="n">luaEngine</span><span class="o">-&gt;</span><span class="n">executeScriptFile</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>可以看到这里有三个方法，runCpp 、runLua 和 runJsb，这三者可单独独立运行，也可同时运行，在脚本实现不同的 log 打印，便能知晓，但如如果你在这三处同时运行了一个场景的话，那么根据场景的运行规则，后面运行的场景会入栈，替换之前场景的运行，三者的运行顺序，可以随意修改，并观其运行结果。为了测试这一点，我们同时运行 runLua、runCpp 和 runJsb ，然后使用一个全局定时器（请看 实现 <a href="http://blog.leafsoar.com/archives/2013/05-08.html">『Cocos2d-x 全局定时器』</a> 一文），每三秒钟弹出一个场景。而每一个场景的内部不同，这样我们便能看见首先运行了 runJsb 场景，三秒后 runLua ，之后 runCpp 场景，最终三秒后，所有场景弹出，Game Over 了。</p>

<h2>脚本绑定技术的特性</h2>

<p>以上通过对源代码的修改，一个例子，让 lua 和 js 两种脚本引擎同时运行，由于在任何时候只能有一个场景运行，所以，无论由 C++、lua 还是 js 来启动游戏，另外两种语言将会得不倒执行的权利，但是从另一个侧面，全局定时器它得的运行并不依赖场景的运行，这对我们研究程序执行过程中对象的特性提供了方便，前文通过一个 C++ 端实现的全局定时器，不论你运行的是不是脚本，是什么脚本，都不影响它之运行，那么我们就能能用这个定时器去定期的调用各种脚本，以让这三种脚本语言同时运行，在这样一个过程中，去验证对它们的内存分布，操作机制的的情况等 ~</p>

<p>一叶在 C++ 端开启了一个定时器，且由 C++ 运行了第一个场景，然后修改全局定时器的定时调用实现，添加对 lua 和 js 的脚本调用：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="kt">void</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">globalUpdate</span><span class="p">(</span><span class="kt">float</span> <span class="n">dt</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// 这里写全局定时器的逻辑处理代码</span>
</span><span class='line'>    <span class="n">CCLOG</span><span class="p">(</span><span class="s">&quot;global update&quot;</span><span class="p">);</span>
</span><span class='line'><span class="c1">//    Director::getInstance()-&gt;popScene();</span>
</span><span class='line'>    <span class="n">count</span> <span class="o">++</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">auto</span> <span class="n">scene</span> <span class="o">=</span> <span class="n">Director</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getRunningScene</span><span class="p">();</span>
</span><span class='line'>    <span class="n">LabelTTF</span><span class="o">*</span> <span class="n">label</span> <span class="o">=</span> <span class="p">(</span><span class="n">LabelTTF</span><span class="o">*</span><span class="p">)</span><span class="n">scene</span><span class="o">-&gt;</span><span class="n">getChildByTag</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">label</span><span class="p">){</span>
</span><span class='line'>        <span class="n">label</span> <span class="o">=</span> <span class="n">LabelTTF</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;一叶 v 5~&quot;</span><span class="p">,</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="mi">24</span><span class="p">);</span>
</span><span class='line'>        <span class="n">label</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="mi">250</span><span class="p">,</span> <span class="mi">300</span><span class="p">));</span>
</span><span class='line'>        <span class="n">label</span><span class="o">-&gt;</span><span class="n">setColor</span><span class="p">(</span><span class="n">Color3B</span><span class="o">::</span><span class="n">BLACK</span><span class="p">);</span>
</span><span class='line'>        <span class="n">scene</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">label</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span><span class='line'>            <span class="n">label</span><span class="o">-&gt;</span><span class="n">setScale</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>        <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
</span><span class='line'>            <span class="n">ScriptingCore</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">runScript</span><span class="p">(</span><span class="s">&quot;jsbMethod.js&quot;</span><span class="p">);</span>
</span><span class='line'>        <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="o">%</span><span class="mi">3</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span>
</span><span class='line'>            <span class="n">LuaEngine</span><span class="o">::</span><span class="n">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">executeScriptFile</span><span class="p">(</span><span class="s">&quot;luaMethod.lua&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>这是全局定时器的实现，它在当前运行的场景中添加了一个 Label ，label 的内容 &ldquo;<strong>一叶 v 5~</strong>&#8220;，并且通过一个执行技术 <strong>count</strong> 来决定当前执行的是 C++ 还是 lua 或者 js，在不同的语言中，修改同一个元素的大小 <strong>Scale</strong>，看看 js 和 lua 的 method 文件实现：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='lua'><span class='line'><span class="c1">-- luaMethod.lua 具体实现</span>
</span><span class='line'><span class="n">cclog</span> <span class="o">=</span> <span class="k">function</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
</span><span class='line'>    <span class="nb">print</span><span class="p">(</span><span class="nb">string.format</span><span class="p">(</span><span class="o">...</span><span class="p">))</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">cclog</span><span class="p">(</span><span class="s2">&quot;</span><span class="s">lua method .&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="kd">local</span> <span class="n">scene</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="p">:</span><span class="n">getInstance</span><span class="p">():</span><span class="n">getRunningScene</span><span class="p">()</span>
</span><span class='line'><span class="kd">local</span> <span class="n">label</span> <span class="o">=</span> <span class="n">scene</span><span class="p">:</span><span class="n">getChildByTag</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
</span><span class='line'><span class="n">label</span><span class="p">:</span><span class="n">setScale</span><span class="p">(</span><span class="mf">0.8</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="c1">// jsbMethod.js 具体实现</span>
</span><span class='line'><span class="nx">cc</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot; jsb method .&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">scene</span> <span class="o">=</span> <span class="nx">cc</span><span class="p">.</span><span class="nx">Director</span><span class="p">.</span><span class="nx">getInstance</span><span class="p">().</span><span class="nx">getRunningScene</span><span class="p">();</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">label</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getChildByTag</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
</span><span class='line'><span class="nx">label</span><span class="p">.</span><span class="nx">setScale</span><span class="p">(</span><span class="mf">1.2</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>以上的代码都很简单，各种语言的逻辑一样，首先或者当前运行着的场景，然后通过 tag 获取场景中的元素 Label，再之修改它的大小，这样将程序运行，便能看见此 Label 定时改变大小，而且是三种大小状态不停的切换，可见已经完成了我们之前的目标，双开脚本引擎，用不语言控制同一个元素（文章最后给出所有代码）。</p>

<h3>绑定技术的特性浅析</h3>

<p>说道脚本绑定技术，这里可以插入一个新的内容来说，Cocos2d-html5 版本！作为对比，更为明了，h5 的实现和 jsb 的实现显然不同，h5 是跑在浏览器上的，jsb 是跑在移动终端上的。但是它们都用统一的接口实现，即用 js 写的游戏（同一套代码）即能够跑在浏览器上，又能够能跑在手机的 js 引擎上，这两者之间 <strong>表面相同，本质不同 </strong>，也是隐藏了内部实现，提供统一的接口让写程序更为简单。有兴趣的朋友可以去了解一下。在 Emacs 内置的 lisp 语言函数中有很多性能要求比较高的是使用 c 语言实现的，但在调用的时候全然不知（不知道就对了）。</p>

<p>而 jsb 和 lua 之间：知其不同，是见其表，知其皆同，是知其本，舍不同而观其同，可游心于物之初，哈。 在脚本引擎库中，以 C++ 实现的类型为基本，通过动态往虚拟机（引擎环境，或者上下文对象）里添加类型定义并绑定，每钟脚本类型都有其对应的 C++ 类型作为依据，通过脚本创建的对象最终被映射为调用 C++ 创建对象，而在 C++ 中创建的对象，也可以在脚本中随时获取，并修改其属性，当然其内部还有复杂的内存管理解决方案 (特别是本文中这样混合形的运行时环境，其对象生命周期就更复杂了，关系到引擎内部实现的细节，由不同语言创建的对象，由谁管理，由谁释放等等)，在需要之时可以深究，而这里显然没有必要（这里引擎双开仅作学习之用），宏观角度考量，内存管理无非是定义一套规则，或是规范，这样能保证出错误的最小可能性（在 <a href="http://blog.leafsoar.com/archives/2013/05-22.html">『Cocos2d-x 内存管理浅说』</a> , <a href="http://blog.leafsoar.com/archives/2013/05-29.html">『Cocos2d-x 内存管理的一种实现』</a>, <a href="http://blog.leafsoar.com/archives/2013/06-04.html">『深入理解 Cocos2d-x 内存管理』</a>) 几篇文章有怎样通过编程规范来尽量避免内存出现的问题）。</p>

<p>如果我们需要添加一种新脚本绑定实现，比如使用 lisp 语言作为绑定 （Emacs 用户首先想到的就是 lisp 了），那么我们需要一个 lisp 运行时环境的实现，然后通过函数绑定，javascript 和 lua 的第一类型是 函数（First-class Function），它们都有很强的函数式语言特性，其封装的 Cocos2d-x 调用方式不过是语法糖衣，看起来像面相对象而已，此点 js 表现更甚。所以对于 lisp 实现来说，是可行的，至于最后写起来是否顺手不得而知，目测如果实现，写法更像 lua 对 Cocos2d-x 的 style，可能很好使，可能很糟糕 :P 也许使用对象形的脚本语言更加合宜。</p>

<h2>非吾小天下 宏观而已</h2>

<p>想要玩转这里脚本引擎，那么你至少会绑定，知道怎么绑定，其具体步骤 ？jsb 怎么手动绑定，lua 怎么手动绑定，而且还有自动绑定脚本，jsb 的内部使用了 spidermonkey 开源的 js 引擎，lua 还可以开 jit，其运行环境有很多复杂的上下文参数，各种错综复杂，提出各种专有的概念，有着各自不同的游戏规则，其内部的细枝末叶是对具体问题的解决方案，然而有的时候我们并不知道需要解决的问题由来，一环套着一环，我在这里却避而不谈，一方面是因为我也不知 :p ,另一方面是因为不想让我或者别人陷入这样那样的泥沼中去，从宏观的角度去看问题，或者抽象，在 lua 和 js 这两种脚本引擎中，其特点为何，能达到什么样的效果，在本文的操作过程，并没有什么复杂的步骤，修改了一处编译报错问题，引擎双开，操作同一对象。避开了很多各脚本的内部实现细节内容。把复杂的问题简单化 ~</p>

<p>关于本文的内容，一叶会将代码项目提交到 github 以供参考（在文章最后给出<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>），内容不多，组织凌乱（时不时想修改，临时添加以看不同的测试效果），所以就将就着看了，哈，我的博文从不倾向给出一个完整的解决方案，以思路为重，其过程比结果更为重要。</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>本文环境及其代码：<a href="https://github.com/leafsoar/cocos2d-x-script-engine">https://github.com/leafsoar/cocos2d-x-script-engine</a><a href="#fnref:1" rev="footnote">&#8617;</a></p></li>
</ol>
</div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CCScrollView 实现帮助界面、关卡选择]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/07-27.html"/>
    <updated>2013-07-27T17:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/ccscrollview-level</id>
    <content type="html"><![CDATA[<p>本文介绍了 CCScrollView 来编写帮助界面和关卡选择界面的方法，在编写这样一个功能之时，大多会遇到一些困难，这里也是同样，最后提供了一个相应且合理的解决方案，并解说了其它实现方案的优缺点，这里的内容，你可以直接拿去用，或者可以作为实现的参考。总能找到你需要的东西，或多～或少～。文章大致内容如下：</p>

<ul>
<li>首先实现了一个可拖动的界面，滚屏屏幕，它可以用于完成帮助界面的设计</li>
<li>接着实现了关卡选择功能，这里的着重点是 <strong>如何处理触摸机制</strong> 。以达到不错的协同工作</li>
<li>由于是分屏滚动，所以完成了一个页索引 “指示球功能”</li>
</ul>


<p>本文所使用的 Cocos2d-x 为当前的稳定版本 2.1.4。（如无说明，文章内容总是配合 当前最新 稳定版库）
原来是使用 Cocos2d-x 2.0.4 编写的功能，周末花了点事件进行了整理 和 重构（触摸机制的重构）。</p>

<!-- more -->


<hr />

<h2>可拖动界面的实现 （帮助界面）</h2>

<p>实现帮助界面，那么我们首先要考虑的是，我们需要一个什么样的效果？大致总结如下：</p>

<ul>
<li>一个可分屏显示的界面是必须的</li>
<li>界面可以拖动操作，多屏滚动</li>
<li>还想添加一个滚动屏幕的校队，以使显示区域正好是屏幕宽度的倍数</li>
</ul>


<p>现在我们将要使用 CCScrollView 来实现这么样一个功能，那么它需要哪些 <strong>元素</strong> 以及需要解决哪些设计上的问题，整理一下思路先：</p>

<ul>
<li>首先需要一个 CCScrollView 层，和一个包含内容的容器层（CCLayer）</li>
<li>处理触摸操作，我们直接启用 CCScrollView 的可触摸操作，就已经能够完成对 CCScrollView 的拖动，这是它本身所提供的功能</li>
<li>CCScrollView 本身所提供的触摸操作，默认情况有诸多不便，虽然能够拖动，但区域控制器来确很繁琐，更何况我们还需要校队，对齐等操作</li>
<li>所以我们将 触摸 的操作交由 CCScrollView 所在的层（或者当前运行的场景），禁用 CCScrollView 的触摸，我们通过处理当前界面的触摸，用以控制 CCScrollView 的行为，是一个可行的解决方案</li>
</ul>


<p>下面给出相应的关键代码，实现以上功能（本文的示例都在此处 <a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/MacCpp/Classes/LevelView.cpp">源码查看</a>）：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 创建一个 CCScrollView, 内容大小和当前的界面一样</span>
</span><span class='line'><span class="n">CCScrollView</span><span class="o">*</span> <span class="n">scrollView</span> <span class="o">=</span> <span class="n">CCScrollView</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="k">this</span><span class="o">-&gt;</span><span class="n">getContentSize</span><span class="p">());</span>
</span><span class='line'><span class="c1">// 设定容器层，我们并不需要重新设置 scrollview 的 ContentSize，容器层内部设定即可</span>
</span><span class='line'><span class="n">scrollView</span><span class="o">-&gt;</span><span class="n">setContainer</span><span class="p">(</span><span class="n">getContainLayer</span><span class="p">());</span>
</span><span class='line'><span class="c1">// 关闭 scrollView 的可触摸操作</span>
</span><span class='line'><span class="n">scrollView</span><span class="o">-&gt;</span><span class="n">setTouchEnabled</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 容器层内容实现</span>
</span><span class='line'><span class="n">CCLayer</span><span class="o">*</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">getContainLayer</span><span class="p">(){</span>
</span><span class='line'>    <span class="n">m_nPageCount</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">CCSize</span> <span class="n">winSize</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span><span class='line'>    <span class="n">CCPoint</span> <span class="n">pointCenter</span> <span class="o">=</span> <span class="n">ccp</span><span class="p">(</span><span class="n">winSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">winSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">CCLayer</span><span class="o">*</span> <span class="n">layer</span> <span class="o">=</span> <span class="n">CCLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>    <span class="n">layer</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">CCPointZero</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 添加 frame，每 一页 用一张背景图显示</span>
</span><span class='line'>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">m_nPageCount</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>        <span class="n">CCSprite</span><span class="o">*</span> <span class="n">frame</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;level/frame.png&quot;</span><span class="p">);</span>
</span><span class='line'>        <span class="n">frame</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccpAdd</span><span class="p">(</span><span class="n">pointCenter</span><span class="p">,</span> <span class="n">ccp</span><span class="p">(</span><span class="n">winSize</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">)));</span>
</span><span class='line'>        <span class="n">layer</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">frame</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">layer</span><span class="o">-&gt;</span><span class="n">setContentSize</span><span class="p">(</span><span class="n">CCSizeMake</span><span class="p">(</span><span class="n">winSize</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">m_nPageCount</span><span class="p">,</span> <span class="n">winSize</span><span class="p">.</span><span class="n">height</span><span class="p">));</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">layer</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>完成以上内容，那么基本准备工作就做好了。上面我们要注意区分两个概念，ViewSize 和 ContentSize，ViewSize 是 scrollView 所显示区域的大小，ContentSize 是滚动层的区域大小，一般而言，ViewSize 就是 ContentSize 上可见的一部分区域，通过拖动可以显示不同的部分。</p>

<p>后面继续，触摸处理相关代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 关闭 scrollview 的触摸，相应的，我们要启用当前的触摸，并注册为单点触摸类型</span>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">registerWithTouchDispatcher</span><span class="p">(){</span>
</span><span class='line'>    <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getTouchDispatcher</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addTargetedDelegate</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">bool</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">ccTouchBegan</span><span class="p">(</span><span class="n">cocos2d</span><span class="o">::</span><span class="n">CCTouch</span> <span class="o">*</span><span class="n">pTouch</span><span class="p">,</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">){</span>
</span><span class='line'>  <span class="c1">// 记录触摸起始点的位置</span>
</span><span class='line'>    <span class="n">m_touchPoint</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">convertToGL</span><span class="p">(</span><span class="n">pTouch</span><span class="o">-&gt;</span><span class="n">getLocationInView</span><span class="p">());</span>
</span><span class='line'>  <span class="c1">// 记录触摸起始点的偏移</span>
</span><span class='line'>    <span class="n">m_touchOffset</span> <span class="o">=</span> <span class="n">getScrollView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getContentOffset</span><span class="p">();</span>
</span><span class='line'>    <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">ccTouchMoved</span><span class="p">(</span><span class="n">cocos2d</span><span class="o">::</span><span class="n">CCTouch</span> <span class="o">*</span><span class="n">pTouch</span><span class="p">,</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">){</span>
</span><span class='line'>    <span class="n">CCPoint</span> <span class="n">movePoint</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">convertToGL</span><span class="p">(</span><span class="n">pTouch</span><span class="o">-&gt;</span><span class="n">getLocationInView</span><span class="p">());</span>
</span><span class='line'>  <span class="c1">// 获得当前的拖动距离</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">distance</span> <span class="o">=</span> <span class="n">movePoint</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">m_touchPoint</span><span class="p">.</span><span class="n">x</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 设定当前偏移位置</span>
</span><span class='line'>    <span class="n">CCPoint</span> <span class="n">adjustPoint</span> <span class="o">=</span> <span class="n">ccp</span><span class="p">(</span><span class="n">m_touchOffset</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">distance</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// 让 scrollView 跟着 move 操作而移动</span>
</span><span class='line'>    <span class="n">getScrollView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setContentOffset</span><span class="p">(</span><span class="n">adjustPoint</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">ccTouchEnded</span><span class="p">(</span><span class="n">cocos2d</span><span class="o">::</span><span class="n">CCTouch</span> <span class="o">*</span><span class="n">pTouch</span><span class="p">,</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">){</span>
</span><span class='line'>    <span class="n">CCPoint</span> <span class="n">endPoint</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">convertToGL</span><span class="p">(</span><span class="n">pTouch</span><span class="o">-&gt;</span><span class="n">getLocationInView</span><span class="p">());</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">distance</span> <span class="o">=</span> <span class="n">endPoint</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">m_touchPoint</span><span class="p">.</span><span class="n">x</span><span class="p">;</span>
</span><span class='line'>  
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">fabs</span><span class="p">(</span><span class="n">distance</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>        <span class="c1">// 小于三，不做拖动操作，也排除了（抖动误操作）</span>
</span><span class='line'>    <span class="p">}</span><span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">fabs</span><span class="p">(</span><span class="n">distance</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">50</span><span class="p">){</span>
</span><span class='line'>        <span class="c1">// 大于 50，执行拖动效果</span>
</span><span class='line'>        <span class="n">adjustScrollView</span><span class="p">(</span><span class="n">distance</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span><span class="k">else</span><span class="p">{</span>
</span><span class='line'>        <span class="c1">// 回退为拖动之前的位置</span>
</span><span class='line'>        <span class="n">adjustScrollView</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">ccTouchCancelled</span><span class="p">(</span><span class="n">cocos2d</span><span class="o">::</span><span class="n">CCTouch</span> <span class="o">*</span><span class="n">pTouch</span><span class="p">,</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">){</span>
</span><span class='line'>  <span class="c1">// 参数为 0 表示 恢复之前的屏幕位置</span>
</span><span class='line'>    <span class="n">adjustScrollView</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">adjustScrollView</span><span class="p">(</span><span class="kt">float</span> <span class="n">offset</span><span class="p">){</span>
</span><span class='line'>    <span class="n">CCSize</span> <span class="n">winSize</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span><span class='line'>    <span class="c1">// 我们根据 offset 的实际情况来判断移动效果</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">offset</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>     <span class="c1">// 表示右移</span>
</span><span class='line'>        <span class="n">m_nCurPage</span> <span class="o">++</span><span class="p">;</span>
</span><span class='line'>    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">offset</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span>
</span><span class='line'>        <span class="n">m_nCurPage</span> <span class="o">--</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 屏幕 页数 检测</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">m_nCurPage</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
</span><span class='line'>        <span class="n">m_nCurPage</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">m_nCurPage</span> <span class="o">&gt;</span> <span class="n">m_nPageCount</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span><span class='line'>        <span class="n">m_nCurPage</span> <span class="o">=</span> <span class="n">m_nPageCount</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 根据当前的 页数 获得偏移量，并设定新的位置，且启用动画效果</span>
</span><span class='line'>    <span class="n">CCPoint</span> <span class="n">adjustPoint</span> <span class="o">=</span> <span class="n">ccp</span><span class="p">(</span><span class="o">-</span><span class="n">winSize</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">m_nCurPage</span> <span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'>    <span class="n">getScrollView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setContentOffsetInDuration</span><span class="p">(</span><span class="n">adjustPoint</span><span class="p">,</span> <span class="mf">0.2f</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;current page index: %d&quot;</span><span class="p">,</span> <span class="n">m_nCurPage</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>由以上的内容，便完成了我们所需要的帮助界面的效果，一个可拖动，滚动的界面，页面数根据自己需要来定，这里只是实现的步骤，当然在这个界面里面要放什么元素，那就要看你的心情了，哈！</p>

<p>要放什么元素？我们基于以上的实现，在里面添加可点击项，以完成一个关卡选择功能！</p>

<hr />

<h2>扩展，实现关卡选择功能</h2>

<p>关卡选择 就界面而言，和上面所说的帮助界面并没有太大区别，所不同的是，除了触摸拖动界面之外，还可以点击内部的元素，如关卡，以实现不同的功能，所以我们基于以上的内容，扩展添加实现关卡选择功能。</p>

<p>实现以下代码，完成在界面添加关卡精灵元素：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 修改层内容实现</span>
</span><span class='line'><span class="n">CCLayer</span><span class="o">*</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">getContainLayer</span><span class="p">(){</span>
</span><span class='line'>    <span class="n">m_nPageCount</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// ..... 此处省略，参照上文</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 在此处添加关卡精灵</span>
</span><span class='line'>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">levelCount</span><span class="p">;</span> <span class="n">i</span> <span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>        <span class="n">CCNode</span><span class="o">*</span> <span class="n">level</span> <span class="o">=</span> <span class="n">getSpriteByLevel</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
</span><span class='line'>        <span class="c1">// 设置位置</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">curPageIndex</span> <span class="o">=</span> <span class="n">i</span> <span class="o">/</span> <span class="p">(</span><span class="n">widthCount</span> <span class="o">*</span> <span class="n">heightCount</span><span class="p">);</span>
</span><span class='line'>        <span class="kt">float</span> <span class="n">xOffset</span> <span class="o">=</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">4</span> <span class="o">*</span> <span class="mi">100</span> <span class="o">+</span> <span class="mi">90</span><span class="p">;</span>
</span><span class='line'>        <span class="kt">float</span> <span class="n">yOffset</span> <span class="o">=</span> <span class="n">winSize</span><span class="p">.</span><span class="n">height</span> <span class="o">-</span> <span class="p">((</span><span class="n">i</span> <span class="o">%</span> <span class="p">(</span><span class="n">widthCount</span> <span class="o">*</span> <span class="n">heightCount</span><span class="p">))</span> <span class="o">/</span> <span class="n">widthCount</span> <span class="o">*</span> <span class="mi">120</span> <span class="o">+</span> <span class="mi">180</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">level</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccp</span><span class="p">(</span><span class="n">xOffset</span> <span class="o">+</span> <span class="n">winSize</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">curPageIndex</span><span class="p">,</span> <span class="n">yOffset</span><span class="p">));</span>
</span><span class='line'>      <span class="c1">// 这里使用了 zOrder = 2，用此值来构建层次关系，如后文将要添加的显示点击背景效果</span>
</span><span class='line'>        <span class="n">layer</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">level</span> <span class="p">,</span><span class="mi">2</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">layer</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 这里是上面所用到的方法</span>
</span><span class='line'><span class="n">CCNode</span><span class="o">*</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">getSpriteByLevel</span><span class="p">(</span><span class="kt">int</span> <span class="n">level</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">CCSprite</span><span class="o">*</span> <span class="n">sprite</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;level/level.png&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="c1">// 添加关卡标示</span>
</span><span class='line'>    <span class="n">CCString</span><span class="o">*</span> <span class="n">str</span> <span class="o">=</span> <span class="n">CCString</span><span class="o">::</span><span class="n">createWithFormat</span><span class="p">(</span><span class="s">&quot;%d&quot;</span><span class="p">,</span> <span class="n">level</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>    <span class="n">CCLabelBMFont</span><span class="o">*</span> <span class="n">label</span> <span class="o">=</span> <span class="n">CCLabelBMFont</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="n">str</span><span class="o">-&gt;</span><span class="n">getCString</span><span class="p">(),</span><span class="s">&quot;level/prim30.fnt&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="n">label</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccp</span><span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="mi">45</span><span class="p">));</span>
</span><span class='line'>    <span class="n">sprite</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">label</span><span class="p">);</span>
</span><span class='line'>  
</span><span class='line'>    <span class="c1">// 这里可以再为 关卡精灵做些装饰，就像 lable 一样，如样式，关卡锁等其它元素</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">sprite</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>写到这里，我们就完成了所有的显示效果，并且可以拖动界面显示不同的页，还有关卡选择的精灵，不过现在还欠缺的就是，关卡点击的操作了！要实现一个可点击操作的功能，我们可以有以下几种常用的方式：</p>

<ul>
<li>使用 CCMenu 来作为点击项的操作：一般而言，一叶不喜欢使用 CCMenu，因为它的触摸时机不好控制，特别是在当前界面可拖动的情况，还有些冲突，解决起来也挺麻烦，一个显著的影响是，点击 CCMenu 的时候，拖动滚屏就失去了效果，如果你有精力着折腾使用 CCMenu ,那么无妨～</li>
<li>使用常用精灵，以容器层接受触摸消息，然后依次遍历精灵，条件判断是否产生点击项，这是一个常用的方法，需要设定好一系列集合，遍历，判断等复杂的步骤，特别是类似方块游戏中用的挺多，总乐此不疲～话说一叶之前也是这么实现的！但是实现起来也时相当麻烦的～而且编写的逻辑不能够被重用（其它游戏类似功能）</li>
<li>建立一套新的机制，来满足特性情况下的需求，也就是封装一套解决方案，以方便对诸如此类的操作，这让一叶想到了之前的文章 《<a href="http://blog.leafsoar.com/archives/2013/05-25.html">多层 UI 触摸事件的轻量级设计</a>》（这种设计能够适应大多情况，正好用在此处，看看它的实用性如何！），在写这篇文章的时候，也将此处的操作用这样的机制重构一番。</li>
</ul>


<hr />

<h3><strong>基于 LsTouch 的触摸机制实现</strong></h3>

<p>在阅读以下内容之前，可以先看《<a href="http://blog.leafsoar.com/archives/2013/05-25.html">多层 UI 触摸事件的轻量级设计</a>》一文，里面详细介绍了它的实现机制，以及特性，可以简称它为 <strong>LsTouch</strong>，而此文是将这种设计用在可用之处。当然作为封装来说，你并不需要了解它的内部实现，就能够很好的使用它。或者换句话说，作为封装的模块，你只需要知道，如下这样使用它就行，它能帮我们解决触摸操作的问题，如果对内部实现感兴趣，可以去看一看实现。它的步骤如下。</p>

<p> 继承 <strong>LsTouchEvent</strong> 并实现 <strong>touchEventAction</strong> 接口函数，这样做以后将意味着，你可以在这个类中使用 <strong>addLsTouch</strong> 方法添加 “可触摸” 元素，其自动管理，之后可以在任意地方调用 <strong>sendTouchMessage</strong> 方法（它将会传入当前的点击 pTouch 参数），后自动回调 touchEventAction 方法，回调参数将包含了，当前的 “可触摸” 元素的引用，你因此知道，你点击的是哪个元素（如 哪个关卡）。以下用代码来说明其实现（我们将旧代码注释，以体现所改动的地方）：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 继承 LsTouchEvent 并实现接口函数</span>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">touchEventAction</span><span class="p">(</span><span class="n">LsTouch</span> <span class="o">*</span><span class="n">touch</span><span class="p">,</span> <span class="kt">int</span> <span class="n">type</span><span class="p">){</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">touch</span><span class="p">)</span>
</span><span class='line'>        <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;touch event action id: %d  type: %d&quot;</span><span class="p">,</span> <span class="n">touch</span><span class="o">-&gt;</span><span class="n">getEventId</span><span class="p">(),</span> <span class="n">type</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 改写上文，返回精灵函数，使之变为可操作项</span>
</span><span class='line'><span class="n">CCNode</span><span class="o">*</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">getSpriteByLevel</span><span class="p">(</span><span class="kt">int</span> <span class="n">level</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// CCSprite* sprite = CCSprite::create(&quot;level/level.png&quot;);</span>
</span><span class='line'>    <span class="c1">// // 添加关卡标示</span>
</span><span class='line'>    <span class="c1">// CCString* str = CCString::createWithFormat(&quot;%d&quot;, level + 1);</span>
</span><span class='line'>    <span class="c1">// CCLabelBMFont* label = CCLabelBMFont::create(str-&gt;getCString(),&quot;level/prim30.fnt&quot;);</span>
</span><span class='line'>    <span class="c1">// label-&gt;setPosition(ccp(40, 45));</span>
</span><span class='line'>    <span class="c1">// sprite-&gt;addChild(label);</span>
</span><span class='line'>    <span class="c1">// // 这里可以再为 关卡精灵做些装饰，就像 lable 一样</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 可以看到改动的地方不多，这样就把需要显示的精灵，包装成了可操作项</span>
</span><span class='line'>    <span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span> <span class="o">=</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>    <span class="n">touch</span><span class="o">-&gt;</span><span class="n">setDisplay</span><span class="p">(</span><span class="n">sprite</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// 可触摸项添加到可触摸项集合，关卡 level 作为 eventId 传递</span>
</span><span class='line'>    <span class="k">this</span><span class="o">-&gt;</span><span class="n">addLsTouch</span><span class="p">(</span><span class="n">touch</span><span class="p">,</span> <span class="n">level</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">touch</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 在触摸函数里面添加，发送触摸消息，只需要添加一句话</span>
</span><span class='line'><span class="kt">bool</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">ccTouchBegan</span><span class="p">(</span><span class="n">cocos2d</span><span class="o">::</span><span class="n">CCTouch</span> <span class="o">*</span><span class="n">pTouch</span><span class="p">,</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">){</span>
</span><span class='line'>  <span class="c1">// CCLog(&quot;touch begin.&quot;);</span>
</span><span class='line'>    <span class="c1">// m_touchPoint = CCDirector::sharedDirector()-&gt;convertToGL(pTouch-&gt;getLocationInView());</span>
</span><span class='line'>    <span class="c1">// m_touchOffset = getScrollView()-&gt;getContentOffset();</span>
</span><span class='line'>  
</span><span class='line'>    <span class="c1">// 发送触摸消息，并会在 touEventAction 自动相应， 如果触摸到元素</span>
</span><span class='line'>    <span class="n">sendTouchMessage</span><span class="p">(</span><span class="n">pTouch</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 这里也是同样</span>
</span><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">ccTouchEnded</span><span class="p">(</span><span class="n">cocos2d</span><span class="o">::</span><span class="n">CCTouch</span> <span class="o">*</span><span class="n">pTouch</span><span class="p">,</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">){</span>
</span><span class='line'>    <span class="c1">// CCPoint endPoint = CCDirector::sharedDirector()-&gt;convertToGL(pTouch-&gt;getLocationInView());</span>
</span><span class='line'>    <span class="c1">// float distance = endPoint.x - m_touchPoint.x;</span>
</span><span class='line'>    <span class="c1">// float distanceY = endPoint.y - m_touchPoint.y;</span>
</span><span class='line'>    <span class="c1">//if (fabs(distance) &lt; 3 &amp;&amp; fabs(distanceY) &lt; 3){</span>
</span><span class='line'>        <span class="c1">// 小于三，不做拖动操作，也排除了（抖动误操作）,第二个参数，事件类型 1： touch end， 由 touchEventAction 自动响应</span>
</span><span class='line'>        <span class="n">sendTouchMessage</span><span class="p">(</span><span class="n">pTouch</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">//</span>
</span><span class='line'>    <span class="c1">//}else if (fabs(distance) &gt; 50){</span>
</span><span class='line'>    <span class="c1">//    // 大于 50，执行拖动效果</span>
</span><span class='line'>    <span class="c1">//    adjustScrollView(distance);</span>
</span><span class='line'>    <span class="c1">//}else{</span>
</span><span class='line'>    <span class="c1">//    // 回退为拖动之前的位置</span>
</span><span class='line'>    <span class="c1">//    adjustScrollView(0);</span>
</span><span class='line'>    <span class="c1">//}</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 无论如何，触摸结束，类型为 2</span>
</span><span class='line'>    <span class="n">sendTouchMessage</span><span class="p">(</span><span class="n">pTouch</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>上文，我们对 getSpriteByLevel 所返回的精灵做了包装处理，然后在 ccTouch 函数，调用发送触摸消息，然后自动回调 <strong>touchEventAction</strong> 函数，并带回了点击项的参数，这个点击项就包含了关卡信息 eventId ，还扩展了事件类型，表示是在 ccTouchBegin 还是 ccTouchEnd 种调用的，并依次做相应的逻辑操作。</p>

<p>下面具体实现回调函数的逻辑处理，它实现了点击项高亮显示，点击成功时通过 CCMessageBox 弹出提示：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="kt">void</span> <span class="n">LevelView</span><span class="o">::</span><span class="n">touchEventAction</span><span class="p">(</span><span class="n">LsTouch</span> <span class="o">*</span><span class="n">touch</span><span class="p">,</span> <span class="kt">int</span> <span class="n">type</span><span class="p">){</span>
</span><span class='line'>    <span class="c1">// type 事件类型，0：touchbegin 1：touchend 触发 2：touchend 未触发</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">touch</span><span class="p">)</span>
</span><span class='line'>        <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;touch event action id: %d  type: %d&quot;</span><span class="p">,</span> <span class="n">touch</span><span class="o">-&gt;</span><span class="n">getEventId</span><span class="p">(),</span> <span class="n">type</span><span class="p">);</span>
</span><span class='line'>    <span class="kt">int</span> <span class="n">selectTag</span> <span class="o">=</span> <span class="mi">10001</span><span class="p">;</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">touch</span><span class="p">){</span>
</span><span class='line'>        <span class="n">getScrollView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getContainer</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">removeChildByTag</span><span class="p">(</span><span class="n">selectTag</span><span class="p">);</span>
</span><span class='line'>        <span class="c1">// 添加选撞状态的精灵，背景 高亮显示</span>
</span><span class='line'>        <span class="n">CCSprite</span><span class="o">*</span> <span class="n">sprite</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;level/sel.png&quot;</span><span class="p">);</span>
</span><span class='line'>        <span class="n">sprite</span><span class="o">-&gt;</span><span class="n">setScaleX</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
</span><span class='line'>        <span class="n">sprite</span><span class="o">-&gt;</span><span class="n">setScaleY</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
</span><span class='line'>        <span class="n">sprite</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">touch</span><span class="o">-&gt;</span><span class="n">getPosition</span><span class="p">());</span>
</span><span class='line'>      <span class="c1">// 这里使用了 zOrder = 1 以保证，高亮图片显示在 实际关卡图片后面</span>
</span><span class='line'>        <span class="n">getScrollView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getContainer</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">sprite</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">selectTag</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>        <span class="n">getScrollView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getContainer</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">removeChildByTag</span><span class="p">(</span><span class="n">selectTag</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">touch</span><span class="p">){</span>
</span><span class='line'>        <span class="c1">// 收到 type 为 1 表示触发关卡选择</span>
</span><span class='line'>        <span class="n">CCString</span><span class="o">*</span> <span class="n">str</span> <span class="o">=</span> <span class="n">CCString</span><span class="o">::</span><span class="n">createWithFormat</span><span class="p">(</span><span class="s">&quot;您选择的关卡为 %d .&quot;</span><span class="p">,</span> <span class="n">touch</span><span class="o">-&gt;</span><span class="n">getEventId</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>        <span class="n">CCMessageBox</span><span class="p">(</span><span class="s">&quot;关卡&quot;</span><span class="p">,</span> <span class="n">str</span><span class="o">-&gt;</span><span class="n">getCString</span><span class="p">());</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>这里的 LsTouch 根据实际情况 比 原来（原来是指《<a href="http://blog.leafsoar.com/archives/2013/05-25.html">多层 UI 触摸事件的轻量级设计</a>》）做了些改进。</p>

<ul>
<li>内部判断去除了一些不必要的判断</li>
<li>修改消息类型，添加 type 参数，我们可以根据次参数判断消息类型</li>
<li>修改 touchEventAction 为总是回调（在发送消息时），而原来的做法是，这样做的好处是我们可以根据第一个参数是否为空，来做一些处理，而原来只在有点击操作才回调</li>
</ul>


<p>关于这里使用继承 LsTouchEvent 实现 touchEventAction 回调函数的方式，需要简单说明以下，这里设计的核心是使用一个集合管理一推“可触摸”项。至于我用什么方式实现，那不重要，例如换种设计，不用继承实现接口，使用 回调函数绑定，就像绑定 CCMenu 回调一样，如果 C++ 能够像 Java 编写匿名类实现回调，那就更优雅了～实现要 “<strong>达到可用简单，通用难！</strong>”，这里只是一种可行方案。</p>

<hr />

<h2>锦上添花，添加当前页指示球</h2>

<p>当前界面的所有功能已经实现完毕，如果使用它们，你需要注意一些地方，比如关卡精灵可以根据自己需要扩展其元素内容等。由于时滚动分页，为了一目了然我们当前的页，所以也添加了代码实现在屏幕上方设定了 <strong>页数指示球</strong>（我给起的名），指示球会在你拖动界面的时候有动态效果，放大当前 页数的指示球，给予更好的用户体验，关于这部分代码我就不贴了，可以直接从源码里面看见，方法名为 <strong>setCurPageBall</strong>，它会根据总页数和当前页数自动处理，你所需要做的只是在合适的时候调用它即可。</p>

<p>注意：为了让问题更有针对性，在本文中所有的位置关系所参考的都是 WinSize，
这意味着，如果你在不同的屏幕适配方案中可能需要有所改动，对屏幕适配这里有一篇文章可以作为参考《<a href="http://blog.leafsoar.com/archives/2013/05-10.html">Cocos2d-x 屏幕适配新解</a>》。</p>

<p><img src="http://blog.leafsoar.com/images/2013/2013-07-27-1.jpg" alt="图片" /></p>

<p>它完成了以下几个功能（<a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/MacCpp/Classes/LevelView.cpp">示例源码</a>）：</p>

<ul>
<li>帮助界面功能的实现：一个可拖动滚屏的界面展示</li>
<li>实现滚屏的自动校队，一页一页展示</li>
<li>关卡点击事件处理，实现关卡功能</li>
<li>选中关卡的高亮显示，背景标示</li>
<li>由于没有使用 CCMenu ，所以不存在触摸优先级问题，在点击 “关卡” 的同时可拖动屏幕</li>
<li>点击抖动误操作判断（如本来想点击关卡，如果移动了位置[移动范围大于指定值]，那么将执行拖动操作）</li>
<li>当前页指示球功能</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[深入理解 Cocos2d-x 内存管理]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/06-04.html"/>
    <updated>2013-06-04T10:50:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-mem</id>
    <content type="html"><![CDATA[<p>如果 <a href="http://blog.leafsoar.com/archives/2013/05-22.html">Cocos2d-x 内存管理浅说</a> 做为初步认识，而 <a href="http://blog.leafsoar.com/archives/2013/05-29.html">Cocos2d-x 内存管理的一种实现</a>做为进阶使用，那么本文将详细的分析一下 Cocos2d-x 的内存管理的设计实现和原理。<strong>知其然，知其所以然 ~</strong>或者说：嗯，它这么做，一定是有原因的，体会设计者的用意，感同身受，如果是你，将会如何设计！~~</p>

<p>我觉得 <strong>最好的学习方式是以自己的语言组织，说与别人听 ～</strong> 这样对自己：更容易发现平时容易忽略的问题，对别人：或多或少也有所助益！以学习为目的，而别人的受益算是附带的效果，这样一个出发点 ~</p>

<p>由浅入深，总览全局（或者由整体到局部）是我喜欢的出发点，或者思考角度，我不喜欢拘泥于细节的实现，因为那会加大考虑问题的复杂度，所以 <strong>把复杂的问题简单化，是必然的过程。</strong> 那么本文就说说 Cocos2d-x 的架构是如何设计以方便内存管理的。从理论到实践 ~(当然是从我看问题的角度 :P，读者如有异议，欢迎讨论！文本使用 cocos2d-x 2.0.4 解说。)</p>

<!-- more -->


<hr />

<h2>引用计数的由来</h2>

<p>cocos2d-x 的世界是基于 <strong>CCObject</strong> 类构建的，其中的每个元素：层、场景、精灵等都是一个个 CCObject 的对象。所以 <strong>内存管理的本质就是管理一个个 CCObject</strong>。作为一个 cocos2d 的 C++ 移植版本，在它之前有很多其它语言的 <strong>实现</strong>，从架构层次来说，这与语言的实现无关（比如 CCNode 的节点树形关系，其它语言也可以实现，如果是内存方便，C# 等更是无需考虑），但就从内存管理方面来说，参考了 OC （Objective-C） 的内存管理实现。</p>

<p>一个简单的<strong>自动管理原则</strong>：<strong>CCObject 内部维护着一个引用计数，引用计数为 0 就自动释放 ～</strong>（如果么有直接做如 delete 之类的操作）。那么此时可以预见，<strong>管理内存的实质就是管理这些 &ldquo;引用计数&rdquo; </strong> 了！使用 retain 和 release 方法对引用计数进行操作！</p>

<hr />

<h2>为什么要有自动释放池 及其作用</h2>

<p>我们知道 cocos2d-x 使用了自动释放池，自动管理对象，知其然！其所以然呢？<strong>为什么需要自动释放池</strong>，它在整个框架之中又起着什么样的作用！在了解这一点之前，我们需要 <strong>知道 CCObject 从创建之初，到最终销毁</strong>，经历了哪些过程。在此，一叶总结以下几点：</p>

<ul>
<li>刚创建的对象，而 <strong>为了保证在使用之前不会释放</strong>（至少让它存活一帧），所以<strong>自引用</strong>（也就是初始为1）</li>
<li>为了确定是否 <strong>实际使用</strong>，所以需要在一个合适的时机，<strong>解除自身引用。</strong></li>
<li>而这个何时的时机正是在<strong>帧过度之时。</strong></li>
<li>帧过度之后的对象，<strong>用则用矣，不用则弃！</strong></li>
<li>由于已经解除了自身引用，所以它的<strong>引用被使用者管理</strong>（一般而言，内部组成树形结构的链式反应，如 CCNode）。</li>
<li>链式反应，也就是，如果释放一个对象，也会释放它所引用的对象。</li>
</ul>


<p>上面是一个对象的大致流程，我们将对象分为<strong>两个时期</strong>，一个是刚<strong>创建时期</strong>，自引用为 <strong>1</strong>（如果为 0 就会释放对象，这是基本原则，所以要大于 0） 的时期，另一个是<strong>使用时期</strong>。上面说到，为了保证创建时期的对象不被销毁，所以自引用(<strong>并没有实际的使用</strong>)初始化为 1，这就意味着我们需要一个合适的时机，来解除这样的自引用。</p>

<p><strong>何时？</strong>在帧过度之时！(这样可保证当前帧能正确使用对象而没有被销毁。)<strong>怎么样释放？</strong>由于是自引用，我们并不能通过其它方式访问到它，所以就有了自动释放池，我们 <strong>变相的将“自引用”转化“自动释放池引用”，来标记一个 “创建时期的对象”</strong>。然后在帧过度之时，通过自动释放池管理，统一释放 “释放池引用”，也就意味着，去除了“自身引用”。<strong>帧过度之后的对象，才是真正的被使用者所管理。</strong> 下面我们用代码来解释上述过程。</p>

<p>通常我们使用 <code>create();</code> 方法来创建一个自动管理的对象，而其内部实际操作如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 初始化一个对象</span>
</span><span class='line'><span class="k">static</span> <span class="n">CCObject</span><span class="o">*</span> <span class="n">create</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// new CCObject 对象</span>
</span><span class='line'>  <span class="n">CCObject</span> <span class="o">*</span><span class="n">pRet</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCObject</span><span class="p">();</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">pRet</span> <span class="o">&amp;&amp;</span> <span class="n">pRet</span><span class="o">-&gt;</span><span class="n">init</span><span class="p">())</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>      <span class="c1">// 添加到自动释放池</span>
</span><span class='line'>        <span class="n">pRet</span><span class="o">-&gt;</span><span class="n">autorelease</span><span class="p">();</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">pRet</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="k">delete</span> <span class="n">pRet</span><span class="p">;</span>
</span><span class='line'>        <span class="n">pRet</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 我们看到初始化的对象 自引用 m_uReference = 1</span>
</span><span class='line'><span class="n">CCObject</span><span class="o">::</span><span class="n">CCObject</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="o">:</span><span class="n">m_uAutoReleaseCount</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span><span class='line'><span class="p">,</span><span class="n">m_uReference</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// when the object is created, the reference count of it is 1</span>
</span><span class='line'><span class="p">,</span><span class="n">m_nLuaID</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">uObjectCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">m_uID</span> <span class="o">=</span> <span class="o">++</span><span class="n">uObjectCount</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 标记为自动释放对象</span>
</span><span class='line'><span class="n">CCObject</span><span class="o">*</span> <span class="n">CCObject</span><span class="o">::</span><span class="n">autorelease</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 添加到自动释放池</span>
</span><span class='line'>    <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">sharedPoolManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addObject</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 继续跟踪</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">addObject</span><span class="p">(</span><span class="n">CCObject</span><span class="o">*</span> <span class="n">pObject</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">getCurReleasePool</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addObject</span><span class="p">(</span><span class="n">pObject</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 添加到自动释放池的实际操作</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCAutoreleasePool</span><span class="o">::</span><span class="n">addObject</span><span class="p">(</span><span class="n">CCObject</span><span class="o">*</span> <span class="n">pObject</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 内部是由一个 CCArray 维护自动释放对象，并且此操作 会使引用 + 1</span>
</span><span class='line'>    <span class="n">m_pManagedObjectArray</span><span class="o">-&gt;</span><span class="n">addObject</span><span class="p">(</span><span class="n">pObject</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 由于初始化 引用为 1，上面又有操作，所以引用至少为 2 （可能还被其它所引用）</span>
</span><span class='line'>    <span class="n">CCAssert</span><span class="p">(</span><span class="n">pObject</span><span class="o">-&gt;</span><span class="n">m_uReference</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">,</span> <span class="s">&quot;reference count should be greater than 1&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="o">++</span><span class="p">(</span><span class="n">pObject</span><span class="o">-&gt;</span><span class="n">m_uAutoReleaseCount</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// 变相的将自身引用转化为释放池引用，所以减 1</span>
</span><span class='line'>    <span class="n">pObject</span><span class="o">-&gt;</span><span class="n">release</span><span class="p">();</span> <span class="c1">// no ref count, in this case autorelease pool added.</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>上面便是通过 <code>create()</code> 方法创建对象的过程。文中说到，一个合适的时机，解除自身引用（也就是释放池引用），那这又是在何时进行的呢？程序的运行有一个主循环，控制着每一帧的操作，在每一帧画面画完之时会自动调用 <code>CCPoolManager::sharedPoolManager()-&gt;pop();</code> 方法 ( 具体可参见文章<a href="http://blog.leafsoar.com/archives/2013/05-05.html">Cocos2d-x 程序是如何开始运行与结束的</a> ，这里我们只要知道每一帧结束都会调用 pop() 方法)，来自动清理 <strong>创建时期</strong> 的引用。现在我们就来看看 <code>pop()</code> 的方法实现：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="kt">void</span> <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">pop</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">m_pCurReleasePool</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="k">return</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 当前释放池个数，pop 使用栈结构</span>
</span><span class='line'>     <span class="kt">int</span> <span class="n">nCount</span> <span class="o">=</span> <span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">count</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 释放池当中存放的都是 创建时期 对象，此时解除释放池引用</span>
</span><span class='line'>    <span class="n">m_pCurReleasePool</span><span class="o">-&gt;</span><span class="n">clear</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 当前释放池，出栈，在这里可以看到判断 nCount 是否大于 1，文后将会对此做具体说明</span>
</span><span class='line'>      <span class="k">if</span><span class="p">(</span><span class="n">nCount</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span>
</span><span class='line'>      <span class="p">{</span>
</span><span class='line'>        <span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">removeObjectAtIndex</span><span class="p">(</span><span class="n">nCount</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">//         if(nCount &gt; 1)</span>
</span><span class='line'><span class="c1">//         {</span>
</span><span class='line'><span class="c1">//             m_pCurReleasePool = m_pReleasePoolStack-&gt;objectAtIndex(nCount - 2);</span>
</span><span class='line'><span class="c1">//             return;</span>
</span><span class='line'><span class="c1">//         }</span>
</span><span class='line'>        <span class="n">m_pCurReleasePool</span> <span class="o">=</span> <span class="p">(</span><span class="n">CCAutoreleasePool</span><span class="o">*</span><span class="p">)</span><span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">objectAtIndex</span><span class="p">(</span><span class="n">nCount</span> <span class="o">-</span> <span class="mi">2</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/*m_pCurReleasePool = NULL;*/</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 释放池引用清理工作</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCAutoreleasePool</span><span class="o">::</span><span class="n">clear</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 如果释放池存在 创建时期 的对象</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="n">m_pManagedObjectArray</span><span class="o">-&gt;</span><span class="n">count</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="c1">//CCAutoreleasePool* pReleasePool;</span>
</span><span class='line'><span class="cp">#ifdef _DEBUG</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">nIndex</span> <span class="o">=</span> <span class="n">m_pManagedObjectArray</span><span class="o">-&gt;</span><span class="n">count</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">CCObject</span><span class="o">*</span> <span class="n">pObj</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>        <span class="n">CCARRAY_FOREACH_REVERSE</span><span class="p">(</span><span class="n">m_pManagedObjectArray</span><span class="p">,</span> <span class="n">pObj</span><span class="p">)</span>
</span><span class='line'>        <span class="p">{</span>
</span><span class='line'>            <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">pObj</span><span class="p">)</span>
</span><span class='line'>                <span class="k">break</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="o">--</span><span class="p">(</span><span class="n">pObj</span><span class="o">-&gt;</span><span class="n">m_uAutoReleaseCount</span><span class="p">);</span>
</span><span class='line'>            <span class="c1">//(*it)-&gt;release();</span>
</span><span class='line'>            <span class="c1">//delete (*it);</span>
</span><span class='line'><span class="cp">#ifdef _DEBUG</span>
</span><span class='line'>            <span class="n">nIndex</span><span class="o">--</span><span class="p">;</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="c1">// 移除释放池对创建时期对象的引用，从而使对象交由使用者全权管理</span>
</span><span class='line'>        <span class="n">m_pManagedObjectArray</span><span class="o">-&gt;</span><span class="n">removeAllObjects</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><strong>到这里，自动释放池的作用也就完成了！</strong> 可以说创建的对象在一帧 (<strong>但有特殊情况，下一段说明</strong>) 之后就完全脱离了 <strong>自动释放池的控制</strong>，自动释放池，对对象的管理也就在 <strong>创建时期起着作用</strong>！之后便交由使用者管理，释放。</p>

<hr />

<h2>对&#8221;释放池&#8221;的管理说明</h2>

<p>我们知道了释放池管理着 <strong>创建时期</strong> 的对象，那么对于释放池本身是如何管理的？我们知道对于释放池，只需要有一个就已经能够满足我们的需求了，而在 cocos2d-x 的设计中，使用了集合管理 <strong>一堆</strong> 释放池。而在实际，它们又发挥了多大的用处？</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 释放池管理接口</span>
</span><span class='line'><span class="k">class</span> <span class="nc">CC_DLL</span> <span class="n">CCPoolManager</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 释放池对象集合</span>
</span><span class='line'>    <span class="n">CCArray</span><span class="o">*</span>    <span class="n">m_pReleasePoolStack</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 当前操作释放池</span>
</span><span class='line'>    <span class="n">CCAutoreleasePool</span><span class="o">*</span>                    <span class="n">m_pCurReleasePool</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 获取当前释放池</span>
</span><span class='line'>    <span class="n">CCAutoreleasePool</span><span class="o">*</span> <span class="n">getCurReleasePool</span><span class="p">();</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>    <span class="n">CCPoolManager</span><span class="p">();</span>
</span><span class='line'>    <span class="o">~</span><span class="n">CCPoolManager</span><span class="p">();</span>
</span><span class='line'>    <span class="kt">void</span> <span class="n">finalize</span><span class="p">();</span>
</span><span class='line'>    <span class="kt">void</span> <span class="n">push</span><span class="p">();</span>
</span><span class='line'>    <span class="kt">void</span> <span class="n">pop</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kt">void</span> <span class="n">removeObject</span><span class="p">(</span><span class="n">CCObject</span><span class="o">*</span> <span class="n">pObject</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// 添加一个 创建时期 对象</span>
</span><span class='line'>    <span class="kt">void</span> <span class="n">addObject</span><span class="p">(</span><span class="n">CCObject</span><span class="o">*</span> <span class="n">pObject</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">static</span> <span class="n">CCPoolManager</span><span class="o">*</span> <span class="n">sharedPoolManager</span><span class="p">();</span>
</span><span class='line'>    <span class="k">static</span> <span class="kt">void</span> <span class="n">purgePoolManager</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">friend</span> <span class="k">class</span> <span class="nc">CCAutoreleasePool</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 我们从 addObject 开始看起，由上文可以 addObject 是由 CCObject 的 autorelease 自动调用的</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">addObject</span><span class="p">(</span><span class="n">CCObject</span><span class="o">*</span> <span class="n">pObject</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">getCurReleasePool</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">addObject</span><span class="p">(</span><span class="n">pObject</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCAutoreleasePool</span><span class="o">*</span> <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">getCurReleasePool</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 如果当前释放池为空</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">m_pCurReleasePool</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>      <span class="c1">// 添加一个</span>
</span><span class='line'>        <span class="n">push</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">CCAssert</span><span class="p">(</span><span class="n">m_pCurReleasePool</span><span class="p">,</span> <span class="s">&quot;current auto release pool should not be null&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">m_pCurReleasePool</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">push</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">CCAutoreleasePool</span><span class="o">*</span> <span class="n">pPool</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCAutoreleasePool</span><span class="p">();</span>       <span class="c1">//ref = 1</span>
</span><span class='line'>    <span class="n">m_pCurReleasePool</span> <span class="o">=</span> <span class="n">pPool</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 像集合添加一个新的释放池</span>
</span><span class='line'>    <span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">addObject</span><span class="p">(</span><span class="n">pPool</span><span class="p">);</span>                   <span class="c1">//ref = 2</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">pPool</span><span class="o">-&gt;</span><span class="n">release</span><span class="p">();</span>                                       <span class="c1">//ref = 1</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>从 addObject 开始分析，我们知道在 addObject 之前，会首先判断是否有当前的释放池，如果没有则创建，如果有，则直接使用，可想而知，在任何使用，任何情况，通过 addObject 只需要创建一个释放池便已经足够使用了。事实上也是如此。再来看 pop 方法。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="kt">void</span> <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">pop</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">m_pCurReleasePool</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="k">return</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>     <span class="kt">int</span> <span class="n">nCount</span> <span class="o">=</span> <span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">count</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 清楚对 创建对象 的引用</span>
</span><span class='line'>    <span class="n">m_pCurReleasePool</span><span class="o">-&gt;</span><span class="n">clear</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 如果大于 1，这也保证着，在任何时候，总有一个释放池是可以使用的</span>
</span><span class='line'>      <span class="k">if</span><span class="p">(</span><span class="n">nCount</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span>
</span><span class='line'>      <span class="p">{</span>
</span><span class='line'>        <span class="c1">// 移除当前的释放池</span>
</span><span class='line'>        <span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">removeObjectAtIndex</span><span class="p">(</span><span class="n">nCount</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">//         if(nCount &gt; 1)</span>
</span><span class='line'><span class="c1">//         {</span>
</span><span class='line'><span class="c1">//             m_pCurReleasePool = m_pReleasePoolStack-&gt;objectAtIndex(nCount - 2);</span>
</span><span class='line'><span class="c1">//             return;</span>
</span><span class='line'><span class="c1">//         }</span>
</span><span class='line'>      <span class="c1">// 将当前释放池设定为前一个释放池，也就是 “出栈”的操作</span>
</span><span class='line'>        <span class="n">m_pCurReleasePool</span> <span class="o">=</span> <span class="p">(</span><span class="n">CCAutoreleasePool</span><span class="o">*</span><span class="p">)</span><span class="n">m_pReleasePoolStack</span><span class="o">-&gt;</span><span class="n">objectAtIndex</span><span class="p">(</span><span class="n">nCount</span> <span class="o">-</span> <span class="mi">2</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/*m_pCurReleasePool = NULL;*/</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><strong>看到这里</strong> 我就不解了！什么情况下才能用到多个释放池？按照设计的逻辑根本用不到。带着这个疑问，我在 <code>CCPoolManager::push()</code> 方法之内添加了一句话打印（修改源代码） <code>CCLog("这里要长长长的 **********");</code> ，然后重新编译源文件，运行程序，发现实际的使用中，push 只被调用了两次！我们知道，通过 addObject 可能会自动调用 <code>push()</code> 一次，但也仅有一次，所以一定是哪里手动调用了 <code>push()</code> 方法，才会出现这种情况，所以我继续翻看源代码，定位到了 <code>bool CCDirector::init(void)</code> 方法，在这里进行了游戏的全局初始化相关工作：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="kt">bool</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CCLOG</span><span class="p">(</span><span class="s">&quot;cocos2d: %s&quot;</span><span class="p">,</span> <span class="n">cocos2dVersion</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="n">m_dOldAnimationInterval</span> <span class="o">=</span> <span class="n">m_dAnimationInterval</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="n">kDefaultFPS</span><span class="p">;</span>
</span><span class='line'>    <span class="n">m_pobScenesStack</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCArray</span><span class="p">();</span>
</span><span class='line'>    <span class="n">m_pobScenesStack</span><span class="o">-&gt;</span><span class="n">init</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>    <span class="n">m_fContentScaleFactor</span> <span class="o">=</span> <span class="mf">1.0f</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>    <span class="c1">// touchDispatcher</span>
</span><span class='line'>    <span class="n">m_pTouchDispatcher</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCTouchDispatcher</span><span class="p">();</span>
</span><span class='line'>    <span class="n">m_pTouchDispatcher</span><span class="o">-&gt;</span><span class="n">init</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// KeypadDispatcher</span>
</span><span class='line'>    <span class="n">m_pKeypadDispatcher</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCKeypadDispatcher</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// Accelerometer</span>
</span><span class='line'>    <span class="n">m_pAccelerometer</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCAccelerometer</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 这里手动调用了 push 方法，而在这之前的初始化过程中，间接的使用了 CCObject 的 autorelease，已经触发过一次 push 方法</span>
</span><span class='line'>    <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">sharedPoolManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">push</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><strong>所以我们便能够看到 push 方法被调用了两次</strong>，但其实如果我们把这里的手动调用放在方法的开始处，或者干脆就不使用 <code>CCPoolManager::sharedPoolManager()-&gt;push();</code> ，对程序也没任何影响，这样从头到尾，<strong>只创建了一个自动释放池，而这里多创建的一个并没有多大的用处。</strong> 或者用处不甚明显，因为多创建一个释放池是有其效果的，效果具体体现在哪里，那就是 <strong>可以使调用 push() 方法之前的对象，多存活一帧。</strong>，因为 pop 方法只对当前释放池做了 clear 释放。为了方便起见，我们使用 <a href="http://blog.leafsoar.com/archives/2013/05-22.html">Cocos2d-x 内存管理浅说</a> 里面的方法观察每一帧的情况，看下面测试代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 关键代码如下</span>
</span><span class='line'><span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 创建一个自动管理对象</span>
</span><span class='line'>  <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 创建一个新的自动释放池</span>
</span><span class='line'>  <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">sharedPoolManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">push</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 再创建一个自动管理对象</span>
</span><span class='line'>  <span class="n">sprite</span> <span class="o">=</span> <span class="n">LSSprite</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d end&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 打印代码如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 第一帧创建了两个自动管理对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 第一个过度帧只释放了 sprite 对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 第二个过度帧释放了 layer 对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>可以对比 sprite 和 layer 对象，两个对象被放在了不同的自动释放池之中。这就是 手动调用 <code>push()</code> 方法所能达到的效果，至于怎么利用这个特性，<strong>帮助我们完成特殊的功能？我想还是不用了</strong>，这会增加我们程序设计的 <strong>复杂度</strong>，在我看来，甚至想把，cocos2d-x 2.0.4 中那唯一一次调用的 <code>push()</code> 给删了，以保持简单（程序的第一次初始化“可能”会用到这个特性，不过目测是没有多大关系的了 : P），在这里只系统通过这个例子理解 自动释放池是怎样被管理的即可！</p>

<p>从自动释放池管理 <strong>创建时期</strong> 对象，再到对释放池的管理，我们已经大概了解了一个对象的生命周期经历了哪些！ 下面简单说说 <strong>使用时期</strong> 的对象管理。</p>

<hr />

<h2>树形结构的链式反应</h2>

<p>文中我们知道了，自动释放池的存在意义，在于对象 <strong>创建时期</strong> 的处理，而仅仅理解了自动释放池，对于我们使用 cocos2d-x 不够，远远不够！自动释放池只是解决对象初始化的问题，仅此而已，而要在整个使用过程中，相对的自动化管理，那么必须理解两个概念，<strong>树形结构</strong> 和 <strong>链式反应</strong> （链式反应，不错的说法，就像原子弹爆炸一样，一传十，十传百 ：P）</p>

<p>我们当前运行这一个场景，场景初始化，添加了很多层，层里面有其它的层或者精灵，而这些都是 CCNode 节点，以场景为根，形成一个树形结构，场景初始化之后（一帧之后），这些节点将完全 <strong>依附</strong> (内部通过 retain) 在这个树形结构之上，全权交由树来管理，当我们 <strong>砍去一个树枝</strong>，或者将树 <strong>连根拔起</strong>，那么在它之上的“子节点”也会跟着去除(内部通过 release)，这便是链式反应。</p>

<p><a href="http://blog.leafsoar.com/archives/2013/05-29.html">Cocos2d-x 内存管理的一种实现</a>，此文这种实现的本质既是 <strong>强化</strong>这种 <strong>链式反应</strong>，也是解决内存可能出错的一个解决方案。如下（前文片段，具体详见前文）：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 方式一：那么我们的使用过程</span>
</span><span class='line'><span class="n">LUser</span><span class="o">*</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">LUser</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sSprite</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;a.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="c1">// 如果这里不 retain  则以后就用不到了</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sSprite</span><span class="o">-&gt;</span><span class="n">retain</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 方式二：使用方法</span>
</span><span class='line'><span class="n">LUser</span><span class="o">*</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">LUser</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sUserName</span> <span class="o">=</span> <span class="s">&quot;一叶&quot;</span><span class="p">;</span>
</span><span class='line'><span class="c1">// 这里的 sprite 会随着 lu 的消亡而消亡，不用管释放问题了</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">setSprite</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;a.png&quot;</span><span class="p">));</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>我们看到方式二相比方式一的设计，它通过 setSprite 内部对 sprite 本身 retain，从而实现<strong>链式反应</strong>，而不是直接使用 <code>lu-&gt;m_sSprite-&gt;retain();</code>，这样的好处是，我只要想着释放 LUser，而不用考虑LUser 内部 sprite 的引用情况就行了。如此才能把 cocos2d-x 内存的自动管理特性完全发挥 ~</p>

<p>而要实现这样管理的一个明显特征就是，隐藏 <code>retain</code> 和 <code>release</code> 操作 ~</p>

<hr />

<h2>稍作总结</h2>

<p>关于 cocos2d-x 的内存管理从使用到原理，系列文章就到这里了！（三篇也算系列 = =!） 由表象到内部的思考探索过程，其实在 <strong>浅说</strong> 当中对 cocos2d-x 的使用，便已经能够知晓内部细节设计之一二，透过现象看本质！三篇文章包含了，使用浅说（简单的测试），一种防止内存泄漏的设计（加强链式反应），最后纵览 cocos2d-x 的内存管理框架，对 CCObject 的生命周期做了简单的说明，当然其中还是隐藏一些细节的，比如管理都是用 CCArray 来管理，但我们并没有对 CCArray 做介绍，它是如何添加元素，如何引用等。在任何时候我们只针对一个问题进行思考，那我们该把 CCArray 这样的辅助工具类放在何处，如果你了解当然最好，不过不了解，那便 <strong>存疑</strong> ，然后对相应的问题，分而治之 ~</p>

<p><strong>存疑</strong> 可以帮助一叶在某个时刻只针对某一个问题进行思考，从而使问题变的简单。对文中所涉及的到的两个类 <code>CCPoolManager</code> 和 <code>CCAutoreleasePool</code> 其中所有的方法并没有面面俱到，当然有了整体思路，去 <strong>填充那些</strong> 小疑问将会变得简单。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cocos2d-x 内存管理的一种实现]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-29.html"/>
    <updated>2013-05-29T10:10:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-property</id>
    <content type="html"><![CDATA[<p>使用 Cocos2d-x 编写游戏，常被人吐槽，吐槽什么，当然是内存管理，C++ 的使用本以不易，而在 Cocos2d-x 添加了半内存自动管理，在这么一种 <strong>复合机制</strong> 下，使得出现内存问题的概率直线飙升 ~</p>

<p>而关于这一点，可能在于并没有一个通用的合理的内存管理方式，能够更好的使用 Cocos2d-x ，或者说，缺少那么一种 <strong>规范</strong>，如果存在了这么一种 <strong>规范</strong>，而使得 Cocos2d-x 更为简单优雅，那势必是游戏的开发过程，更加从新所欲，把重点放在游戏本身的设计之上。</p>

<h2>Retain 与 Release 乃万恶之源</h2>

<p>稍微了解一点就能知道 Cocos2d-x 是基于引用计数来管理内存的，应用计数的加减就是 retain 和 release 方法的实现。在大多数情况下我们不用 <strong>显示</strong> 的去调用这两种方法，如在 <strong>CCNode</strong> 的 <strong>addChild</strong> 和 <strong>removeChild</strong> 方法，<strong>CCArray</strong> 的 <strong>addObject</strong> 和 <strong>removeObject</strong> 等这样成双成对的方法，对于这些的使用很简单，一叶上篇文章 <strong><a href="http://blog.leafsoar.com/archives/2013/05-22.html">Cocos2d-x 内存管理浅说</a></strong> 从概念上简单的分析了内部对象的生命周期特点，在此 <strong>浅说</strong> 之中，我刻意的绕过了它的底层实现，并没有深究其原理，对引用计数等概念也只是几句话一带而过，重点放在使用者该关心什么，该注意什么。因为我觉得 <strong>引用计数是个坑，一个很大的坑 ~</strong></p>

<!-- more -->


<p>当我们想要长期 <strong>持有</strong> 某个对象的时候，我们会用到 retain 和 release 方法，而这种情况我们会经常遇到，如那些 <strong>非CCNode</strong> 类型，比如一个运行场景里面有一个 <strong>CCString</strong> （以CCString 为例，显然此刻你更愿意用 std::string）保存的场景名称，以便我们随时使用，那我们一个简单的做法就是在场景初始化的时候创建 CCString 对象，赋值，然后 retain，在场景结束或者析构函数中 release，这很简单，一个 retain 对应一个 release 就没有问题了，如果问题稍微变的复杂，在程序的运行中，我们可能会改变这个属性值，创建一个新的 CCString 去替换它，那在执行这些操作的时候我们需要很多判断，是否已经有值，首先要解除之前的引用，在重新引用新的对象~~<strong>诸如此类</strong>，如果中间不需要此对象，中间直接释放，那么我们会 <strong>非常华丽的看到在程序代码之中到处穿插着 retain 和 release 操作</strong>。而这些 retain 和 release 虽然成对出现，但不一定在同一个方法，<strong>这就演变成了，所在的不同方法也要成对的调用。</strong></p>

<p><strong>你把青蛙放到冷水里，再慢慢地加热，青蛙感觉不到什么，直到最后被烫死。</strong> 使用 retain 和 release 就正如温水里的青蛙，刚开始到也没觉得什么，引用计数概念多好。而到后来，发现越来越难以控制，为时以晚矣～</p>

<p>“如果说C语言给了你足够的绳子吊死自己，那么C++给的绳子除了够你上吊之外，还够绑上你所有的邻居，并提供一艘帆船所需的绳索。”（摘自 <strong>UNIX痛恨者手册</strong>） 而此时 ~~~</p>

<h2>建立规范 完全消灭 retain 和 release</h2>

<p>既然说 retain 和 release 乃万恶之源，那么我们只要 <strong>从源头上，解决这个问题</strong>，如此一切将会变的非常简单，我们将建立一种类似 addChild 这样的 <strong>内部处理</strong> 机制，不用显示的调用 retain 和 release ，从而杜绝了 retain “漫天飞”的可能。而要实现这样的机制，只需简单的设计即可 ~代码实现如下<a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/Learn/Classes/Property/Property.h">源码示例</a>：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 为了方便起见，自定义宏，并且为 varName 的实现加上了 __ls_ 的前缀，前缀可以修改，可以很长很长很长</span>
</span><span class='line'><span class="c1">// 加 __ls_ 前缀是为了，在使用的过程只通过 set 和 get 属性包装器调用，而不要直接使用此属性</span>
</span><span class='line'><span class="cp">#define LS_PRE(p) __ls_##p</span>
</span><span class='line'><span class="c1">//#define LS_PRE(p) __retain_##p         // 其它前缀都行，目的是为了不让在直接使用此类型对象</span>
</span><span class='line'>
</span><span class='line'><span class="c1">//   此处定义以弃用</span>
</span><span class='line'><span class="c1">//   #define LS_PROPERTY_RETAIN(varType, varName, funName)\</span>
</span><span class='line'><span class="c1">//   private: varType LS_PRE(varName);\</span>
</span><span class='line'><span class="c1">//   public: void set##funName(varType value){\</span>
</span><span class='line'><span class="c1">//       CC_SAFE_RELEASE_NULL(LS_PRE(varName));\</span>
</span><span class='line'><span class="c1">//       LS_PRE(varName) = value;\</span>
</span><span class='line'><span class="c1">//       CC_SAFE_RETAIN(LS_PRE(varName));\</span>
</span><span class='line'><span class="c1">//   }; \</span>
</span><span class='line'><span class="c1">//   public: varType get##funName(){return LS_PRE(varName);};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 经朋友提醒，发现 cocos2d-x 已经实现了相应功能的宏，并且更好用，那这里的二次包装就算是仅仅加个前缀吧 ！！！</span>
</span><span class='line'><span class="cp">#define LS_PROPERTY_RETAIN(varType, varName, funName)\</span>
</span><span class='line'><span class="cp"> CC_SYNTHESIZE_RETAIN(varType, LS_PRE(varName), funName);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 初始化和释放包装宏，主要为了封装前缀，始定义统一</span>
</span><span class='line'><span class="cp">#define LS_P_INIT(p) LS_PRE(p)(0)</span>
</span><span class='line'><span class="cp">#define LS_P_RELEASE(p) CC_SAFE_RELEASE_NULL(LS_PRE(p))</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * 自定义类型数据：用户信息</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">LUser</span><span class="o">:</span> <span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCObject</span><span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">LUser</span><span class="p">);</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">(){</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="n">LUser</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LUser()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LUser</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LUser().~():%s&quot;</span><span class="p">,</span> <span class="n">m_sUserName</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_sUserName</span><span class="p">;</span>     <span class="c1">// 用户名</span>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_sPassword</span><span class="p">;</span>     <span class="c1">// 用户密码</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">PropertyTest</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCLayer</span><span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">PropertyTest</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;PropertyTest().init()&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="n">LUser</span><span class="o">*</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">LUser</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>      <span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sUserName</span> <span class="o">=</span> <span class="s">&quot;leafsoar&quot;</span><span class="p">;</span>
</span><span class='line'>      <span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sPassword</span> <span class="o">=</span> <span class="s">&quot;123456&quot;</span><span class="p">;</span>
</span><span class='line'>      <span class="n">setLUser</span><span class="p">(</span><span class="n">lu</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 为了方便在不同帧测试，启用定时器</span>
</span><span class='line'>      <span class="k">this</span><span class="o">-&gt;</span><span class="n">scheduleUpdate</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="kt">float</span> <span class="n">fDelta</span><span class="p">){</span>
</span><span class='line'>          <span class="c1">// 为了方便观察，不让 update 内部无止境的打印下去</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">){</span>
</span><span class='line'>              <span class="n">updateCount</span> <span class="o">++</span><span class="p">;</span>
</span><span class='line'>              <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>              <span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'>              <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
</span><span class='line'>                  <span class="c1">// 这里使用 getLUser 获取数据，而非 [__ls_]m_pLUser，所以我设置了前缀</span>
</span><span class='line'>                  <span class="k">if</span> <span class="p">(</span><span class="n">getLUser</span><span class="p">())</span>
</span><span class='line'>                      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;log lu: %s&quot;</span><span class="p">,</span> <span class="n">getLUser</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">m_sUserName</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'>              <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
</span><span class='line'>                  <span class="c1">// 重新赋值</span>
</span><span class='line'>                  <span class="n">LUser</span><span class="o">*</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">LUser</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>                  <span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sUserName</span> <span class="o">=</span> <span class="s">&quot;一叶&quot;</span><span class="p">;</span>
</span><span class='line'>                  <span class="n">setLUser</span><span class="p">(</span><span class="n">lu</span><span class="p">);</span>
</span><span class='line'>              <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>                  <span class="k">if</span> <span class="p">(</span><span class="n">getLUser</span><span class="p">())</span>
</span><span class='line'>                      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;log lu: %s&quot;</span><span class="p">,</span> <span class="n">getLUser</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">m_sUserName</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>              <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">4</span><span class="p">){</span>
</span><span class='line'>                  <span class="c1">// 这里调用 seLUser(0),直接取消引用持有对象，如果不调用也没有关系</span>
</span><span class='line'>                  <span class="c1">// 因为在当前类析构的时候会自动检测释放</span>
</span><span class='line'>                  <span class="n">setLUser</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'>              <span class="p">}</span>
</span><span class='line'>              <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d end&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>      <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 构造函数，初始化 LS_PROPERTY_RETAIN 属性为空</span>
</span><span class='line'>  <span class="n">PropertyTest</span><span class="p">()</span><span class="o">:</span>
</span><span class='line'>      <span class="n">LS_P_INIT</span><span class="p">(</span><span class="n">m_pLUser</span><span class="p">),</span>
</span><span class='line'>      <span class="n">updateCount</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 析构函数释放</span>
</span><span class='line'>  <span class="o">~</span><span class="n">PropertyTest</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">LS_P_RELEASE</span><span class="p">(</span><span class="n">m_pLUser</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 使用 LS_PROPERTY_RETAIN 宏定义的属性，必须在构造和析构函数中初始化和释放</span>
</span><span class='line'>  <span class="c1">// 初始化为 0 或者 NULL，是为了在进行赋值操作前判断是否以有引用</span>
</span><span class='line'>  <span class="c1">// 析构函数释放是为了解除对持有对象的引用，如果有的话</span>
</span><span class='line'>  <span class="n">LS_PROPERTY_RETAIN</span><span class="p">(</span><span class="n">LUser</span><span class="o">*</span><span class="p">,</span> <span class="n">m_pLUser</span><span class="p">,</span> <span class="n">LUser</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>  <span class="kt">int</span> <span class="n">updateCount</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 程序执行打印如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">PropertyTest</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="c1">// init 方法创建对象并通过 setLUser 持有对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LUser</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 第一帧顺利访问 持有对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">log</span> <span class="nl">lu:</span> <span class="n">leafsoar</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 第二帧创建新的 用户信息</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LUser</span><span class="p">()]</span>
</span><span class='line'><span class="c1">// 通过 setLUser 改变用户信息，这会使得之前设置的用户信息“自动”释放</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LUser</span><span class="p">().</span><span class="o">~</span><span class="p">()</span><span class="o">:</span><span class="n">leafsoar</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 跨帧继续访问新值</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">log</span> <span class="nl">lu:</span> <span class="err">一叶</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">4</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 调用了 setLUser(0) 说明已经解除了之前持有对象的引用，如果有的话</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LUser</span><span class="p">().</span><span class="o">~</span><span class="p">()</span><span class="o">:</span><span class="err">一叶</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">4</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">5</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">5</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>通过上面的例子，可以看到将 <strong>持有对象</strong> 的操作变的非常简单，<strong>只通过</strong> set 和 get 属性包装器存取数据，而并没有 <strong>显示</strong> 的调用 retain 和 release 方法来操作，最大程度的自动化管理引用计数问题，一切皆在掌控之中。从此，世界清净了 ~ <strong>你不用再为何时 retain 何处 release 而烦恼。</strong></p>

<p>而要做到如上的使用方法，在定义之初需规范化设计，大致如下：</p>

<ul>
<li>通过 <strong>LS_PROPERTY_RETAIN</strong> 宏创建 <strong>可持有对象属性</strong>，并自动创建 set 和 get 属性包装器。宏的设计并非毫无来由，我们知道 cocos2d-x 内部定义了很多以 <strong>CC_</strong> 为前缀的宏，方便使用，比如 <strong>CC_PROPERTY[xxx]</strong> 此类。set 方法会自动的根据需要处理 retain 和 release。</li>
<li>宿主类的构造函数必须初始化对象为 NULL 或者 0，这是 C++ 的特性使然。LS_P_INIT，简化了操作。</li>
<li>宿主类的析构函数必须释放对象[如果有]，这样我们就不用 <strong>显示</strong> 的调用释放了。可以通过 LS_P_RELEASE 调用。</li>
</ul>


<h3>LS_PROPERTY_RETAIN 宏的实现</h3>

<p>在上面的例程中，我们使用了 <strong>LS_PROPERTY_RETAIN(LUser*, m_pLUser, LUser);</strong> 定义一个属性，那么我们看这个宏做了哪些事情，我们展开这个宏看看：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">LS_PROPERTY_RETAIN</span><span class="p">(</span><span class="n">LUser</span><span class="o">*</span><span class="p">,</span> <span class="n">m_pLUser</span><span class="p">,</span> <span class="n">LUser</span><span class="p">);</span>
</span><span class='line'><span class="c1">// 展开如下</span>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">// 定义私有属性</span>
</span><span class='line'>  <span class="n">LUser</span><span class="o">*</span> <span class="n">__ls_m_pLUser</span><span class="p">;</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">// 实现 set 方法</span>
</span><span class='line'>  <span class="kt">void</span> <span class="n">setLUser</span><span class="p">(</span><span class="n">LUser</span><span class="o">*</span> <span class="n">var</span><span class="p">){</span>
</span><span class='line'>      <span class="c1">// 首先释放当前的持有对象，没有则罢，如果有，那么就 release，因为如果有值，毕定是通过此方法设置并 retain 的</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">__ls_m_pLUser</span> <span class="o">!=</span> <span class="n">var</span><span class="p">){</span>
</span><span class='line'>          <span class="c1">// 持有新的对象，这些都是 SAFE  安全操作的</span>
</span><span class='line'>          <span class="n">CC_SAFE_RETAIN</span><span class="p">(</span><span class="n">var</span><span class="p">);</span>
</span><span class='line'>          <span class="c1">// 这里是 cocos2d-x 提供的宏，就不展开了              </span>
</span><span class='line'>          <span class="n">CC_SAFE_RELEASE</span><span class="p">(</span><span class="n">__ls_m_pLUser</span><span class="p">);</span>
</span><span class='line'>          <span class="c1">// 设置新的属性</span>
</span><span class='line'>          <span class="n">__ls_m_pLUser</span> <span class="o">=</span> <span class="n">var</span><span class="p">;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">LUser</span><span class="o">*</span>  <span class="n">getLUser</span><span class="p">(){</span>
</span><span class='line'>      <span class="c1">// 直接返回持有对象</span>
</span><span class='line'>      <span class="k">return</span> <span class="n">__ls_m_pLUser</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>基本在设计之时，满足以上规范，就能想这里一样，通过 set 和 get 简单的对可持有对象进行任意的操作了。</p>

<h2>应用</h2>

<p>这样的设计使得 <strong>所有基于</strong> CCObject 的类型都能够方便的使用。那我们就能够很容易的持有 CCNode，层，精灵，CCArray，等数据了。而且不会看到漫天飞舞的 retain 和 release ~</p>

<p>当然作用还不止如此，我们可能创建自己的类型继承 CCObject 以方便统一管理，在配合 CCArray ，使自定义的数据和 cocos2d-x <strong>无缝的集成</strong>。有些游戏需要处理很多数据，如网络传输接受的数据，自定义常用数据等 ~</p>

<p>文中我们自定义了 LUser 是继承于 CCObject  的，这只是简单数据类型，复杂点的，LUser 中包含了其它 CCObject 的数据，如果按照以前的写法，设置之后就 retain ，那很难判断在哪里 release。如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">class</span> <span class="nc">LUser</span><span class="o">:</span> <span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCObject</span><span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">LUser</span><span class="p">);</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">(){</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="n">LUser</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LUser()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LUser</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LUser().~():%s&quot;</span><span class="p">,</span> <span class="n">m_sUserName</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_sUserName</span><span class="p">;</span>     <span class="c1">// 用户名</span>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_sPassword</span><span class="p">;</span>     <span class="c1">// 用户密码</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 其它数据</span>
</span><span class='line'>  <span class="n">CCSprite</span><span class="o">*</span> <span class="n">m_pSprite</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 那么我们的使用过程</span>
</span><span class='line'><span class="n">LUser</span><span class="o">*</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">LUser</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sSprite</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;a.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="c1">// 如果这里不 retain  则以后就用不到了</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sSprite</span><span class="o">-&gt;</span><span class="n">retain</span><span class="p">();</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>LUser 持有 m_sSprite 正如 文中 PropertyTest 持有 m_pLUser 一样，我们重新设计：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">class</span> <span class="nc">LUser</span><span class="o">:</span> <span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCObject</span><span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">LUser</span><span class="p">);</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">(){</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="n">LUser</span><span class="p">()</span><span class="o">:</span>
</span><span class='line'>      <span class="n">LS_P_INIT</span><span class="p">(</span><span class="n">m_pSprite</span><span class="p">)</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LUser()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LUser</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LUser().~():%s&quot;</span><span class="p">,</span> <span class="n">m_sUserName</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>      <span class="n">LS_P_RELEASE</span><span class="p">(</span><span class="n">m_pSprite</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_sUserName</span><span class="p">;</span>     <span class="c1">// 用户名</span>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_sPassword</span><span class="p">;</span>     <span class="c1">// 用户密码</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 其它数据</span>
</span><span class='line'>  <span class="n">LS_PROPERTY_RETAIN</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">*</span><span class="p">,</span> <span class="n">m_pSprite</span><span class="p">,</span> <span class="n">Sprite</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 使用方法</span>
</span><span class='line'><span class="n">LUser</span><span class="o">*</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">LUser</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">m_sUserName</span> <span class="o">=</span> <span class="s">&quot;一叶&quot;</span><span class="p">;</span>
</span><span class='line'><span class="c1">// 这里的 sprite 会随着 lu 的消亡而消亡，不用管释放问题了</span>
</span><span class='line'><span class="n">lu</span><span class="o">-&gt;</span><span class="n">setSprite</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;a.png&quot;</span><span class="p">));</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>这样便将 m_pSprite 控制权，完全交给了 LUser 来处理了。基于这样的考虑，我们完全可以使用复杂的自定义类型，包含很多 CCObject 属性，而属性之中可能又包含其它 CCObject 的类型，而并不用担心释放问题，<strong>谁持有，谁管理，谁释放</strong>(而不会出现 lu->m_sSprite->retain(); 这样的情况)。这些数据可以在游戏中任意的传递，并且都是CCObject 类型的，并很好的结合 CCArray 管理。让自定义类型与 cocos2d-x 两者天衣无缝，配合无间 ~</p>

<p>这里自定义的宏，加了个复杂的前缀，仅仅想提醒大家，只通过 set 和 get 来进行存取的操作，从而避免使用 retain 和 release 来管理，更简单的写法，使用 cocos2d-x 自带的宏即可：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">//  定义可以加 &quot;__&quot; 双下划，以告诉自己这是可持有属性</span>
</span><span class='line'><span class="n">CC_SYNTHESIZE_RETAIN</span><span class="p">(</span><span class="n">LUser</span><span class="o">*</span><span class="p">,</span> <span class="n">__m_pLUser</span><span class="p">,</span> <span class="n">LUser</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 构造函数直接使用 __m_pLUser(0)</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 析构函数调用如下</span>
</span><span class='line'><span class="n">CC_SAFE_RELEASE_NULL</span><span class="p">(</span><span class="n">__m_pLUser</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 如此倒也省事，事省 : P</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<h3>为什么 LUser 继承自 CCObject</h3>

<p>如果不集成自 CCObject 而使用原来的 C++ 方式也并无不可，但 CCObject 的优势是很明显的，如果能够善于使用。如果你想在 cocos2d-x 一个CCNode绑定数据有 setUserObject() 方法，如果多个 LUser 那么可以用 CCArray 进行管理，如果你想使用通知功能 CCNotificationCenter，而此  LUser 是可被传递的，我们设置了 LUser 然后靠诉别人我更新了，发送一条通知，谁对这个通知感兴趣，那谁就自己处理去吧 ~ 如果 ~ 如果你对此文感兴趣，不妨一试 ~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[多层 UI 触摸事件的轻量级设计]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-25.html"/>
    <updated>2013-05-25T10:10:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-ui-event</id>
    <content type="html"><![CDATA[<p><strong>轻量级</strong>:一叶非常喜欢的名词，在重量级和轻量级之间，如果做选择的话，一定会选择轻量级，它的特点首先是设计简单小巧，使用方便，更具有灵活性，扩展方便。重量级则大而丰富，全面，但略显笨重，在程序设计之初大多需要全盘考虑。而轻重之间的概念是相对而言，并没有严格的界限。</p>

<h2>Cocos2d-x 触摸事件机制概论</h2>

<p>在 cocos2d-x 使用触摸来触发一些操作是很常用的功能，如果界面非常简单，只需要启用相应层的触摸功能，并处理其触摸事件即可，而如果界面的 UI 复杂，多层管理，又有着隐藏控制，灵活多变，比如 MMO 游戏，当然手游不会 <strong>那么</strong> 复杂，那么现有的机制实现起来就显得捉襟见肘了，即便实现，也很难维护，而一个简单的方式是 <strong>只在场景的 基层 接受触摸消息，然后由此基层向上层发送触摸的消息</strong>，上层再根据实际情况进行处理，判断可触摸元素优先级，是否隐藏，返回处理结果，再一层层向下传递，保证实际的操作是我们所期望的。</p>

<!-- more -->


<p>在基层接受触摸消息，然后向上层发送触摸消息，而在 cocos2d-x 中并没有这样一个机制，所以已经有人基于 cocos2d-x 实现了这样一个机制，比如我们 <strong>实现自己的场景、层等，和自己的 一套层级控制</strong>，这个控制具有传递触摸消息的机制，但是这样我们就不能继续使用原有的层级管理机制。还有 <strong>通过修改 cocos2d-x 的源代码，达到这样的效果</strong> ，而这样的 <strong>侵入 API</strong> 的方式不甚可取，无论如何，这样的方式略显笨重，使用之前需要做很多工作，算是重量级的设计思路吧 ~</p>

<p>为了使用的简单，并基于以上考虑，所以想到要设计一个 <strong>轻量级 的复杂 UI 触摸事件管理机制</strong>。首先从使用者角度考虑，要使用简单，嵌入到现有 cocos2d-x 方便，并没有什么复杂的特性，其次从设计角度考虑，充分利用 cocos2d-x 现有的特性，保持自身的简洁，关于此点，将会在后面的文章内容体验。</p>

<h2>抽象：轻量级设计的可行性分析</h2>

<p>触摸事件，从触摸开始，到有效点击，然后触发点击事件，从这么一个过程我们提取 <strong>两个抽象概念</strong>，而这两个概念将是我们的设计核心内容。首先要有 <strong>“可触摸对象”</strong> 类，也就是界面上一个可点击操作的元素，我们知道在 cocos2d-x 中有 CCScene、CCLayer、CCNode 等，大多情况都只是作为 <strong>容器</strong> 使用，本身并不处理触摸操作，而这些内容我们完全不用关注。还需要一个<strong>“可触摸对象事件管理对象”</strong> 类型，就简称 <strong>管理类</strong> 吧，管理类管理可触摸对象。</p>

<p>现在我们设想这样一种情况，场景基层作为管理层，在这之中维护着一个 “可触摸对象”的集合，当我们创建一个可触摸对象的并把它添加到界面上之时，我们将它添加到这个集合中，当然这个可触摸对象包含一些属性标示，比如设定事件 Id 等。无论界面怎么布局，层次关系如何复杂，我们只需要关注这个可触摸对象的集合即可。好了，现在我们点击界面，通过场景基层接受触摸消息，获得点击的点，<strong>现在我们要做的就是判断哪个可触摸对象是有效点击就行了</strong>，从集合中找出有效点击的对象是很容易的。我们可以做一些判断，以确定哪个元素是有效点击，从而触发它的事件，而这个触发操作统一由管理层触发，现在我们来定一些有效点击的规则，并且这个规则是可以根据自己需要添加修改的：</p>

<ul>
<li>可触摸对象有个可触摸的范围（ContentSize），判断触摸的点是否在可触摸范围之内</li>
<li>可触摸对象是否正在运行（IsRunning），排除了，已经从界面移除可触摸对象，可能没有及时释放而触发的情形</li>
<li>可触摸对象是否隐藏 （IsVisible），如果不可见，当然无效点击</li>
<li>可触摸对象的父层是否有隐藏，只需要不停的获取父层，判断是否存在以藏即可</li>
<li>其它判断，自己添加定义 ~~~</li>
</ul>


<p>从集合中找出满足以上条件的元素是可行的，如果满足条件的有多个元素呢？这是可能的，比如两个可触摸对象的可触摸范围重叠，这是我们就需要对这两个元素做优先级比较了，如何比较？我们知道任意两个可触摸对象，是被添加的场景基层中的 <strong>树形结构</strong>，我们只需要分析这个树形结构，找到这两个可触摸节点的优先级即可，过程简说：找出两个节点最近的共同父节点，从而定位到此父节点下，两个元素所在的子节点，此两节点首先根据 ZOrder 判断优先，如果 ZOrder 相同，判断节点在父节点的索引位置，从而判断优先级。</p>

<p>至此我们就能从可触摸对象集合中找到 <strong>一个</strong> 最终满足所有条件的对象，有了这个对象，我们就可以够精确的触发其触摸事件！</p>

<h2>一个简单的设计雏形</h2>

<p>雏形的设计一切从简，200 行代码左右。首先定义了一个 <strong>可触摸对象</strong> 类型 <strong>LsTouch</strong> ，它标示一个可触摸的对象，其中有一个 CCSprite 属性，显示和判断可点击范围都靠它（简单起见，这里可以定义自己的属性扩充，满足各种需要），还包含一个事件 Id 属性，知道触发什么事件（可以添加如事件类型属性等方便事件的处理）。另外定义了 <strong>LsTouchEvent</strong> 事件处理类，也是管理类，在使用的时候，场景基层实现它，并实现 <strong>touchEventAction</strong> 方法，此方法用户处理事件响应，而在 <strong>ccTouchesBegan</strong> 方法之内调用 LsToucheEvent 定义的 <code>sendTouchEvent(CCTouch* ccTouch)</code> 方法，传递 <strong>CCTouch</strong> 参数，之后方法内部会自动判断有效点击，并自动触发 touchEventAction 方法。</p>

<p>在介绍实现之前，先通过简单的代码看看使用方法，从使用过程中体现它的简洁：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 场景基层定义，实现 LsTouchEvent 的 touchEventAction 事件响应方法即可</span>
</span><span class='line'><span class="k">class</span> <span class="nc">TouchEventTest</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCLayer</span> <span class="p">,</span> <span class="k">public</span> <span class="n">LsTouchEvent</span><span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">TouchEventTest</span><span class="p">)</span>
</span><span class='line'>  <span class="p">;</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">ccTouchesBegan</span><span class="p">(</span><span class="n">CCSet</span> <span class="o">*</span><span class="n">pTouches</span><span class="p">,</span> <span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">touchEventAction</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">);</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// TouchEventTest 实现</span>
</span><span class='line'><span class="kt">bool</span> <span class="n">TouchEventTest</span><span class="o">::</span><span class="n">init</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">bRef</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'>  <span class="k">do</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">CC_BREAK_IF</span><span class="p">(</span><span class="o">!</span><span class="n">CCLayer</span><span class="o">::</span><span class="n">init</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 启用触摸</span>
</span><span class='line'>      <span class="n">setTouchEnabled</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">CCSize</span> <span class="n">winSize</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span><span class='line'>      <span class="n">CCPoint</span> <span class="n">center</span> <span class="o">=</span> <span class="n">ccp</span><span class="p">(</span><span class="n">winSize</span><span class="p">.</span><span class="n">width</span><span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">winSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 创建可触摸精灵</span>
</span><span class='line'>      <span class="n">LsTouch</span><span class="o">*</span> <span class="n">lt</span> <span class="o">=</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>      <span class="c1">// 设置位置</span>
</span><span class='line'>      <span class="n">lt</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">center</span><span class="p">);</span>
</span><span class='line'>      <span class="c1">// 设置显示精灵</span>
</span><span class='line'>      <span class="n">lt</span><span class="o">-&gt;</span><span class="n">setDisplay</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Peas.png&quot;</span><span class="p">));</span>
</span><span class='line'>      <span class="c1">// 添加到显示</span>
</span><span class='line'>      <span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">lt</span><span class="p">);</span>
</span><span class='line'>      <span class="c1">// 添加到触摸管理，第二个参数，事件 Id</span>
</span><span class='line'>      <span class="k">this</span><span class="o">-&gt;</span><span class="n">addLsTouch</span><span class="p">(</span><span class="n">lt</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">LsTouch</span><span class="o">*</span> <span class="n">lt2</span> <span class="o">=</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>      <span class="n">lt2</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccpAdd</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">ccp</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">10</span><span class="p">)));</span>
</span><span class='line'>      <span class="n">lt2</span><span class="o">-&gt;</span><span class="n">setDisplay</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Peas.png&quot;</span><span class="p">));</span>
</span><span class='line'>      <span class="n">addChild</span><span class="p">(</span><span class="n">lt2</span><span class="p">);</span>
</span><span class='line'>      <span class="k">this</span><span class="o">-&gt;</span><span class="n">addLsTouch</span><span class="p">(</span><span class="n">lt2</span><span class="p">,</span> <span class="mi">101</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">bRef</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">return</span> <span class="n">bRef</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">TouchEventTest</span><span class="o">::</span><span class="n">ccTouchesBegan</span><span class="p">(</span><span class="n">CCSet</span> <span class="o">*</span><span class="n">pTouches</span><span class="p">,</span> <span class="n">CCEvent</span> <span class="o">*</span><span class="n">pEvent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCSetIterator</span> <span class="n">it</span> <span class="o">=</span> <span class="n">pTouches</span><span class="o">-&gt;</span><span class="n">begin</span><span class="p">();</span>
</span><span class='line'>  <span class="n">CCTouch</span><span class="o">*</span> <span class="n">touch</span> <span class="o">=</span> <span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// 发送触摸消息，并在 touchEventAction 自动回调相应的事件</span>
</span><span class='line'>  <span class="n">sendTouchMessage</span><span class="p">(</span><span class="n">touch</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">TouchEventTest</span><span class="o">::</span><span class="n">touchEventAction</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;touch event action id: %d&quot;</span><span class="p">,</span> <span class="n">touch</span><span class="o">-&gt;</span><span class="n">getEventId</span><span class="p">());</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>上述使用方法，在 init() 方法中创建了两个可触摸元素，并设置显示的精灵，这里只实现了 ccTouchesBegan 方法，当然也可以添加 ccTouchesMoved 等方法的实现，这是为了雏形的设计简单，LsTouch 的实现可以自定义，显示什么，范围如何判断可以自行扩展，它本身也是个 CCNode ，所以可以通过 addChild 添加到界面显示，然后调用 addLsTouch 方法，添加到触摸管理，此时 精灵才能在调用 <strong>sendTouchMessage</strong> 时，接受触摸消息，从而判断点击的有效性，并在 touchEventAction 方法自动相应。这里可接受 <strong>复杂多变的界面设计</strong>，应为这并不会影响到触摸消息的管理，它是通过 addLsTouch 方法添加到内部的一个 <strong>CCArray</strong> 之中，如果从界面移除了可触摸元素，可以调用 <strong>removeLsTouch</strong> 方法，自动回收，如果没有显示的调用此方法，将会在基层场景销毁时，自动释放 CCArray 里面的所有元素，区别就是是否能够及时释放元素，但就使用来说，并没什么区别。</p>

<p>简单的使用当然基于简单的设计，请看如下(<a href="https://github.com/leafsoar/ls-cocos2d-x/tree/master/Learn/Classes/TouchEventTest">源码查看</a>，GitHub 之上的源码今后可能有所扩展，而下面贴出的是此时的“雏形”)：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
<span class='line-number'>166</span>
<span class='line-number'>167</span>
<span class='line-number'>168</span>
<span class='line-number'>169</span>
<span class='line-number'>170</span>
<span class='line-number'>171</span>
<span class='line-number'>172</span>
<span class='line-number'>173</span>
<span class='line-number'>174</span>
<span class='line-number'>175</span>
<span class='line-number'>176</span>
<span class='line-number'>177</span>
<span class='line-number'>178</span>
<span class='line-number'>179</span>
<span class='line-number'>180</span>
<span class='line-number'>181</span>
<span class='line-number'>182</span>
<span class='line-number'>183</span>
<span class='line-number'>184</span>
<span class='line-number'>185</span>
<span class='line-number'>186</span>
<span class='line-number'>187</span>
<span class='line-number'>188</span>
<span class='line-number'>189</span>
<span class='line-number'>190</span>
<span class='line-number'>191</span>
<span class='line-number'>192</span>
<span class='line-number'>193</span>
<span class='line-number'>194</span>
<span class='line-number'>195</span>
<span class='line-number'>196</span>
<span class='line-number'>197</span>
<span class='line-number'>198</span>
<span class='line-number'>199</span>
<span class='line-number'>200</span>
<span class='line-number'>201</span>
<span class='line-number'>202</span>
<span class='line-number'>203</span>
<span class='line-number'>204</span>
<span class='line-number'>205</span>
<span class='line-number'>206</span>
<span class='line-number'>207</span>
<span class='line-number'>208</span>
<span class='line-number'>209</span>
<span class='line-number'>210</span>
<span class='line-number'>211</span>
<span class='line-number'>212</span>
<span class='line-number'>213</span>
<span class='line-number'>214</span>
<span class='line-number'>215</span>
<span class='line-number'>216</span>
<span class='line-number'>217</span>
<span class='line-number'>218</span>
<span class='line-number'>219</span>
<span class='line-number'>220</span>
<span class='line-number'>221</span>
<span class='line-number'>222</span>
<span class='line-number'>223</span>
<span class='line-number'>224</span>
<span class='line-number'>225</span>
<span class='line-number'>226</span>
<span class='line-number'>227</span>
<span class='line-number'>228</span>
<span class='line-number'>229</span>
<span class='line-number'>230</span>
<span class='line-number'>231</span>
<span class='line-number'>232</span>
<span class='line-number'>233</span>
<span class='line-number'>234</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">class</span> <span class="nc">LsTouchEvent</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * 定义可触摸元素，用于统一管理</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">LsTouch</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCNode</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">LsTouch</span><span class="p">();</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LsTouch</span><span class="p">();</span>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">LsTouch</span><span class="p">);</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">()</span>    <span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 设置显示项</span>
</span><span class='line'>  <span class="kt">void</span> <span class="n">setDisplay</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">*</span> <span class="n">dis</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="kt">void</span> <span class="n">setEventId</span><span class="p">(</span><span class="kt">int</span> <span class="n">eventId</span><span class="p">);</span>
</span><span class='line'>  <span class="kt">int</span> <span class="n">getEventId</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">/// 常规判断</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">selfCheck</span><span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span> <span class="n">ccTouch</span><span class="p">,</span> <span class="n">LsTouchEvent</span><span class="o">*</span> <span class="n">lsTe</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">// 判断当前的元素是否被点击</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">containsCCTouchPoint</span><span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span> <span class="n">ccTouch</span><span class="p">);</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">isParentAllVisible</span><span class="p">(</span><span class="n">LsTouchEvent</span><span class="o">*</span> <span class="n">lsTe</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 用户保存显示精灵的 tag</span>
</span><span class='line'>  <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">TAG_DISPLAY</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
</span><span class='line'>  <span class="kt">int</span> <span class="n">m_iEventId</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">LsTouchEvent</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="n">LsTouchEvent</span><span class="p">();</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LsTouchEvent</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="kt">void</span> <span class="n">addLsTouch</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">,</span> <span class="kt">int</span> <span class="n">eventId</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="kt">void</span> <span class="n">removeLsTouch</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">sendTouchMessage</span><span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span> <span class="n">ccTouch</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 返回优先级较高的可触摸对象</span>
</span><span class='line'>  <span class="n">LsTouch</span><span class="o">*</span> <span class="n">getPriorityTouch</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">a</span><span class="p">,</span> <span class="n">LsTouch</span><span class="o">*</span> <span class="n">b</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">touchEventAction</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>  <span class="n">CCArray</span><span class="o">*</span> <span class="n">m_pLsTouches</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 类实现    </span>
</span><span class='line'><span class="cp">#include &quot;LsTouch.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="n">LsTouch</span><span class="o">::</span><span class="n">LsTouch</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LsTouch()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">m_iEventId</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">LsTouch</span><span class="o">::~</span><span class="n">LsTouch</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LsTouch().~()&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">bool</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">init</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">setDisplay</span><span class="p">(</span><span class="n">CCSprite</span><span class="o">*</span> <span class="n">dis</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 设置之前先清除，没有也无所谓</span>
</span><span class='line'>  <span class="n">removeChildByTag</span><span class="p">(</span><span class="n">TAG_DISPLAY</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'>  <span class="n">addChild</span><span class="p">(</span><span class="n">dis</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">TAG_DISPLAY</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">setEventId</span><span class="p">(</span><span class="kt">int</span> <span class="n">eventId</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">m_iEventId</span> <span class="o">=</span> <span class="n">eventId</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">int</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">getEventId</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">m_iEventId</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">bool</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">selfCheck</span><span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span> <span class="n">ccTouch</span><span class="p">,</span> <span class="n">LsTouchEvent</span><span class="o">*</span> <span class="n">lsTe</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">bRef</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 可点击项的检测，可扩展</span>
</span><span class='line'>  <span class="k">do</span> <span class="p">{</span>
</span><span class='line'>      <span class="c1">// 是否通过点击位置检测</span>
</span><span class='line'>      <span class="n">CC_BREAK_IF</span><span class="p">(</span><span class="o">!</span><span class="n">containsCCTouchPoint</span><span class="p">(</span><span class="n">ccTouch</span><span class="p">));</span>
</span><span class='line'>      <span class="c1">// 是否正在运行，排除可能存在已经从界面移除，但是并没有释放的可能</span>
</span><span class='line'>      <span class="n">CC_BREAK_IF</span><span class="p">(</span><span class="o">!</span><span class="n">isRunning</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 判断是否隐藏</span>
</span><span class='line'>      <span class="n">CC_BREAK_IF</span><span class="p">(</span><span class="o">!</span><span class="n">isVisible</span><span class="p">());</span>
</span><span class='line'>      <span class="c1">// 这里可能还需要判断内部显示项目是否隐藏</span>
</span><span class='line'>      <span class="c1">///// 暂留</span>
</span><span class='line'>      <span class="c1">// 不仅判断当前元素是否隐藏，还需要判断在它之上的元素直到事件处理层，是否存在隐藏</span>
</span><span class='line'>      <span class="n">CC_BREAK_IF</span><span class="p">(</span><span class="o">!</span><span class="n">isParentAllVisible</span><span class="p">(</span><span class="n">lsTe</span><span class="p">));</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">bRef</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">bRef</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">bool</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">containsCCTouchPoint</span><span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span> <span class="n">ccTouch</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 获得显示内容</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">dis</span> <span class="o">=</span> <span class="n">getChildByTag</span><span class="p">(</span><span class="n">TAG_DISPLAY</span><span class="p">);</span>
</span><span class='line'>  <span class="n">CCSprite</span><span class="o">*</span> <span class="n">sprite</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">CCSprite</span><span class="o">*&gt;</span><span class="p">(</span><span class="n">dis</span><span class="p">);</span>
</span><span class='line'>  <span class="n">CCPoint</span> <span class="n">point</span> <span class="o">=</span> <span class="n">sprite</span><span class="o">-&gt;</span><span class="n">convertTouchToNodeSpaceAR</span><span class="p">(</span><span class="n">ccTouch</span><span class="p">);</span>
</span><span class='line'>  <span class="n">CCSize</span> <span class="n">s</span> <span class="o">=</span> <span class="n">sprite</span><span class="o">-&gt;</span><span class="n">getTexture</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getContentSize</span><span class="p">();</span>
</span><span class='line'>  <span class="n">CCRect</span> <span class="n">rect</span> <span class="o">=</span> <span class="n">CCRectMake</span><span class="p">(</span><span class="o">-</span><span class="n">s</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="n">s</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">width</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">height</span><span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">rect</span><span class="p">.</span><span class="n">containsPoint</span><span class="p">(</span><span class="n">point</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">bool</span> <span class="n">LsTouch</span><span class="o">::</span><span class="n">isParentAllVisible</span><span class="p">(</span><span class="n">LsTouchEvent</span><span class="o">*</span> <span class="n">lsTe</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">bRef</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 向父类转型，以便获取地址比较对象，LsTouchEvent 的对象必须同时直接或者简介继承 CCNode</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">nLsTe</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">CCNode</span><span class="o">*&gt;</span><span class="p">(</span><span class="n">lsTe</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">parent</span> <span class="o">=</span> <span class="n">getParent</span><span class="p">();</span>
</span><span class='line'>  <span class="k">do</span> <span class="p">{</span>
</span><span class='line'>      <span class="c1">// 如果遍历完毕，说明 LsTouch 不再 LsTouchEvent 之内</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">parent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>          <span class="n">bRef</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'>          <span class="k">break</span><span class="p">;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>      <span class="c1">// 如果 LsTouch 在 LsTouchEvent 之内，返回 true</span>
</span><span class='line'>      <span class="c1">// 注意：如果想让LsTouchEvent 处理 不在其 CCNode 结构之内的元素，则取消此处判断</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">nLsTe</span> <span class="o">==</span> <span class="n">parent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>          <span class="k">break</span><span class="p">;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">parent</span><span class="o">-&gt;</span><span class="n">isVisible</span><span class="p">())</span> <span class="p">{</span>
</span><span class='line'>          <span class="n">bRef</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'>          <span class="k">break</span><span class="p">;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>      <span class="n">parent</span> <span class="o">=</span> <span class="n">parent</span><span class="o">-&gt;</span><span class="n">getParent</span><span class="p">();</span>
</span><span class='line'>  <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">bRef</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">LsTouchEvent</span><span class="o">::</span><span class="n">LsTouchEvent</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LsTouchEvent()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">m_pLsTouches</span> <span class="o">=</span> <span class="n">CCArray</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">m_pLsTouches</span><span class="o">-&gt;</span><span class="n">retain</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">LsTouchEvent</span><span class="o">::~</span><span class="n">LsTouchEvent</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LsTouchEvent().~()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">m_pLsTouches</span><span class="o">-&gt;</span><span class="n">release</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LsTouchEvent</span><span class="o">::</span><span class="n">addLsTouch</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">,</span> <span class="kt">int</span> <span class="n">eventId</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">touch</span><span class="o">-&gt;</span><span class="n">setEventId</span><span class="p">(</span><span class="n">eventId</span><span class="p">);</span>
</span><span class='line'>  <span class="n">m_pLsTouches</span><span class="o">-&gt;</span><span class="n">addObject</span><span class="p">(</span><span class="n">touch</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LsTouchEvent</span><span class="o">::</span><span class="n">removeLsTouch</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">touch</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">m_pLsTouches</span><span class="o">-&gt;</span><span class="n">removeObject</span><span class="p">(</span><span class="n">touch</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">bool</span> <span class="n">LsTouchEvent</span><span class="o">::</span><span class="n">sendTouchMessage</span><span class="p">(</span><span class="n">CCTouch</span><span class="o">*</span> <span class="n">ccTouch</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 编写判断，集合中的哪个元素级别高，就触发哪一个</span>
</span><span class='line'>  <span class="n">LsTouch</span><span class="o">*</span> <span class="n">lsTouch</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 获得点击的点</span>
</span><span class='line'>  <span class="n">CCObject</span><span class="o">*</span> <span class="n">pObj</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>  <span class="n">LsTouch</span><span class="o">*</span> <span class="n">lt</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>  <span class="n">CCARRAY_FOREACH</span><span class="p">(</span><span class="n">m_pLsTouches</span><span class="p">,</span> <span class="n">pObj</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">lt</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">LsTouch</span><span class="o">*&gt;</span><span class="p">(</span><span class="n">pObj</span><span class="p">);</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">lt</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="n">lt</span><span class="o">-&gt;</span><span class="n">selfCheck</span><span class="p">(</span><span class="n">ccTouch</span><span class="p">,</span> <span class="k">this</span><span class="p">))</span> <span class="p">{</span>
</span><span class='line'>              <span class="k">if</span> <span class="p">(</span><span class="n">lsTouch</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
</span><span class='line'>                  <span class="n">lsTouch</span> <span class="o">=</span> <span class="n">lt</span><span class="p">;</span>
</span><span class='line'>              <span class="k">else</span>
</span><span class='line'>                  <span class="c1">// 如果已存在符合条件元素，比较优先级</span>
</span><span class='line'>                  <span class="n">lsTouch</span> <span class="o">=</span> <span class="n">getPriorityTouch</span><span class="p">(</span><span class="n">lsTouch</span><span class="p">,</span> <span class="n">lt</span><span class="p">);</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="c1">// 比对最终只有一个元素触发</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">lsTouch</span><span class="p">){</span>
</span><span class='line'>      <span class="n">touchEventAction</span><span class="p">(</span><span class="n">lsTouch</span><span class="p">);</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">LsTouch</span><span class="o">*</span> <span class="n">LsTouchEvent</span><span class="o">::</span><span class="n">getPriorityTouch</span><span class="p">(</span><span class="n">LsTouch</span><span class="o">*</span> <span class="n">a</span><span class="p">,</span> <span class="n">LsTouch</span><span class="o">*</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 触摸优先级通过 CCNode 树判断，也既是显示层次级别等因素</span>
</span><span class='line'>  <span class="c1">// 以当前元素为“根”向父类转型，以便获取地址比较对象，LsTouchEvent 的对象必须同时直接或者简介继承 CCNode</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">nLsTe</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">CCNode</span><span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 共同的分枝</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">allParent</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 寻找 a 与 b 共同的分枝</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">nAParent</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">nBParent</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">nAChild</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>  <span class="n">CCNode</span><span class="o">*</span> <span class="n">nBChild</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>  <span class="k">do</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">nAChild</span> <span class="o">=</span> <span class="n">nAParent</span><span class="p">;</span>
</span><span class='line'>      <span class="n">nAParent</span> <span class="o">=</span> <span class="n">nAParent</span><span class="o">-&gt;</span><span class="n">getParent</span><span class="p">();</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">nAParent</span><span class="p">)</span>
</span><span class='line'>          <span class="k">break</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">nBParent</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span>
</span><span class='line'>      <span class="k">do</span> <span class="p">{</span>
</span><span class='line'>          <span class="n">nBChild</span> <span class="o">=</span> <span class="n">nBParent</span><span class="p">;</span>
</span><span class='line'>          <span class="n">nBParent</span> <span class="o">=</span> <span class="n">nBParent</span><span class="o">-&gt;</span><span class="n">getParent</span><span class="p">();</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">nBParent</span><span class="p">)</span>
</span><span class='line'>              <span class="k">break</span><span class="p">;</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="n">nAParent</span> <span class="o">==</span> <span class="n">nBParent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>              <span class="n">allParent</span> <span class="o">=</span> <span class="n">nAParent</span><span class="p">;</span>
</span><span class='line'>              <span class="k">break</span><span class="p">;</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="n">nBParent</span> <span class="o">==</span> <span class="n">nLsTe</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>              <span class="k">break</span><span class="p">;</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">allParent</span><span class="p">)</span>
</span><span class='line'>          <span class="k">break</span><span class="p">;</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">nAParent</span> <span class="o">==</span> <span class="n">nLsTe</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>          <span class="k">break</span><span class="p">;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 此处只需要判断 nAChild 和 nBChild 的优先级即可，默认返回 a</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">nAChild</span> <span class="o">||</span> <span class="o">!</span><span class="n">nBChild</span><span class="p">)</span>
</span><span class='line'>      <span class="k">return</span> <span class="n">a</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 根据 ZOrder 判断，如果 ZOrder一样，根据索引位置判断</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">nAChild</span><span class="o">-&gt;</span><span class="n">getZOrder</span><span class="p">()</span> <span class="o">==</span> <span class="n">nBChild</span><span class="o">-&gt;</span><span class="n">getZOrder</span><span class="p">())</span>
</span><span class='line'>      <span class="k">return</span> <span class="n">allParent</span><span class="o">-&gt;</span><span class="n">getChildren</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">indexOfObject</span><span class="p">(</span><span class="n">nAChild</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">allParent</span><span class="o">-&gt;</span><span class="n">getChildren</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">indexOfObject</span><span class="p">(</span><span class="n">nBChild</span><span class="p">)</span><span class="o">?</span> <span class="nl">a:</span> <span class="n">b</span><span class="p">;</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>      <span class="k">return</span> <span class="n">nAChild</span><span class="o">-&gt;</span><span class="n">getZOrder</span><span class="p">()</span> <span class="o">&gt;</span> <span class="n">nBChild</span><span class="o">-&gt;</span><span class="n">getZOrder</span><span class="p">()</span><span class="o">?</span> <span class="nl">a:</span> <span class="n">b</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>关于后续</h2>

<p>实现了这样一个简单的事件处理模型，可以稍加修改扩展，基本能满足大部分的使用需求了，优势是使用简单，当然也有不足之处（这点也是今后需要完善的所在），比如事件的处理统一由场景基层实现调用，而我的理想使用方式，是 LsTouchEvent 可以添加到其它的 LsTouchEvent 之中，并且可以控制这样一种子层的可视范围（这确实很有用处，比如层级遮挡等），这样如果界面太过复杂不用把所有的事件响应都放在场景基层之中了，可以在任意的某一个层处理，分而治之，这样也就能够非常方便的处理非常复杂的 UI 逻辑！而要在现有雏形实现此功能，我们只需要在 LsTouchEvent 内部添加一个 LsTouchEvent 类型的集合，从而使场景基层管理到所有的 LsTouchEvent 事件相应层，LsTouchEvent 将会组成一个树形结构，也可以使触摸消息传递到所有的 LsTouchEvent 层中。如此，场景基层同样能管理到所有的可触摸元素，并判断优先级。</p>

<p>cocos2d-x 本来提供的触摸消息机制，通过实现各个层的 ccTouchesBegan 等方法，使用确实灵活，但界面一复杂，就灵活的有些难以驾驭，比如我们需要在每个地方对内部元素做是否运行（IsRunning）是否隐藏(IsVisible)判断等，还需要对其相应的优先级多做了解，才能保证使用过程中不会出现什么纰漏。</p>

<p>而对于本文，如果有什么异议，或者有什么其它的设计方式，欢迎留言讨论 ~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cocos2d-x 内存管理浅说]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-22.html"/>
    <updated>2013-05-22T23:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-mem-mgr</id>
    <content type="html"><![CDATA[<p>使用过 Cocos2d-x 都知道，其中有一套自己实现的内存管理机制，不同于一般 C++ 的编写常规，而在使用前，了解其原理是有必要的，网上已经有很多对内部实现详细解说的文章。而对于使用者而言，并不需要对其内部有很深的了解，注重其<strong>“机制”</strong>，而非内部实现，在这里只是简单的聊一聊它的管理方式以及使用，固为浅说。</p>

<h2>无用对象 与 管理对象</h2>

<p><strong>Cocos2d-x 将会在下一帧自动清理无用的对象，什么是无用的对象，通过 create() 方法创建的就是无用的对象。</strong></p>

<p>为了简要说明，代码的组织设计一切从简，我们创建了两个辅助类和一个容器类 BaseLayer，在 BaseLayer 之上管理内部对象，并观察它是怎么自动管理对象的。实现了其 构造函数 方法和 析构函数，并做些日志打印，以方便我们观察：</p>

<!-- more -->




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">class</span> <span class="nc">LSLayer</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCNode</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LSLayer().init()&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">LSLayer</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">LSLayer</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LSLayer().()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LSLayer</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LSLayer().~()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">LSSprite</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCNode</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LSSprite().init()&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">LSSprite</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">LSSprite</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LSSprite().()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">LSSprite</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;LSSprite().~()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">BaseLayer</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCLayer</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;BaseLayer().init()&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="c1">// 我们创建了两个 “无用”对象</span>
</span><span class='line'>      <span class="n">LSLayer</span><span class="o">*</span> <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>      <span class="n">LSSprite</span><span class="o">*</span> <span class="n">sprite</span> <span class="o">=</span> <span class="n">LSSprite</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>      <span class="c1">// 使用了 layer 变为受“管理”的对象</span>
</span><span class='line'>      <span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">layer</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">BaseLayer</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">BaseLayer</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;BaseLayer().()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">BaseLayer</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;BaseLayer().~()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>如上所示，我们在 BaseLayer 中创建了两个对象， layer 和 sprite，而只使用了 layer ，如果要运行上面的 BaseLayer 代码，我们需要创建一个 BaseLayer  的层对象，并将它添加到运行的场景或者层中： <code>addChild(BaseLayer::create());</code>，以保证 BaseLayer 开始运行，现在我们分析一下运行的结果：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>// 由 addChild<span class="o">(</span>BaseLayer::create<span class="o">())</span>; 方法开始，创建并初始化了 BaseLayer 层
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>BaseLayer<span class="o">()</span>.<span class="o">()]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>BaseLayer<span class="o">()</span>.init<span class="o">()]</span>
</span><span class='line'>// BaseLayer init 方法我们创建了两个对象
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>LSLayer<span class="o">()</span>.<span class="o">()]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>LSLayer<span class="o">()</span>.init<span class="o">()]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>LSSprite<span class="o">()</span>.<span class="o">()]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>LSSprite<span class="o">()</span>.init<span class="o">()]</span>
</span><span class='line'>// 对象创建完成，紧接着这“无用”对象便已经释放了，而另一个已经使用的对象没有释放
</span><span class='line'>cocos2d-x debug info <span class="o">[</span>LSSprite<span class="o">()</span>.~<span class="o">()]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>通过上面两个例子对比，对 cocos2d-x 的对象管理有了初步的认识，它会自动清理 <strong>“无用对象”</strong>。为了区分概念，我们将另一种对象称之为 <strong>“管理对象”</strong>，它是受管理的，有用的对象。比如上文中的 <strong>layer</strong>。</p>

<p>！！这也算初步认识，当然，这至少解决了我们这样一个疑问：<strong>我们在场景初始化的时候，通过 create() 创建了成员变量，以备需要的时候使用，但发现在使用的时候这个对象已经不存在了，从而导致程序崩溃。</strong></p>

<h3>管理对象不用之时立即回收</h3>

<p>我们再继续演变 BaseLayer 的实现，以方便我们观察在每一帧对象的情况，添加实现了定时器功能：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">class</span> <span class="nc">BaseLayer2</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCLayer</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">init</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;BaseLayer2().init()&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="c1">// 启用定时器，自动在每一帧调用 update 方法</span>
</span><span class='line'>      <span class="k">this</span><span class="o">-&gt;</span><span class="n">scheduleUpdate</span><span class="p">();</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 定义 update 统计</span>
</span><span class='line'>  <span class="kt">int</span> <span class="n">updateCount</span><span class="p">;</span>
</span><span class='line'>  <span class="n">LSLayer</span><span class="o">*</span> <span class="n">layer</span><span class="p">;</span>
</span><span class='line'>  <span class="n">LSSprite</span><span class="o">*</span> <span class="n">sprite</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="kt">float</span> <span class="n">fDelta</span><span class="p">){</span>
</span><span class='line'>      <span class="c1">// 为了方便观察，不让 update 内部无止境的打印下去</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>          <span class="n">updateCount</span> <span class="o">++</span><span class="p">;</span>
</span><span class='line'>          <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>          <span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
</span><span class='line'>              <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>              <span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">layer</span><span class="p">);</span>
</span><span class='line'>              <span class="n">sprite</span> <span class="o">=</span> <span class="n">LSSprite</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>          <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
</span><span class='line'>              <span class="k">this</span><span class="o">-&gt;</span><span class="n">removeChild</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>          <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>          <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d end&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CREATE_FUNC</span><span class="p">(</span><span class="n">BaseLayer2</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">BaseLayer2</span><span class="p">()</span><span class="o">:</span>
</span><span class='line'>      <span class="n">updateCount</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span>
</span><span class='line'>      <span class="n">layer</span><span class="p">(</span><span class="nb">NULL</span><span class="p">),</span>
</span><span class='line'>      <span class="n">sprite</span><span class="p">(</span><span class="nb">NULL</span><span class="p">)</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;BaseLayer2().()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>  <span class="o">~</span><span class="n">BaseLayer2</span><span class="p">(){</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;BaseLayer2().~()&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 打印如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">BaseLayer2</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">BaseLayer2</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="c1">// 第一帧创建两个对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 我们看到 sprite 无用对象在 第一帧和第二帧之间被释放</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 在第二帧移除管理对象，可以看到它是立即释放，在 index: 2 end 之前</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>与无用对象不同的是，管理对象在不用之时，立即释放，这决定着如果想在其它地方使用此对象，在“完全”不用之前，一定要有所作为。重写 update 方法如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">virtual</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="kt">float</span> <span class="n">fDelta</span><span class="p">){</span>
</span><span class='line'>  <span class="c1">// 为了方便观察，不让 update 内部无止境的打印下去</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>      <span class="n">updateCount</span> <span class="o">++</span><span class="p">;</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
</span><span class='line'>          <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>          <span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">layer</span><span class="p">);</span>
</span><span class='line'>          <span class="n">sprite</span> <span class="o">=</span> <span class="n">LSSprite</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>          <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;%d&quot;</span><span class="p">,</span> <span class="n">layer</span><span class="p">);</span>
</span><span class='line'>      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
</span><span class='line'>          <span class="n">layer</span><span class="o">-&gt;</span><span class="n">retain</span><span class="p">();</span>
</span><span class='line'>          <span class="k">this</span><span class="o">-&gt;</span><span class="n">removeChild</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'>          <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;%d&quot;</span><span class="p">,</span> <span class="n">layer</span><span class="p">);</span>
</span><span class='line'>      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>          <span class="n">layer</span><span class="o">-&gt;</span><span class="n">release</span><span class="p">();</span>
</span><span class='line'>          <span class="k">if</span> <span class="p">(</span><span class="n">layer</span><span class="p">){</span>
</span><span class='line'>              <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;%d&quot;</span><span class="p">,</span> <span class="n">layer</span><span class="p">);</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d end&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 打印如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="mi">147867424</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 第二帧并没有释放 layer，因为它还是有用的管理对象</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="mi">147867424</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span><span class="p">]</span>
</span><span class='line'><span class="c1">// 完全弃用，立即释放   </span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="c1">// 但是 layer 对象的地址还是可用的</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="mi">147867424</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">3</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><strong>在完全不用之前，要有所作为。</strong> 如果我们将第二帧中的 <code>layer-&gt;retain();</code> <strong>放在</strong>  <code>this-&gt;removeChild(layer, true);</code> <strong>之后</strong> 呢，我们知道在 removeChild 之后是立即释放的，此时 layer 对象已经不存在了，而 layer 所指向的内存地址是个无效地址。如果你的程序继续运行，那么一定会出现内存错误。</p>

<p><strong>如果程序直接错误异常退出，倒也罢了，怕就怕，程序可能继续运行</strong>，layer 虽然是无效地址，但并不是 NULL，可能所指向的地址可用，可能还能继续执行，更可能的还能继续 <code>layer-&gt;retain();</code> 操作。这会影响我们的判断，程序真的有问题么。如果留下了这种隐患，那么排除错误的难度会大大加深。比如程序莫名其妙的退出，时好时坏！（经过一叶的测试，这种情况是可能发生的，而且频率相当高，测试平台：Linux 平台，Android平台可能性稍低）</p>

<p>第三帧我们通过 <code>if (layer)</code> 判断对象是否可用，如果可用我们继续操作 layer ，这样的使用方式也将会留下内存隐患，因为这样的判断是能通过的，但却是 <strong>不一定</strong> 能够正确使用的。</p>

<p>一般而言，我们不一定需要 <code>if(layer)</code> 诸如此类的判断，这也是不推荐的。管理对象，<strong>谁使用，那么谁就是可控的！</strong>如果在对象销毁之前 谁 retain() ，那么在 release() 之前，它无需判断即可使用。谁 <strong>addXXX</strong> 使用，一般能通过 <strong>getXXX</strong> 获取。</p>

<p>简而言之，谁使用（引用），你就找谁就行了，不论是获取，或者移除。</p>

<p>我们前面所言，管理对象不用之时，立即回收，那么我们在同一帧使用，然后移除呢？我们继续改写 update 方法，验证想法：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="k">virtual</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="kt">float</span> <span class="n">fDelta</span><span class="p">){</span>
</span><span class='line'>  <span class="c1">// 为了方便观察，不让 update 内部无止境的打印下去</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>      <span class="n">updateCount</span> <span class="o">++</span><span class="p">;</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
</span><span class='line'>          <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>          <span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">layer</span><span class="p">);</span>
</span><span class='line'>          <span class="k">this</span><span class="o">-&gt;</span><span class="n">removeChild</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'>      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'>      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;update index: %d end&quot;</span><span class="p">,</span> <span class="n">updateCount</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 其打印如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="n">init</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="c1">// layer 在两帧之间释放，也既是在一下帧自动清理</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>这里我们在同一帧 addChild 并且随之 removeChild，那么 layer 的性质又是如何，我们知道 <strong>管理对象</strong> 在不用之时会立即释放，但在这里并没有立即释放，那说明什么，说明 layer 并不是管理对象，还只是无用对象，并且在这一帧结束时，或者说在 <strong>帧过度</strong> 的时候，并没有使用，可想而知，在 帧过度的时候，其内部做了些处理，首先自动清理无用对象，或者将以使用的无用对象变成管理对象，而在以后的帧，如果在管理对象不用之时，将会立即释放。</p>

<p>现在来看一看稍微复杂点的结构会如何。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
</span><span class='line'>  <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">sprite</span> <span class="o">=</span> <span class="n">LSSprite</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">layer</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">sprite</span><span class="p">);</span>
</span><span class='line'>  <span class="n">addChild</span><span class="p">(</span><span class="n">layer</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">this</span><span class="o">-&gt;</span><span class="n">removeChild</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 打印如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>我们创建了两个对象 layer 和 sprite，将 sprite 添加到 layer，并把通过 addChild(layer) 使用 layer，可以看到，在第二帧移除 layer 的时候，立即释放了 layer 和 sprite 对象。这也是 cocos2d-x 自动管理所实现的功能，<strong>在 使用者 不用的时候，它也将会解除对其它对象的使用。</strong></p>

<p>基于以上情况，做些变形：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 在不同的帧做相关操作，以便观察</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
</span><span class='line'>  <span class="n">layer</span> <span class="o">=</span> <span class="n">LSLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">sprite</span> <span class="o">=</span> <span class="n">LSSprite</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">layer</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">sprite</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
</span><span class='line'>  <span class="k">this</span><span class="o">-&gt;</span><span class="n">removeChild</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">updateCount</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
</span><span class='line'>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 打印如下</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">1</span> <span class="n">end</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSLayer</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">LSSprite</span><span class="p">().</span><span class="o">~</span><span class="p">()]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span><span class="p">]</span>
</span><span class='line'><span class="n">cocos2d</span><span class="o">-</span><span class="n">x</span> <span class="n">debug</span> <span class="n">info</span> <span class="p">[</span><span class="n">update</span> <span class="nl">index:</span> <span class="mi">2</span> <span class="n">end</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>创建了两个对象 layer 和 sprite，将 sprite 添加到 layer 之中，而对 layer 不做处理，我们知道 layer 在第一帧结束后，会自动释放，所以也会释放其所引用的 sprite，而此时 sprite 的性质就有点微妙了。它在帧过度之间是怎么处理的，它是不是我们这所说的无用对象呢？哈！如果 layer 首先被自动管理，那么它会首先回收，并取消对 sprite 的引用，那么 sprite 就是个无用对象，<strong>被自动回收</strong>。如果 sprite 首先被自动管理，那么它将会先变成一个管理对象，然后在 layer 自动释放并取消对 sprite 引用的时候，<strong>被立即释放</strong>。从效果上来说，都是一帧之内完成的。但具体是哪种情况呢？我不知晓 : p 也不用知晓 ~ 所谓不知为不知，是知也 ～</p>

<h2>写在后面</h2>

<p>自动管理，所谓自动管理就是通过 <code>create()</code> 方法创建的对象（当然其内部是通过 autorelease() 方法标示，create 只是提供一个统一的创建对象方式），而什么又是有用无用呢，文中我们看到 <code>retain()</code> 和 <code>release()</code>，而这就是有用无用的实现原理，使用就 retain ，移除使用就用 release，再细究内部，可知里面维护了一个引用计数，从而判断是否被使用 ，而前文我们知道 layer->addChild(obj)，那么 obj 就为 layer 所用，究其本质，也是其内部调用了其 retain 等方法，可以阅读官方相关文档，有详细的说明，而本文多是以抽象的概念解说其设计理念，从使用者的角度分析在使用过程中可能会出现的问题，因为要想达到相同的自动管理效果，实现方式可以有很多种。别太注重细节，如果有什么疑问，可以像这样，通过几个小例程去验证我们的想法。对于本文，也只是我对 cocos2d-x 自动管理的理解，如果在实现和概念上有什么说的不对，还请指出，毕竟是 <strong>浅说</strong> ～</p>

<p>cocos2d-x 主要以 CCNode 为基类的树形结构组织管理，所以本文所创建的例程，基于 CCNode 编写，当然内存的自动管理还有很多内容，比如缓存的实现，消息机制对象的生命周期等。但基于谁使用，谁处理的原则，思路倒也明晰 ~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[类 Android 多级日志系统应用]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-15.html"/>
    <updated>2013-05-15T17:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-log</id>
    <content type="html"><![CDATA[<p>在 cocos2d-x 中实现类 Android 多级日志系统！写程序，免不了调试打印 Log ，而一个方便的日志系统，可以提高不少开发的效率，写过 Android 应用的朋友应该了解在 Android 中的日志包含很多等级，查看日志的时候可以指定日志的级别，从而过滤一些无用的信息，能够更为快速的定位问题的所在。而在 cocos2d-x 的开发中，统一使用 <strong>CCLog</strong>，只能算是最基本的功能，既然有好的思想可以借鉴，何乐而不为呢～</p>

<p>先看看最终实现的效果，我们使用简单封装过的方法调用打印日志系统（Leafsoar Log:LSLog）：</p>

<!-- more -->




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>LSLog::verbose<span class="o">(</span><span class="s2">&quot;博客名称： %s&quot;</span>,<span class="s2">&quot;无间落叶&quot;</span><span class="o">)</span>;
</span><span class='line'>LSLog::debug<span class="o">(</span><span class="s2">&quot;博客地址： %s&quot;</span>, <span class="s2">&quot;http://blog.leafsoar.com&quot;</span><span class="o">)</span>;
</span><span class='line'>LSLog::info<span class="o">(</span><span class="s2">&quot;基本信息： %s&quot;</span>, <span class="s2">&quot;吾名 一叶&quot;</span><span class="o">)</span>;
</span><span class='line'>LSLog::warn<span class="o">(</span><span class="s2">&quot;多出警告： %s %s&quot;</span>, <span class="s2">&quot;警告一&quot;</span>, <span class="s2">&quot;警告二&quot;</span><span class="o">)</span>;
</span><span class='line'>LSLog::error<span class="o">(</span><span class="s2">&quot;坐标错误： (%f, %f)&quot;</span>, 800.0f, 600.0f<span class="o">)</span>;
</span><span class='line'>
</span><span class='line'>// Linux 系统下打印信息 （非 Android）
</span><span class='line'>cocos2d-x debug info <span class="o">[(</span>verbose<span class="o">)</span>  :博客名称： 无间落叶<span class="o">]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[(</span>debug<span class="o">)</span>        :博客地址： http://blog.leafsoar.com<span class="o">]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[(</span>info<span class="o">)</span>         :基本信息： 吾名 一叶<span class="o">]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[(</span>warn<span class="o">)</span>         :多出警告： 警告一 警告二<span class="o">]</span>
</span><span class='line'>cocos2d-x debug info <span class="o">[(</span>error<span class="o">)</span>        :坐标错误： <span class="o">(</span>800.000000, 600.000000<span class="o">)]</span>
</span></code></pre></td></tr></table></div></figure>


<p>在 Android 的 Logcat 下显示效果：
<img src="http://blog.leafsoar.com/images/2013/cocos2d-x-log.png" alt="图片" /></p>

<p>在 Android 平台，可以打印所有信息，并且通过 LogCat 过滤信息，还有相应的高亮显示。而这些都已经在 <strong>LSLog</strong> 内部通过 Jni 调用实现，如需如上所示的调用即可。</p>

<p>通过日志的等级划分过滤，可以让我们在调试某一个功能时只关注某一类调试信息，比如只显示警告信息和错误信息，而不是哗啦啦所有的日志都打印出来，然后一行一行读，查看，排错。</p>

<p>而在非 Android 平台，并没有如 LogCat 这样的工具，其它平台我不知晓，但我所在的 Linux 平台显然之用默认的日志打印，所以在 LSLog 的内部实现之中，<strong>通过一个开关控制显示哪些级别的日志信息，这个级别可以任意的定义。</strong> 看下面实现<a href="https://github.com/leafsoar/ls-cocos2d-x/tree/master/Learn/Classes">源码获取</a>：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
<span class='line-number'>166</span>
<span class='line-number'>167</span>
<span class='line-number'>168</span>
<span class='line-number'>169</span>
<span class='line-number'>170</span>
<span class='line-number'>171</span>
<span class='line-number'>172</span>
<span class='line-number'>173</span>
<span class='line-number'>174</span>
<span class='line-number'>175</span>
<span class='line-number'>176</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// LSLog.h</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#ifndef LSLOG_H_</span>
</span><span class='line'><span class="cp">#define LSLOG_H_</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &quot;cocos2d.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 日志级别，也可根据自己需要修改添加类别</span>
</span><span class='line'><span class="k">enum</span><span class="p">{</span>
</span><span class='line'>  <span class="n">LSLOG_VERBOSE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span><span class='line'>  <span class="n">LSLOG_DEBUG</span><span class="p">,</span>
</span><span class='line'>  <span class="n">LSLOG_INFO</span><span class="p">,</span>
</span><span class='line'>  <span class="n">LSLOG_WARN</span><span class="p">,</span>
</span><span class='line'>  <span class="n">LSLOG_ERROR</span><span class="p">,</span>
</span><span class='line'>  <span class="n">LSLOG_COUNT</span><span class="p">,</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 打印日志类别前缀</span>
</span><span class='line'><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">lsLog_name</span><span class="p">[</span><span class="n">LSLOG_COUNT</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>      <span class="s">&quot;(verbose)</span><span class="se">\t</span><span class="s">&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;(debug)</span><span class="se">\t\t</span><span class="s">&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;(info)</span><span class="se">\t\t</span><span class="s">&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;(warn)</span><span class="se">\t\t</span><span class="s">&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;(error)</span><span class="se">\t\t</span><span class="s">&quot;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 不同级别对应的 Android Jni 实现方法名称</span>
</span><span class='line'><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">lsLog_androidMethod</span><span class="p">[</span><span class="n">LSLOG_COUNT</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>      <span class="s">&quot;v&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;d&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;i&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;w&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="s">&quot;e&quot;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> @brief 自定义日志系统，前期使用，以后可以扩展优化</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">LSLog</span><span class="o">:</span> <span class="k">public</span> <span class="n">cocos2d</span><span class="o">::</span><span class="n">CCObject</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">/// verbose 详细日志，一般常用的打印信息</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">verbose</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...);</span>
</span><span class='line'>  <span class="c1">/// debug 调试 ,调试过程所注意的信息</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">debug</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...);</span>
</span><span class='line'>  <span class="c1">/// info 一般信息,</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">info</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...);</span>
</span><span class='line'>  <span class="c1">///  warn 警告信息</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">warn</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...);</span>
</span><span class='line'>  <span class="c1">/// error 错误信息</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">error</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...);</span>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">// 需要显示的日志级别定义</span>
</span><span class='line'>  <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">LOG_VALUE</span><span class="p">;</span>
</span><span class='line'>  <span class="c1">// 打印日志方法</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">printLog</span><span class="p">(</span><span class="kt">int</span> <span class="n">type</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">format</span><span class="p">,</span> <span class="n">va_list</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// Android 平台日志打印</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">printAndroidLog</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">methodName</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">log</span><span class="p">);</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#endif </span><span class="cm">/* LSLOG_H_ */</span><span class="cp"></span>
</span><span class='line'>
</span><span class='line'><span class="c1">// LSLog.cpp</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &quot;LSLog.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &quot;platform/android/jni/JniHelper.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;platform/android/jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h&quot;</span>
</span><span class='line'><span class="cp">#include &lt;jni.h&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'>
</span><span class='line'><span class="n">USING_NS_CC</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#define kMaxStringLen (1024*100)</span>
</span><span class='line'><span class="cp">#define LOG_V 1</span>
</span><span class='line'><span class="cp">#define LOG_D 2</span>
</span><span class='line'><span class="cp">#define LOG_I 4</span>
</span><span class='line'><span class="cp">#define LOG_W 8</span>
</span><span class='line'><span class="cp">#define LOG_E 16</span>
</span><span class='line'>
</span><span class='line'><span class="c1">/// 需要打印的日志级别，根据 LOG_VALUE 的设置打印不同级别的日志</span>
</span><span class='line'><span class="c1">//const int LSLog::LOG_VALUE = LOG_V | LOG_D | LOG_I | LOG_W | LOG_E;</span>
</span><span class='line'><span class="c1">//const int LSLog::LOG_VALUE = LOG_D | LOG_I | LOG_W | LOG_E;</span>
</span><span class='line'><span class="k">const</span> <span class="kt">int</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">LOG_VALUE</span> <span class="o">=</span> <span class="n">LOG_I</span> <span class="o">|</span> <span class="n">LOG_W</span> <span class="o">|</span> <span class="n">LOG_E</span><span class="p">;</span>
</span><span class='line'><span class="c1">//const int LSLog::LOG_VALUE = LOG_W | LOG_E;</span>
</span><span class='line'><span class="c1">//const int LSLog::LOG_VALUE = LOG_E;</span>
</span><span class='line'><span class="c1">//const int LSLog::LOG_VALUE = 0;</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 这里灵活控制，可以只打印某一个级别</span>
</span><span class='line'><span class="c1">//const int LSLog::LOG_VALUE = LOG_D;</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">verbose</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">LOG_V</span> <span class="o">&amp;</span> <span class="n">LOG_VALUE</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">va_list</span> <span class="n">ap</span><span class="p">;</span>
</span><span class='line'>      <span class="n">va_start</span><span class="p">(</span><span class="n">ap</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">);</span>
</span><span class='line'>      <span class="n">LSLog</span><span class="o">::</span><span class="n">printLog</span><span class="p">(</span><span class="n">LSLOG_VERBOSE</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>      <span class="n">va_end</span><span class="p">(</span><span class="n">ap</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">debug</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">LOG_D</span> <span class="o">&amp;</span> <span class="n">LOG_VALUE</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">va_list</span> <span class="n">ap</span><span class="p">;</span>
</span><span class='line'>      <span class="n">va_start</span><span class="p">(</span><span class="n">ap</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">);</span>
</span><span class='line'>      <span class="n">LSLog</span><span class="o">::</span><span class="n">printLog</span><span class="p">(</span><span class="n">LSLOG_DEBUG</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>      <span class="n">va_end</span><span class="p">(</span><span class="n">ap</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">info</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">LOG_I</span> <span class="o">&amp;</span> <span class="n">LOG_VALUE</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">va_list</span> <span class="n">ap</span><span class="p">;</span>
</span><span class='line'>      <span class="n">va_start</span><span class="p">(</span><span class="n">ap</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">);</span>
</span><span class='line'>      <span class="n">LSLog</span><span class="o">::</span><span class="n">printLog</span><span class="p">(</span><span class="n">LSLOG_INFO</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>      <span class="n">va_end</span><span class="p">(</span><span class="n">ap</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">warn</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">LOG_W</span> <span class="o">&amp;</span> <span class="n">LOG_VALUE</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">va_list</span> <span class="n">ap</span><span class="p">;</span>
</span><span class='line'>      <span class="n">va_start</span><span class="p">(</span><span class="n">ap</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">);</span>
</span><span class='line'>      <span class="n">LSLog</span><span class="o">::</span><span class="n">printLog</span><span class="p">(</span><span class="n">LSLOG_WARN</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>      <span class="n">va_end</span><span class="p">(</span><span class="n">ap</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">error</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">LOG_E</span> <span class="o">&amp;</span> <span class="n">LOG_VALUE</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">va_list</span> <span class="n">ap</span><span class="p">;</span>
</span><span class='line'>      <span class="n">va_start</span><span class="p">(</span><span class="n">ap</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">);</span>
</span><span class='line'>      <span class="n">LSLog</span><span class="o">::</span><span class="n">printLog</span><span class="p">(</span><span class="n">LSLOG_ERROR</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>      <span class="n">va_end</span><span class="p">(</span><span class="n">ap</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">printLog</span><span class="p">(</span><span class="kt">int</span> <span class="n">type</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">format</span><span class="p">,</span> <span class="n">va_list</span> <span class="n">ap</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="kt">char</span><span class="o">*</span> <span class="n">pBuf</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="n">kMaxStringLen</span><span class="p">);</span>
</span><span class='line'>  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">mstr</span><span class="p">;</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">pBuf</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">vsnprintf</span><span class="p">(</span><span class="n">pBuf</span><span class="p">,</span> <span class="n">kMaxStringLen</span><span class="p">,</span> <span class="n">format</span><span class="p">,</span> <span class="n">ap</span><span class="p">);</span>
</span><span class='line'>      <span class="n">mstr</span> <span class="o">=</span> <span class="n">pBuf</span><span class="p">;</span>
</span><span class='line'>      <span class="n">free</span><span class="p">(</span><span class="n">pBuf</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="cp">#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)</span>
</span><span class='line'>  <span class="n">printAndroidLog</span><span class="p">(</span><span class="n">lsLog_androidMethod</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">mstr</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'><span class="cp">#else</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;%s :%s&quot;</span><span class="p">,</span> <span class="n">lsLog_name</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">mstr</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">LSLog</span><span class="o">::</span><span class="n">printAndroidLog</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">methodName</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">log</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'><span class="cp">#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)</span>
</span><span class='line'>  <span class="n">JniMethodInfo</span> <span class="n">t</span><span class="p">;</span>
</span><span class='line'>  <span class="kt">bool</span> <span class="n">isHave</span> <span class="o">=</span> <span class="n">JniHelper</span><span class="o">::</span><span class="n">getStaticMethodInfo</span><span class="p">(</span><span class="n">t</span><span class="p">,</span>
</span><span class='line'>          <span class="s">&quot;android/util/Log&quot;</span><span class="p">,</span>
</span><span class='line'>          <span class="n">methodName</span><span class="p">,</span>
</span><span class='line'>          <span class="s">&quot;(Ljava/lang/String;Ljava/lang/String;)I&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">isHave</span><span class="p">)</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>      <span class="n">jstring</span> <span class="n">jTitle</span> <span class="o">=</span> <span class="n">t</span><span class="p">.</span><span class="n">env</span><span class="o">-&gt;</span><span class="n">NewStringUTF</span><span class="p">(</span><span class="s">&quot;cocos2d-x&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="n">jstring</span> <span class="n">jMsg</span> <span class="o">=</span> <span class="n">t</span><span class="p">.</span><span class="n">env</span><span class="o">-&gt;</span><span class="n">NewStringUTF</span><span class="p">(</span>
</span><span class='line'>              <span class="n">log</span><span class="p">);</span>
</span><span class='line'>      <span class="n">t</span><span class="p">.</span><span class="n">env</span><span class="o">-&gt;</span><span class="n">CallStaticVoidMethod</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">classID</span><span class="p">,</span> <span class="n">t</span><span class="p">.</span><span class="n">methodID</span><span class="p">,</span> <span class="n">jTitle</span><span class="p">,</span>
</span><span class='line'>              <span class="n">jMsg</span><span class="p">);</span>
</span><span class='line'>      <span class="n">t</span><span class="p">.</span><span class="n">env</span><span class="o">-&gt;</span><span class="n">DeleteLocalRef</span><span class="p">(</span><span class="n">jTitle</span><span class="p">);</span>
</span><span class='line'>      <span class="n">t</span><span class="p">.</span><span class="n">env</span><span class="o">-&gt;</span><span class="n">DeleteLocalRef</span><span class="p">(</span><span class="n">jMsg</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>      <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;the jni method is not exits&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>这使前期开发方便了许多，而使用自定义的日志系统，另一个好处就是后期扩展，比如我们想将日志保存文本，收集错误信息等，都可以只通过修改日志内部方法的实现即可完成 ~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cocos2d-x 屏幕适配新解 - 兼容与扩展]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-13.html"/>
    <updated>2013-05-13T08:02:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-screen-solutions-extension</id>
    <content type="html"><![CDATA[<p>在读这篇文章之前，先读前一篇文章 <a href="http://blog.leafsoar.com/archives/2013/05-10.html">Cocos2d-x 屏幕适配新解</a> 是必要的。</p>

<p>如果说前一篇文章文章在 LsSize 提出之前的是基础，LsSize 是应用，那么对于这篇文章来说，LsSize 是基础，而这里是其的综合应用，我之初衷是其扩展性和兼容性，激发读者思维。也许你并没有体会出 LsSize 的强大，而实际上，<strong>它能做的比你想象的要多的多，这是前话 ~</strong></p>

<h2>ShoAll 模式的兼容</h2>

<p>首先 LsSize 能满足 ShowAll 模式的需要，因为开始就是把 LsSize 当作 ShowAll 中的 WinSize 来设计的。 并且可以为背景做装饰，而在游戏设计之时并没有什么区别，LsSize 可以设定显示区域的大小，使背景层与 LsSize 分离（这一点在上一篇文章最后已经提到），从而保证了游戏的元素不会超出 LsSize 而露出到 VisibleSize 的区域内。</p>

<!-- more -->


<h2>NoBorder 模式兼容</h2>

<p>为什么说 NoBorder <strong>兼容</strong>模式，它本身不就是 NoBorder 么，它与实际的 NoBorder 区别又在何处，有何优势？首先说说兼容，使用此模式，<strong>并不影响</strong> 你继续使用 VisibleSize 和 VisibleOrigin(以后简写 <strong>Visible</strong>)，你可以不使用 LsSize 的参考点，而使用 <strong>Visible</strong> 的相关值获取屏幕的拐点，游戏元素按照 Visible 来设置也可。下面详细介绍基于 LsSize 的 NoBorder 和原油 NoBorder 的区别以及其优势。</p>

<p>我们设想这样一个 <strong>实际情况</strong> 。我们需要一套资源图片，做为在适合分辨率的资源展示，当屏幕的大小分辨率在 <strong>854x480，800x480，728x480</strong> (横屏下：为什么高度同样是 480 而宽度有这么多值 : P 这也是屏幕适配万恶之一了吧) 时，我们使用一套资源，当高度小于 480 时，我们使用另一套小的资源是合理的设计。而这里我们的资源宽姑且先不论，高一定是 480 最为合适了，最接近此分辨率的图片。那我们使用 NoBorder 的时候该 <strong>设置 WinSize 为多少</strong> 了呢？</p>

<p><s>基于 854x480 设计！好，那么当程序跑在 854x480 的屏幕上，正好满屏显示，而图片资源并没有放大或者缩小，或者说基于像素点点对点显示的。但是当这样设计的 WinSize 跑在 800x480 和 728x480 分辨率会如何？也许已经知道了，为了保证小于 854 那一小块区域的显示，画面将会缩小那么一点点，也许在如今屏幕的 ppi 日益渐高的情况下，并不十分明显，但画面一定是有那么一点模糊了。同理可以遇见，<strong>不论 WinSize 如何设置，在 三种少许不同分辨率下，显示的效果肯定略有不同。</strong> 而分辨率差别越大，这种效果就越明显。</s></p>

<p><strong>注：细心的朋友已经读出上文描述中出现的 Bug ，并多谢指出问题的朋友。下面修复 Bug 并重新描述问题的情况 ～</strong></p>

<p>折衷方案，我们基于 800x480 设计，那么此时出现的情况是，当跑在 800x480 的屏幕上时，正好满屏显示，而图片并没有任何放大或者缩小，或者说基于像素点点对点显示的。而当这样设计的 WinSize 跑在 728x480 和 854x480 的分辨率会如何？ 854x480 相比 800x480，<strong>前者的宽高比要大于后者，所以它是宽对齐</strong>的，这意味着，画面有所放大，而上下将会有一部分残缺，<strong>此时设计高度将会失去参考价值</strong>。728x480 相比 800x480 ，<strong>前者的宽高比小于后者，所以它是高对齐</strong>的，此时画面并没有缩放，只是横向截取了小部分，这样的情况是由于 NoBorder 的实现机制所决定。<strong>当然我们可以将设计的宽度设置的很宽很宽，以保证高对齐，哈～但是魔(设计宽度)高一尺，道(实际宽度)高一丈,倒不如使用后文提到的“固定高度”方式了~</strong> 而这里的 854x480，800x480，728x480 等数据只是屏幕适配等问题的<strong>“缩影”</strong>。</p>

<p>读到这里也许已经发现了，LsSize 已经完美 <strong>(</strong>这里的完美，并非只此特殊情况下的解决方法，而是总览全文，基于 LsSize  的设计理念，其兼容性和可扩展性，显然在此时，固定高度是更好的实现方式<strong>)</strong> 的解决了这个问题，动态 WinSize ，一个合理的设计，我梦将 LsSize 设定为 720x480，并且使用 高度为 480 的图片资源，而宽度可以往大了设计，比如 854x480  的图片资源，读过前文 LsSize 的实现原理，我们可以知道，<strong>在这三种情况下，屏幕的画面并没有缩放，因为实际的宽度总是大于 720 ，从而达不到缩放的条件。</strong>480 高度的图片，能够正好填充 480 高度的屏幕，而图片的宽度往大了设计，在宽度稍微小的屏幕下，会被截取一部分，但就显示效果来说，并没有什么损失，而游戏的元素位置可以用原来的方法基于 Visible 来设计。</p>

<p>为什么可以做到如此！原本的  NoBorder 通过固定 WinSize 根据屏幕宽高比缩放，所以会有不同程度的缩放，而 LsSizeNoBorder 的设计实现，通过屏幕宽高比来获得 WinSize 的值，以保证 LsSize 总能在屏幕上正好全部显示。</p>

<p>LsSizeNoBorder 比 NoBorder 好，好多少，这就仁者见仁，智者见智了 ~</p>

<h2>kResolutionFixedHeight，kResolutionFixedWidth 扩展兼容模式</h2>

<p>FixedHeight 和 FixedWidth 是什么模式，如果你试用了最新版的  cocos2d-x (2.1.3)就能发现这两种模式，一种是固定设计时的高，一种是固定设计时的宽。而在当前的 2.0.4 并没有这两种模式，而现在，你可以通过 LsSize 来实现这两种模式。存在既是合理，FixedHeight 和 FixedWidth 的存在是合理的，比如我们写一个横版过关游戏，同样是三种分辨率 <strong>854x480，800x480，728x480</strong> 使用固定设计高度的方法，可以避免在 NoBorder 中会根据宽度而做的缩放。</p>

<p>而在 LsSizeNoBorder 中好似也实现了相同的功能！但注意有一点区别，在 LsSizeNoBorder 中，实际屏幕高度为 480 ，如果宽度小于 720 时，那么画面会缩放，而这里新模式固定高度不会。如果我们想让 LsSize 实现这种功能怎么做，我们将对 LsSize 的设计稍作扩展，上篇文章的代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCSize</span> <span class="n">frameSize</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getFrameSize</span><span class="p">();</span>
</span><span class='line'><span class="c1">// 设置 LsSize 固定值</span>
</span><span class='line'><span class="n">CCSize</span> <span class="n">lsSize</span> <span class="o">=</span> <span class="n">CCSizeMake</span><span class="p">(</span><span class="mi">480</span><span class="p">,</span> <span class="mi">320</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="kt">float</span> <span class="n">scaleX</span> <span class="o">=</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">frameSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">width</span><span class="p">;</span>
</span><span class='line'><span class="kt">float</span> <span class="n">scaleY</span> <span class="o">=</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">frameSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 定义 scale 变量</span>
</span><span class='line'><span class="kt">float</span> <span class="n">scale</span> <span class="o">=</span> <span class="mf">0.0f</span><span class="p">;</span> <span class="c1">// MAX(scaleX, scaleY);</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">scaleX</span> <span class="o">&gt;</span> <span class="n">scaleY</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// 如果是 X 方向偏大，那么 scaleX 需要除以一个放大系数，放大系数可以由枞方向获取，</span>
</span><span class='line'>    <span class="c1">// 因为此时 FrameSize 和 LsSize 的上下边是重叠的</span>
</span><span class='line'>    <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleX</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>    <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleY</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">width</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;x: %f; y: %f; scale: %f&quot;</span><span class="p">,</span> <span class="n">scaleX</span><span class="p">,</span> <span class="n">scaleY</span><span class="p">,</span> <span class="n">scale</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 根据 LsSize 和屏幕宽高比动态设定 WinSize</span>
</span><span class='line'><span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setDesignResolutionSize</span><span class="p">(</span><span class="n">lsSize</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">scale</span><span class="p">,</span>
</span><span class='line'>      <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span> <span class="o">*</span> <span class="n">scale</span><span class="p">,</span> <span class="n">kResolutionNoBorder</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>我们的实际缩放系数，是根据 scaleX 和 scaleY 的大小来判断，依据哪个方向缩放，从而在显示效果上是高对齐还是宽对齐。而想要固定是高度对其还是宽度对其，那只要换用如下方法即可：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 要实现这种功能，我们需要做的就是算得 缩放系数，缩放系数由 原来的设计稍作演变即可</span>
</span><span class='line'><span class="c1">// 由于 NoBorder 的缩放是根据 scaleX 和 scaleY 的熟大熟小来判断缩放系数是参照横向还是竖向</span>
</span><span class='line'><span class="c1">// 固我们需要两个先决条件，固定的方向 和 缩放的参照方向，而得到如下算法</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 固定高度</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">scaleX</span> <span class="o">&gt;</span> <span class="n">scaleY</span><span class="p">)</span>
</span><span class='line'>  <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleX</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span><span class="p">);</span>
</span><span class='line'><span class="k">else</span>
</span><span class='line'>  <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleX</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">width</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 固定宽度</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">scaleX</span> <span class="o">&gt;</span> <span class="n">scaleY</span><span class="p">)</span>
</span><span class='line'>  <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleY</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span><span class="p">);</span>
</span><span class='line'><span class="k">else</span>
</span><span class='line'>  <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleY</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">width</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>下面通过几张效果图展示 <strong>固定高度</strong> 和 <strong>固定宽度</strong> 效果：</p>

<p>显示效果：（NoBorder <strong>固定高度</strong>模式 ;FrameSize = 520x320; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-extension-1.jpg" alt="图片" /></p>

<p>显示效果：（NoBorder <strong>固定高度</strong>模式 ;FrameSize = 520x360; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-extension-2.jpg" alt="图片" /></p>

<p>显示效果：（NoBorder <strong>固定宽度</strong>模式 ;FrameSize = 480x360; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-extension-3.jpg" alt="图片" /></p>

<p>显示效果：（NoBorder <strong>固定宽度</strong>模式 ;FrameSize = 480x300; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-extension-4.jpg" alt="图片" /></p>

<p>如图所示，我们固定了一个方向，使得这个方向上的设计长度正好填充屏幕，而另一个方向上会有所延伸或截取，而此时如果想或者屏幕拐点，可以配合 Visible 的显示区域算得。而这也正式 cocos2d-x 2.1.3 所实现的功能，而如果你此时为了稳定而使用 2.0.4 stable 版本，那么就<strong>可以通过这种基于 LsSize 的设计方法实现 FixedHeight 与 FixedWidth。</strong> 而在将来后续版本稳定，也可以很平滑的升级到使用自带的方式替换，其显示效果一样，只是后续版本 cocos2d-x 在内部将它封装了而已。</p>

<h2>kResolutionLeafsoar 模式的核心思想</h2>

<p>透过现象看本质！基于固定 LsSize 的动态 WinSize 设计。之所以能够兼容这么多模式并且有所加强，在于 LsSize 在 FrameSize、WinSize、VisibleSize、VisibleOrigin等概念之外的存在，并且通过动态计算 scale  而游走于此等之间。它的存在并不依赖于 这些已有概念，而反过来，让已有的概念去依赖 LsSize 。从而保持设计上的灵活性与扩展性。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cocos2d-x 屏幕适配新解]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-10.html"/>
    <updated>2013-05-10T19:02:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-screen-solutions</id>
    <content type="html"><![CDATA[<p>为了适应移动终端的各种分辨率大小，各种屏幕宽高比，在 cocos2d-x（当前稳定版：<strong>2.0.4</strong>） 中，提供了相应的解决方案，以方便我们在设计游戏时，能够更好的适应不同的环境。</p>

<p>而在设计游戏之初，决定着我们屏幕适配的因素有哪些，简而言之只有两点：<strong>屏幕大小 和 宽高比</strong>。这两个因素是如何影响游戏的：</p>

<ul>
<li><strong>屏幕大小：</strong> 从小分辨率 <strong>480x320</strong> 到 <strong>1280x800</strong> 分辨率，再到全高清 <strong>1080p</strong>，从手机到平板，还有苹果设备的 <strong>Retina</strong> 屏，这么多不同的分辨率，而且大小差距甚大，不可能做到一套资源走天下，资源往小了设计，在大屏幕会显示模糊，图片往大了设计，在小屏幕设备又太浪费，而且小屏幕的手机硬件资源也会相对的紧缺，所以 <strong>根据屏幕大小使用不同的资源</strong> 是有必要的，而 cocos2d-x 也帮我们解决了这一点。</li>
<li><strong>宽高比：</strong> 什么是宽高比，就是你的屏幕是方的还是长的，靠近方形的分辨率如 480x320，比例为 <strong>3:2</strong>，还有 960x540 的 <strong>16:9</strong> 标准宽屏，这也算是两种总极端情况了，如果能在这两种比例情况做好适配基本就可以了，如果比 3:2 “更方”如 4:3，比 16:9 “更长”，那么不论如何布局，显示效果差距甚大，最好对固定比例优化吧。当在宽高比在一定范围内，可以通过灵活编写程序去适应，而在显示效果上，cocos2d-x 为我们提供了三种模式，这些 <strong>模式更多的是帮我们解决比例不一的情况而存在</strong> 的，如果只是屏幕大小（比例一样），那通过简单的放大缩小即可完成。</li>
</ul>


<!-- more -->


<h2>三种模式</h2>

<p>说是三种模式，其实还有一种 <strong>无模式</strong>，也就是 cocos2d-x 默认的适配方案，现在我们就来认识一下这些模式，并且通过这些模式去认识其中一些概念 <strong>FrameSize</strong>、<strong>WinSize</strong>、<strong>VisibleSize</strong>、<strong>VisibleOrigin</strong>，以及它们存在的意义，并且最后灵活运行这些概念 <strong>创建出一个不属于这些模式而超越这些模式的新适配解决方案</strong>，这是最终目的。</p>

<h3>kResolutionUnKnown 认识 FrameSize</h3>

<p>这是 cocos2d-x 编写的默认模式，没有做任何处理，在这种情况下，游戏画面的大小与比例都是不可控的，在程序运行之初，由各个平台入口函数定义画面大小：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// proj.linux/main.cpp  linux 平台手动指定画面大小</span>
</span><span class='line'><span class="n">CCEGLView</span><span class="o">*</span> <span class="n">eglView</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">();</span>
</span><span class='line'><span class="n">eglView</span><span class="o">-&gt;</span><span class="n">setFrameSize</span><span class="p">(</span><span class="mi">720</span><span class="p">,</span> <span class="mi">480</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// proj.android/jni/hellocpp/main.cpp android 平台由 jni 调用传入设备分辨率参数</span>
</span><span class='line'><span class="kt">void</span> <span class="n">Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit</span><span class="p">(</span><span class="n">JNIEnv</span><span class="o">*</span>  <span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thiz</span><span class="p">,</span> <span class="n">jint</span> <span class="n">w</span><span class="p">,</span> <span class="n">jint</span> <span class="n">h</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getOpenGLView</span><span class="p">())</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">CCEGLView</span> <span class="o">*</span><span class="n">view</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">();</span>
</span><span class='line'>        <span class="n">view</span><span class="o">-&gt;</span><span class="n">setFrameSize</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">AppDelegate</span> <span class="o">*</span><span class="n">pAppDelegate</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AppDelegate</span><span class="p">();</span>
</span><span class='line'>        <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="c1">// other</span>
</span><span class='line'>      <span class="p">...</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>在此我们首先认识了 <strong>FrameSize</strong> 参数，在游戏运行时，我们可以通过 <code>CCEGLView::sharedOpenGLView()-&gt;getFrameSize();</code> 获得此值。如果在手机上运行，那么不同分辨率将会得到不同的值，既然这个值不可控，那么在写游戏中也就没有参考价值了，比如我们写一个精灵的位置距离底部 320 高度，在 480x320 分辨率，能看到其在屏幕上方，如果换一台手机分辨率 960x540 那么只能显示在中间靠上的位置，如果设置精灵位置为距离屏幕上方（高度）320，反之依然，显示效果不一。</p>

<p>此时可行的方案是使用百分比，如精灵位置在屏幕横向距离左边 1/3 宽度，在 &frac12; 正中间处，而类似这样的设置也不用依赖 FrameSize 的具体数值。而这样的做法，使得内部元素像弹簧一样，随着 FrameSize 的大小改变而改变，伸缩或者挤压，对于图片资源大小也是完全不可控，如果根据屏幕大小放大缩小，那我们可以考虑用下面要说的模式，在此不推荐使用  cocos2d-x 的无模式方案。</p>

<h3>kResolutionExactFit and kResolutionShowAll 认识 WinSize</h3>

<p>在 AppDelegate.cpp 处可以通过设置：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setDesignResolutionSize</span><span class="p">(</span><span class="mi">720</span><span class="p">,</span> <span class="mi">480</span><span class="p">,</span> <span class="n">kResolutionShowAll</span><span class="p">);</span>
</span><span class='line'><span class="c1">// 或者</span>
</span><span class='line'><span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setDesignResolutionSize</span><span class="p">(</span><span class="mi">720</span><span class="p">,</span> <span class="mi">480</span><span class="p">,</span> <span class="n">kResolutionExactFit</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>DesignResolutionSize！顾名思义，也就是逻辑上的游戏屏幕大小，在这里我们设置了其分辨率为 720x480 为例，那么在游戏中，我么设置精灵的位置便可以参照此值，如 左下角 ccp(0,0)，右上角 ccp(720, 480)，而不论 FrameSize 的大小为多少，是 720x480 也好，是 480x320 也罢，总能正确显示其位置，左下角和右上角。能够实现这一点的原因是，固定了设计分辨率大小，从而确定了其固定的宽高比，它的 <strong>优势</strong> 是可以使用具体的数值摆放精灵位置，<strong>不会因为实际屏幕大小宽高比而是内部元素相对位置关系出现混乱</strong>。</p>

<p>而为了保持画面的宽高比，cocos2d-x 做了些牺牲，牺牲了什么呢？kResolutionExactFit 牺牲了画质而保持了全屏显示，对画面进行了拉伸，这意味着什么？意味着相对极端情况下，本来精灵是方形的，显示出来变成长方形，本来圆形的变成了椭圆，固此模式不推荐使用。kResolutionShowAll 为了保持设计画面比例对四周进行留黑边处理，使得不同比例下画面不能全屏。鱼和熊掌不能兼得也 ~</p>

<p>我们可以通过如下方法获取到 <strong>setDesignResolutionSize</strong> 所设置的值：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCSize</span> <span class="n">winSize</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>我们可以用 <a href="http://blog.leafsoar.com/archives/2013/05-05.html">Cocos2d-x 程序是如何开始运行与结束的</a> 一文的方法，跟踪 WinSize 的初始化，获取过程，在这里简单提一下，如下步骤：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 获得 winSize</span>
</span><span class='line'><span class="n">CCSize</span> <span class="n">winSize</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 查看其 getWinSize(); 方法实现</span>
</span><span class='line'><span class="p">[</span><span class="n">cocos2dx</span><span class="o">-</span><span class="n">path</span><span class="p">]</span><span class="o">/</span><span class="n">cocos2dx</span><span class="o">/</span><span class="n">CCDirector</span><span class="p">.</span><span class="n">cpp</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCSize</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">getWinSize</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">m_obWinSizeInPoints</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 而 m_obWinSizeInPoints 是何时被赋值的</span>
</span><span class='line'><span class="p">[</span><span class="n">cocos2dx</span><span class="o">-</span><span class="n">path</span><span class="p">]</span><span class="o">/</span><span class="n">cocos2dx</span><span class="o">/</span><span class="n">platform</span><span class="o">/</span><span class="n">CCEGLViewProtocol</span><span class="p">.</span><span class="n">cpp</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">CCEGLViewProtocol</span><span class="o">::</span><span class="n">setDesignResolutionSize</span><span class="p">(</span><span class="kt">float</span> <span class="n">width</span><span class="p">,</span> <span class="kt">float</span> <span class="n">height</span><span class="p">,</span> <span class="n">ResolutionPolicy</span> <span class="n">resolutionPolicy</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>    <span class="n">m_obDesignResolutionSize</span><span class="p">.</span><span class="n">setSize</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>    <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">m_obWinSizeInPoints</span> <span class="o">=</span> <span class="n">getDesignResolutionSize</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">const</span> <span class="n">CCSize</span><span class="o">&amp;</span> <span class="n">CCEGLViewProtocol</span><span class="o">::</span><span class="n">getDesignResolutionSize</span><span class="p">()</span> <span class="k">const</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">m_obDesignResolutionSize</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>具体的优势：通过设置逻辑分辨率大小，相比无模式，可以帮我们解决了屏幕自动放大缩小问题，并且保持屏幕宽高比，使得游戏更好设计，可以将设计画面大小作为默认背景图片大小等，唯一点遗憾就是那点前面所提到的一点点牺牲。</p>

<p>kResolutionShowAll 方案可以作为我们的默认解决方案，使得游戏的设计更为简化，但为了补填拉伸或留黑边这点缺憾，进入下一个模式！</p>

<h3>kResolutionNoBorder 了解 VisibleSize 与 VisibleOrigin</h3>

<p>此模式可以解决两个问题，其一：游戏画面全屏；其二：保持设置游戏时的宽高比例，相比 kResolutionShowAll 有所区别的是，<strong>为了填补留下的黑边，将画面稍微放大，以至于能够正好补齐黑边</strong>，而这样做的后果可想而知，补齐黑边的同时，另一个方向上将会有一部分画面露出屏幕之外，如下示意图：</p>

<p><img src="http://blog.leafsoar.com/images/2013/screen-resolution-1.jpg" alt="图片" /></p>

<p>黑色边框标示实际的屏幕分辨率，紫色区域标示游戏设计大小，而通过放大缩小，保持宽高比固定，
可以看到 <strong>Show All</strong> 之中的黑色阴影部分为留边，而 <strong>No Border</strong> 的紫色阴影部分则不能显示，而这紫色区域的大小是游戏设计之时是不可控的。那么原设计的画面大小就失去了 <strong>一定的</strong> 参考价值了，因为这可能让你的画面显示残缺。这时仅仅通过 WinSize 满足不了我们的设计需求，所以引入了 <strong>VisibleSize</strong> 与 <strong>VisibleOrigin</strong> 概念。</p>

<p><img src="http://blog.leafsoar.com/images/2013/screen-resolution-2.png" alt="图片" /></p>

<p>如上所示，紫色区域是被屏幕截去的部分，不可显示的，根据实际情况，可能出现横向截取和竖向截取，这取决于实际分辨率的宽高比。而 A、B、C、D所标示的是设计分辨率，固定大小。如果我们想让一个精灵元素显示在屏幕上方靠边，那么如果使用 WinSize 的高度设置其位置，可能出现的情况就是显示到屏幕之外了。FrameSize 和 WinSize 我们已经知道其概念，而 VisibleSize 和 VisibleOrigin 所代表的是什么呢，又时如何为我们解决靠边的问题！注意上图下方的定义， <strong>VisibleSize = H I J K 是用紫色标注的。</strong> 而在上图是 <strong>黑色</strong> 标注，标示屏幕实际分辨率，虽然 FrameSize 和 VisibleSize 都是 H I J K，但其意义不同，紫色表明它是与设计分辨率相关的。</p>

<p>FrameSize 是实际的屏幕分辨率，而 <strong>VisibleSize 是在 WinSize 之内，保持 FrameSize 的宽高比所能占用的最大区域</strong>，实际屏幕分辨率 H I J K (黑色) 可以大于 WinSize ，但VisibleSize 一定会小于或者等于 WinSize，这两者相同的是宽高比。VisibleSize 有着 WinSize 大小（随WinSize  的大小改变而改变），还有着 FrameSize 的宽高比，它标示 <strong>在设计分辨率（WinSize）下，在屏幕中的可见区域大小。</strong> 而 VisibleOrigin 则标示在设计分辨率下被截取的区域大小，用点 K 标示，有了这些数据，我们想让游戏元素始终在屏幕显示的区域之内不成难事。下面通过几个数值带入，加深这些概念的印象。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 组[1] :</span>
</span><span class='line'><span class="nl">FrameSize:</span>            <span class="n">width</span> <span class="o">=</span> <span class="mi">720</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">420</span>
</span><span class='line'><span class="nl">WinSize:</span>          <span class="n">width</span> <span class="o">=</span> <span class="mi">720</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">480</span>
</span><span class='line'><span class="nl">VisibleSize:</span>      <span class="n">width</span> <span class="o">=</span> <span class="mi">720</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">420</span>
</span><span class='line'><span class="nl">VisibleOrigin:</span>        <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">30</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 组[2] :相比 组 [1] FrameSize 不变 VisibleSize 和 VisibleOrigin 随着 WinSize 的变小而变小</span>
</span><span class='line'><span class="nl">FrameSize:</span>            <span class="n">width</span> <span class="o">=</span> <span class="mi">720</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">420</span>
</span><span class='line'><span class="nl">WinSize:</span>          <span class="n">width</span> <span class="o">=</span> <span class="mi">480</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">320</span>
</span><span class='line'><span class="nl">VisibleSize:</span>      <span class="n">width</span> <span class="o">=</span> <span class="mi">480</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">280</span>
</span><span class='line'><span class="nl">VisibleOrigin:</span>        <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">20</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 组[3] : 相比组 [1] WinSize 不变，VisibleSize 随着 FrameSize 的比例改变而改变</span>
</span><span class='line'><span class="nl">FrameSize:</span>            <span class="n">width</span> <span class="o">=</span> <span class="mi">720</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">540</span>
</span><span class='line'><span class="nl">WinSize:</span>          <span class="n">width</span> <span class="o">=</span> <span class="mi">720</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">480</span>
</span><span class='line'><span class="nl">VisibleSize:</span>      <span class="n">width</span> <span class="o">=</span> <span class="mi">640</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">480</span>
</span><span class='line'><span class="nl">VisibleOrigin:</span>        <span class="n">x</span> <span class="o">=</span> <span class="mi">40</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// WinSize VisibleSize VisibleOrigin 与都设计的分辨率相关，满足如下关系</span>
</span><span class='line'><span class="n">WinSize</span><span class="p">.</span><span class="n">width</span> <span class="o">=</span> <span class="p">(</span><span class="n">VisibleOrigin</span><span class="p">.</span><span class="n">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="n">VisibleSize</span><span class="p">.</span><span class="n">width</span>
</span><span class='line'><span class="n">WinSize</span><span class="p">.</span><span class="n">height</span> <span class="o">=</span> <span class="p">(</span><span class="n">VisibleOrigin</span><span class="p">.</span><span class="n">y</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="n">VisibleSize</span><span class="p">.</span><span class="n">height</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>NoBorder 具体的使用方法可以参考 cocos2d-x 自带例程 <strong>TestCpp</strong> ，有详细的使用方法，并且封装了 <strong>VisibleRect</strong> 类，可以获取设计分辨率，不同比例屏幕之时的主要参考点，屏幕四个拐角，和边的中点等，让我们设置元素位置时，使其总能显示在屏幕之内，这里就不详细介绍了。</p>

<p>基于这几种模式的程序使用方法，cocos2d-x  自带例程或者网上有很多教程，这里只详细解释了其中各种概念，而知道了这些概念，当然用起来就没有多大问题了。</p>

<h2><strong>kResolutionLeafsoar</strong></h2>

<p>！！！这是什么模式！好吧，Leafsoar 是 一叶 的 ID ，或者是本博客的一级域名而已 :P  在 cocos2d-x 中并没有这种模式。除却 <strong>UnKnown</strong> 与 <strong>ExactFit</strong> 不说，ShowAll 的优势是，只需要一个设计分辨率，然后通过 WinSize 设置相对对位即可，而且位置的最大长宽都是确定，方便了开发，但屏幕不能填满， NoBorder 模式的优势是在画面不变形的情况下，实现全屏，显示效果更好，但 WinSize 一定程度失效，需要通过运行时计算 VisibleSize 和 VisibleOrigin 来设置位置，由于是运行时计算，所以也就会出现，各种屏幕显示效果不一样的情况。</p>

<p>ShowAll 和 NoBorder 各有所长，各有所短，而这里提出的新适配解决方案正是取两者之长，舍两者之短的 <strong>组合模式</strong>。简单说来就是用 NoBorder 去实现 ShowAll 的思想。NoBorder 可以保证全屏利用，ShowAll 可以更好的使用实际设计坐标固定位置，而且相对位置不会随宽高比的改变而改变，这在编写游戏的时候能方便不少。先上一个示意图，一目了然 （两个图，两个方向）：</p>

<p><img src="http://blog.leafsoar.com/images/2013/screen-resolution-3.png" alt="图片" /></p>

<p>在原来 NoBorder 模式示意图上添加了新的概念，<strong>LsSize = X Y M N</strong> (leafsoar 简写了，为了不跟 cocos2d-x 的一些概念混淆，什么名字不重要，只要了解其含义即可)，在 NoBorder 模式下的 LsSize 相对于 FrameSize 而言，正如 在 <strong>ShowAll</strong> 模式下的 WinSize 相对于 FrameSize，所以说这是 ShowAll NoBorder 的组合概念，<strong>而这里的 LsSize 与 WinSize 的宽高比是一致的。</strong></p>

<p>猛地一看，似乎把问题复杂化了，仔细一看，还不如猛地一看 ~~</p>

<p>在 ShowAll 中，WinSize 作为最高的宽高，以此参照设置位置，因为在此范围内都能在屏幕上显示，用了 NoBorder 使得四周可能被截去一块区域，而这个区域大小不可控制，所以不能再使用 WinSize 作为参考点来设置位置，而这里的 LsSize 同样，因为 LsSzie 不论在什么情况下，总能显示在屏幕之内，我们可以方便的使用 LsSize  作为坐标系参考，并且可以全屏显示，在配合 VisibleSize ，相比纯的 NoBorder 加强了不少。它可以怎么用？</p>

<p>可以把 LsSize 当作 ShowAll 中的 WinSize 来用，而黑边可以使用稍大的图片填充，或者使用其它<strong>图片修饰边框</strong>，修饰的边框图案可大可小，可长可短，填充屏幕，保持全屏。</p>

<h2>开始基于 LsSize 的游戏设计实现</h2>

<p>为了能够准确实现基于 LsSize 的设计，初步计划将 LsSize 设定在 480x320 的分辨率方案，为此做了些准备，首先不使用任何模式情况下，在场景内调用如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCSize</span> <span class="n">size</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCPoint</span> <span class="n">center</span> <span class="o">=</span> <span class="n">ccp</span><span class="p">(</span><span class="n">size</span><span class="p">.</span><span class="n">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">size</span><span class="p">.</span><span class="n">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 大小 600x500 为了 NoBorder 看到效果，使用稍大的背景图</span>
</span><span class='line'><span class="n">CCSprite</span><span class="o">*</span> <span class="n">pb</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Back.jpg&quot;</span><span class="p">);</span>
</span><span class='line'><span class="n">pb</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">center</span><span class="p">);</span>
</span><span class='line'><span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">pb</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 480x320 此图为使用于设计分辨率 LsSize 的图片</span>
</span><span class='line'><span class="n">CCSprite</span><span class="o">*</span> <span class="n">pSprite</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;HelloWorld.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="n">pSprite</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">center</span><span class="p">);</span>
</span><span class='line'><span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">pSprite</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 37x37 在 480x320 画面的四个拐角处，添加参照</span>
</span><span class='line'><span class="n">CCSprite</span><span class="o">*</span> <span class="n">p1</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Peas.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="n">p1</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccpAdd</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">ccp</span><span class="p">(</span><span class="o">-</span><span class="mi">240</span><span class="p">,</span> <span class="o">-</span><span class="mi">160</span><span class="p">)));</span>
</span><span class='line'><span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">p1</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCSprite</span><span class="o">*</span> <span class="n">p2</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Peas.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="n">p2</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccpAdd</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">ccp</span><span class="p">(</span><span class="mi">240</span><span class="p">,</span> <span class="mi">160</span><span class="p">)));</span>
</span><span class='line'><span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">p2</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCSprite</span><span class="o">*</span> <span class="n">p3</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Peas.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="n">p3</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccpAdd</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">ccp</span><span class="p">(</span><span class="o">-</span><span class="mi">240</span><span class="p">,</span> <span class="mi">160</span><span class="p">)));</span>
</span><span class='line'><span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">p3</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCSprite</span><span class="o">*</span> <span class="n">p4</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Peas.png&quot;</span><span class="p">);</span>
</span><span class='line'><span class="n">p4</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">ccpAdd</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">ccp</span><span class="p">(</span><span class="mi">240</span><span class="p">,</span> <span class="o">-</span><span class="mi">160</span><span class="p">)));</span>
</span><span class='line'><span class="k">this</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">p4</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>显示效果：(FrameSize = 640x540)
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-4.jpg" alt="图片" /></p>

<p>显示效果：(ShowAll; FrameSize = 520x320; WinSize = 480x320)
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-5.jpg" alt="图片" /></p>

<p>显示效果：(NoBorder; FrameSize = 520x320; WinSize = 480x320)
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-6.jpg" alt="图片" /></p>

<p>通过效果我们可以看到，在相同 FrameSize 下 NoBorder 时，画面由于填充了黑边，将画面放大，以至于上下有部分显示不全，通过拐角四个精灵可以看出。</p>

<p>好！既然我们知道是由于放大所致，那么我们将画面缩小呢？cocos2d-x 提供了一个方法，我们调用如下代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCDirector</span> <span class="o">*</span><span class="n">pDirector</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">();</span>
</span><span class='line'><span class="n">pDirector</span><span class="o">-&gt;</span><span class="n">setContentScaleFactor</span><span class="p">(</span>
</span><span class='line'>              <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getScaleY</span><span class="p">()</span> <span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>为了弥补画面因需要不填空白出现的方法，我们将画面缩小，放大系数可以通过 <strong>CCEGLView::sharedOpenGLView()&ndash;>getScaleY() </strong> 取得。其实 setContentScaleFactor 方法是为了适配不同资源而设计的，可以用此方法对不同资源适配，缩放等。效果如下：</p>

<p><img src="http://blog.leafsoar.com/images/2013/screen-resolution-7.jpg" alt="图片" /></p>

<p>我们看到 480x320 的图片显示完全正确了，也正是我们想要的效果，但唯一的缺点是 ~~ 拐角处四个精灵的位置依然不是我们想要的，我们设计的位置是以 480x320 设置位置的，而 WinSize 也是 480x320 ，而此时基于 480x320 的设计必然会显示到屏幕之外，而要想不修改精灵位置，而让其显示正确的位置，那么为了保证 LsSize 的固定，我们需要一个方法，那就是 <strong>动态设置 WinSize</strong>。</p>

<p>什么意思？我们知道一般这些模式设计游戏时，是通过 <strong>setDesignResolutionSize</strong> 设置 WinSize 的，这个值在游戏运行其间是定植，动态改变的是 VisibleSize 等，而这里提出了 LsSize 的概念，可想而知，如果 WinSize 固定，那么 LsSize 会随着屏幕宽高比的改变而改变，那么我们反其道而行，固定 <strong>LsSize</strong> 值，那么在运行时可以通过实际的宽高比来算得 WinSize 的值，这样动态算得的 WinSize 值就能够保证我们的 LsSize 是一个定值了。</p>

<p><strong>相对论</strong>，WinSize 与 LsSize 的值是相对的，与其通过固定 WinSize 在运行时动态获得 LsSize （这也是 NoBorder 的默认方式，而导致的结果是 WinSize 没有参考价值），不如我们固定 LsSize 而在运行时算得 WinSize 设置来的要更妙一些。</p>

<p>现在不使用 <strong>setContentScaleFactor</strong> 方法，而修改 <strong>setDesignResolutionSize</strong> 这里的值，我们知道 WinSize 是 480x320 时，LsSize 必然会小于此值，而 NoBorder 的放大系数我们可以通过如下方式算得（可以参考setDesignResolutionSize方法内部实现），并在 AppDelegate 里执行：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCSize</span> <span class="n">frameSize</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getFrameSize</span><span class="p">();</span>
</span><span class='line'><span class="c1">// 设置 LsSize 固定值</span>
</span><span class='line'><span class="n">CCSize</span> <span class="n">lsSize</span> <span class="o">=</span> <span class="n">CCSizeMake</span><span class="p">(</span><span class="mi">480</span><span class="p">,</span> <span class="mi">320</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="kt">float</span> <span class="n">scaleX</span> <span class="o">=</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">frameSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">width</span><span class="p">;</span>
</span><span class='line'><span class="kt">float</span> <span class="n">scaleY</span> <span class="o">=</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">frameSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 定义 scale 变量</span>
</span><span class='line'><span class="kt">float</span> <span class="n">scale</span> <span class="o">=</span> <span class="mf">0.0f</span><span class="p">;</span> <span class="c1">// MAX(scaleX, scaleY);</span>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="n">scaleX</span> <span class="o">&gt;</span> <span class="n">scaleY</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 如果是 X 方向偏大，那么 scaleX 需要除以一个放大系数，放大系数可以由枞方向获取，</span>
</span><span class='line'>  <span class="c1">// 因为此时 FrameSize 和 LsSize 的上下边是重叠的</span>
</span><span class='line'>  <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleX</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">height</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">scale</span> <span class="o">=</span> <span class="n">scaleY</span> <span class="o">/</span> <span class="p">(</span><span class="n">frameSize</span><span class="p">.</span><span class="n">width</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">lsSize</span><span class="p">.</span><span class="n">width</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;x: %f; y: %f; scale: %f&quot;</span><span class="p">,</span> <span class="n">scaleX</span><span class="p">,</span> <span class="n">scaleY</span><span class="p">,</span> <span class="n">scale</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 根据 LsSize 和屏幕宽高比动态设定 WinSize</span>
</span><span class='line'><span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setDesignResolutionSize</span><span class="p">(</span><span class="n">lsSize</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">scale</span><span class="p">,</span>
</span><span class='line'>      <span class="n">lsSize</span><span class="p">.</span><span class="n">height</span> <span class="o">*</span> <span class="n">scale</span><span class="p">,</span> <span class="n">kResolutionNoBorder</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>显示效果：（NoBorder 模式 ;FrameSize = 520x320; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-8.jpg" alt="图片" /></p>

<p>我们看到在没有修改源代码，并且在设计中使用 480x320 的参考系，也既是基于  LsSize 的设计显示效果如我们预期，那么我们换一个 FrameSize 来看看是否能够自动适应呢？如下：</p>

<p>显示效果：（NoBorder 模式 ;FrameSize = 600x480; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-9.jpg" alt="图片" /></p>

<p>到此，基于 LsSize 参考系的游戏设计已经完成了，这样做的好处是很明显的，集 ShowAll 和 NoBorder 的优点于一处，这里的图片元素是为了好定位，实现的需要而写的，具体场景可以使用背景地图，或一张大的图片显示，而没有任何影响，也可以继续使用 VisibleSize 得到 LsSize 之外的部分区域大小，在 LsSize 之外可以使用背景图片作为装饰，即保证了游戏的全屏，又保证了游戏设计时的方便，如果使用完全基于 LsSize  的设计实现，除了显示背景装饰之外，我们不想让 LsSize 的内部元素显示到 LsSize 之外如何做呢？我们只需要设定 LsSize 层的的显示区域即可，我们可以修改场景的实现：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 这里先简单实现思路</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCScene</span><span class="o">*</span> <span class="n">HelloWorld</span><span class="o">::</span><span class="n">scene</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CCScene</span> <span class="o">*</span><span class="n">scene</span> <span class="o">=</span> <span class="n">CCScene</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 创建背景层</span>
</span><span class='line'>  <span class="n">CCLayer</span><span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="n">CCLayer</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">scene</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 添加背景图片和设置位置，可以使用其它装饰，或者小图片屏幕都行</span>
</span><span class='line'>  <span class="n">CCSize</span> <span class="n">size</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getWinSize</span><span class="p">();</span>
</span><span class='line'>  <span class="n">CCPoint</span> <span class="n">center</span> <span class="o">=</span> <span class="n">ccp</span><span class="p">(</span><span class="n">size</span><span class="p">.</span><span class="n">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">size</span><span class="p">.</span><span class="n">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
</span><span class='line'>  <span class="n">CCSprite</span><span class="o">*</span> <span class="n">pb</span> <span class="o">=</span> <span class="n">CCSprite</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">&quot;Back.jpg&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">pb</span><span class="o">-&gt;</span><span class="n">setPosition</span><span class="p">(</span><span class="n">center</span><span class="p">);</span>
</span><span class='line'>  <span class="n">b</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">pb</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 创建 LsLayer 层</span>
</span><span class='line'>  <span class="n">HelloWorld</span> <span class="o">*</span><span class="n">lsLayer</span> <span class="o">=</span> <span class="n">HelloWorld</span><span class="o">::</span><span class="n">create</span><span class="p">();</span>
</span><span class='line'>  <span class="n">scene</span><span class="o">-&gt;</span><span class="n">addChild</span><span class="p">(</span><span class="n">lsLayer</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">return</span> <span class="n">scene</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 在 HelloWorld 中重写 visit() 函数 设定显示区域</span>
</span><span class='line'><span class="kt">void</span> <span class="n">HelloWorld</span><span class="o">::</span><span class="n">visit</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">glEnable</span><span class="p">(</span><span class="n">GL_SCISSOR_TEST</span><span class="p">);</span>              <span class="c1">// 开启显示指定区域</span>
</span><span class='line'>  <span class="c1">// 在这里只写上固定值，在特性环境下，以便快速看效果，实际的值，需要根据实际情况算得</span>
</span><span class='line'>  <span class="n">glScissor</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">480</span><span class="p">,</span> <span class="mi">320</span><span class="p">);</span>     <span class="c1">// 只显示当前窗口的区域</span>
</span><span class='line'>  <span class="n">CCLayer</span><span class="o">::</span><span class="n">visit</span><span class="p">();</span>                       <span class="c1">// 调用下面的方法</span>
</span><span class='line'>  <span class="n">glDisable</span><span class="p">(</span><span class="n">GL_SCISSOR_TEST</span><span class="p">);</span>             <span class="c1">// 禁用</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>显示效果：（NoBorder 模式 ;FrameSize = 520x320; LsSize = 480x320; WinSize = 动态获取）
<img src="http://blog.leafsoar.com/images/2013/screen-resolution-10.jpg" alt="图片" /></p>

<h2>屏幕适配新解</h2>

<p>看完这篇文章想必对 cocos2d-x 的屏幕适配方案及其原理有了相当的认识，从内部提供的三种模式，再到我们自定义基于 LsSize 的 <strong>Leafsoar 模式</strong> (好把，因该叫做 ShowAllNoBorder)。这里已经给出了完全的实现原理以及实现方法，并配有效果图，当然这其中还有些细节需要注意，比如我们基于 LsSize 的大小设计，那么实际的图片肯定需要比 LsSize 的要大，大多少，太小了不够适应，太大了又浪费，如何取舍等问题，这一点取决的因素是什么，留给读者思考 ~~</p>

<p>一叶将在 GitHub 处建立一个<a href="https://github.com/leafsoar/ls-cocos2d-x/tree/master/ScreenSolutions">ScreenSolutions</a> 项目，读者可以从这里参考实现的方案。(也许<strong>此时</strong>在 GitHub 所看到的实现并不完全，但已经有了简单的实现方法，并且能够运行，如有必要，将会新写一篇博客，去实现 ScreenSolutions 并且解说)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[实现 Cocos2d-x 全局定时器]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-08.html"/>
    <updated>2013-05-08T21:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-global-schedule</id>
    <content type="html"><![CDATA[<p>cocos2d-x 中有自己的定时器实现，一般用法是在场景，层等内部实现，定时器的生命周期随着它们的消亡而消亡，就运行周期而言，相对最长的是场景，如果在多个场景切换并且保持定时器的运行，那我们就需要定义一个自己的  <strong>全局定时器</strong>。</p>

<p>平时所使用的定时器，我们可以直接使用，是因为 <strong>CCNode</strong> 帮我们实现了定时器的封装，一个简单的做法，是定义个全局的静态 CCNode 对象，在程序运行之初初始化，并执行其定时器任务，而不由任何场景所管理即可实现，但在这里，一叶对定时器的内部实现稍作了解后，封装了自己实现的全局定时解决方案，代码如下(<a href="https://github.com/leafsoar/ls-cocos2d-x/tree/master/Learn/Classes/GlobalSchedule">获取源码</a> )：</p>

<!-- more -->




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">////////////////////</span>
</span><span class='line'><span class="c1">// GlobalSchedule.h</span>
</span><span class='line'><span class="c1">//////////////////// </span>
</span><span class='line'>
</span><span class='line'><span class="cp">#ifndef GLOBALSCHEDULE_H_</span>
</span><span class='line'><span class="cp">#define GLOBALSCHEDULE_H_</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &quot;cocos2d.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="n">USING_NS_CC</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> *   全局定时器</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">GlobalSchedule</span><span class="o">:</span> <span class="k">public</span> <span class="n">CCObject</span> <span class="p">{</span>
</span><span class='line'><span class="k">public</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">// 开始全局定时器 fInterval: 时间间隔 ; fDelay: 延迟运行</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">start</span><span class="p">(</span><span class="kt">float</span> <span class="n">fInterval</span> <span class="o">=</span> <span class="mf">0.0f</span><span class="p">,</span> <span class="kt">float</span> <span class="n">fDelay</span> <span class="o">=</span> <span class="mf">0.0f</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// 停止全局定时器</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">stop</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 全局定时器暂停</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">pause</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// 全局定时器暂停恢复</span>
</span><span class='line'>  <span class="k">static</span> <span class="kt">void</span> <span class="n">resume</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 全局定时器主逻辑实现</span>
</span><span class='line'>  <span class="kt">void</span> <span class="n">globalUpdate</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'><span class="k">private</span><span class="o">:</span>
</span><span class='line'>  <span class="c1">// 构造函数私有化，只能通过 start 来启用全局定时器</span>
</span><span class='line'>  <span class="n">GlobalSchedule</span><span class="p">(</span><span class="kt">float</span> <span class="n">fInterval</span><span class="p">,</span> <span class="kt">float</span> <span class="n">fDelay</span><span class="p">);</span>
</span><span class='line'>  <span class="o">~</span><span class="n">GlobalSchedule</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 静态变量保持单例</span>
</span><span class='line'>  <span class="k">static</span> <span class="n">GlobalSchedule</span><span class="o">*</span> <span class="n">m_pSchedule</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#endif </span><span class="cm">/* GLOBALSCHEDULE_H_ */</span><span class="cp"></span>
</span><span class='line'>
</span><span class='line'><span class="c1">/////////////////////</span>
</span><span class='line'><span class="c1">// GlobalSchedule.cpp</span>
</span><span class='line'><span class="c1">/////////////////////    </span>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &quot;GlobalSchedule.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#define SCHEDULE CCDirector::sharedDirector()-&gt;getScheduler()</span>
</span><span class='line'>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">*</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">m_pSchedule</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">GlobalSchedule</span><span class="p">(</span><span class="kt">float</span> <span class="n">fInterval</span><span class="p">,</span> <span class="kt">float</span> <span class="n">fDelay</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;GlobalSchedule()&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CCAssert</span><span class="p">(</span><span class="o">!</span><span class="n">m_pSchedule</span><span class="p">,</span> <span class="s">&quot;已定义，不能重复定义&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">SCHEDULE</span><span class="o">-&gt;</span><span class="n">scheduleSelector</span><span class="p">(</span>
</span><span class='line'>          <span class="n">schedule_selector</span><span class="p">(</span><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">globalUpdate</span><span class="p">),</span> <span class="k">this</span><span class="p">,</span> <span class="n">fInterval</span><span class="p">,</span>
</span><span class='line'>          <span class="kc">false</span><span class="p">,</span>
</span><span class='line'>          <span class="n">kCCRepeatForever</span><span class="p">,</span> <span class="n">fDelay</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">m_pSchedule</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">::~</span><span class="n">GlobalSchedule</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;GlobalSchedule().~()&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">SCHEDULE</span><span class="o">-&gt;</span><span class="n">unscheduleSelector</span><span class="p">(</span>
</span><span class='line'>          <span class="n">schedule_selector</span><span class="p">(</span><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">globalUpdate</span><span class="p">),</span> <span class="k">this</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">globalUpdate</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 这里写全局定时器的逻辑处理代码</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;global update&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">start</span><span class="p">(</span><span class="kt">float</span> <span class="n">fInterval</span><span class="p">,</span> <span class="kt">float</span> <span class="n">fDelay</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">new</span> <span class="n">GlobalSchedule</span><span class="p">(</span><span class="n">fInterval</span><span class="p">,</span> <span class="n">fDelay</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">stop</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;GlobalSchedule().stop()&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CCAssert</span><span class="p">(</span><span class="n">m_pSchedule</span><span class="p">,</span> <span class="s">&quot;未定义&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">CC_SAFE_DELETE</span><span class="p">(</span><span class="n">m_pSchedule</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">pause</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;GlobalSchedule().pause()&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CCAssert</span><span class="p">(</span><span class="n">m_pSchedule</span><span class="p">,</span> <span class="s">&quot;未定义&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">SCHEDULE</span><span class="o">-&gt;</span><span class="n">pauseTarget</span><span class="p">(</span><span class="n">m_pSchedule</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">resume</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;GlobalSchedule().resume()&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">CCAssert</span><span class="p">(</span><span class="n">m_pSchedule</span><span class="p">,</span> <span class="s">&quot; 未定义&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">SCHEDULE</span><span class="o">-&gt;</span><span class="n">resumeTarget</span><span class="p">(</span><span class="n">m_pSchedule</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><font color="red" >注意事项：根据一朋友的使用反馈（多谢这位朋友:P），以上代码并不能在 2.1.x 版本如期运行，原因为 scheduleSelector（） 中的形参位置有变，请根据实际情况修改此构造函数内调用定时器 实参 的位置！</font> <strong>除非说明，本博客默认使用当前稳定版：2.0.4</strong></p>

<h3>使用方法</h3>

<p>这样的封装，在使用的时候只要填写 <strong>globalUpdate()</strong> 方法，处理具体的逻辑，然后在 <strong>AppDelegate</strong> 的 <strong>applicationDidFinishLaunching</strong> 调用如下代码:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// 启动定时器</span>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">start</span><span class="p">();</span>
</span><span class='line'><span class="c1">// 启动定时器，每 0.2 秒间隔执行</span>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">start</span><span class="p">(</span><span class="mf">0.2f</span><span class="p">);</span>
</span><span class='line'><span class="c1">// 每 0.5 秒间隔运行，延迟 3 秒启动</span>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">start</span><span class="p">(</span><span class="mf">0.5f</span><span class="p">,</span> <span class="mf">3.0f</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>注意，<strong>start()</strong> 不论调用哪个重载的方法， 只能调用一次。当然可以在调用 <strong>stop()</strong> 方法重新调用 <strong>start()</strong> 启动定时器，方法的重载实现了定时器的时间间隔和延迟运行，并实现了定时器的暂停和恢复功能。</p>

<h3>什么时候结束</h3>

<p>推荐的结束时机为在最后一个场景结束之时：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">end</span><span class="p">();</span>
</span><span class='line'><span class="n">GlobalSchedule</span><span class="o">::</span><span class="n">stop</span><span class="p">();</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>在前面的博文 <a href="http://blog.leafsoar.com/archives/2013/05-05.html">Cocos2d-x 程序是如何开始运行与结束的</a>，我们分析了 cocos2d-x 程序运行的始末，故推荐在此时调用停止定时器的方法。</p>

<p>有了全局定时器我们能做什么？这就要问你为何而实现全局定时器了 : P</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cocos2d-x 程序是如何开始运行与结束的]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/05-05.html"/>
    <updated>2013-05-05T23:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/cocos2dx-end</id>
    <content type="html"><![CDATA[<p><strong>题记：对于技术，我们大可不必挖得那么深，但一定要具备可以挖得很深的能力</strong></p>

<h2>问题的由来</h2>

<p>怎么样使用 Cocos2d-x 快速开发游戏，方法很简单，你可以看看其自带的例程，或者从网上搜索教程，运行起第一个 Scene <strong>HelloWorldScene</strong>，然后在 HelloWorldScene 里面写相关逻辑代码，添加我们的层、精灵等 ~ 我们并不一定需要知道 Cocos2d-x 是如何运行或者在各种平台之上运行，也不用知道 Cocos2d-x 的游戏是如何运行起来的，它又是如何渲染界面的 ~~~</p>

<p>我们只用知道 Cocos2d-x 的程序是由 <strong>AppDelegate</strong> 的方法 <strong>applicationDidFinishLaunching</strong> 开始，在其中做些必要的初始化，并创建运行<strong>第一个 CCScene</strong> 即可，正如我们第一次使用各种编程语言写 <strong>Hello World!</strong> 的程序一样，如 Python 打印：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">print</span><span class="p">(</span><span class="s">&#39;Hello World!&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<!-- more -->


<p>我们可以不用关心其是怎么实现的，我们只要知道这样就能打印一句话就够了，这就是 <strong>封装所带来的好处</strong> 。</p>

<p>Cocos2d-x 自带的例程已经足够丰富，但是有些问题并不是看看例子，调用其方法就能明白的事情，在这里一叶遇到了如下问题：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// AppDelegate.cpp 文件</span>
</span><span class='line'>
</span><span class='line'><span class="n">AppDelegate</span><span class="o">::</span><span class="n">AppDelegate</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;AppDelegate()&quot;</span><span class="p">);</span>       <span class="c1">// AppDelegate 构造函数打印</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">AppDelegate</span><span class="o">::~</span><span class="n">AppDelegate</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CCLog</span><span class="p">(</span><span class="s">&quot;AppDelegate().~()&quot;</span><span class="p">);</span>       <span class="c1">// AppDelegate 析构函数打印</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 程序入口</span>
</span><span class='line'><span class="kt">bool</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">applicationDidFinishLaunching</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// initialize director</span>
</span><span class='line'>  <span class="n">CCDirector</span> <span class="o">*</span><span class="n">pDirector</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">();</span>
</span><span class='line'>  <span class="n">pDirector</span><span class="o">-&gt;</span><span class="n">setOpenGLView</span><span class="p">(</span><span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 初始化，资源适配，屏幕适配，运行第一个场景等代码</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  
</span><span class='line'>  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">applicationDidEnterBackground</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">pause</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">AppDelegate</span><span class="o">::</span><span class="n">applicationWillEnterForeground</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">resume</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>此时我并不知道程序运行时，何时调用 AppDelegate 的构造函数，析构函数和程序入口函数，我们只要知道，程序在这里调用了其构造函数，然后进入入口函数执行其过程，最后再调用其析构函数即可。然而<strong>事与愿违</strong>，在实际执行的过程中，发现程序只调用其构造函数和入口函数，而直到程序结束运行，都 <strong>没有调用其析构函数</strong>。要验证此说法很简单，只要如上在析构函数中调用打印日志便可验证。</p>

<p>发生这样的情况，让我 <strong>在构造函数创建[资源]，并且在析构函数中释放[资源]</strong> 的想法不能完成！！！ 我们<strong>知道它是从哪里开始运行，但却不知道它在哪里结束！</strong>疑问，唯有疑问！</p>

<h2>两个入口</h2>

<p>程序入口的概念是<strong>相对的</strong>，<strong>AppDelegate</strong> 作为跨平台程序入口，在这之上做了另一层的封装，封装了不同平台的不同实现，比如我们通常认为一个程序是由 <strong>main</strong> 函数开始运行，那我们就去找寻，我们看到了在 <strong>proj.linux</strong> 目录下存在 <strong>main.cpp</strong> 文件，这就是我们要看的内容，如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="cp">#include &quot;main.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;../Classes/AppDelegate.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;cocos2d.h&quot;</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="cp">#include &lt;stdlib.h&gt;</span>
</span><span class='line'><span class="cp">#include &lt;stdio.h&gt;</span>
</span><span class='line'><span class="cp">#include &lt;unistd.h&gt;</span>
</span><span class='line'><span class="cp">#include &lt;string&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="n">USING_NS_CC</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 500 is enough?</span>
</span><span class='line'><span class="cp">#define MAXPATHLEN 500</span>
</span><span class='line'>
</span><span class='line'><span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="c1">// get application path</span>
</span><span class='line'>    <span class="kt">int</span> <span class="n">length</span><span class="p">;</span>
</span><span class='line'>    <span class="kt">char</span> <span class="n">fullpath</span><span class="p">[</span><span class="n">MAXPATHLEN</span><span class="p">];</span>
</span><span class='line'>    <span class="n">length</span> <span class="o">=</span> <span class="n">readlink</span><span class="p">(</span><span class="s">&quot;/proc/self/exe&quot;</span><span class="p">,</span> <span class="n">fullpath</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">fullpath</span><span class="p">));</span>
</span><span class='line'>    <span class="n">fullpath</span><span class="p">[</span><span class="n">length</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;\0&#39;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">resourcePath</span> <span class="o">=</span> <span class="n">fullpath</span><span class="p">;</span>
</span><span class='line'>    <span class="n">resourcePath</span> <span class="o">=</span> <span class="n">resourcePath</span><span class="p">.</span><span class="n">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">resourcePath</span><span class="p">.</span><span class="n">find_last_of</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">));</span>
</span><span class='line'>    <span class="n">resourcePath</span> <span class="o">+=</span> <span class="s">&quot;/../../../Resources/&quot;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// create the application instance</span>
</span><span class='line'>    <span class="n">AppDelegate</span> <span class="n">app</span><span class="p">;</span>
</span><span class='line'>    <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setResourceRootPath</span><span class="p">(</span><span class="n">resourcePath</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
</span><span class='line'>    <span class="n">CCEGLView</span><span class="o">*</span> <span class="n">eglView</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">();</span>
</span><span class='line'>    <span class="n">eglView</span><span class="o">-&gt;</span><span class="n">setFrameSize</span><span class="p">(</span><span class="mi">720</span><span class="p">,</span> <span class="mi">480</span><span class="p">);</span>
</span><span class='line'><span class="c1">//    eglView-&gt;setFrameSize(480, 320);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>在这里我们看见了程序的<strong>真正</strong>入口，包含一个 main 函数，从此进入，执行 cocos2d-x 程序。</p>

<p>我们看到 main 就知道其是入口函数，那么没有 main 函数就没有入口了吗？显然不是，以 Android 平台启动 cocos2d-x 程序为例。我们找到 Android 平台与上面 <strong>等价</strong> 的入口点，<code>proj.android/jni/hellocpp/main.cpp</code>：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="cp">#include &quot;cocos2d.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;AppDelegate.h&quot;</span>
</span><span class='line'><span class="cp">#include &quot;platform/android/jni/JniHelper.h&quot;</span>
</span><span class='line'><span class="cp">#include &lt;jni.h&gt;</span>
</span><span class='line'><span class="cp">#include &lt;android/log.h&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="cp">#define  LOG_TAG    &quot;main&quot;</span>
</span><span class='line'><span class="cp">#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)</span>
</span><span class='line'>
</span><span class='line'><span class="k">using</span> <span class="k">namespace</span> <span class="n">cocos2d</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">extern</span> <span class="s">&quot;C&quot;</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>
</span><span class='line'><span class="n">jint</span> <span class="n">JNI_OnLoad</span><span class="p">(</span><span class="n">JavaVM</span> <span class="o">*</span><span class="n">vm</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">reserved</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">JniHelper</span><span class="o">::</span><span class="n">setJavaVM</span><span class="p">(</span><span class="n">vm</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">JNI_VERSION_1_4</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit</span><span class="p">(</span><span class="n">JNIEnv</span><span class="o">*</span>  <span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thiz</span><span class="p">,</span> <span class="n">jint</span> <span class="n">w</span><span class="p">,</span> <span class="n">jint</span> <span class="n">h</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getOpenGLView</span><span class="p">())</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">CCEGLView</span> <span class="o">*</span><span class="n">view</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">();</span>
</span><span class='line'>        <span class="n">view</span><span class="o">-&gt;</span><span class="n">setFrameSize</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">AppDelegate</span> <span class="o">*</span><span class="n">pAppDelegate</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AppDelegate</span><span class="p">();</span>
</span><span class='line'>        <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">ccDrawInit</span><span class="p">();</span>
</span><span class='line'>        <span class="n">ccGLInvalidateStateCache</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">CCShaderCache</span><span class="o">::</span><span class="n">sharedShaderCache</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">reloadDefaultShaders</span><span class="p">();</span>
</span><span class='line'>        <span class="n">CCTextureCache</span><span class="o">::</span><span class="n">reloadAllTextures</span><span class="p">();</span>
</span><span class='line'>        <span class="n">CCNotificationCenter</span><span class="o">::</span><span class="n">sharedNotificationCenter</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">postNotification</span><span class="p">(</span><span class="n">EVNET_COME_TO_FOREGROUND</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>        <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">setGLDefaultValues</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>我们并没有看到所谓的 main 函数，这是由于不同的平台封装所以有着不同的实现，在 Android 平台，默认是使用 Java 开发，可以使用 Java 通过 Jni 调用 C++ 程序，而这里也正式如此。我们暂且只需知道，由 Android 启动一个应用，通过各种<strong>峰回路转</strong>，最终执行到了 <code>Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit</code> 函数，由此，变开始了我们 cocos2d-x Android 平台的程序入口处。对于跨平台的 cocos2d-x 来说，除非必要，否则可不必深究其理，比如想要使用 Android 平台固有的特性等，那就需要更多的了解 Jni 使用方法，以及 Android 操作系统的更多细节。</p>

<p>所以说程序的入口是相对的，正如博文开始的 <code>print('Hello World')</code> 一样，不同的语言，不同平台总有着不同的实现。</p>

<p>这里我们参考了两个不同平台的实现， Linux 和 Android 平台 cocos2d-x 程序入口 main.cpp的实现，那么其它平台呢，如 iOS ,Win32 等 <del>~~ 殊途同归，其它平台程序的入口必然包含着其它平台的不同 <strong>封装实现</strong> ，知道有<strong>等价</strong>在此两平台的程序入口即可。而通过这两个平台也足够解决我们的疑问，<strong>程序的开始与结束</strong> </del></p>

<h2>问题的推测</h2>

<p>我们就从 Linux 和 Android 这两个平台的入口函数开始，看看 cocos2d-x 的执行流程到底为何？何以发生只执行了 AppDelegate 的构造函数，而没有析构函数。在查看 cocos2d-x 程序代码时，我们只关注 <strong>必要的</strong> 内容，何谓 必要，只要能解决我们此时的疑问即可！在两个平台的入口函数，我们看到如下内容：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// Linux 平台关键代码</span>
</span><span class='line'><span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 初始化等内容</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="c1">// 创建 app 变量</span>
</span><span class='line'>    <span class="n">AppDelegate</span> <span class="n">app</span><span class="p">;</span> 
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>  <span class="c1">// 执行 核心 run() 方法</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// Android 平台关键代码</span>
</span><span class='line'><span class="kt">void</span> <span class="n">Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit</span><span class="p">(</span><span class="n">JNIEnv</span><span class="o">*</span>  <span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thiz</span><span class="p">,</span> <span class="n">jint</span> <span class="n">w</span><span class="p">,</span> <span class="n">jint</span> <span class="n">h</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">getOpenGLView</span><span class="p">())</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">CCEGLView</span> <span class="o">*</span><span class="n">view</span> <span class="o">=</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">();</span>
</span><span class='line'>        <span class="n">view</span><span class="o">-&gt;</span><span class="n">setFrameSize</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// 创建 AppDelegate 对象</span>
</span><span class='line'>        <span class="n">AppDelegate</span> <span class="o">*</span><span class="n">pAppDelegate</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AppDelegate</span><span class="p">();</span>
</span><span class='line'>      <span class="c1">// 执行 核心 run() 方法</span>
</span><span class='line'>        <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>      <span class="p">...</span>
</span><span class='line'>      <span class="p">...</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>不同的平台，却实现相同操作，创建 <strong>AppDelegate</strong> 变量和执行 <strong>run</strong> 方法。下面将以 Linux 平台为例，来说明程序是如何开始与结束的，因为 Linux 的内部实现要简单一点，而 Android 平台的实现稍显麻烦，Jni 之间来回调用，对我们理解 cocos2d-x 的执行流程反而有所 <strong>阻碍</strong>，况且 cocos2d-x 本身就是跨平台的程序。不必拘泥于特有平台的专有特性。</p>

<h2>程序的流程 （这里以 Linux 的实现为主，其它平台触类旁通即可）</h2>

<h3>AppDelegate 与 CCApplication</h3>

<p>我们从 <strong>main.cpp</strong> 中 <strong>CCApplication::sharedApplication()&ndash;>run();</strong> 这一句看起，这一句标志着， cocos2d-x 程序正式开始运行，一点点开始分析，我们定位到 <strong>sharedApplication()</strong> 方法的实现，这里只给出 <strong>必要</strong> 的代码，具体看一自己直接看源码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// [cocos2dx-path]/cocos2dx/platform/linux/CCApplication.cpp</span>
</span><span class='line'><span class="p">...</span>
</span><span class='line'><span class="c1">// 此变量为定义了一个 CCApplication 的静态变量，也及时自己类型本身，实现单例模式</span>
</span><span class='line'><span class="n">CCApplication</span> <span class="o">*</span> <span class="n">CCApplication</span><span class="o">::</span><span class="n">sm_pSharedApplication</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="p">...</span>
</span><span class='line'><span class="c1">// 构造函数，将所创建的 对象直接付给其静态变量</span>
</span><span class='line'><span class="n">CCApplication</span><span class="o">::</span><span class="n">CCApplication</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 断言在此决定着此构造函数只能运行一次</span>
</span><span class='line'>  <span class="n">CC_ASSERT</span><span class="p">(</span><span class="o">!</span> <span class="n">sm_pSharedApplication</span><span class="p">);</span>
</span><span class='line'>  <span class="n">sm_pSharedApplication</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCApplication</span><span class="o">::~</span><span class="n">CCApplication</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CC_ASSERT</span><span class="p">(</span><span class="k">this</span> <span class="o">==</span> <span class="n">sm_pSharedApplication</span><span class="p">);</span>
</span><span class='line'>  <span class="n">sm_pSharedApplication</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>  <span class="n">m_nAnimationInterval</span> <span class="o">=</span> <span class="mf">1.0f</span><span class="o">/</span><span class="mf">60.0f</span><span class="o">*</span><span class="mf">1000.0f</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// run 方法，整个 cocos2d-x 的主循环在这里开始</span>
</span><span class='line'><span class="kt">int</span> <span class="n">CCApplication</span><span class="o">::</span><span class="n">run</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 首次启动调用初始化函数</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">applicationDidFinishLaunching</span><span class="p">())</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// 游戏主循环，这里 Linux 的实现相比其它平台的实现，简单明了</span>
</span><span class='line'>  <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span><span class='line'>      <span class="kt">long</span> <span class="n">iLastTime</span> <span class="o">=</span> <span class="n">getCurrentMillSecond</span><span class="p">();</span>
</span><span class='line'>      <span class="c1">// 在循环之内调用每一帧的逻辑，组织并且控制 cocos2d-x 之中各个组件</span>
</span><span class='line'>      <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">mainLoop</span><span class="p">();</span>
</span><span class='line'>      <span class="kt">long</span> <span class="n">iCurTime</span> <span class="o">=</span> <span class="n">getCurrentMillSecond</span><span class="p">();</span>
</span><span class='line'>      <span class="c1">// 这里的几个时间变量，可以控制每一帧所运行的 最小 时间，从而控制游戏的帧率</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="n">iCurTime</span><span class="o">-</span><span class="n">iLastTime</span><span class="o">&lt;</span><span class="n">m_nAnimationInterval</span><span class="p">){</span>
</span><span class='line'>          <span class="n">usleep</span><span class="p">((</span><span class="n">m_nAnimationInterval</span> <span class="o">-</span> <span class="n">iCurTime</span><span class="o">+</span><span class="n">iLastTime</span><span class="p">)</span><span class="o">*</span><span class="mi">1000</span><span class="p">);</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="c1">// 注意，这里的 for 循环，并没有退出循环条件，这也决定着 run() 方法永远也不会返回</span>
</span><span class='line'>  <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 方法直接返回了静态对象，并且做了断言，也既是在调用此方法之前，</span>
</span><span class='line'><span class="c1">// 必须事先创建一个 CCApplication 的对象，以保证其静态变量能够初始化，否则返回空</span>
</span><span class='line'><span class="n">CCApplication</span><span class="o">*</span> <span class="n">CCApplication</span><span class="o">::</span><span class="n">sharedApplication</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="n">CC_ASSERT</span><span class="p">(</span><span class="n">sm_pSharedApplication</span><span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">sm_pSharedApplication</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>从上面的内容可以看出，从 <strong>sharedApplication()</strong> 方法，到 <strong>run()</strong> 方法，在这之前，我们需要调用到它的构造函数，否则不能运行，这就是为什么在 <strong>CCApplication::sharedApplication()&ndash;>run();</strong> 之前，我们首先使用了 <strong>AppDelegate app;</strong> 创建 AppDelegate 变量的原因！ 嗯 ！！ <strong>AppDelegate 和 CCAppliation 是什么关系！</strong> 由 AppDelegate 的定义我们可以知道，它是 CCApplication 的子类，在创建子类对象的时候，调用其构造函数的同时，父类构造函数也会执行，然后就将 AppDelegate 的对象赋给了 CCApplication 的静态变量，而在 AppDelegate 之中我们实现了 <strong>applicationDidFinishLaunching</strong> 方法，所以在 CCApplication 中 <strong>run</strong> 方法的开始处调用的就是 AppDelegate 之中的实现。而我们在此方法中我们初始化了一些变量，创建了第一个 CCScene 场景等，之后的控制权，便全权交给了 <strong>CCDirector::sharedDirector()&ndash;>mainLoop();</strong> 方法了。</p>

<p>（这里的实现机制，不做详细说明，简单说来：<strong>applicationDidFinishLaunching</strong> 是由 CCApplicationProtocol 定义，CCApplication 继承， AppDelegate 实现的 ~）</p>

<p><strong>比较重要的所在，for 循环并没有循环退出条件，所以 run 方法永远不会返回。那么是怎么结束的呢！要学会存疑！</strong></p>

<h3>从 CCApplication 到 CCDirector</h3>

<p>cocos2d-x 程序已经运行起来了，我们继续下一步，<strong>mainLoop</strong> 函数：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// [cocos2dx-path]/cocos2dx/CCDirector.cpp</span>
</span><span class='line'><span class="p">...</span>
</span><span class='line'><span class="c1">// 定义静态变量，实现单例模式</span>
</span><span class='line'><span class="k">static</span> <span class="n">CCDisplayLinkDirector</span> <span class="o">*</span><span class="n">s_SharedDirector</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'><span class="p">...</span>
</span><span class='line'><span class="c1">// 返回 CCDirector 实例</span>
</span><span class='line'><span class="n">CCDirector</span><span class="o">*</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 判断静态变量，以保证只有一个实例</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">s_SharedDirector</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">s_SharedDirector</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCDisplayLinkDirector</span><span class="p">();</span>
</span><span class='line'>        <span class="n">s_SharedDirector</span><span class="o">-&gt;</span><span class="n">init</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="c1">// CCDisplayLinkDirector 为 CCDirector 的子类，这里返回了其子类</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">s_SharedDirector</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// mainLoop 方法的具体实现</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCDisplayLinkDirector</span><span class="o">::</span><span class="n">mainLoop</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 此变量是我们需要关注，并且跟踪的，因为它决定着程序的结束时机</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="n">m_bPurgeDirecotorInNextLoop</span><span class="p">)</span>
</span><span class='line'>   <span class="p">{</span>
</span><span class='line'>       <span class="n">m_bPurgeDirecotorInNextLoop</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'>     <span class="c1">// 运行到此，说明程序的运行，已经没有逻辑代码需要处理了</span>
</span><span class='line'>       <span class="n">purgeDirector</span><span class="p">();</span>
</span><span class='line'>   <span class="p">}</span>
</span><span class='line'>   <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">m_bInvalid</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>      <span class="c1">// 屏幕绘制，并做一些相应的逻辑处理，其内部处理，这里暂且不做过多探讨</span>
</span><span class='line'>        <span class="n">drawScene</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="c1">// 这里实现了 cocos2d-x CCObject 对象的内存管理机制，对此有兴趣者，可以深入下去</span>
</span><span class='line'>        <span class="n">CCPoolManager</span><span class="o">::</span><span class="n">sharedPoolManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">pop</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 弹出场景 CCScene</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">popScene</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">CCAssert</span><span class="p">(</span><span class="n">m_pRunningScene</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">&quot;running scene should not null&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">m_pobScenesStack</span><span class="o">-&gt;</span><span class="n">removeLastObject</span><span class="p">();</span>
</span><span class='line'>    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">m_pobScenesStack</span><span class="o">-&gt;</span><span class="n">count</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">c</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>      <span class="c1">// 如果没有场景，调用 end() 方法</span>
</span><span class='line'>        <span class="n">end</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">m_bSendCleanupToScene</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'>        <span class="n">m_pNextScene</span> <span class="o">=</span> <span class="p">(</span><span class="n">CCScene</span><span class="o">*</span><span class="p">)</span><span class="n">m_pobScenesStack</span><span class="o">-&gt;</span><span class="n">objectAtIndex</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kt">void</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">end</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="c1">// 在 end 方法中，设置了变量为 true，这所致的结果，在 mainLoop 函数中，达成了运行 purgeDirector 方法的条件</span>
</span><span class='line'>  <span class="n">m_bPurgeDirecotorInNextLoop</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 此方法做些收尾清理的工作</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">purgeDirector</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">m_pRunningScene</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">m_pRunningScene</span><span class="o">-&gt;</span><span class="n">onExit</span><span class="p">();</span>
</span><span class='line'>        <span class="n">m_pRunningScene</span><span class="o">-&gt;</span><span class="n">cleanup</span><span class="p">();</span>
</span><span class='line'>        <span class="n">m_pRunningScene</span><span class="o">-&gt;</span><span class="n">release</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="c1">// 做一些清理的工作</span>
</span><span class='line'>   <span class="p">...</span>
</span><span class='line'>    <span class="c1">// OpenGL view</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// ###此句代码关键###</span>
</span><span class='line'>    <span class="n">m_pobOpenGLView</span><span class="o">-&gt;</span><span class="n">end</span><span class="p">();</span>
</span><span class='line'>    <span class="n">m_pobOpenGLView</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// delete CCDirector</span>
</span><span class='line'>    <span class="n">release</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 设置 openglview</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">setOpenGLView</span><span class="p">(</span><span class="n">CCEGLView</span> <span class="o">*</span><span class="n">pobOpenGLView</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">CCAssert</span><span class="p">(</span><span class="n">pobOpenGLView</span><span class="p">,</span> <span class="s">&quot;opengl view should not be null&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">m_pobOpenGLView</span> <span class="o">!=</span> <span class="n">pobOpenGLView</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="c1">// EAGLView is not a CCObject</span>
</span><span class='line'>        <span class="k">delete</span> <span class="n">m_pobOpenGLView</span><span class="p">;</span> <span class="c1">// [openGLView_ release]</span>
</span><span class='line'>      <span class="c1">// 为当前 CCDirector m_pobOpenGLView  赋值</span>
</span><span class='line'>        <span class="n">m_pobOpenGLView</span> <span class="o">=</span> <span class="n">pobOpenGLView</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>        <span class="c1">// set size</span>
</span><span class='line'>        <span class="n">m_obWinSizeInPoints</span> <span class="o">=</span> <span class="n">m_pobOpenGLView</span><span class="o">-&gt;</span><span class="n">getDesignResolutionSize</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">createStatsLabel</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="p">(</span><span class="n">m_pobOpenGLView</span><span class="p">)</span>
</span><span class='line'>        <span class="p">{</span>
</span><span class='line'>            <span class="n">setGLDefaultValues</span><span class="p">();</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">CHECK_GL_ERROR_DEBUG</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">m_pobOpenGLView</span><span class="o">-&gt;</span><span class="n">setTouchDelegate</span><span class="p">(</span><span class="n">m_pTouchDispatcher</span><span class="p">);</span>
</span><span class='line'>        <span class="n">m_pTouchDispatcher</span><span class="o">-&gt;</span><span class="n">setDispatchEvents</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>游戏的运行以场景为基础，每时每刻都有一个场景正在运行，其内部有一个场景栈，遵循后进后出的原则，当我们显示的调用 end() 方法，或者弹出当前场景之时，其自动判断，如果没有场景存在，也会触发 end() 方法，以说明场景运行的结束，而游戏如果没有场景，就像演出没有了舞台，程序进入最后收尾的工作，通过修改变量 <strong>m_bPurgeDirecotorInNextLoop</strong> 促使在程序 <strong>mainLoop</strong> 方法之内调用 <strong>purgeDirector</strong> 方法。</p>

<h3>CCEGLView 的收尾工作</h3>

<p>purgeDirector 方法之内，通过猜测与排查，最终定位到 <strong>m_pobOpenGLView->end();</strong> 方法，在这里结束了 cocos2d-x 游戏进程。而 m_pobOpenGLView 有时何时赋值，它的具体实现又在哪里呢？我们可以在 AppDelegate 的 <strong>applicationDidFinishLaunching</strong> 方法中找到如下代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// AppDelegate.cpp</span>
</span><span class='line'>
</span><span class='line'><span class="n">CCDirector</span> <span class="o">*</span><span class="n">pDirector</span> <span class="o">=</span> <span class="n">CCDirector</span><span class="o">::</span><span class="n">sharedDirector</span><span class="p">();</span>
</span><span class='line'><span class="n">pDirector</span><span class="o">-&gt;</span><span class="n">setOpenGLView</span><span class="p">(</span><span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">());</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>我们终于走到最后一步，看 CCEGLView 是如果负责收尾工作的:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='c++'><span class='line'><span class="c1">// [cocos2dx-path]/cocos2dx/platform/linux.CCEGLView.cpp</span>
</span><span class='line'>
</span><span class='line'><span class="p">...</span>
</span><span class='line'><span class="n">CCEGLView</span><span class="o">*</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">sharedOpenGLView</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">static</span> <span class="n">CCEGLView</span><span class="o">*</span> <span class="n">s_pEglView</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">s_pEglView</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="n">s_pEglView</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CCEGLView</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">s_pEglView</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="p">...</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// openglview 结束方法</span>
</span><span class='line'><span class="kt">void</span> <span class="n">CCEGLView</span><span class="o">::</span><span class="n">end</span><span class="p">()</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="cm">/* Exits from GLFW */</span>
</span><span class='line'>  <span class="n">glfwTerminate</span><span class="p">();</span>
</span><span class='line'>  <span class="k">delete</span> <span class="k">this</span><span class="p">;</span>
</span><span class='line'>  <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><strong>end()</strong> 方法很简单，只需要看到最后一句 <strong>exit(0);</strong> 就明白了。</p>

<h3>cocos2d-x 程序的结束流程</h3>

<p>程序运行时期，由 <strong>mainLoop</strong> 方法维持运行着游戏之内的各个逻辑，当在弹出最后一个场景，或者直接调用 <strong>CCDirector::end();</strong> 方法后，触发游戏的清理工作，执行 <strong>purgeDirector</strong> 方法，从而结束了 CCEGLView（不同平台不同封装，PC使用OpenGl封装，移动终端封装的为 OpenGl ES） 的运行，调用其 <strong>end()</strong> 方法，从而直接执行 <strong>exit(0);</strong> 退出程序进程，从而结束了整个程序的运行。（Android 平台的 end() 方法内部通过Jni 方法 <strong>terminateProcessJNI();</strong> 调用 Java 实现的功能，其功能一样，直接结束了当前运行的进程）</p>

<p>从程序的 main 方法开始，再创建 AppDelegate 等对象，运行过程中确实通过 exit(0); 来退出程序。所以我们看到了 AppDelegate 构造函数被调用，而其析构函数没有被调用的现象。</p>

<p><strong>exit(0);</strong> 的执行，意味着我们的程序完全结束，当然我们的进程资源也会被操作系统释放。但是注意，这里的 <strong>在构造函数创建[资源]，并且在析构函数中释放[资源]</strong> 并非绝对意义上的程序进程资源，在程序退出的时候，程序所使用的资源当然会被系统回收，但是如果我在构造函数调用网络接口初始化，析构在调用一次通知，所影响到的类似这种的 <strong>非本地资源</strong> 逻辑上的处理，而留下隐患。而通过理解 cocos2d-x 的运行机制，可以减少这种可能存在的隐患。</p>

<h2>cocos2d-x 的整体把握</h2>

<p>在本文通过解决一个小疑问，而去分析 cocos2d-x 游戏的运行流程，当然其中很多细致末叶我们并没有深入下去。不去解决这个疑问也可以，知道没有调用析构函数，那我就不调用便是 （这也是简单的解决方法，也不用觉得这不可行 ）。这里只是借着这个疑问，对 cocos2d-x 的流程稍作探寻而已。也没有贴一堆 cocos2d-x 源码去分析，其思路也有迹可循。</p>

<p>什么是 cocos2d-x ,它是 cocos2d 一个 C++ 的实现，除 C++ 之外，有 python ，Objective-C 等其它语言的实现，那该怎么去理解 cocos2d ，可以这么理解，cocos2d 是一个编写 2D 游戏的通用形框架，这种框架提供了一个通用模型，而这种模型或者说架构是 <strong>无关语言与平台</strong> 的，说 cocos2d-x 使用 C++ 编写，其跨平台能力很强，但它能跑在浏览器上么？cocos2d 还是有着 html5  的实现，当然平台决定着语言的选择，而 cocos2d 能够适应这么多不同的语言和平台，其良好的设计，清晰的结构功不可没。 而对不同语言，对相同功能有着不同的封装，正如在本文问题中，在不同平台（Linux 和 Android），对相同功能有着不同的封装异曲同工。那么封装到最后，我们对 cocos2d  的理解就只剩下了，我们要写游戏，那么需要导演，场景、层、精灵、动作等 <del>~ 组织好这个中之间的关系即可 </del></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Eclipse Cocos2d-x 开发自动管理]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/04-24.html"/>
    <updated>2013-04-24T12:15:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/linux-eclipse-advanced</id>
    <content type="html"><![CDATA[<h2>Makefile Android.mk 引发的思索</h2>

<p>在我们编写 Android 平台 cocos2d-x 游戏的时候，我们除了编写 <code>Classes</code> 之内的源代码文件之外，我们还需要维护其编译文件 Android.mk，如我们在 Classes 添加新的源文件，那么我们就要在 Android.mk 配置添加其编译路径，如：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>LOCAL_SRC_FILES :<span class="o">=</span> hellocpp/main.cpp <span class="se">\</span>
</span><span class='line'>                   ../../Classes/AppDelegate.cpp <span class="se">\</span>
</span><span class='line'>                   ../../Classes/HelloWorldScene.cpp
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>每添加一个源文件，我们就要手动添加一个配置，始其能够被编译，同样的，在 proj.linux 的 Makefile 文件也有这样的情况：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='makefile'><span class='line'><span class="nv">OBJECTS</span> <span class="o">=</span> ./main.o <span class="se">\</span>
</span><span class='line'>        ../Classes/AppDelegate.o <span class="se">\</span>
</span><span class='line'>        ../Classes/HelloWorldScene.o
</span></code></pre></td></tr></table></div></figure>


<p>当然让我们手动维护其配置，当然可以，不过麻烦非常，对于像我这样“懒惰”之人，当然需要想办法让其自动管理喽 ~</p>

<!-- more -->


<h2>自动编译、自动维护</h2>

<p>如果要自动维护编译文件之内的源代码文件，我们需要的无非就是所有的源代码文件及其路径，而这样的工作可以通过 Linux 强大的命令 find 来实现自动完成，Android.mk 文件如下(<a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/HelloWorld/proj.android/jni/Android.mk">获取源码</a>)：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class='makefile'><span class='line'><span class="nv">LOCAL_PATH</span> <span class="o">:=</span> <span class="k">$(</span>call my-dir<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="cp">include $(CLEAR_VARS)</span>
</span><span class='line'>
</span><span class='line'><span class="nv">LOCAL_MODULE</span> <span class="o">:=</span> game_shared
</span><span class='line'>
</span><span class='line'><span class="nv">LOCAL_MODULE_FILENAME</span> <span class="o">:=</span> libgame
</span><span class='line'>
</span><span class='line'><span class="c"># 定义 all-cpp-files 返回当前路径和 Classes 路径想的所有 cpp 文件，注意：这里只考虑 cpp 而没有 c，如果需要自行添加</span>
</span><span class='line'><span class="cp">define all-cpp-files</span>
</span><span class='line'><span class="k">$(</span>patsubst jni/%,%, <span class="k">$(</span>shell find <span class="k">$(</span>LOCAL_PATH<span class="k">)</span>/../../Classes/ <span class="k">$(</span>LOCAL_PATH<span class="k">)</span>/hellocpp -name <span class="s2">&quot;*.cpp&quot;</span><span class="k">))</span>
</span><span class='line'><span class="cp">endef</span>
</span><span class='line'>
</span><span class='line'><span class="c"># 这里使用新的方式替换换来的方式，以自动添加源文件</span>
</span><span class='line'>LOCAL_SRC_FILES :<span class="o">=</span> <span class="k">$(</span>call all-cpp-files<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="c">#LOCAL_SRC_FILES := hellocpp/main.cpp \</span>
</span><span class='line'><span class="c">#                  ../../Classes/AppDelegate.cpp \</span>
</span><span class='line'><span class="c">#                  ../../Classes/HelloWorldScene.cpp</span>
</span><span class='line'>  
</span><span class='line'>LOCAL_C_INCLUDES :<span class="o">=</span> <span class="k">$(</span>LOCAL_PATH<span class="k">)</span>/../../Classes
</span><span class='line'>
</span><span class='line'>LOCAL_WHOLE_STATIC_LIBRARIES :<span class="o">=</span> cocos2dx_static cocosdenshion_static cocos_extension_static
</span><span class='line'>
</span><span class='line'><span class="cp">include $(BUILD_SHARED_LIBRARY)</span>
</span><span class='line'>
</span><span class='line'><span class="k">$(</span>call import-module,CocosDenshion/android<span class="k">)</span> <span class="se">\</span>
</span><span class='line'><span class="k">$(</span>call import-module,cocos2dx<span class="k">)</span> <span class="se">\</span>
</span><span class='line'><span class="k">$(</span>call import-module,extensions<span class="k">)</span>        <span class="c"># 根据自己需要是否启用，上面的静态库同样</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>这样一个 Android.mk 算是<strong>万能</strong>的配置了，基本能满足我们编写 cocos2d-x 游戏的大多数需求了，当然如果你使用了第三方库，当然还是需要手动添加一下配置了，不过就源文件来说，不需要手动维护，倒是省事许多。下面在贴一个 Makefile 的万能配置(<a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/HelloWorld/proj.linux/Makefile">获取源码</a>)：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
</pre></td><td class='code'><pre><code class='makefile'><span class='line'><span class="nv">CC</span>      <span class="o">=</span> gcc
</span><span class='line'><span class="nv">CXX</span>     <span class="o">=</span> g++
</span><span class='line'><span class="nv">TARGET</span>    <span class="o">=</span> leafsoar           <span class="c"># 为了保持通用性，干脆起个不相干的目标文件，此名随意</span>
</span><span class='line'><span class="nv">CCFLAGS</span> <span class="o">=</span> -Wall
</span><span class='line'><span class="nv">CXXFLAGS</span> <span class="o">=</span> -Wall
</span><span class='line'><span class="nv">VISIBILITY</span> <span class="o">=</span>
</span><span class='line'>
</span><span class='line'><span class="c"># COCOS2DX_ROOT = /home/leafsoar/...      # 如果已经配置过此环境变量，可以不需要此，否则添加此变量值</span>
</span><span class='line'>
</span><span class='line'><span class="nv">COCOS2DX_PATH</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx
</span><span class='line'><span class="nv">INCLUDES</span> <span class="o">=</span>  -I../ <span class="se">\</span>
</span><span class='line'>          -I../Classes <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span> <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libfreetype2 <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/cocoa <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/include <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/linux <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/glew-1.7.0/glew-1.7.0/include/ <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/kazmath/include <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libxml2 <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libjpeg  <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/CocosDenshion/include <span class="se">\</span>
</span><span class='line'><span class="c">#         -I$(COCOS2DX_ROOT)/extensions/ \            # 根据自己需要是否包含 extensions 扩展</span>
</span><span class='line'>
</span><span class='line'><span class="nv">DEFINES</span> <span class="o">=</span> -DLINUX
</span><span class='line'>
</span><span class='line'><span class="c"># 获取源文件列表</span>
</span><span class='line'><span class="cp">define all-cpp-files</span>
</span><span class='line'><span class="k">$(</span>patsubst ./%,%, <span class="k">$(</span>shell find  ../Classes ./ -name <span class="s2">&quot;*.cpp&quot;</span><span class="k">))</span>
</span><span class='line'><span class="cp">endef</span>
</span><span class='line'>
</span><span class='line'><span class="c"># 我是打算让所以编译后的 &quot;.o&quot; 临时文件，全部生成在 &quot;obj&quot; 目录，而不是和源代码同目录</span>
</span><span class='line'><span class="cp">define all-cpp-dir</span>
</span><span class='line'><span class="k">$(</span>patsubst ../%,obj/%, <span class="k">$(</span>shell find  ../Classes -type d<span class="k">))</span>
</span><span class='line'><span class="cp">endef</span>
</span><span class='line'>
</span><span class='line'><span class="c"># obj 默认目录</span>
</span><span class='line'><span class="nv">OBJDIR</span><span class="o">=</span>obj/Classes
</span><span class='line'>
</span><span class='line'><span class="c"># 获取所有的编译文件列表</span>
</span><span class='line'><span class="nv">OBJECTS</span><span class="o">=</span><span class="k">$(</span>patsubst %.cpp,<span class="k">$(</span>OBJDIR<span class="k">)</span>/%.o,<span class="k">$(</span>call all-cpp-files<span class="k">))</span>
</span><span class='line'>
</span><span class='line'><span class="c"># 获取所有的编译文件路径，如果不存在路径则，编译可能出现问题</span>
</span><span class='line'><span class="nv">OBJECTS_DIR</span><span class="o">=</span><span class="k">$(</span>call all-cpp-dir<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="c"># 如果目录不存在，则创建相应的目录，-p 命令保证了，如果存在，不需要重新创建，这样没有修改的源文件就无需重新编译，提高速度</span>
</span><span class='line'><span class="k">$(</span>shell mkdir -p obj<span class="k">)</span>
</span><span class='line'><span class="k">$(</span>shell mkdir -p <span class="k">$(</span>OBJECTS_DIR<span class="k">))</span>
</span><span class='line'>
</span><span class='line'><span class="c">#echo:</span>
</span><span class='line'><span class="c"># @echo $(OBJECTS_DIR)</span>
</span><span class='line'>
</span><span class='line'><span class="c">#OBJECTS = ./main.o \</span>
</span><span class='line'><span class="c">#        ../Classes/AppDelegate.o</span>
</span><span class='line'>
</span><span class='line'>LBITS :<span class="o">=</span> <span class="k">$(</span>shell getconf LONG_BIT<span class="k">)</span>
</span><span class='line'><span class="cp">ifeq ($(LBITS),64)</span>
</span><span class='line'><span class="nv">STATICLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/libraries/lib64
</span><span class='line'><span class="cp">else</span>
</span><span class='line'><span class="nv">STATICLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/libraries
</span><span class='line'><span class="cp">endif</span>
</span><span class='line'><span class="nv">STATICLIBS</span> <span class="o">=</span>
</span><span class='line'><span class="nv">STATICLIBS</span> <span class="o">=</span> <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libfreetype.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libxml2.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libpng.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libjpeg.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libtiff.a <span class="se">\</span>
</span><span class='line'><span class="c">#             $(STATICLIBS_DIR)/libGLEW.a \</span>
</span><span class='line'>
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">=</span>
</span><span class='line'><span class="cp">ifeq ($(LBITS),64)</span>
</span><span class='line'><span class="nv">SHAREDLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/CocosDenshion/third_party/fmod/lib64/api/lib
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">=</span> -L<span class="k">$(</span>SHAREDLIBS_DIR<span class="k">)</span> -lfmodex64
</span><span class='line'><span class="cp">else</span>
</span><span class='line'><span class="nv">SHAREDLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/CocosDenshion/third_party/fmod/api/lib
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">=</span> -L<span class="k">$(</span>SHAREDLIBS_DIR<span class="k">)</span> -lfmodex
</span><span class='line'><span class="cp">endif</span>
</span><span class='line'>
</span><span class='line'>SHAREDLIBS +<span class="o">=</span> -lglfw -lGL
</span><span class='line'>SHAREDLIBS +<span class="o">=</span> -Wl,-rpath,<span class="k">$(</span>SHAREDLIBS_DIR<span class="k">)</span>
</span><span class='line'>SHAREDLIBS +<span class="o">=</span> -L<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/glew-1.7.0/glew-1.7.0/lib -lGLEW
</span><span class='line'>SHAREDLIBS +<span class="o">=</span> -Wl,-rpath,<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/glew-1.7.0/glew-1.7.0/lib
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="nv">BIN_DIR_ROOT</span><span class="o">=</span>bin
</span><span class='line'><span class="nv">BIN_DIR</span> <span class="o">=</span> <span class="k">$(</span>BIN_DIR_ROOT<span class="k">)</span>
</span><span class='line'>
</span><span class='line'>debug: <span class="nv">BIN_DIR</span> <span class="o">=</span> <span class="k">$(</span>BIN_DIR_ROOT<span class="k">)</span>/debug
</span><span class='line'>debug: CCFLAGS +<span class="o">=</span> -g3 -O0
</span><span class='line'>debug: CXXFLAGS +<span class="o">=</span> -g3 -O0
</span><span class='line'>debug: SHAREDLIBS +<span class="o">=</span> -L<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/lib/linux/Debug -lcocos2d -lrt -lz -lcocosdenshion
</span><span class='line'>debug: SHAREDLIBS +<span class="o">=</span> -Wl,-rpath,<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/lib/linux/Debug/
</span><span class='line'>debug: DEFINES +<span class="o">=</span> -DDEBUG
</span><span class='line'>debug: <span class="k">$(</span>TARGET<span class="k">)</span>
</span><span class='line'>
</span><span class='line'>release: <span class="nv">BIN_DIR</span> <span class="o">=</span> <span class="k">$(</span>BIN_DIR_ROOT<span class="k">)</span>/release
</span><span class='line'>release: CCFLAGS +<span class="o">=</span> -O3
</span><span class='line'>release: CXXFLAGS +<span class="o">=</span> -O3
</span><span class='line'>release: SHAREDLIBS +<span class="o">=</span> -L.<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/lib/linux/Release -lcocos2d -lrt -lz -lcocosdenshion
</span><span class='line'>release: SHAREDLIBS +<span class="o">=</span> -Wl,-rpath,<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/lib/linux/Release/
</span><span class='line'>release: DEFINES +<span class="o">=</span> -DNDEBUG
</span><span class='line'>release: <span class="k">$(</span>TARGET<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="c">####### Build rules</span>
</span><span class='line'><span class="k">$(</span>TARGET<span class="k">)</span>: <span class="k">$(</span>OBJECTS<span class="k">)</span>
</span><span class='line'>  mkdir -p <span class="k">$(</span>BIN_DIR<span class="k">)</span>
</span><span class='line'>  <span class="k">$(</span>CXX<span class="k">)</span> <span class="k">$(</span>CXXFLAGS<span class="k">)</span> <span class="k">$(</span>INCLUDES<span class="k">)</span> <span class="k">$(</span>DEFINES<span class="k">)</span> <span class="k">$(</span>OBJECTS<span class="k">)</span> -o <span class="k">$(</span>BIN_DIR<span class="k">)</span>/<span class="k">$(</span>TARGET<span class="k">)</span> <span class="k">$(</span>SHAREDLIBS<span class="k">)</span> <span class="k">$(</span>STATICLIBS<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="c">####### Compile</span>
</span><span class='line'><span class="k">$(</span>OBJDIR<span class="k">)</span>/%.o: %.cpp
</span><span class='line'>  <span class="k">$(</span>CXX<span class="k">)</span> <span class="k">$(</span>CXXFLAGS<span class="k">)</span> <span class="k">$(</span>INCLUDES<span class="k">)</span> <span class="k">$(</span>DEFINES<span class="k">)</span> <span class="k">$(</span>VISIBILITY<span class="k">)</span> -c <span class="nv">$&lt;</span> -o <span class="nv">$@</span>
</span><span class='line'>
</span><span class='line'>%.o: %.c
</span><span class='line'>  <span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CCFLAGS<span class="k">)</span> <span class="k">$(</span>INCLUDES<span class="k">)</span> <span class="k">$(</span>DEFINES<span class="k">)</span> <span class="k">$(</span>VISIBILITY<span class="k">)</span> -c <span class="nv">$&lt;</span> -o <span class="nv">$@</span>
</span><span class='line'>
</span><span class='line'>clean:
</span><span class='line'>  rm -f <span class="k">$(</span>OBJECTS<span class="k">)</span> <span class="k">$(</span>TARGET<span class="k">)</span> core
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>有了此 Makefile 我们就能满足我们绝大多数需求了，并且还做了目录优化，将所有源文件生成的 <code>.o</code> 文件统一放在了 obj 目录之下，方便管理，否则源文件路径会稍显零乱。实现方式，就是通过命令先创建符合条件的路径，然后修改其编译生成的临时文件路径。这只是我在使用 cocos2d-x 2.0.4 才出现的问题，而在最新版本2.1.12好似做了些修改，不需要显示的修改其 <code>.o</code> 文件路径。</p>

<h2>获取项目</h2>

<p>关于如此管理项目，我在网上提供的完整的例子，可以从 <a href="https://github.com/leafsoar/ls-cocos2d-x/tree/master/HelloWorld">GitHub</a> <sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> 上面下载，包含了一个完整 HelloWorld 工程项目。可以从这理获取，其中 <a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/HelloWorld/proj.android/jni/Android.mk">Android.mk</a> 和 <a href="https://github.com/leafsoar/ls-cocos2d-x/blob/master/HelloWorld/proj.linux/Makefile">Makefile</a> 文件可以直接使用。</p>

<p>如果你是在 Windows 下使用 cygwin 编译，那么这篇文章只能作为参考，其也是 unix 环境的一个模拟，但这里并不能确定其过程是否会出现什么问题。</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>关于本博客以后可能会出现的例子代码，都将放在 <a href="https://github.com/leafsoar/ls-cocos2d-x">GitHub</a> 之上，可以从 <a href="https://github.com/leafsoar/ls-cocos2d-x">这里</a> 获取到所有的内容。<a href="#fnref:1" rev="footnote">&#8617;</a></p></li>
</ol>
</div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Eclipse 组织跨平台开发 Cocos2d-x 游戏]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/04-23.html"/>
    <updated>2013-04-23T16:15:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/linux-eclipse-cocos2dx</id>
    <content type="html"><![CDATA[<p>前面我们完成了，在 <a href="http://blog.leafsoar.com/archives/2013/04-17-17.html">Linux 上运行 cocos2d-x</a> 游戏，然后使用 <a href="http://blog.leafsoar.com/archives/2013/04-19-11.html">Eclipse 开发 Linux 平台 cocos2d-x</a> 游戏，最后完成了在 Linux 下使用 <a href="http://blog.leafsoar.com/archives/2013/04-22-22.html">Eclipse 开发 Android 平台的 cocos2d-x</a> 游戏。</p>

<p>Ecilpse 开发 Linux 平台游戏使用的是 <code>proj.linux</code> 项目，Android 平台的使用的是 <code>proj.android</code> 项目，现在我们将所有项目整合，提供一个 Eclipse 完全开发 cocos2d-x 跨平台游戏的解决方案。我们将以上篇博文所建立的 Android 平台项目 <code>HelloWorld</code> 为基础，整合进 Linux 平台项目，并使用其作为开发调试的主要项目。</p>

<h2>Eclipse 组织说明</h2>

<p>使用 Eclipse 组织 cocos2d-x 项目，除了 Eclipse 所管理的 proj.linux 项目和 proj.android 项目，我们还需要一个项目，用户管理项目根目录，至于为何如此，后面将会说明，最终项目如下所示：</p>

<!-- more -->




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>HelloWorld/          <span class="c"># Eclipse 项目，项目名：HelloWorld</span>
</span><span class='line'>├── Classes
</span><span class='line'>│   ├── AppDelegate.cpp
</span><span class='line'>│   ├── AppDelegate.h
</span><span class='line'>│   ├── HelloWorldScene.cpp
</span><span class='line'>│   └── HelloWorldScene.h
</span><span class='line'>├── proj.android        <span class="c"># Android 项目，项目名：HelloWorld_j</span>
</span><span class='line'>│   ├── AndroidManifest.xml
</span><span class='line'>│   ├── ant.properties
</span><span class='line'>│   ├── assets
</span><span class='line'>│   ├── bin
</span><span class='line'>│   ├── build_native.sh
</span><span class='line'>│   ├── build.xml
</span><span class='line'>│   ├── Classes
</span><span class='line'>│   ├── gen
</span><span class='line'>│   ├── jni
</span><span class='line'>│   ├── libs
</span><span class='line'>│   ├── local.properties
</span><span class='line'>│   ├── ndkgdb.sh
</span><span class='line'>│   ├── obj
</span><span class='line'>│   ├── proguard-project.txt
</span><span class='line'>│   ├── proj.android
</span><span class='line'>│   ├── project.properties
</span><span class='line'>│   ├── res
</span><span class='line'>│   ├── Resources
</span><span class='line'>│   └── src
</span><span class='line'>├── proj.linux      <span class="c"># Linux 项目，项目名：HelloWorld_dx</span>
</span><span class='line'>│   ├── bin
</span><span class='line'>│   ├── Debug
</span><span class='line'>│   ├── main.cpp
</span><span class='line'>│   ├── main.h
</span><span class='line'>│   ├── main.o
</span><span class='line'>│   └── Makefile
</span><span class='line'>└── Resources
</span><span class='line'>    ├── CloseNormal.png
</span><span class='line'>    ├── CloseSelected.png
</span><span class='line'>    └── HelloWorld.png
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>最终效果，一个 HelloWorld 目录，包含四个文件夹 Classes、proj.android、proj.linux 和 Resources，还有三个项目，但明眼所见只有两个项目，何来三个，除了 Android 平台，Linuxe 平台的开发项目，还有一个组织全代码工程的项目 <strong>HelloWorld</strong>，最终在 Eclipse 将显示三个项目，HelloWorld、HelloWorld_dx 和 HelloWorld_j,由于在 Eclipse 中同一个工作空间之中不能出现相同的项目名称，所以在 Linux 平台加了个 <strong>_dx</strong> 后缀，Android 平台加了个 <strong>_j</strong> 后缀，加以区分，后缀名称为何 不重要，只要区分项目名称就行，以保证能在 Eclipse 同时打开这三个项目。</p>

<p>Eclipse 打开 proj.linux 是为了开发 cocos2d-x 游戏源代码，调试运行之用，proj.android 是为了编译到 android 平台运行之用，为什么还要加一个 HelloWorld 总项目呢，我们看到 Resources 和 Classes 目录所在的位置很是特殊，作为 proj.linux 和 proj.android 项目，我们可以将这两个目录的源代码添加到编译路径，但从目录结构上来说，是属于它们的父目录，如果我们开发过程使用如 SVN 这样的代码管理工具，那么 proj.android 和 proj.linux 项目，将<strong>照顾</strong>不到这两个目录，修改文件，不能签入，不能更新，所以添加了 HelloWorld 项目，这样就可以在 Eclipse 编写调试运行，并且通过 HelloWorld 项目和 SVN 做整个工程的同步，这一点在团队合作开发尤为重要，即便是个人开发，也最好用代码管理跟踪记录我们的代码，这是一个很好的习惯。</p>

<h2>Eclipse 组织实现步骤</h2>

<ul>
<li>在<a href="http://blog.leafsoar.com/archives/2013/04-22-22.html">上篇博文</a>，我们已经通过 Eclipse 添加了一个名为 HelloWorld 的 Android 平台项目。基于此，我们首先修改这个项目的名称 <code>HelloWorld</code> 改为 <code>HelloWorld_j</code>，只要右击项目 <strong>Rename</strong> 即可。</li>
<li>然后我们 Eclipse 新建项目 <code>New -&gt; Other -&gt; General -&gt; Project -&gt; Next</code> ,输入项目名称 <code>HelloWorld</code> 后 <code>Finish</code>。注意这里的项目类型是 <strong>General</strong>，并不是 Android 或是其它项目，因为我们只需要用此管理目录即可，由于工作空间中已经存在 HelloWorld 目录，会自动以此目录创建 HelloWorld 项目，创建完成便能够在  Eclipse HelloWorld 项目中看到三个文件夹。Classes、proj.android 和 Resources。</li>
<li>最后我们需要一个 proj.linux 项目，cocos2d-x 本身并没有明确的创建方式，不像 VS 和 Xcode  都有项目模板可以和 IDE 自动集成，不过我们可以 copy cocos2dx 自带的例子 <a href="http://blog.leafsoar.com/archives/2013/04-19-11.html">HelloCpp</a> 中的 proj.linux 拿过来一用。将其目录的 proj.linux 复制到 HelloWorld 目录之下。</li>
<li>复制了 proj.linux 目录，我们用 Eclipse 导入此项目。导入过以后修改项目名 HelloCpp 为 HelloWorld_dx。</li>
</ul>


<p>至此，在 Eclipse 已经有了三个项目 HelloWorld、HelloWorld_dx 和 HelloWorld_j 了，android 项目已经是配置好的，可以直接使用而 Linux 项目由于是从 HelloCpp copy 过来的工程文件，所以还需要做些配置修改，才能运行。</p>

<ul>
<li>我们先要做到能通过 make 命令编译此项目，然后在配置使用 Eclipse 可以开发，并提供自动补全功能，CDT 的功能还是很强大很好用的。</li>
<li>参照 <a href="http://blog.leafsoar.com/archives/2013/04-19-11.html">此篇博文</a> 修改 makefile 已使 make 能进行项目的编译运行。</li>
</ul>


<p>如果出现如下错误：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>../Classes/HelloWorldScene.cpp:2:31: fatal error: SimpleAudioEngine.h: No such file or directory
</span><span class='line'>compilation terminated.
</span><span class='line'>make: *** <span class="o">[</span>../Classes/HelloWorldScene.o<span class="o">]</span> Error 1
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>则在 <strong>Makefile</strong> 文件中的 <strong>INCLUDES</strong>  添加 <strong>CocosDenshion</strong> 的相关内容，最终如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">INCLUDES</span> <span class="o">=</span>  -I../ <span class="se">\</span>
</span><span class='line'>          -I../Classes <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span> <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libfreetype2 <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/cocoa <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/include <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/linux <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/glew-1.7.0/glew-1.7.0/include/ <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/kazmath/include <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libxml2 <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libjpeg  <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/CocosDenshion/include <span class="se">\   </span>     <span class="c"># 添加的内容</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>此时 make 已经能够在 bin 目录之下生成可执行文件。然后我们在来配置 Eclipse 开发环境。</p>

<h2>Eclipse Linux 项目配置全攻略</h2>

<p>我们虽然已经能够通过 make 编译，但是并不能通过 Ecilpse 编译，因为 proj.linux 是从 cocos2d-x 里面 copy 出来的，里面的配置多使用相对路径，这对项目来说显然是不可行的，所以需要修改成适用于任何位置的项目，让其只依赖 环境变量：</p>

<ul>
<li>修改包含源代码目录，使之正确。此时 HelloWorld_dx 的 Classes 并不能正确显示源代码（视具体环境而定，如果 Classes 能看到源代码，跳过此步骤）。修改项目属性找到如下选项 <code>C/C++ General -&gt; Paths and Symbols</code> ，定位到 <code>Source Location</code>  选项卡，<strong>delete</strong> <code>/HelloWorld_dx/Classes</code>  项，然后添加一个 <strong>Link Folder</strong> ，<code>Link folder in the file system</code> 勾上，填写值为 <strong>PARENT-1-PROJECT_LOC/Classes</strong>，Folder name 自动变为 Classes 后点击 <strong>OK</strong>。 此时便能够在 HelloWorld_dx 看到 Classes 文件夹和其中的源代码了。</li>
<li>修改包含头文件路径，使之正确。我们点开项目的 Includes 看到所引用的相关 cocos2dx 头文件路径都不正确，还是定位到 <code>C/C++ General -&gt; Paths and Symbols</code> 选项查看 <strong>Include</strong> 选项卡中 <strong>GNU C++</strong>  右侧包含很多头文件，修改成 <strong>${cocos2dx_loc}/cocos2dx</strong> 诸如此值，其它错误路径同样修改。</li>
<li>我们需要在 <code>Eclipse -&gt; Windows</code> 属性里面 <code>C/C++ -&gt; Build -&gt; Build Variable</code> 添加 <strong>cocos2dx_loc</strong> 的变量，其变量值为 [cocos2dx-path] 主目录。</li>
<li>修改项目类型为是用自定义 Makefile 编译运行。</li>
</ul>


<p>我们就能完全用 Eclipse 编写 cocos2d-x 程序了，并且有着完善的代码提示功能。提高开发效率。从代码的编写运行调试，到跨平台的 Android 运行，Eclipse 组织项目可以同步 SVN 多人协作。到此，已经提供了一个基本的解决方案 ~</p>

<p>当然开发环境的灵活性，也许可能遇到我们未知的问题，总是在不断的发现问题，并解决问题。灵活的部署，项目的组织，环境的配置。有一个好用顺手的开发环境是我们在开发前必做的准备 ~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Linux 下开发 Android Cocos2d-x 游戏]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/04-22.html"/>
    <updated>2013-04-22T22:15:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/linux-cocos2dx-develop-android</id>
    <content type="html"><![CDATA[<p>开发 Android 应用的首选 IDE 是什么，是 Eclipse ，而开发 Android 平台的 cocos2d-x 游戏呢，当然也是 Eclipse 。</p>

<h2>Eclipse Android 开发环境搭建</h2>

<ul>
<li>如果你的 Eclipse 不支持 Java 开发，请安装相关插件，或者使用 <a href="http://www.eclipse.org/downloads/">Eclipse IDE for Java Developers</a> 版本集成的 Java 开发环境。</li>
<li>仅仅 Java 开发环境还不够，我们还需要 <a href="http://developer.android.com/tools/sdk/eclipse-adt.html">ADT</a>(Android Development Tools) ，顾名思义，通过它，我们才能在 Eclipse 建立 Android 项目，与 Eclipse 集成，打包生成 Android 应用程序包 Apk 文件。</li>
<li>作为 ADT 的依赖环境，<a href="http://developer.android.com/sdk/index.html">Android SDK</a> 也是必须的。</li>
<li>由于 cocos2d-x 是由 C/C++ 编写，为了编译 Android 平台 C/C++ 程序，我们还需要安装 <a href="http://developer.android.com/tools/sdk/ndk/index.html#Downloads">NDK</a>， 注意选择  Linux 版本， 32 位或者 64 位视开发机而定。</li>
</ul>


<!-- more -->


<p>安装好 Eclipse、ADT 和 Android SDK、NDK，打开 Eclipse 做些简单的配置，打开 Eclipse:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Eclipse -&gt; Window -&gt; Preferences -&gt; Android
</span></code></pre></td></tr></table></div></figure>


<p></p>

<ul>
<li>在右侧设置 <strong>SDK Location</strong> 为你的 Android SDK 位置。只有当位置正确，才能正确点击 OK。</li>
<li>Linux 下进入 Android SDK 目录，运行 <code>[android-sdk-linux]/tools/android</code> ，程序，安装相关工具，各种版本的 Android SDK Platform，代码实例等，可以选择 4.1.2 版本。</li>
<li>Eclipse 切换到 Java Perspective (Eclipse 右上角设置)，点击 Eclipse 菜单 <code>Window -&gt; Android Virtual Device Manager</code> 创建一个虚拟机，版本对应上一步骤所安装的 SDK 版本。</li>
<li>为了方便起见，我们将 Android SDK 和 NDK 的执行命令等（<code>[android-sdk-linux/tools] 和 ndk-build</code>），添加到 Linux 系统 PATH 环境变量。</li>
</ul>


<p>此时，通过安装配置，要能<strong>完成在 Linux 下使用 Eclipse 开发 Android 应用和 Android Jni 应用</strong>，我们才能继续接下来的过程，如果配置出现问题，不能开发 Android 或者 Jni 应用，那么请先解决之 ~</p>

<p>环境搭建过程，如果出现什么问题或者疑问，可以 <a href="http://www.google.com">Google</a> 之，或者在博客之后留言交流 ~</p>

<h2>创建 Linux Cocos2d-x for Android 项目</h2>

<p>我们首先通过 cocos2d-x 自带的创建脚本创建 Android cocos2d-x 项目。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> <span class="o">[</span>cocos2d-x-path<span class="o">]</span>
</span><span class='line'>./create-android-project.sh <span class="c"># 回车</span>
</span><span class='line'>...
</span><span class='line'>Input package path. For example: org.cocos2dx.example
</span><span class='line'>com.leafsoar.HelloWorld    <span class="c"># 输入包名</span>
</span><span class='line'>...
</span><span class='line'>...
</span><span class='line'>----------
</span><span class='line'>id: 7 or <span class="s2">&quot;android-16&quot;</span>
</span><span class='line'>     Name: Android 4.1.2
</span><span class='line'>     Type: Platform
</span><span class='line'>     API level: 16
</span><span class='line'>     Revision: 3
</span><span class='line'>     Skins: QVGA, WVGA800 <span class="o">(</span>default<span class="o">)</span>, WSVGA, HVGA, WQVGA432, WVGA854, WQVGA400, WXGA720, WXGA800, WXGA800-7in
</span><span class='line'>     ABIs : armeabi-v7a
</span><span class='line'>input target id:
</span><span class='line'>7    <span class="c"># 输入 target id，参照上面，根据自己的 sdk 版本选择</span>
</span><span class='line'>...
</span><span class='line'>input your project name:
</span><span class='line'>HelloWorld            <span class="c"># 输入项目名称</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>会在 <code>[cocos2d-x-path]</code> 目录创建一个 <code>HelloWorld</code> 的目录，里面包含文件如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>HelloWorld/
</span><span class='line'>├── Classes
</span><span class='line'>│   ├── AppDelegate.cpp
</span><span class='line'>│   ├── AppDelegate.h
</span><span class='line'>│   ├── HelloWorldScene.cpp
</span><span class='line'>│   └── HelloWorldScene.h
</span><span class='line'>├── proj.android
</span><span class='line'>│   ├── AndroidManifest.xml
</span><span class='line'>│   ├── ant.properties
</span><span class='line'>│   ├── bin
</span><span class='line'>│   ├── build_native.sh
</span><span class='line'>│   ├── build.xml
</span><span class='line'>│   ├── jni
</span><span class='line'>│   ├── libs
</span><span class='line'>│   ├── local.properties
</span><span class='line'>│   ├── ndkgdb.sh
</span><span class='line'>│   ├── proguard-project.txt
</span><span class='line'>│   ├── project.properties
</span><span class='line'>│   ├── res
</span><span class='line'>│   └── src
</span><span class='line'>└── Resources
</span><span class='line'>    ├── CloseNormal.png
</span><span class='line'>    ├── CloseSelected.png
</span><span class='line'>    └── HelloWorld.png
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><a href="http://blog.leafsoar.com/archives/2013/04-19-11.html">上篇博文</a>我们简单分析了一下这样的目录组织方式，和其共用。创建好 cocos2d-x android 项目，我们开始编译，<code>proj.android</code>目录下提供一个自动编辑脚本，完成的工作是，编译 cocos2d-x C/C++ 程序，并且在 libs 目录生成相应的 <strong>so</strong> 库文件。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> <span class="o">[</span>HelloWorld<span class="o">]</span>/proj.android
</span><span class='line'>././build_native.sh
</span><span class='line'>...
</span><span class='line'>...
</span><span class='line'>...
</span><span class='line'>StaticLibrary  : libextension.a
</span><span class='line'>SharedLibrary  : libgame.so
</span><span class='line'>Install        : libgame.so <span class="o">=</span>&gt; libs/armeabi/libgame.so
</span><span class='line'>make: Leaving directory <span class="s1">&#39;[cocos2dx-path]/HelloWorld/proj.android&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>看到如上信息，说明已经编译成功，首次编译过程稍微缓慢一点，如果没有出现以上结果，或者编译错误，多是因为系统环境没有配置正确。需要环境变量 <code>NDK_ROOT</code>、<code>COCOS2DX_ROOT</code>等，根据提示具体分析。</p>

<h2>配置集成开发环境</h2>

<p>为了方便项目管理，我们把 <code>HelloWorld</code> 目录移动到 Ecilpse 的工作空间之中，默认实在 [cocos2dx-path] 目录。然后使用 Eclipse 导入本地项目，指定 [HelloWorld/proj.android] 目录导入项目。</p>

<ul>
<li>导入之后我们发现项目出现感叹号，这是因为 Eclipse 管理此项目的依赖项目并不存在，我们继续用 Eclipse 导入 <code>[cocos2dx-path]/cocos2dx/platform/android/java</code> <strong>libcocos2dx</strong> 项目。</li>
<li>我们右击 HelloWorld 修改项目属性，找到 Android  项，看到 Library 属性框，所引用的项目出现问题，首先 remove 然后 重新 Add 选择刚才添加的 libcocos2dx 项目。</li>
<li>我们 clean 清空一下 HelloWorld  项目。</li>
<li>此时在我的项目中 <strong>AndroidManifest.xml</strong> 文件出现 <code>androi:icon</code> 图标的错误，修改成 <code>@drawable/ic_launcher</code></li>
<li>右击项目 <strong>Run as &ndash;> Android Application</strong> 就能运行此应用了</li>
</ul>


<p><strong>以上问题视自己的具体情况而定，可能出现不同的错误。</strong></p>

<p>此时我们发现 Android 项目中，<strong>bin</strong> 目录生成了 HelloWorld.apk 文件，这个就是最终的 Android 平台 cocos2d-x 游戏安装包了。并且可以运行。</p>

<p>至此，我们已经能够在 Linux 上运行编译运行 Android 平台的 cocos2d-x 游戏，但是每次我们在编写完 cocos2d-x 游戏源代码，我们都要执行 <code>build_native.sh</code> 命令，当然可以简化此步骤，并且将上一偏博文的的 Linux 下开发 Cocos2d-x 游戏，一遍编写调试，一边运行在 Android 平台，或者两个项目同时进行。这些内容将会在下一篇文章之中 ~</p>

<p>至此还没有完，因为我们移动了项目目录，所以再次执行 <code>build_native.sh</code> 命令会出现问题，我们需要修改此文件中的配置：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">COCOS2DX_ROOT</span><span class="o">=</span><span class="s2">&quot;$DIR/../..&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>将此值设置为 [cocos2dx-path] 的绝对目录，或者使用 COCOS2DX_ROOT 的环境变量。以保证此命令能够执行编译成功。这个问题留给读者自己解决吧 : p</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[善其事先利其器 Eclipse 开发 Cocos2d-x]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/04-19.html"/>
    <updated>2013-04-19T11:20:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/linux-cocos2dx-develop</id>
    <content type="html"><![CDATA[<p><a href="http://blog.leafsoar.com/archives/2013/04-17-17.html">上篇博客</a>，我们实现了在 Linux 下运行 cocos2d-x 游戏，这意味着我们可以在 Linux PC 机上进行游戏的编写、运行和调试，提高开发效率，而在手机上运行的过程大致分为：</p>

<ul>
<li>PC 上编写游戏源代码</li>
<li>NDK 编译生成 so 库文件</li>
<li>Android 工程打包生成 Apk 文件</li>
<li>传输到模拟器或真机运行</li>
</ul>


<p>这么个手机上运行的过程繁琐非常，而且这只是运行在 Android 上的过程，如果通过 Android Jni 调用调试 C++ 更为麻烦，现今的 NDK 版本应该支持 Android Jni C++ 程序调试了。而在 PC 端开发运行和调试，<strong>偶尔</strong> 在手机上运行看看效果的开发过程，更为合适！虽然 cocos2d-x 是跨平台的，但常在目标平台运行，可以提前发现因平台特性可能出现的问题，并即时解决。</p>

<!-- more -->


<h2>Eclipse 上开发 Cocos2d-x  游戏</h2>

<p>善其事先利其器，在做开发之前，搭建一个顺手的开发环境是必要的准备！</p>

<h3>安装开发环境</h3>

<p>在 Debian  系统下，可以直接通过 <code>sudo apt-get install eclipse</code> 安装开发环境，并自动安装依赖项，如 JDK 等。而这里是从官方网站下载最新版本。手动配置，可以选择一个自己熟悉的方式。</p>

<ul>
<li>这里使用的是 <a href="http://www.eclipse.org/downloads/"><strong>Eclipse Juno (4.2)</strong></a> 可以下载 <strong>IDE for Java</strong> 版本之后在安装 <strong>CDT</strong>，也可以直接下载 <strong>IDE for C/C++</strong> 版本的 Eclipse</li>
<li>安装 <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html"><strong>JDK</strong></a> ，只需要 JAR 支持，就能运行 Eclipse 编写 C++ 了，为了以后编写 Java Android 程序，这里直接安装 JDK。</li>
<li>下载之后配置环境变量，把 JDK bin 目录添加到 $PATH 环境变量。</li>
</ul>


<h3>第一个程序 <strong>HelloCpp</strong></h3>

<p>现在的准备环境 Eclipse 和已经配置好的 CDT，并且能够运行普通 C++ 项目，而 cocos2d-x 的 Linux 也就是一个普通的 C++ 项目（ cocos2d-x 的跨平台特性）。我们先来看一下 cocos2d-x 是如何组织项目的，如下所示：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>HelloCpp/
</span><span class='line'>├── Classes     <span class="c"># cocos2d-x 游戏源代码</span>
</span><span class='line'>├── proj.android        <span class="c"># Android 平台项目目录组织</span>
</span><span class='line'>├── proj.blackberry     <span class="c"># blackberry 项目组织</span>
</span><span class='line'>├── proj.ios        <span class="c"># iOS 平台项目</span>
</span><span class='line'>├── proj.linux      <span class="c"># Linux PC 项目，也是我们要用到的</span>
</span><span class='line'>├── proj.mac        <span class="c"># Mac 项目</span>
</span><span class='line'>├── proj.win32      <span class="c"># Windows VS 下 Win32项目</span>
</span><span class='line'>└── Resources       <span class="c"># 游戏资源，包含图片、声音、字体等</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>在此处，我们只需要用到 <code>Classes</code>、<code>Resources</code> 和 <code>proj.linux</code> 就可以了，其中<code>proj.[平台]</code> 就是不同的开发平台，之后编译运行在不同平台的项目组织，而他们共用了源代码 <code>Classes</code> 和 <code>Resources</code> 资源文件。如果我们今后自己创建项目，最好也保持这样的组织方式！</p>

<p>用 Eclipse 打开添加 HelloCpp 项目到：</p>

<p>Eclipse &ndash;> File &ndash;> Import &ndash;> General &ndash;> Existing Projects into Workspace &ndash;> Browse 浏览目录，选中 <code>[cocos2dx-path]/samples/HelloCpp/proj.linux</code>， 点击 <strong>OK</strong> 之后 <strong>Finish</strong> ，我们就能在 Eclipse 看见被导入的项目了。</p>

<p>现在我们试着运行 HelloCpp 项目，右击项目 <strong>Build Project</strong>（如果此项“灰显”不能点击的话，打开 Eclipse Problems 窗口，把 Errors 和 Warnings 都给删除即可），此时编译会编译不过去，提示如下错误信息：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Description  Resource    Path    Location    Type
</span><span class='line'>  cannot find -lcocosdenshion HelloCpp            C/C++ Problem
</span><span class='line'>  cannot find -lcocos2d   HelloCpp            C/C++ Problem
</span><span class='line'>  make: *** <span class="o">[</span>HelloCpp<span class="o">]</span> Error 1  HelloCpp            C/C++ Problem
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>在继续操作之前，我们先来了解一下 Eclipse 中 编写 C/C++ 程序的一般方式，作为编写程序来说，我们只要包含正确头文件的位置，就能够使用 CDT 带来的快捷，自动补全，而作为编译过程，这里有两种方式。<strong>其一： Eclipse 组织编译</strong> , Eclipse 之中设置很多参数，源代码路径，包含文件，包含的库文件等以系列信息，根据这些信息，它就能为我们自动生成 makefile 文件（具体见项目之下 <code>Debug</code> 目录），然后再根据这个文件自动编译，这样我们只需要写代码程序，不需要手动维护 Makefile 文件。<strong>其二：自定义 Makefile</strong>，如 HelloCpp 项目之中包含一 Makefile 文件，我们只要进入这个目录执行 <code>make</code> 命令，就能完成项目的编译，上篇博客就是使用这种方式，而在 Eclipse 自动调用 make 效果同样。</p>

<p>而编写 <strong>cocos2d-x</strong> 游戏，这里我推荐第二种方式，有几点原因和优势。如果使用 Eclipse 自动生成的 makefile 编译方式，那么在编译当前项目之时，我们需要在 Eclipse 编译它的依赖项目，这会始事情变的复杂，其依赖项目有两个是必须的(如 [<code>[cocos2dx-path]/cocos2dx</code> 和 <code>[cocos2dx-path]/CocosDenshion</code>)，还有可选的(如<code>[cocos2dx-path]/external/Box2D</code> 物理引擎库)。还有优势，Eclipse 只作为项目组织编写，如果没有 Eclipse 环境，我们同样能够用 make 编译整个项目，所以维护好我们的 Makefile 可以省事很多。</p>

<p>我们编译出现的错误，找不到库是因为 Eclipse 自动生成的 makefile 不知道从哪里去找库文件，当然我们可以把库项目添加到 Eclipse 之中，然后先把库项目编译成功，再来编译此项目，当然是完全可行的，但不推荐。</p>

<p>知道原因后，我们做简单的修改</p>

<h3>修改项目，编译运行</h3>

<ul>
<li>右击项目，查看属性 (Properties)</li>
<li>选中 <code>C/C++ Build</code> 项，找到 <code>Makefile generation</code> 组合框之中的复选框 <code>Generate Makefiles automatically</code>，将 <strong>勾</strong> 去掉，以使用我们自己编写的 Makefile 编译。</li>
<li>同样 <code>C/C++ Build</code> 项，找到标签 <code>Behaviour</code> 将 <code>Build (Incremental build)</code> 复选框之后的 变量值 <strong>all</strong> 删除，设置为空，否则编译项目会出现 <code>make: *** No rule to make target 'all'.  Stop.  HelloCpp</code> 的 错误</li>
</ul>


<p>此时我们在 <strong>Build Project</strong> 项目，就已经在 <code>bin</code> 目录生成可执行文件了。我们在项目右击 <code>Run as</code> &ndash;> <code>Local C/C++ Application</code> 但却运行不了，与 <a href="http://blog.leafsoar.com/archives/2013/04-17-17.html">上篇博客</a> 相比，虽然生成的方式略有不同，但本质一样，都是通过 <strong>Makefile</strong> 生成，由于配置原因，必须要在 <strong>当前目录之下才能运行</strong> 。这是因为 Makefile 之中默认配置的库路径问题所致。</p>

<p>Makefile 使用的是 <strong>相对路径</strong> 引用库文件的，这也就是因为只有在 当前目录运行有效(工作目录在当前目录)，而在 Eclipse 之中运行无效的原因，Eclipse 的运行 <strong>工作目录</strong> 不是可执行程序的目录！！！</p>

<p>不能运行，当然也就不能调试，我们还需要继续配置。</p>

<h3>修改配置，集成开发环境并运行调试</h3>

<p>现在开始到维护我们的 Makefile 文件了，修改 Makefile 之前，我们先定一个环境变量， <strong>$COCOS2DX_ROOT</strong> 以标示 cocos2dx的主目录。在 Eclipse 之中操作：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Ecilpse -&gt; Windows -&gt; Preferences -&gt; C/C++ -&gt; Build -&gt; Environment
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>点击 <strong>Add</strong> ， <strong>Name</strong> 为 <strong>COCOS2DX_ROOT</strong>，<strong>Value</strong> 为 <strong>[cocos2dx-path]</strong></p>

<p>(此处视你的环境而定，比如 <strong>&ldquo;[xxx/xxx/xxx]/cocos2d-2.0-x-2.0.4&rdquo;</strong>)</p>

<p>然后修改我们的 Makefile 文件，把一些相对路径转换成基于环境变量的绝对路径，最终如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
</pre></td><td class='code'><pre><code class='makefile'><span class='line'><span class="nv">CC</span>      <span class="o">=</span> gcc
</span><span class='line'><span class="nv">CXX</span>     <span class="o">=</span> g++
</span><span class='line'><span class="nv">TARGET</span>    <span class="o">=</span> HelloCpp
</span><span class='line'><span class="nv">CCFLAGS</span> <span class="o">=</span> -Wall
</span><span class='line'><span class="nv">CXXFLAGS</span> <span class="o">=</span> -Wall
</span><span class='line'><span class="nv">VISIBILITY</span> <span class="o">=</span>
</span><span class='line'>
</span><span class='line'><span class="nv">COCOS2DX_PATH</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx
</span><span class='line'><span class="nv">INCLUDES</span> <span class="o">=</span>  -I../ <span class="se">\</span>
</span><span class='line'>          -I../Classes <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span> <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libfreetype2 <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/cocoa <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/include <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/linux <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/glew-1.7.0/glew-1.7.0/include/ <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/kazmath/include <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libxml2 <span class="se">\</span>
</span><span class='line'>          -I<span class="k">$(</span>COCOS2DX_PATH<span class="k">)</span>/platform/third_party/linux/libjpeg  <span class="se">\</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="nv">DEFINES</span> <span class="o">=</span> -DLINUX
</span><span class='line'>
</span><span class='line'><span class="nv">OBJECTS</span> <span class="o">=</span> ./main.o <span class="se">\</span>
</span><span class='line'>        ../Classes/AppDelegate.o <span class="se">\</span>
</span><span class='line'>        ../Classes/HelloWorldScene.o
</span><span class='line'>
</span><span class='line'><span class="nv">LBITS</span> <span class="o">:=</span> <span class="k">$(</span>shell getconf LONG_BIT<span class="k">)</span>
</span><span class='line'><span class="cp">ifeq ($(LBITS),64)</span>
</span><span class='line'><span class="nv">STATICLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/libraries/lib64
</span><span class='line'><span class="cp">else</span>
</span><span class='line'><span class="nv">STATICLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/libraries
</span><span class='line'><span class="cp">endif</span>
</span><span class='line'><span class="nv">STATICLIBS</span> <span class="o">=</span>
</span><span class='line'><span class="nv">STATICLIBS</span> <span class="o">=</span> <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libfreetype.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libxml2.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libpng.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libjpeg.a <span class="se">\</span>
</span><span class='line'>              <span class="k">$(</span>STATICLIBS_DIR<span class="k">)</span>/libtiff.a <span class="se">\</span>
</span><span class='line'><span class="c">#             $(STATICLIBS_DIR)/libGLEW.a \</span>
</span><span class='line'>
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">=</span>
</span><span class='line'><span class="cp">ifeq ($(LBITS),64)</span>
</span><span class='line'><span class="nv">SHAREDLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/CocosDenshion/third_party/fmod/lib64/api/lib
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">=</span> -L<span class="k">$(</span>SHAREDLIBS_DIR<span class="k">)</span> -lfmodex64
</span><span class='line'><span class="cp">else</span>
</span><span class='line'><span class="nv">SHAREDLIBS_DIR</span> <span class="o">=</span> <span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/CocosDenshion/third_party/fmod/api/lib
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">=</span> -L<span class="k">$(</span>SHAREDLIBS_DIR<span class="k">)</span> -lfmodex
</span><span class='line'><span class="cp">endif</span>
</span><span class='line'>
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">+=</span> -lglfw -lGL
</span><span class='line'><span class="c">#SHAREDLIBS += -L../../../lib/linux/Debug -lcocos2d -lrt -lz -lcocosdenshion -Wl,-rpath,../../../../lib/linux/Debug/ </span>
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">+=</span> -Wl,-rpath,<span class="k">$(</span>SHAREDLIBS_DIR<span class="k">)</span>
</span><span class='line'><span class="c">#SHAREDLIBS += -Wl,-rpath,../../../../cocos2dx/platform/third_party/linux/glew-1.7.0/glew-1.7.0/lib</span>
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">+=</span> -L<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/glew-1.7.0/glew-1.7.0/lib -lGLEW
</span><span class='line'><span class="nv">SHAREDLIBS</span> <span class="o">+=</span> -Wl,-rpath,<span class="k">$(</span>COCOS2DX_ROOT<span class="k">)</span>/cocos2dx/platform/third_party/linux/glew-1.7.0/glew-1.7.0/lib
</span><span class='line'>
</span><span class='line'><span class="c">#$(shell ../../build-linux.sh $&lt;)</span>
</span><span class='line'>
</span><span class='line'><span class="nv">BIN_DIR_ROOT</span><span class="o">=</span>bin
</span><span class='line'><span class="nv">BIN_DIR</span> <span class="o">=</span> <span class="k">$(</span>BIN_DIR_ROOT<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">BIN_DIR = $(BIN_DIR_ROOT)/debug</span>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">CCFLAGS += -g3 -O0</span>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">CXXFLAGS += -g3 -O0</span>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">SHAREDLIBS += -L$(COCOS2DX_ROOT)/lib/linux/Debug -lcocos2d -lrt -lz -lcocosdenshion</span>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">SHAREDLIBS += -Wl</span><span class="p">,</span><span class="m">-rpath</span><span class="p">,</span><span class="m">$(COCOS2DX_ROOT)/lib/linux/Debug/</span>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">DEFINES += -DDEBUG</span>
</span><span class='line'><span class="nf">debug</span><span class="o">:</span> <span class="m">$(TARGET)</span>
</span><span class='line'>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">BIN_DIR = $(BIN_DIR_ROOT)/release</span>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">CCFLAGS += -O3</span>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">CXXFLAGS += -O3</span>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">SHAREDLIBS += -L$(COCOS2DX_ROOT)/lib/linux/Release -lcocos2d -lrt -lz -lcocosdenshion</span>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">SHAREDLIBS += -Wl</span><span class="p">,</span><span class="m">-rpath</span><span class="p">,</span><span class="m">$(COCOS2DX_ROOT)/lib/linux/Release/</span>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">DEFINES += -DNDEBUG</span>
</span><span class='line'><span class="nf">release</span><span class="o">:</span> <span class="m">$(TARGET)</span>
</span><span class='line'>
</span><span class='line'><span class="c">####### Build rules</span>
</span><span class='line'><span class="k">$(</span>TARGET<span class="k">)</span>: <span class="k">$(</span>OBJECTS<span class="k">)</span>
</span><span class='line'>  mkdir -p <span class="k">$(</span>BIN_DIR<span class="k">)</span>
</span><span class='line'>  <span class="k">$(</span>CXX<span class="k">)</span> <span class="k">$(</span>CXXFLAGS<span class="k">)</span> <span class="k">$(</span>INCLUDES<span class="k">)</span> <span class="k">$(</span>DEFINES<span class="k">)</span> <span class="k">$(</span>OBJECTS<span class="k">)</span> -o <span class="k">$(</span>BIN_DIR<span class="k">)</span>/<span class="k">$(</span>TARGET<span class="k">)</span> <span class="k">$(</span>SHAREDLIBS<span class="k">)</span> <span class="k">$(</span>STATICLIBS<span class="k">)</span>
</span><span class='line'>
</span><span class='line'><span class="c">####### Compile</span>
</span><span class='line'>%.o: %.cpp
</span><span class='line'>  <span class="k">$(</span>CXX<span class="k">)</span> <span class="k">$(</span>CXXFLAGS<span class="k">)</span> <span class="k">$(</span>INCLUDES<span class="k">)</span> <span class="k">$(</span>DEFINES<span class="k">)</span> <span class="k">$(</span>VISIBILITY<span class="k">)</span> -c <span class="nv">$&lt;</span> -o <span class="nv">$@</span>
</span><span class='line'>
</span><span class='line'>%.o: %.c
</span><span class='line'>  <span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CCFLAGS<span class="k">)</span> <span class="k">$(</span>INCLUDES<span class="k">)</span> <span class="k">$(</span>DEFINES<span class="k">)</span> <span class="k">$(</span>VISIBILITY<span class="k">)</span> -c <span class="nv">$&lt;</span> -o <span class="nv">$@</span>
</span><span class='line'>
</span><span class='line'>clean:
</span><span class='line'>  rm -f <span class="k">$(</span>OBJECTS<span class="k">)</span> <span class="k">$(</span>TARGET<span class="k">)</span> core
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>需要注意 <strong>$(COCOS2DX_ROOT)</strong> 和 <strong>$(COCOS2DX_PATH)</strong>  的区别，前者是 cocos2d-x 总目录，后者是 cocos2d-x 其中基础库的目录。</p>

<p>如果需要在命令行之内直接 <code>make</code> 编译，只要创建环境变量 <code>COCOS2DX_ROOT</code> 即可。</p>

<p>修改之后，我们再次编译，运行，就能够在 Eclipse 之中运行游戏，看其效果，并且可以在代码之中设置断点，<strong>调试运行</strong> 。</p>

<h3>稍作总结</h3>

<p>在 Linux 下使用 Eclipse 开发 cocos2d-x 游戏的环境配置大致是这样的了，Eclipse 作为编写代码，自己使用 Makefile 来维护项目的编译的推荐的方式。这只是实现了基本的配置方法，实际问题远不止这些，比如 此环境是默认的，在 Eclipse 项目中引用的库文件路径还是 <strong>相对路径</strong>，如果移动到其它目录(项目肯定用我们自己的目录)，则破坏了 Eclipse 的开发环境。当然最终的编写是为了运行在手机之中，以后也会给出怎么编译到手机 Android 平台，并给出相应的推荐做法，以简化开发步骤！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Linux 环境 Cocos2d-x开发]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/04-17.html"/>
    <updated>2013-04-17T17:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/linux-cocos2dx-run</id>
    <content type="html"><![CDATA[<h2>Cocos2d-x 跨平台特性分析</h2>

<p>作为一款跨平台的 2D 游戏引擎 <a href="http://cocos2d-x.org/">Cocos2d-x</a> ，方便发布到各种移动平台，支持也在不断完善。可以跨平台运行，更据优势的是可以跨平台开发！</p>

<p>作为运行平台来说，目前主要以 <strong>iOS</strong> 和 <strong>Android</strong> 平台为多，对其它平台也有支持，如 <strong>BlackBerry </strong>平台，但基本只要满足前两者，就能达到我们跨平台运行的目的，这是由用户量决定的。</p>

<p>作为开发平台来说，常用的三种 <strong>IDE</strong>(集成开发环境) 开发方式：</p>

<ul>
<li><strong>Windows</strong> 系统下使用 <strong>Visual Stuido</strong> 开发</li>
<li><strong>Mac</strong> 系统下使用 <strong>Xcode</strong> 开发</li>
<li><strong>Linux</strong> 系统下使用 <strong>Eclipse + CDT</strong> 开发</li>
</ul>


<p>用过 Xcode 的人都说 Xcode 好用（ps:我没用过 :P），这是一套完整的开发环境，基于 <strong>llvm</strong> 的编译器，优秀的架构提供非常完善的工具链，先且不说，还有快速的模拟器，使开发过程流畅， Windows 平台的标准 IDE VS 也是易于使用，有 cocos2d-x 在 VS 中的项目模板，使开发简化了许多，并且直生成 Win32 可执行程序，即时看到运行效果。而使用 Eclipse 在 Linux 上开发 cocos2d-x 的人相对较少。并没有多少体会这样开发有什么优势！</p>

<!-- more -->


<p>以 Mac 用户来说，使用 cocos2d-x 很大原因是其跨平台（Android）的特性，否则有更为成熟的 <strong>cocos2d-iphone</strong> 可以使用，最后还是需要维护一个 Android 的开发环境，以方便移植。从 Windows 角度考虑，大多都是为了开发 Android 平台游戏，VS 作为开发来说是挺方便，但要编译到 Android 平台，就相当麻烦了，而这对于 Linux 的开发来说，相对容易，不需要开两个 IDE , VS 和 Eclipse 同时跑着了。</p>

<p>仁者见仁，智者见智，<strong>用自己最熟悉的开发环境去写程序才能发挥应有的效率</strong>。</p>

<hr />

<h2>为什么使用 Linux 开发cocos2d-x</h2>

<p>Linux 开发优势：</p>

<ul>
<li>相比 Mac 下开发来说，开发成本低，普通 PC 机即可</li>
<li>相比 Windows 开发环境，只需要熟练使用一个 IDE Eclipse 即可</li>
<li>Eclipse 作为默认的 Android 开发环境，总是不可避免要去使用</li>
<li>gcc 编译器的编译异常信息比 VS 异常信息更容易找出问题 （个人感觉，VS 异常信息有如“天书”:P）</li>
<li>默认 UTF-8 编码，Windows 下开发 cocos2d-x 乱码解决起来麻烦，而 Linux 下，没有这个问题</li>
</ul>


<p>Linux 开发劣势：</p>

<ul>
<li><strong>有所长必有所短～</strong></li>
</ul>


<hr />

<h2>Linux 下怎样运行 cocos2d-x</h2>

<p>要在 Linux 开发，我们首先要做的就是让 cocos2d-x 程序在 Linux 下跑起来。</p>

<p>开发机系统信息：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Debian 3.2.41-2 i686 GNU/Linux
</span><span class='line'>Debian/Wheezy testing
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>cocos2d-x 当前稳定版本：<code>cocos2d-2.0-x-2.0.4</code></p>

<p>下载地址：<a href="http://cocos2d-x.googlecode.com/files/cocos2d-2.0-x-2.0.4.zip">http://cocos2d-x.googlecode.com/files/cocos2d-2.0-x-2.0.4.zip</a></p>

<p>下载后解压，进入 <strong>cocos2d-2.0-x-2.0.4</strong> 目录执行脚本(编译过程需要检测依赖程序包，并且自动下载安装所需要的软件包，可以使用 <strong>sudo</strong> 提升权限运行)：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c"># [cocos2dx-path] 为 zip 解压后的目录 cocos2d-2.0-x-2.0.4 ，以后用此标示其项目目录</span>
</span><span class='line'><span class="nb">cd</span> <span class="o">[</span>cocos2dx-path<span class="o">]</span>
</span><span class='line'>
</span><span class='line'>./make-all-linux-project.sh           <span class="c"># cocos2dx-path 当前目录执行命令</span>
</span></code></pre></td></tr></table></div></figure>


<p>一会编译完毕，先不要问我这个脚本做了哪些事情，我们首先要做的就是把游戏跑起来，渐进式一点一点学习 cocos2d-x ~</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> <span class="o">[</span>cocos2dx-path<span class="o">]</span>/samples/HelloCpp/proj.linux/bin/release
</span><span class='line'>
</span><span class='line'>./HelloCpp            <span class="c"># 注意在当前目录执行 HelloCpp 以保证引用资源和库的相对路径正确</span>
</span><span class='line'>
</span><span class='line'><span class="c"># 如果出现类似一下错误，说明执行命令的路径不正确</span>
</span><span class='line'>HelloCpp: error <span class="k">while </span>loading shared libraries: libfmodex.so: cannot open shared object file: No such file or directory
</span></code></pre></td></tr></table></div></figure>


<p><strong>注意：</strong> 在编译之前确保系统环境已经安装 gcc make 等程序， <strong>Debian</strong> 可以使用如下命令安装编译环境</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>sudo apt-get install build-essential
</span><span class='line'>
</span><span class='line'>gcc version 4.7.2 <span class="o">(</span>Debian 4.7.2-5<span class="o">)</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<hr />

<p><img src="http://blog.leafsoar.com/images/2013/cocos2d-x-helloworld.jpg" alt="Hello World" /></p>

<p>至此 cocos2d-x 自带的 <strong>HelloCpp</strong> 就已经能在 Linux 平台下运行了！</p>

<p>如果想看 cocos2d-x 具体能做哪些事情，可以看看 <strong>TestCpp</strong> 例子，里面包含了 cocos2d-x 的各种使用方法以及效果，这是一个非常实用的例子，如果有什么功能需要实现，就可以参考这个项目。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> <span class="o">[</span>cocos2dx-path<span class="o">]</span>/samples/TestCpp/proj.linux/bin/release
</span><span class='line'>
</span><span class='line'>./TestCpp
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p><strong>工欲善其事 必先利其器</strong></p>

<p>后面将使用 Eclipse 来管理开发 cocos2d-x 项目 ~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[初见]]></title>
    <link href="http://blog.leafsoar.com/archives/2013/04-16.html"/>
    <updated>2013-04-16T17:30:00+08:00</updated>
    <id>http://blog.leafsoar.com/archives/2013/first</id>
    <content type="html"><![CDATA[<h2>天下至柔 驰骋天下至坚 无间落叶 无有入无间 ~</h2>

<p><img src="http://blog.leafsoar.com/images/2013/leafsoar.jpg" title="物本清华 心若琉璃 亦如止水 亦如明镜 此时只道是寻常 ~" alt="leafsoar" /></p>

<!-- more -->


<p><EMBED id=leafsoar src="http://dl.dropboxusercontent.com/u/54723974/leafsoar.mp3" width=327 height=50 type=audio/mpeg autostart="true" loop="true"></EMBED></p>
]]></content>
  </entry>
  
</feed>
