<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Easy2D 轻量级游戏开发框架</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://easy2d.cn/"/>
  <updated>2025-07-16T12:23:40.812Z</updated>
  <id>https://easy2d.cn/</id>
  
  <author>
    <name>Nomango</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>v2.0.0-beta7 更新内容简介</title>
    <link href="https://easy2d.cn/2018/05/25/easy2d-release-2-0-0-beta7/"/>
    <id>https://easy2d.cn/2018/05/25/easy2d-release-2-0-0-beta7/</id>
    <published>2018-05-25T22:05:55.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p>本次更新内容较多，但也许这是 Easy2D v2.0.0 正式版发布前的最后一个版本了。</p><p>我最近逐渐认识到，在人气不高的时候把框架的功能过于细化只能起反作用，因为细化也意味着复杂。何况当初设计这个框架的本意就是为了方便 C++ 新手学习，所以新版本 beta7 进一步简化 Easy2D ，删除了大段代码，同时也带来了一些新特性。</p><p>这次更新几乎将整个 E2D 框架重做，不要担心这会花费很大的学习成本，它只会让你更容易上手，而且会减少你对一些模糊不清的函数的疑问。</p><span id="more"></span><h3 id="Game-类更新内容"><a href="#Game-类更新内容" class="headerlink" title="Game 类更新内容"></a>Game 类更新内容</h3><p>此次更新修改了 <code>Game</code> 类的几个方法名，所以 beta7 不兼容旧的项目。</p><p>现在，一个最简单的 Easy2D 程序如下：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;easy2d.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 初始化</span></span><br><span class="line">    Game::<span class="built_in">init</span>();</span><br><span class="line">    <span class="comment">// 开始游戏</span></span><br><span class="line">    Game::<span class="built_in">start</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>重做后的 <code>Game::init</code> 方法必须在主函数的第一行调用，其他任何操作都应该在初始化成功后执行。这个方法不再设置窗口标题和大小，但你可以通过 <code>Window::setTitle</code> 方法设置窗口标题，<code>Window::setSize</code> 方法设置窗口大小。</p><p>而且你也不必再判断 <code>Game::init</code> 函数的返回值，因为初始化失败时，它将抛出异常，终止程序。你可以用下面的方法让异常处理的方式更加友好。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;easy2d.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        Game::<span class="built_in">init</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (SystemException e)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 捕获异常，并弹窗提示</span></span><br><span class="line">        Window::<span class="built_in">error</span>(e.<span class="built_in">msg</span>());</span><br><span class="line">        <span class="comment">// 结束程序</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Game::<span class="built_in">start</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Game::run</code> 函数更名为 <code>Game::start</code> ，通常它应在程序的最后一行调用，因为这个函数返回时表示游戏已经结束。这个函数会在游戏结束时自动回收游戏资源。</p><p><code>Game::uninit</code> 函数更名为 <code>Game::destroy</code> ，现在你不必手动执行这个函数，因为 <code>Game::start</code> 会自动调用它。</p><p>如果你不希望 <code>start</code> 函数自动回收资源，可以使用 <code>Game::start(false)</code> 启动游戏，然后在你需要的地方调用 <code>destroy</code> 方法。</p><h3 id="工厂模式与垃圾回收"><a href="#工厂模式与垃圾回收" class="headerlink" title="工厂模式与垃圾回收"></a>工厂模式与垃圾回收</h3><p>beta7 版本之前，e2d::Object 对象是直接用 new 运算符创建的，如下面的代码。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个精灵对象</span></span><br><span class="line"><span class="keyword">auto</span> sprite = <span class="keyword">new</span> <span class="built_in">Sprite</span>(<span class="string">&quot;image.png&quot;</span>);</span><br></pre></td></tr></table></figure><p>我在 Object 的构造函数中做了些 “手脚”，使它的内存可以被自动回收，所以你会发现示例代码中从来没有 delete 语句，但却不会发生内存泄漏。</p><p>这种做法其实很糟糕，因为你不能自由控制 new 创建的对象，而且通过其他方式创建的对象在回收时会崩溃。为了解决这个问题，beta7 版本增加了全局的 <code>Create</code> 函数。</p><p>这是一种工厂模式，你所学过的工厂模式也许是这样的：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简单工厂模式</span></span><br><span class="line">Factory::<span class="built_in">create</span>(<span class="string">&quot;Sprite&quot;</span>, <span class="string">&quot;image.png&quot;</span>);</span><br><span class="line"><span class="comment">// 另外一种简单工厂模式</span></span><br><span class="line">Factory::<span class="built_in">createSprite</span>(<span class="string">&quot;image.png&quot;</span>);</span><br></pre></td></tr></table></figure><p>通过 <code>Factory</code> 工厂来创建不同的对象，这个对象就是经过了处理的对象。还有另外一种工厂方法模式，如下</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 工厂方法模式</span></span><br><span class="line">Sprite::<span class="built_in">create</span>(<span class="string">&quot;image.png&quot;</span>);</span><br></pre></td></tr></table></figure><p>这三种方法各有优势，但它们都有一个共同缺陷：扩展性差。如果你自定义了一个 <code>Bird</code> 类，那么你就需要为它添加一个 <code>Bird::create</code> 方法，或者 <code>Factory::createBird</code> 方法，才能创建它。</p><p>beta7 版本新增了 <code>Create</code> 函数，它是一个模版函数，并拥有强大的扩展性。它的使用方法如下</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> sprite = gcnew <span class="built_in">Sprite</span>(<span class="string">&quot;image.png&quot;</span>);</span><br></pre></td></tr></table></figure><p>使用 Create 函数创建的对象将被 <code>GC(垃圾回收装置)</code> 跟踪，当这个对象不再被需要时，GC 会自动 delete 它。</p><p><code>GC</code> 判断一个对象是否需要被释放的方法如下：</p><ul><li>Object 对象保存了一个引用计数，这个计数表示它被 “使用” 的次数，初始的引用计数为 0</li><li>当引用计数 &lt;= 0 时，GC 会认为这个对象可以被回收，并在适当的时候 delete 它</li><li>当引用计数 &gt; 0 时，GC 会认为这个对象正被使用着，不会对它采取任何操作</li><li>Object 的 <code>retain</code> 和 <code>release</code> 方法可以使引用计数加一或减一</li><li><code>Game::destory</code> 方法会强制让 GC 释放所有对象</li></ul><p>比如我们使用 <code>Create</code> 函数创建了一个 <code>Scene</code> ，下面的代码展示了引用计数的变化</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个场景，此时引用计数为 0</span></span><br><span class="line"><span class="keyword">auto</span> scene = gcnew Scene;</span><br><span class="line"><span class="comment">// 进入场景，它的引用计数变为 1</span></span><br><span class="line">SceneManager::<span class="built_in">enter</span>(scene);</span><br><span class="line"><span class="comment">// 退出场景，它的引用计数变为 0，GC 会自动将 scene 回收</span></span><br><span class="line">SceneManager::<span class="built_in">back</span>();</span><br></pre></td></tr></table></figure><p>另外，你仍然可以使用 new 去创建对象，但是需要你自己去 delete。</p><h3 id="Music-重做内容"><a href="#Music-重做内容" class="headerlink" title="Music 重做内容"></a>Music 重做内容</h3><p>beta7 版本移除了 <code>MusicManager</code> 类，并新增了 <code>Player</code> 播放器类，它更加简单易用。</p><p>现在，如果你想播放一段音乐，只需要：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Player::<span class="built_in">play</span>(<span class="string">&quot;music.wav&quot;</span>);</span><br></pre></td></tr></table></figure><p>如果你想停止它，只需要：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Player::<span class="built_in">stop</span>(<span class="string">&quot;music.wav&quot;</span>);</span><br></pre></td></tr></table></figure><p>另外需要注意的是，在游戏开始之前，最好把游戏中所有的音乐预加载，防止第一次播放音乐时卡顿。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 预加载音乐</span></span><br><span class="line">Player::<span class="built_in">preload</span>(<span class="string">&quot;music.wav&quot;</span>);</span><br></pre></td></tr></table></figure><p><code>Player</code> 的所有操作都被最大限度的简化，当然这也意味着不够灵活，和受更大的限制。beta7 版本保留了 <code>Music</code> 类，你可以手动创建一个音乐对象。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个音乐对象</span></span><br><span class="line"><span class="keyword">auto</span> music = gcnew <span class="built_in">Music</span>(<span class="string">&quot;music.wav&quot;</span>);</span><br></pre></td></tr></table></figure><p>有了这个对象，你可以设置它的音量，判断它的播放状态，以及设置它播放结束时执行特定的函数。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 设置音乐对象的音量</span></span><br><span class="line">music-&gt;<span class="built_in">setVolume</span>(<span class="number">2</span>);</span><br><span class="line"><span class="comment">// 判断音乐是否正在播放</span></span><br><span class="line"><span class="type">bool</span> playing = music-&gt;<span class="built_in">isPlaying</span>();</span><br><span class="line"><span class="comment">// 设置音乐播放结束时的回调函数</span></span><br><span class="line">music-&gt;<span class="built_in">setFuncOnEnd</span>(func);</span><br></pre></td></tr></table></figure><p>虽然 <code>Music</code> 对象是通过 Create 函数创建，但它在播放时不会被引擎自动回收，直到它播放结束。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个音乐对象并播放</span></span><br><span class="line"><span class="comment">// 这个对象将在音乐结束时自动释放内存</span></span><br><span class="line"><span class="function">gcnew <span class="title">Music</span><span class="params">(<span class="string">&quot;music.wav&quot;</span>)</span>-&gt;<span class="title">play</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure><h3 id="从程序资源加载图片或音乐"><a href="#从程序资源加载图片或音乐" class="headerlink" title="从程序资源加载图片或音乐"></a>从程序资源加载图片或音乐</h3><p>现在，Easy2D 支持了从资源加载图片或音乐的功能，所以你可以把游戏中所有的图片和音乐都打包到 exe 中。</p><p>方法如下：</p><ol><li>在 VS 中右键项目 =&gt; 添加 =&gt; 资源</li><li>点击“导入” =&gt; 选择你想导入的文件 =&gt; 确认</li><li>在 cpp 中引入 resource.h</li><li>打开 VS 的“资源视图”，查看你刚刚添加的资源的名称和分类名称</li><li>通过资源名称和分类名称加载图片或音乐</li></ol><p>例如，当你导入第一张 .png 图片时，资源名称往往是 IDB_PNG1 ，资源类型是 “PNG” ，然后你就可以使用下面的代码创建一个精灵</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> s = <span class="keyword">new</span> <span class="built_in">Sprite</span>(IDB_PNG1, <span class="string">&quot;PNG&quot;</span>);</span><br></pre></td></tr></table></figure><p>PS. Visual Studio 的添加资源功能一直存在问题，偶尔会导致 VS 崩溃，而且也经常无法正常识别 resource.h 中的宏，但是它仍然可以正常编译。</p><h3 id="Timer-重做内容"><a href="#Timer-重做内容" class="headerlink" title="Timer 重做内容"></a>Timer 重做内容</h3><p><code>Timer</code> 类中的方法全都改为了静态方法，这说明你不再需要 new 一个定时器出来再去操作它，而是直接开启一个定时器，在启动时设置好它的参数即可。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加一个定时器，该定时器执行 func 函数</span></span><br><span class="line">Timer::<span class="built_in">add</span>(func);</span><br></pre></td></tr></table></figure><p>添加定时器时，你可以给它起一个名称</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加定时器，该定时器执行 func 函数</span></span><br><span class="line">Timer::<span class="built_in">add</span>(func, <span class="string">&quot;定时器&quot;</span>);</span><br></pre></td></tr></table></figure><p>这样你就可以把名字叫 “定时器” 的定时器停止或开启</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 停止名称叫 &quot;定时器&quot; 的定时器</span></span><br><span class="line">Timer::<span class="built_in">stop</span>(<span class="string">&quot;定时器&quot;</span>);</span><br><span class="line"><span class="comment">// 开启名称叫 &quot;定时器&quot; 的定时器</span></span><br><span class="line">Timer::<span class="built_in">start</span>(<span class="string">&quot;定时器&quot;</span>);</span><br></pre></td></tr></table></figure><p>添加定时器时，你还可以设置定时器的执行时间间隔、执行次数、以及创建后是否暂停</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加定时器，该定时器执行 func 函数，执行间隔为 1.5 秒，</span></span><br><span class="line"><span class="comment">// 执行次数为 10 次，创建后暂停，名称是 &quot;定时器&quot;</span></span><br><span class="line">Timer::<span class="built_in">add</span>(func, <span class="number">1.5</span>, <span class="number">10</span>, <span class="literal">true</span>, <span class="string">&quot;定时器&quot;</span>);</span><br></pre></td></tr></table></figure><p>当你不需要这个定时器时，你可以把它移除，移除的定时器无法再启动</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 移除名称叫 &quot;定时器&quot; 的定时器</span></span><br><span class="line">Timer::<span class="built_in">remove</span>(<span class="string">&quot;定时器&quot;</span>);</span><br></pre></td></tr></table></figure><p>定时器也可以在等待足够时间后执行一个函数</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 启动定时器，该定时器在 2 秒后执行一次 func 函数</span></span><br><span class="line">Timer::<span class="built_in">start</span>(<span class="number">2</span>, func);</span><br></pre></td></tr></table></figure><h3 id="Collider-重做内容"><a href="#Collider-重做内容" class="headerlink" title="Collider 重做内容"></a>Collider 重做内容</h3><p>beta7 中增加了 <code>Collider::Type</code> 枚举，可以使用 <code>Node::setCollider</code> 方法直接设置碰撞体的形状，这意味着你不需要 new 一个 Collider 再把它赋给 Node 了。</p><p><code>Collider::Type</code> 枚举有三个类型，分别是</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Collider::Type::RECT      <span class="comment">// 矩形</span></span><br><span class="line">Collider::Type::CIRCLE    <span class="comment">// 圆形</span></span><br><span class="line">Collider::Type::ELLIPSE   <span class="comment">// 椭圆形</span></span><br></pre></td></tr></table></figure><p>你应该这样去使用它</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 设置碰撞体类型为圆形</span></span><br><span class="line">node-&gt;<span class="built_in">setCollider</span>(Collider::Type::CIRCLE);</span><br></pre></td></tr></table></figure><p>碰撞体只是描述了物体的形状，你还需要告诉 Easy2D 哪些物体间可以发生碰撞。</p><p>假设节点 node1 和 node2 的名称分别为 “节点一” 和 “节点二”</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">node1-&gt;<span class="built_in">setName</span>(<span class="string">&quot;节点一&quot;</span>);</span><br><span class="line">node2-&gt;<span class="built_in">setName</span>(<span class="string">&quot;节点二&quot;</span>);</span><br></pre></td></tr></table></figure><p>如果想检测到 node1 与 node2 的碰撞，需要调用 <code>Collision::addName</code> 方法把它们的名字加进去。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加可碰撞物体名称</span></span><br><span class="line">Collision::<span class="built_in">addName</span>(<span class="string">&quot;节点一&quot;</span>, <span class="string">&quot;节点二&quot;</span>);</span><br></pre></td></tr></table></figure><p>这样设置过后，node1 和 node2 之间的碰撞就会被检测到。</p><p>为了检测碰撞的发生，你需要创建一个监听器去监听碰撞事件，方法如下</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个伪函数类</span></span><br><span class="line">Function func = CollisionListen;</span><br><span class="line"><span class="comment">// 创建一个监听器</span></span><br><span class="line"><span class="keyword">auto</span> listener = gcnew <span class="built_in">Listener</span>(func);</span><br><span class="line"><span class="comment">// 让监听器去监听碰撞事件</span></span><br><span class="line">Collision::<span class="built_in">addListener</span>(listener);</span><br><span class="line"><span class="comment">// 打开碰撞监听</span></span><br><span class="line">Collision::<span class="built_in">setEnable</span>(<span class="literal">true</span>);</span><br></pre></td></tr></table></figure><p>其中 <code>CollisionListen</code> 是一个函数，它可以定义如下</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">CollisionListen</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 判断碰撞是否由它们产生</span></span><br><span class="line">    <span class="keyword">if</span> (Collision::<span class="built_in">isCausedBy</span>(<span class="string">&quot;节点一&quot;</span>, <span class="string">&quot;节点二&quot;</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 执行相应操作</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="初始化列表"><a href="#初始化列表" class="headerlink" title="初始化列表"></a>初始化列表</h3><p>在 VS2013 及以上版本中，可以使用初始化列表一次性添加多个值。</p><p>例如，下面的代码使用初始化列表将多个节点一次性添加到场景中</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用初始化列表一次添加多个值</span></span><br><span class="line">scene-&gt;<span class="built_in">add</span>(&#123; node1, node2, node3 &#125;);</span><br></pre></td></tr></table></figure><p>再如，一次性添加多个可碰撞物体名称</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用初始化列表一次添加多个值</span></span><br><span class="line">Collision::<span class="built_in">addName</span>(&#123;</span><br><span class="line">    &#123; <span class="string">&quot;节点一&quot;</span>, <span class="string">&quot;节点二&quot;</span> &#125;,</span><br><span class="line">    &#123; <span class="string">&quot;节点一&quot;</span>, <span class="string">&quot;节点三&quot;</span> &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>再如，一次性添加多个 Image 到 Animation 中</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用初始化列表一次添加多个值</span></span><br><span class="line">animation-&gt;<span class="built_in">add</span>(&#123; image1, image2, image3 &#125;);</span><br></pre></td></tr></table></figure><h3 id="其他新功能"><a href="#其他新功能" class="headerlink" title="其他新功能"></a>其他新功能</h3><ul><li><code>Text</code> 现在具备了简单的文字排版能力，包括文字描边、行间距、对齐方式、自动换行、下划线、删除线等。</li><li><code>String::format</code> 支持创建格式化的字符串，如下所示</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 字符串 str 的值为 &quot;level 12&quot;</span></span><br><span class="line">String str = String::format(<span class="string">&quot;level %d&quot;</span>, <span class="number">12</span>);</span><br></pre></td></tr></table></figure><ul><li><p>调用 <code>Renderer::showFps</code> 函数可以显示画面的 FPS 值</p></li><li><p><code>NodeProperty</code> 结构体可获取节点的所有属性，如下所示</p></li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取节点所有属性</span></span><br><span class="line">NodeProperty prop = node-&gt;<span class="built_in">getProperty</span>();</span><br><span class="line"><span class="comment">// 设置节点所有属性</span></span><br><span class="line">node-&gt;<span class="built_in">setProperty</span>(prop);</span><br></pre></td></tr></table></figure><p>更多新内容请到入门教程中查看。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;本次更新内容较多，但也许这是 Easy2D v2.0.0 正式版发布前的最后一个版本了。&lt;/p&gt;
&lt;p&gt;我最近逐渐认识到，在人气不高的时候把框架的功能过于细化只能起反作用，因为细化也意味着复杂。何况当初设计这个框架的本意就是为了方便 C++ 新手学习，所以新版本 beta7 进一步简化 Easy2D ，删除了大段代码，同时也带来了一些新特性。&lt;/p&gt;
&lt;p&gt;这次更新几乎将整个 E2D 框架重做，不要担心这会花费很大的学习成本，它只会让你更容易上手，而且会减少你对一些模糊不清的函数的疑问。&lt;/p&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>v2.0.0-beta6 更新内容简介</title>
    <link href="https://easy2d.cn/2018/03/13/easy2d-release-2-0-0-beta6/"/>
    <id>https://easy2d.cn/2018/03/13/easy2d-release-2-0-0-beta6/</id>
    <published>2018-03-13T23:22:30.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p>此次更新主要针对以下几点：</p><ul><li>没有专门用来监听用户输入的工具类</li><li>Shape 形状类使用起来太繁琐</li></ul><h3 id="命名上的一些变化"><a href="#命名上的一些变化" class="headerlink" title="命名上的一些变化"></a>命名上的一些变化</h3><p><code>File</code> 类更名为 <code>Path</code> 类，因为这个类只提供一些系统路径、数据保存路径等。</p><span id="more"></span><h3 id="监听器"><a href="#监听器" class="headerlink" title="监听器"></a>监听器</h3><p>时隔两个月，我们又将 Listener（监听器）这一概念加了进来，它配合 <code>Input</code> 类可以达到监听用户按键和鼠标消息的功能。</p><p>监听器的执行方式和定时器类似，在监听到用户输入时执行回调函数。你需要先创建一个回调函数。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">GetInput</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 假设存在精灵 sprite</span></span><br><span class="line">    <span class="comment">// 用户按下右键时，将精灵向右移动</span></span><br><span class="line">    <span class="keyword">if</span> (Input::<span class="built_in">isKeyDown</span>(KeyCode::RIGHT))</span><br><span class="line">    &#123;</span><br><span class="line">        sprite-&gt;<span class="built_in">movePosX</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后创建一个监听器，并启动它。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建监听器</span></span><br><span class="line"><span class="keyword">auto</span> l = <span class="keyword">new</span> <span class="built_in">Listener</span>();</span><br><span class="line"><span class="comment">// 设置监听器的回调函数为 GetInput 函数</span></span><br><span class="line">l-&gt;<span class="built_in">setCallback</span>(GetInput);</span><br><span class="line"><span class="comment">// 启动监听器</span></span><br><span class="line">l-&gt;<span class="built_in">start</span>();</span><br></pre></td></tr></table></figure><p>监听器启动后，当检测到用户按键时，它会自动执行 GetInput 函数，判断用户按下的是否是右键，如果是，移动精灵。</p><p>如果你觉得创建监听器的方法太繁琐，可以直接使用 <code>Input::add</code> 函数添加一个监听器。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加监听器</span></span><br><span class="line">Input::<span class="built_in">add</span>(GetInput);</span><br></pre></td></tr></table></figure><p><code>Input::add</code> 函数把 GetInput 函数添加到了监听队列中，检测到用户输入时自动执行 GetInput 函数。</p><h3 id="默认形状"><a href="#默认形状" class="headerlink" title="默认形状"></a>默认形状</h3><p>为了让 Shape（形状）更好使用，现在每个节点都默认包含了一个矩形形状。</p><p>让我们看看 FlappyBird 游戏中展现的效果。调用场景的 <code>Scene::setShapeVisiable</code> 函数，让形状可见，如下图所示</p><p><img src="FlappyBird-screenshot.png" alt="FlappyBird截图"></p><p>可以看到，即使没有创建 Shape，所有的图形边框也都被显示了出来。这在 Debug 时很有帮助，同时也能更好的帮助我们观察游戏中物体的运动。</p><p>之前 Shape 类是为了检测物体间碰撞存在的，现在所有节点都有 Shape，为了防止碰撞的频繁发生，也为了游戏性能，碰撞检测默认是关闭的，可以通过 <code>ShapeManager::setCollisionEnable</code> 函数重新启用。开启后，当 ShapeManager 检测到碰撞发生时，会自动调用发生碰撞节点和其所在场景的 <code>onCollide</code> 函数。</p><p>如果你不想让节点包含默认形状，可以通过 <code>Node::setDefaultShapeEnable</code> 函数开启或关闭。关闭后，新建的节点将不包含默认形状。</p><h3 id="数据字段属性"><a href="#数据字段属性" class="headerlink" title="数据字段属性"></a>数据字段属性</h3><p><code>Data</code> 类用来保存用户的数据，它将数据和键值对应保存，当用户需要取出数据时，可以根据键值取出相应的数据。键值和数据的关系就像钥匙和抽屉，一把钥匙对应一个抽屉，一个键值也对应一个数据。</p><p>现在，Data 增加了 <code>字段</code> 这个新属性，就好比柜子，一个柜子有很多个抽屉，你可以把数据放置到不同的柜子里。这样，用同一把钥匙，可以在不同的柜子打开不同的抽屉。</p><p>Data 保存的文件名也可以通过 <code>Data::setDataFileName</code> 设置（注意：不应有特殊字符和后缀名），就好比房间的概念。</p><p>简单来说，一个房间里面有很多个柜子，柜子里有很多个抽屉，一个抽屉里面放着一个物品。<br>对应到 Data 上，一个数据文件有很多个字段，字段里有很多个键值，一个键值对应一个数据。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次更新主要针对以下几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有专门用来监听用户输入的工具类&lt;/li&gt;
&lt;li&gt;Shape 形状类使用起来太繁琐&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;命名上的一些变化&quot;&gt;&lt;a href=&quot;#命名上的一些变化&quot; class=&quot;headerlink&quot; title=&quot;命名上的一些变化&quot;&gt;&lt;/a&gt;命名上的一些变化&lt;/h3&gt;&lt;p&gt;&lt;code&gt;File&lt;/code&gt; 类更名为 &lt;code&gt;Path&lt;/code&gt; 类，因为这个类只提供一些系统路径、数据保存路径等。&lt;/p&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>v2.0.0-beta5 更新内容简介</title>
    <link href="https://easy2d.cn/2018/03/06/easy2d-release-2-0-0-beta5/"/>
    <id>https://easy2d.cn/2018/03/06/easy2d-release-2-0-0-beta5/</id>
    <published>2018-03-06T15:47:08.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p>此次更新主要针对以下几个点：</p><ul><li>MusicManager（音乐播放器）存在隐患，且新手不易察觉</li><li>有些人 Unicode 和 ANSI 傻傻分不清楚</li><li>对于新手来说 Timer（定时器）的用法过于复杂</li><li>没有判断节点碰撞的简单方法</li></ul><span id="more"></span><h3 id="命名上的一些变化"><a href="#命名上的一些变化" class="headerlink" title="命名上的一些变化"></a>命名上的一些变化</h3><p>首先要说明的是函数命名上发生了一些变化</p><p>例如，进入场景函数 <code>SceneManager::enterScene</code> 改为了 <code>SceneManager::enter</code>，改名的原因是太啰嗦，场景管理器的 enter 函数必然是进入场景，不用再加一个 Scene 后缀。</p><p>更名的函数有</p><ul><li><code>SceneManager::enterScene</code> =&gt; <code>SceneManager::enter</code></li><li><code>SceneManager::backScene</code> =&gt; <code>SceneManager::back</code></li><li><code>MusicManager::add</code> =&gt; <code>MusicManager::preload</code></li><li><code>Image::loadFrom</code> =&gt; <code>Image::open</code></li><li><code>Text::setWordWrapping</code> =&gt; <code>Text::setWordWrappingEnable</code></li><li><code>Timer::setRepeatTimes</code> =&gt; <code>Timer::setUpdateTimes</code></li></ul><h3 id="音乐播放器更新"><a href="#音乐播放器更新" class="headerlink" title="音乐播放器更新"></a>音乐播放器更新</h3><p>曾经的 <code>MusicManager</code> 需要用 <code>get</code> 函数获取一个 <code>Music</code> 对象的指针，这个指针可能为空指针（如果找不到那个音乐文件），这是个新手可能忽略的安全隐患。</p><p>新的 <code>MusicManager</code> 可以直接使用 <code>play</code>、<code>pause</code>、<code>resume</code>、<code>stop</code>这四个函数控制音乐的播放、暂停、继续、停止，而不需要考虑空指针的问题。如果你播放了一个不存在的音乐文件，游戏不会崩溃也不会暂停，而是在控制台输出一条警告信息。</p><p>另外，<code>Music</code> 类现在可以手动创建（上一个版本不能创建 Music 对象），不过不建议这样使用。</p><h3 id="判断两节点是否碰撞的简单方法"><a href="#判断两节点是否碰撞的简单方法" class="headerlink" title="判断两节点是否碰撞的简单方法"></a>判断两节点是否碰撞的简单方法</h3><p>一直以来我都忘了 1.x 中一个非常好用的函数，现在我把它重新添加了进来</p><p><code>Node::isIntersectWith</code> 函数用来判断两个节点是否相交，也就是碰撞，这个函数返回 true 说明发生了碰撞。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 假设存在节点 node1 和 node2</span></span><br><span class="line"><span class="comment">// 判断两节点是否碰撞</span></span><br><span class="line"><span class="keyword">if</span> (node1-&gt;<span class="built_in">isIntersectWith</span>(node2))</span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// 两节点发生碰撞</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="字符串操作更新"><a href="#字符串操作更新" class="headerlink" title="字符串操作更新"></a>字符串操作更新</h3><p>对于现在的 String 来说，Unicode 和 ANSI 没有任何区别，这是 <code>String</code> 类的新功能~</p><p>所以下面的写法都是对的</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ANSI 版</span></span><br><span class="line">String str = <span class="string">&quot;你好&quot;</span>;</span><br><span class="line"><span class="comment">// Unicode 版</span></span><br><span class="line">String str = <span class="string">L&quot;你好&quot;</span>;</span><br><span class="line">String str = _T(<span class="string">&quot;你好&quot;</span>);</span><br><span class="line">String str = <span class="built_in">TEXT</span>(<span class="string">&quot;你好&quot;</span>);</span><br></pre></td></tr></table></figure><p>如果你不考虑性能问题的话，直接使用 ANSI 字符串会非常方便（其实不会影响多少性能）</p><p>另外新的 String 可以方便地转换成整数、浮点数，例如下面的代码</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">String str = <span class="string">&quot;123&quot;</span>;</span><br><span class="line"><span class="type">int</span> x = str.<span class="built_in">toInt</span>();    <span class="comment">// x 的值为 123</span></span><br></pre></td></tr></table></figure><p><code>String::toInt</code>、<code>String::toDouble</code>、<code>String::toBool</code>函数用于将字符串转化成不同的类型。</p><p>其他类型的值也可以使用<code>String::toString</code>非常方便地转化成字符串</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> x = <span class="number">123</span>;</span><br><span class="line">String str = String::<span class="built_in">toString</span>(x);   <span class="comment">// 字符串的值为 &quot;123&quot;</span></span><br></pre></td></tr></table></figure><p>使用 <code>&lt;&lt;</code> 运算符可以将任意类型的值存入字符串，如下所示</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">String str;</span><br><span class="line">str &lt;&lt; <span class="string">&quot;Hello &quot;</span> &lt;&lt; <span class="number">2017</span> &lt;&lt; <span class="string">&quot;!&quot;</span>;</span><br><span class="line"><span class="comment">// 在控制台输出 str 的值，显示 &quot;Hello 2017!&quot;</span></span><br><span class="line">std::cout &lt;&lt; str;</span><br></pre></td></tr></table></figure><p>上面的代码中，在将内容存入 str 的同时，自动将整型2017的值转化为了字符串。</p><h3 id="定时器更新"><a href="#定时器更新" class="headerlink" title="定时器更新"></a>定时器更新</h3><p>新版本的定时器可谓是重焕新生 (&gt;▽&lt;)，再也不用使用什么烦人的 std::bind 函数了！例如我们想在游戏启动一段时间后在控制台输出一个 Hello，可以用下面的代码做到</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;easy2d.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 控制台输出 Hello</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Hello!&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Game::<span class="built_in">init</span>(<span class="string">&quot;Test&quot;</span>, <span class="number">300</span>, <span class="number">300</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 打开控制台</span></span><br><span class="line">    Window::<span class="built_in">showConsole</span>();</span><br><span class="line">    <span class="comment">// 2 秒后自动一次执行 Test 函数</span></span><br><span class="line">    TimerManager::<span class="built_in">start</span>(<span class="number">2</span>, Test);</span><br><span class="line"></span><br><span class="line">    Game::<span class="built_in">run</span>();</span><br><span class="line">    Game::<span class="built_in">uninit</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面的代码运行后，程序运行后的第 2 秒会输出一个 Hello。</p><p>上面的代码中，Test函数只管输出，让 TimerManager 控制何时执行 Test 函数。<code>TimerManager::start</code> 函数需要两个参数，第一个表示等待时长，第二个表示执行的函数，比如 TimerManager::start(2, Test) 的意思就是 2 秒后自动执行一次 Test 函数。</p><p><code>Timer</code> 定时器类可以更灵活地使用定时功能，首先你得创建一个定时器</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个定时器，它与 Test 函数绑定了</span></span><br><span class="line"><span class="keyword">auto</span> timer = <span class="keyword">new</span> <span class="built_in">Timer</span>(Test);</span><br></pre></td></tr></table></figure><p>然后该怎么做，绑定在节点上吗？还是添加到 TimerManager 中？</p><p>这都是曾经的用法了，现在的 Timer 只需要 start（启动）</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 启动定时器</span></span><br><span class="line">timer-&gt;<span class="built_in">start</span>();</span><br></pre></td></tr></table></figure><p>然后这个定时器将会疯狂输出 “Hello”。</p><p>如果 Test 函数是类的成员函数，那么定时器需要函数名和对象指针。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Test</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Hello!&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 如果想让定时器执行 Test::test 函数，应使用下面的写法 */</span></span><br><span class="line"><span class="comment">// 创建一个 Test 对象</span></span><br><span class="line"><span class="keyword">auto</span> t = <span class="keyword">new</span> <span class="built_in">Test</span>();</span><br><span class="line"><span class="comment">// 创建定时器的函数（回调函数）</span></span><br><span class="line">TimerCallback tcb = <span class="built_in">CreateCallback</span>(t, Test::test);</span><br><span class="line"><span class="comment">// 创建定时器</span></span><br><span class="line"><span class="keyword">auto</span> timer = <span class="keyword">new</span> <span class="built_in">Timer</span>();</span><br><span class="line"><span class="comment">// 启动定时器</span></span><br><span class="line">timer-&gt;<span class="built_in">start</span>();</span><br></pre></td></tr></table></figure><p>其中 CreateCallback(t, Test::test) 的意思是，创建一个定时器的执行函数，它让 t 对象执行 test 函数。</p><p>有关定时器的更多用法请看 <a href="/tutorial/tools.html#Timer-定时器类">入门教程-定时器</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次更新主要针对以下几个点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MusicManager（音乐播放器）存在隐患，且新手不易察觉&lt;/li&gt;
&lt;li&gt;有些人 Unicode 和 ANSI 傻傻分不清楚&lt;/li&gt;
&lt;li&gt;对于新手来说 Timer（定时器）的用法过于复杂&lt;/li&gt;
&lt;li&gt;没有判断节点碰撞的简单方法&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D v2.0.0-beta2 发布</title>
    <link href="https://easy2d.cn/2017/11/09/easy2d-release-2-0-0-beta2/"/>
    <id>https://easy2d.cn/2017/11/09/easy2d-release-2-0-0-beta2/</id>
    <published>2017-11-09T21:00:27.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p>此次版本更新的内容有：</p><ul><li><code>新增</code> EButtonToggle开关按钮类；</li><li><code>新增</code> EMenu菜单类；</li><li><code>新增</code> 监听器增加吞噬消息功能；</li><li><code>新增</code> ENode::setDefaultPivot函数，用于设置节点的默认中心点；</li><li><code>更新</code> EButton的监听方法；</li><li><code>更新</code> 更新了判断点是否在节点内的算法；</li><li><code>更新</code> 中心点默认位置改为(0,0)；</li><li><code>修复</code> EFont某些情况下崩溃的bug；</li><li><code>修复</code> EButton没有获取启用和禁用状态的函数的bug；</li><li><code>修复</code> EButton不显示禁用状态的bug；</li><li><code>修复</code> 所有回调函数不检测空引用就执行的bug；</li><li><code>修复</code> EFileUtils中参数类型与EString不兼容的问题；</li><li><code>修复</code> 子节点与父节点相对位置错误的bug；</li><li><code>修复</code> 修复了其他的一些小bug。</li></ul><span id="more"></span><p>目前存在的已知 BUG 有：</p><ul><li>更新节点的二维矩阵变换算法后，场景切换动画不正常的问题</li><li>循环播放音乐的暂停问题</li><li>播放音乐时偶尔造成卡顿的问题</li><li>背景音乐没有预加载函数的问题</li><li>设置音量后，新添加的音乐音量仍然为最大的问题</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; EButtonToggle开关按钮类；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; EMenu菜单类；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 监听器增加吞噬消息功能；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; ENode::setDefaultPivot函数，用于设置节点的默认中心点；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; EButton的监听方法；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 更新了判断点是否在节点内的算法；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 中心点默认位置改为(0,0)；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; EFont某些情况下崩溃的bug；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; EButton没有获取启用和禁用状态的函数的bug；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; EButton不显示禁用状态的bug；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 所有回调函数不检测空引用就执行的bug；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; EFileUtils中参数类型与EString不兼容的问题；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 子节点与父节点相对位置错误的bug；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 修复了其他的一些小bug。&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D v2.0.0 测试版发布！</title>
    <link href="https://easy2d.cn/2017/11/05/easy2d-release-2-0-0-beta/"/>
    <id>https://easy2d.cn/2017/11/05/easy2d-release-2-0-0-beta/</id>
    <published>2017-11-05T00:13:40.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p>Easy2D 迎来了一个全新的版本！新版本的引擎使用 Direct2D 进行渲染，功能和性能都得到了大幅提升！</p><p>v2.0.0 测试版引入了节点、支点、几何形状等新概念，新增了碰撞检测功能。想了解更多相关信息请查看 <a href="/tutorial">[Easy2D 入门教程]</a></p><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Easy2D 迎来了一个全新的版本！新版本的引擎使用 Direct2D 进行渲染，功能和性能都得到了大幅提升！&lt;/p&gt;
&lt;p&gt;v2.0.0 测试版引入了节点、支点、几何形状等新概念，新增了碰撞检测功能。想了解更多相关信息请查看 &lt;a href=&quot;/tutorial&quot;&gt;[Easy2D 入门教程]&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.1.2 发布啦！</title>
    <link href="https://easy2d.cn/2017/10/09/easy2d-release-1-1-2/"/>
    <id>https://easy2d.cn/2017/10/09/easy2d-release-1-1-2/</id>
    <published>2017-10-09T14:54:38.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p>此次版本更新的内容有：</p><ul><li><code>新增</code> 新增Timer::addTimer重载函数，默认时间间隔为20毫秒</li><li><code>新增</code> 新增Sprite::runAction函数，实际效果与addAction相同</li><li><code>修复</code> 批量节点的移动问题</li><li><code>修复</code> Sprite进行碰撞判断时的bug</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 新增Timer::addTimer重载函数，默认时间间隔为20毫秒&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 新增Sprite::runAction函数，实际效果与addAction相同&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 批量节点的移动问题&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; Sprite进行碰撞判断时的bug&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.1.1 发布啦！</title>
    <link href="https://easy2d.cn/2017/10/08/easy2d-release-1-1-1/"/>
    <id>https://easy2d.cn/2017/10/08/easy2d-release-1-1-1/</id>
    <published>2017-10-08T19:20:20.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>此次版本更新的内容有：</p><ul><li><code>新增</code> Image::load 函数实现图片的预加载</li><li><code>新增</code> Math类和random函数，可以获取任意范围内的随机数</li><li><code>新增</code> 对监听器、定时器和动画加入了等待和唤醒机制</li><li><code>新增</code> BatchSprite::addAction函数，使所有精灵同时执行同一个动画</li><li><code>新增</code> Sprite暂停、继续、停止动画</li><li><code>新增</code> Action::getTarget函数，获取执行该动作的目标</li><li><code>更新</code> 重整了场景切换时的流程，应重写Scene::init函数对场景进行初始化</li><li><code>更新</code> 使用图片缓存机制防止重复加载同一图片</li><li><code>更新</code> 获取鼠标消息改为MouseMsg::getMsg</li><li><code>更新</code> Object不再自动释放，除非调用autoRelease函数将其加入释放管理池中</li><li><code>更新</code> 取消安全宏，改用inline函数代替</li><li><code>更新</code> tstring宏改为类型定义TString</li><li><code>更新</code> 动作初始化的时机改为第一次运行时</li><li><code>修复</code> App::free 和 App::destory 函数造成内存泄漏的bug函数造成内存泄漏的bug</li><li><code>修复</code> BatchNode清空所有节点时，未销毁子节点的bug</li><li><code>修复</code> 创建窗口时重置AppName的bug</li><li><code>修复</code> 重置动画时的一些bug</li><li><code>修复</code> Image裁剪图片范围越界导致图片不显示的bug</li><li><code>修复</code> ActionManager在动作执行时添加动作崩溃的bug</li><li><code>修复</code> Sprite未设置图片时崩溃的bug</li><li><code>修复</code> Action在拷贝和逆向拷贝时导致错误的BUG</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; Image::load 函数实现图片的预加载&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; Math类和random函数，可以获取任意范围内的随机数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 对监听器、定时器和动画加入了等待和唤醒机制&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; BatchSprite::addAction函数，使所有精灵同时执行同一个动画&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; Sprite暂停、继续、停止动画&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; Action::getTarget函数，获取执行该动作的目标&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 重整了场景切换时的流程，应重写Scene::init函数对场景进行初始化&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 使用图片缓存机制防止重复加载同一图片&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 获取鼠标消息改为MouseMsg::getMsg&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; Object不再自动释放，除非调用autoRelease函数将其加入释放管理池中&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 取消安全宏，改用inline函数代替&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; tstring宏改为类型定义TString&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 动作初始化的时机改为第一次运行时&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; App::free 和 App::destory 函数造成内存泄漏的bug函数造成内存泄漏的bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; BatchNode清空所有节点时，未销毁子节点的bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 创建窗口时重置AppName的bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 重置动画时的一些bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; Image裁剪图片范围越界导致图片不显示的bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; ActionManager在动作执行时添加动作崩溃的bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; Sprite未设置图片时崩溃的bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; Action在拷贝和逆向拷贝时导致错误的BUG&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.1.0 发布啦！</title>
    <link href="https://easy2d.cn/2017/09/27/easy2d-release-1-1-0/"/>
    <id>https://easy2d.cn/2017/09/27/easy2d-release-1-1-0/</id>
    <published>2017-09-27T15:26:34.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>从上个版本更新动画以来，各种BUG搞得我头都大了，昨天通宵改到两点半终于实现了一个较稳定的版本。</p><p>此次版本更新的内容有：</p><ul><li><code>新增</code> 批精灵<code>BatchSprite</code>，可以同时管理多个精灵的属性</li><li><code>新增</code> 矩形节点<code>RectNode</code>，可以方便的判断矩形碰撞和其他矩形操作</li><li><code>新增</code> 文本类、图片类、精灵类、按钮类现在都继承自<code>RectNode</code></li><li><code>修复</code> 图片默认透明度为 0 的BUG</li><li><code>修复</code> 执行缩放动画时的BUG</li><li><code>修复</code> 帧动画和其他动画一起使用时动画混乱的BUG</li><li><code>修复</code> 按钮设置了不同大小的图片时，范围判断不准确的BUG</li><li><code>修复</code> 上个版本删除定时器会崩溃的BUG</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;从上个版本更新动画以来，各种BUG搞得我头都大了，昨天通宵改到两点半终于实现了一个较稳定的版本。&lt;/p&gt;
&lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 批精灵&lt;code&gt;BatchSprite&lt;/code&gt;，可以同时管理多个精灵的属性&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 矩形节点&lt;code&gt;RectNode&lt;/code&gt;，可以方便的判断矩形碰撞和其他矩形操作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 文本类、图片类、精灵类、按钮类现在都继承自&lt;code&gt;RectNode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 图片默认透明度为 0 的BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 执行缩放动画时的BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 帧动画和其他动画一起使用时动画混乱的BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 按钮设置了不同大小的图片时，范围判断不准确的BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 上个版本删除定时器会崩溃的BUG&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.1.0 测试版发布啦！</title>
    <link href="https://easy2d.cn/2017/09/25/easy2d-release-1-1-0-beta/"/>
    <id>https://easy2d.cn/2017/09/25/easy2d-release-1-1-0-beta/</id>
    <published>2017-09-25T16:28:42.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>再也不用为动画头疼了！运行动画只需两步——创建一个动画，然后让一个<code>精灵(Sprite)</code>对象运行它！<br>目前实现的动画共有 14 种，包括 10 种持续性动画（相对位移、绝对位移、透明度渐变、淡入淡出、大小渐变、帧动画、延迟）和 4 种逻辑动作（连续两动画、连续多动画、循环动画、回调动作）</p><p>此次版本更新的内容有：</p><ul><li><code>新增</code> 精灵类<code>Sprite</code>，可以执行动作<code>Action</code>、判断两精灵碰撞等</li><li><code>新增</code> 动作类<code>Action</code>，实现了 14 种动作，所有动作都可以暂停、继续和停止</li><li><code>新增</code> 动画管理器<code>ActionManager</code>，用于管理所有当前存在的动作</li><li><code>新增</code> 图片类新增透明度设置函数<code>setOpacity</code></li><li><code>更新</code> App 类的大部分函数都改为了静态方法，但仍保留<code>get</code>方法以保证兼容性</li><li><code>修复</code> 图片类按比例拉伸函数名改为<code>setScale</code></li><li><code>修复</code> 其他细节上的优化</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;再也不用为动画头疼了！运行动画只需两步——创建一个动画，然后让一个&lt;code&gt;精灵(Sprite)&lt;/code&gt;对象运行它！&lt;br&gt;目前实现的动画共有 14 种，包括 10 种持续性动画（相对位移、绝对位移、透明度渐变、淡入淡出、大小渐变、帧动画、延迟）和 4 种逻辑动作（连续两动画、连续多动画、循环动画、回调动作）&lt;/p&gt;
&lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 精灵类&lt;code&gt;Sprite&lt;/code&gt;，可以执行动作&lt;code&gt;Action&lt;/code&gt;、判断两精灵碰撞等&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 动作类&lt;code&gt;Action&lt;/code&gt;，实现了 14 种动作，所有动作都可以暂停、继续和停止&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 动画管理器&lt;code&gt;ActionManager&lt;/code&gt;，用于管理所有当前存在的动作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; 图片类新增透明度设置函数&lt;code&gt;setOpacity&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; App 类的大部分函数都改为了静态方法，但仍保留&lt;code&gt;get&lt;/code&gt;方法以保证兼容性&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 图片类按比例拉伸函数名改为&lt;code&gt;setScale&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 其他细节上的优化&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>从文件中快速存取游戏数据</title>
    <link href="https://easy2d.cn/2017/09/20/fileutils-usage/"/>
    <id>https://easy2d.cn/2017/09/20/fileutils-usage/</id>
    <published>2017-09-20T13:11:52.000Z</published>
    <updated>2025-07-16T12:23:40.812Z</updated>
    
    <content type="html"><![CDATA[<p><code>1.0.4</code>版本新增了将数据保存到文件的功能，可以快速存取简单的数据类型。</p><p>要使用这个功能，首先应该设置你的<code>AppName</code>。AppName 是你游戏的唯一标识，它的默认值和你的窗口名称相同，用于区别其他人做的同类游戏。如果你做了“推箱子”这个游戏而没有设置 AppName，当你运行其他人做的推箱子时，你保存的数据文件就有可能被覆盖。</p><span id="more"></span><p>应在创建 App 对象，并调用 createWindow 函数后设置 AppName，例如：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">App app;</span><br><span class="line">app.<span class="built_in">createWindow</span>(_T(<span class="string">&quot;推箱子&quot;</span>), <span class="number">640</span>, <span class="number">480</span>);</span><br><span class="line">app.<span class="built_in">setAppName</span>(_T(<span class="string">&quot;PushBox-Werelone&quot;</span>));   <span class="comment">// 可以用作者的名称标识这个游戏</span></span><br></pre></td></tr></table></figure><blockquote><p>注意：不要在AppName中设置特殊字符，也尽量不使用中文，防止字符集问题导致错误。</p></blockquote><p><code>FileUtils</code>支持保存的数据类型有<code>int</code>、<code>double</code>和字符串，对应的函数分别如下</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 保存</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">FileUtils::saveInt</span><span class="params">(LPCTSTR key, <span class="type">int</span> value)</span></span>;           <span class="comment">// 保存 int 型的值</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">FileUtils::saveDouble</span><span class="params">(LPCTSTR key, <span class="type">double</span> value)</span></span>;     <span class="comment">// 保存 double 型的值</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">FileUtils::saveString</span><span class="params">(LPCTSTR key, tstring value)</span></span>;    <span class="comment">// 保存 字符串 型的值</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 读取</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">FileUtils::getInt</span><span class="params">(LPCTSTR key, <span class="type">int</span> <span class="keyword">default</span>)</span></span>;           <span class="comment">// 获取 int 型的值</span></span><br><span class="line"><span class="function"><span class="type">double</span> <span class="title">FileUtils::getDouble</span><span class="params">(LPCTSTR key, <span class="type">double</span> <span class="keyword">default</span>)</span></span>;  <span class="comment">// 获取 double 型的值</span></span><br><span class="line"><span class="function">tstring <span class="title">FileUtils::getString</span><span class="params">(LPCTSTR key, tstring <span class="keyword">default</span>)</span></span>;<span class="comment">// 获取 字符串 型的值</span></span><br></pre></td></tr></table></figure><p>第一个参数<code>key</code>用于标识保存的这个变量，例如游戏现在进行到第五关，你想保存这个值，就可以使用</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> level = <span class="number">5</span>;</span><br><span class="line">FileUtils::<span class="built_in">saveInt</span>(_T(<span class="string">&quot;level&quot;</span>), level);    <span class="comment">// 保存当前关卡</span></span><br></pre></td></tr></table></figure><p>保存之后，可以根据这个数据的<code>key</code>把它取出</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> level = FileUtils::<span class="built_in">getInt</span>(_T(<span class="string">&quot;level&quot;</span>), <span class="number">1</span>);    <span class="comment">// 取出之前保存的关卡值</span></span><br></pre></td></tr></table></figure><p>若使用了一个不存在的<code>key</code>，则会用第二个参数的值作为默认值</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> level = FileUtils::<span class="built_in">getInt</span>(_T(<span class="string">&quot;test&quot;</span>), <span class="number">1</span>);    <span class="comment">// 没有 test 对应的值，则 level 为 1</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意: AppName、数据的key、保存的字符串中含有中文时，在Unicode工程下会出现错误</strong></p></blockquote><p><code>FileUtils</code>将数据文件保存在系统的 AppData\Local 文件夹里，数据并不是加密的，你可以在 AppData\Local\你的AppName\DefaultData.ini 中找到保存的数据。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;code&gt;1.0.4&lt;/code&gt;版本新增了将数据保存到文件的功能，可以快速存取简单的数据类型。&lt;/p&gt;
&lt;p&gt;要使用这个功能，首先应该设置你的&lt;code&gt;AppName&lt;/code&gt;。AppName 是你游戏的唯一标识，它的默认值和你的窗口名称相同，用于区别其他人做的同类游戏。如果你做了“推箱子”这个游戏而没有设置 AppName，当你运行其他人做的推箱子时，你保存的数据文件就有可能被覆盖。&lt;/p&gt;
    
    </summary>
    
    
      <category term="技术专区" scheme="https://easy2d.cn/tags/%E6%8A%80%E6%9C%AF%E4%B8%93%E5%8C%BA/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.0.4 发布啦！</title>
    <link href="https://easy2d.cn/2017/09/20/easy2d-release-1-0-4/"/>
    <id>https://easy2d.cn/2017/09/20/easy2d-release-1-0-4/</id>
    <published>2017-09-20T12:47:09.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>此次版本更新的内容有：</p><ul><li><code>新增</code> App 类增加<code>setAppName</code>和<code>getAppName</code>函数，用于设置你游戏的唯一标识</li><li><code>新增</code> FileUtils 增加了<code>int</code>、<code>double</code>、<code>string</code>类型的数据存取功能，具体用法<a href="/2017/09/20/fileutils-usage">点击这里查看</a></li><li><code>新增</code> MusicUtils 现在可以设置游戏内的音量大小了</li><li><code>更新</code> 重新整理了函数的命名，新的命名规则<a href="/examples/advanced.html#关于函数命名">点击这里查看</a></li><li><code>更新</code> 去除了 MouseMsg 的<code>getMsg</code>函数</li><li><code>修复</code> MusicUtils 无法循环播放音乐的 BUG</li><li><code>修复</code> Image 裁剪图片和拉伸图片时的 BUG</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; App 类增加&lt;code&gt;setAppName&lt;/code&gt;和&lt;code&gt;getAppName&lt;/code&gt;函数，用于设置你游戏的唯一标识&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; FileUtils 增加了&lt;code&gt;int&lt;/code&gt;、&lt;code&gt;double&lt;/code&gt;、&lt;code&gt;string&lt;/code&gt;类型的数据存取功能，具体用法&lt;a href=&quot;/2017/09/20/fileutils-usage&quot;&gt;点击这里查看&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; MusicUtils 现在可以设置游戏内的音量大小了&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 重新整理了函数的命名，新的命名规则&lt;a href=&quot;/examples/advanced.html#关于函数命名&quot;&gt;点击这里查看&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 去除了 MouseMsg 的&lt;code&gt;getMsg&lt;/code&gt;函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; MusicUtils 无法循环播放音乐的 BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; Image 裁剪图片和拉伸图片时的 BUG&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>为你制作的游戏添加图标</title>
    <link href="https://easy2d.cn/2017/09/18/add-icon-resource/"/>
    <id>https://easy2d.cn/2017/09/18/add-icon-resource/</id>
    <published>2017-09-18T23:25:00.000Z</published>
    <updated>2025-07-16T12:23:40.810Z</updated>
    
    <content type="html"><![CDATA[<p>前几天收到用户反馈说，希望能给程序设置标题、任务栏处的图标，所以讲一下图标的添加方法。</p><p>程序默认不使用图标，如果要自定义程序图标，应使用 Win32 程序添加图标的方法向工程中添加图标资源。</p><span id="more"></span><p>以 VS2017 为例，先选中当前工程</p><p><img src="选中当前工程.png" alt=""></p><p>然后点击菜单栏中的<code>项目</code> - <code>添加资源</code></p><p><img src="项目添加.png" alt=""></p><p>选中<code>Icon</code>后点击<code>导入</code>，将你的<strong><code>ico</code></strong>格式图标导入工程，再次运行程序即可。</p><p><img src="添加ico.png" alt=""></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;前几天收到用户反馈说，希望能给程序设置标题、任务栏处的图标，所以讲一下图标的添加方法。&lt;/p&gt;
&lt;p&gt;程序默认不使用图标，如果要自定义程序图标，应使用 Win32 程序添加图标的方法向工程中添加图标资源。&lt;/p&gt;
    
    </summary>
    
    
      <category term="技术专区" scheme="https://easy2d.cn/tags/%E6%8A%80%E6%9C%AF%E4%B8%93%E5%8C%BA/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.0.3 发布啦！</title>
    <link href="https://easy2d.cn/2017/09/18/easy2d-release-1-0-3/"/>
    <id>https://easy2d.cn/2017/09/18/easy2d-release-1-0-3/</id>
    <published>2017-09-18T23:01:26.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>此次版本更新的内容有：</p><ul><li><code>新增</code> Scene 类新增<code>onEnter</code>和<code>onExit</code>函数，重写这两个函数，它们将在场景载入和退出时自动调用</li><li><code>新增</code> App 类<code>enterScene</code>函数增加第二个参数，用于设置场景切换是否可逆。参数为 false 时，不可调用<code>backScene</code>函数返回</li><li><code>新增</code> App 类新增<code>clearScene</code>函数，清空所有已保存的场景</li><li><code>新增</code> Layer 图层类可以设置是否阻塞消息向下传递</li><li><code>更新</code> 删除鼠标监听函数名由<code>delListener</code>改为<code>deleteListener</code></li><li><code>修复</code> 防止了持续按键响应</li><li><code>修复</code> 现在 Shape 可以选择<code>ROUND</code>、<code>SOLID</code>、<code>FILL</code>三种填充类型</li><li><code>修复</code> 重合按钮显示不正常的 BUG</li><li><code>修复</code> 字体类中存在已久的 BUG，曾导致游戏一开始就崩溃</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; Scene 类新增&lt;code&gt;onEnter&lt;/code&gt;和&lt;code&gt;onExit&lt;/code&gt;函数，重写这两个函数，它们将在场景载入和退出时自动调用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; App 类&lt;code&gt;enterScene&lt;/code&gt;函数增加第二个参数，用于设置场景切换是否可逆。参数为 false 时，不可调用&lt;code&gt;backScene&lt;/code&gt;函数返回&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; App 类新增&lt;code&gt;clearScene&lt;/code&gt;函数，清空所有已保存的场景&lt;/li&gt;
&lt;li&gt;&lt;code&gt;新增&lt;/code&gt; Layer 图层类可以设置是否阻塞消息向下传递&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 删除鼠标监听函数名由&lt;code&gt;delListener&lt;/code&gt;改为&lt;code&gt;deleteListener&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 防止了持续按键响应&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 现在 Shape 可以选择&lt;code&gt;ROUND&lt;/code&gt;、&lt;code&gt;SOLID&lt;/code&gt;、&lt;code&gt;FILL&lt;/code&gt;三种填充类型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 重合按钮显示不正常的 BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 字体类中存在已久的 BUG，曾导致游戏一开始就崩溃&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.0.2 发布啦！</title>
    <link href="https://easy2d.cn/2017/09/16/easy2d-release-1-0-2/"/>
    <id>https://easy2d.cn/2017/09/16/easy2d-release-1-0-2/</id>
    <published>2017-09-16T21:55:11.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>之前 Easy2D 在按钮的处理上一直不尽如人意，但是现在它有了更丰富的功能！</p><p>此次版本更新的内容有：</p><ul><li><code>增加</code> 鼠标消息监听（MouseMsg::addListener）</li><li><code>增加</code> 按钮在鼠标移入、移出、按下、抬起时的回调函数</li><li><code>更新</code> 设置按钮回调函数名由<code>setOnMouseClicked</code>改为<code>setClickedCallback</code></li><li><code>更新</code> 为 TextButton 和 ImageButton 增加了更简便的构造函数</li><li><code>修复</code> Image 加载空图片时崩溃的 BUG</li><li><code>修复</code> FreePool 允许重复添加对象导致崩溃的 BUG</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;之前 Easy2D 在按钮的处理上一直不尽如人意，但是现在它有了更丰富的功能！&lt;/p&gt;
&lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;增加&lt;/code&gt; 鼠标消息监听（MouseMsg::addListener）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;增加&lt;/code&gt; 按钮在鼠标移入、移出、按下、抬起时的回调函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 设置按钮回调函数名由&lt;code&gt;setOnMouseClicked&lt;/code&gt;改为&lt;code&gt;setClickedCallback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; 为 TextButton 和 ImageButton 增加了更简便的构造函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; Image 加载空图片时崩溃的 BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; FreePool 允许重复添加对象导致崩溃的 BUG&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
  <entry>
    <title>Easy2D 1.0.1 发布啦！</title>
    <link href="https://easy2d.cn/2017/09/11/easy2d-release-1-0-1/"/>
    <id>https://easy2d.cn/2017/09/11/easy2d-release-1-0-1/</id>
    <published>2017-09-11T18:30:23.000Z</published>
    <updated>2025-07-16T12:23:40.811Z</updated>
    
    <content type="html"><![CDATA[<p>此次版本更新的内容有：</p><ul><li><code>更新</code> Application 类更名为 App</li><li><code>更新</code> MouseMsg 鼠标消息检测的相关函数名改动</li><li><code>增加</code> 现在低版本编译器下会报错</li><li><code>增加</code> 现在创建窗口时自动在屏幕居中</li><li><code>修复</code> 加载游戏阶段显示黑窗口的 BUG</li><li><code>修复</code> 修改窗口大小时的一个 BUG</li><li><code>修复</code> FreePool 有时造成内存泄漏的 BUG</li></ul><span id="more"></span>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;此次版本更新的内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; Application 类更名为 App&lt;/li&gt;
&lt;li&gt;&lt;code&gt;更新&lt;/code&gt; MouseMsg 鼠标消息检测的相关函数名改动&lt;/li&gt;
&lt;li&gt;&lt;code&gt;增加&lt;/code&gt; 现在低版本编译器下会报错&lt;/li&gt;
&lt;li&gt;&lt;code&gt;增加&lt;/code&gt; 现在创建窗口时自动在屏幕居中&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 加载游戏阶段显示黑窗口的 BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; 修改窗口大小时的一个 BUG&lt;/li&gt;
&lt;li&gt;&lt;code&gt;修复&lt;/code&gt; FreePool 有时造成内存泄漏的 BUG&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
    
      <category term="版本发布" scheme="https://easy2d.cn/tags/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83/"/>
    
  </entry>
  
</feed>
