<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog</id>
    <title>Dora SSR Blog</title>
    <updated>2025-01-20T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog"/>
    <subtitle>Dora SSR Blog</subtitle>
    <icon>https://ippclub.gitee.io/Dora-SSR/zh-Hans/img/site/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[祝所有 Dora SSR 社区的朋友们蛇年春节快乐！]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/20/year-of-snake</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/20/year-of-snake"/>
        <updated>2025-01-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[&emsp;&emsp;值此新春佳节临近，为了迎接充满灵动与智慧的蛇年，我们特别为 Dora SSR 开源游戏引擎项目创作了几幅充满春节氛围的插画，寄托了对社区所有伙伴的诚挚祝福与真挚感谢。]]></summary>
        <content type="html"><![CDATA[<p>  值此新春佳节临近，为了迎接充满灵动与智慧的蛇年，我们特别为 Dora SSR 开源游戏引擎项目创作了几幅充满春节氛围的插画，寄托了对社区所有伙伴的诚挚祝福与真挚感谢。</p>
<p>  在这组插画中，金发小女孩与憨萌大熊一起穿梭在春节的欢乐场景里：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="春运">春运<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/20/year-of-snake#%E6%98%A5%E8%BF%90" class="hash-link" aria-label="春运的直接链接" title="春运的直接链接" translate="no">​</a></h3>
<p>  他们提着行李袋、背起旅行包，踏上回家的列车或开启新的旅程；</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/2-792906bd551f142571b5b83c2ca9d545.png" alt="春运" width="600px"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="红包">红包<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/20/year-of-snake#%E7%BA%A2%E5%8C%85" class="hash-link" aria-label="红包的直接链接" title="红包的直接链接" translate="no">​</a></h3>
<p>  捧着鲜红的红包，与大家一起分享新年的好运与喜悦；</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/1-3a4beccc69067154aa492ea912442955.png" alt="红包" width="600px"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="烟花">烟花<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/20/year-of-snake#%E7%83%9F%E8%8A%B1" class="hash-link" aria-label="烟花的直接链接" title="烟花的直接链接" translate="no">​</a></h3>
<p>  烟花绽放、鞭炮作响，意味着推陈出新与对未来的热切期望；</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/3-1452190db6077ad44c40c24d74a3d515.png" alt="烟花" width="600px"></p>
<p>  最后，还有 C++、Rust、Lua 等代表编程语言的细节元素，寓意新的一年里我们也将继续探索不同技术领域，为 Dora SSR 带来更多惊喜和可能性。</p>
<p>  回顾过去一年，我们在社区中相互帮助、共同进步，让 Dora SSR 从一个灵感逐步成长为富有活力、不断演进的开源游戏引擎。每一位热心贡献者、开发者与玩家的参与，都是我们前进的动力。正如插画中充满欢笑与热闹的氛围，新的一年也将是充满机遇与挑战的全新征程。</p>
<p>  <strong>蛇</strong>在十二生肖中象征着<strong>灵敏、机智与洞察力</strong>。正如一条敏捷且善于变通的蛇，我们在新的一年里也将通过不断学习、尝试和迭代，带领 Dora SSR 项目继续前行。</p>
<p>  在此，我们衷心祝愿大家在新的一年里：</p>
<ol>
<li class=""><strong>编码顺利</strong>：工作、学习、开发过程中能更顺畅、事半功倍；</li>
<li class=""><strong>创意无限</strong>：无论是游戏创作还是技术研究，都能激发出无限灵感；</li>
<li class=""><strong>身体健康</strong>：热爱编程固然重要，别忘了保持健康的生活方式；</li>
<li class=""><strong>万事如意</strong>：与家人、朋友欢度新春，收获更多美好时刻。</li>
</ol>
<p>  衷心感谢每位伙伴的支持与付出，也期待在 2025 蛇年的新征程中，与大家再度携手，将 Dora SSR 打造得更加精彩。让我们一起挥洒智慧与热情，为社区带来更多惊喜与感动。</p>
<p>  <strong>祝蛇年大吉，阖家幸福，大家春节快乐！</strong></p>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="Chunjie" term="Chunjie"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[给凹语言编写游戏引擎绑定的故事]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa"/>
        <updated>2025-01-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[一、故事的开端]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一故事的开端">一、故事的开端<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E4%B8%80%E6%95%85%E4%BA%8B%E7%9A%84%E5%BC%80%E7%AB%AF" class="hash-link" aria-label="一、故事的开端的直接链接" title="一、故事的开端的直接链接" translate="no">​</a></h2>
<p>  关注凹语言团队并“潜伏”在他们社区群中也一年有余，突然被他们发表的一篇为开源精神正本溯源的文章感染了。其实也一直在关注了解他们开源项目发展生存的进展，我作为 Dora SSR 项目的核心贡献者，知道其实我们都一样，同为底层打工人阶级出身的开源作者，不是站在高处往下看的人，而是混迹在沙丁鱼罐中挣扎的鲶鱼。</p>
<p>  所以在这里先高调的宣布吧，我们优先实现了使用<strong>凹语言结合 Dora SSR 游戏引擎开发跨平台游戏</strong>的功能！</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二学习编程语言就像给自己织茧">二、学习编程语言就像给自己织茧<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E4%BA%8C%E5%AD%A6%E4%B9%A0%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%B0%B1%E5%83%8F%E7%BB%99%E8%87%AA%E5%B7%B1%E7%BB%87%E8%8C%A7" class="hash-link" aria-label="二、学习编程语言就像给自己织茧的直接链接" title="二、学习编程语言就像给自己织茧的直接链接" translate="no">​</a></h2>
<p>  Dora SSR 游戏引擎的目标则是打造一个包容、多样化的引擎生态。很多关注者都会非常疑惑为什么这个引擎要支持那么多的编程语言，而且目前已经官方提供了用作热更新脚本的 Lua、Teal、YueScript、TypeScript、TSX 和 Rust 语言的支持，还是不满足。作为一个写了很多年代码和各式各样项目的“<strong>老东西</strong>”，我最能体会的一件事，就是没有一种编程语言是完美的，如果发现一种语言秒天秒地什么都能做，那只能说明是自己缺乏跨不同领域开发做动手实践的经验和认知，或者是编程语言接触的还不够多缺乏编程审美力，只能被人生先入为主的一两种编程语言劫持认知（暴论结束）。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三正式谈谈凹语言的使用体验">三、正式谈谈凹语言的使用体验<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E4%B8%89%E6%AD%A3%E5%BC%8F%E8%B0%88%E8%B0%88%E5%87%B9%E8%AF%AD%E8%A8%80%E7%9A%84%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C" class="hash-link" aria-label="三、正式谈谈凹语言的使用体验的直接链接" title="三、正式谈谈凹语言的使用体验的直接链接" translate="no">​</a></h2>
<p>  给 Dora SSR 游戏引擎接入凹语言（即提供 FFI 支持）很简单，分为三步：</p>
<ul>
<li class="">
<p>1、复用引擎为 Rust 语言导出的 C API 接口。</p>
</li>
<li class="">
<p>2、在凹语言中导入 C API 接口。</p>
</li>
<li class="">
<p>3、为凹语言手工编写和自动生成 C API 的包装接口代码，提供符合凹语言风格的开发体验。</p>
</li>
</ul>
<p>  然后就可以使用凹语言开发游戏啦！</p>
<p>  但是说的这么轻巧简单是骗人的，实际上的真实接入流程是这样：</p>
<p>  Dora SSR 是一个主要使用 C++ 语言开发的游戏引擎。通过内嵌的 WASM3 虚拟机来解释执行凹语言编译为的 WASM 二级制代码，并提供对引擎的调用功能。Dora C++ 这边的接口筛选出发挥引擎必要的功能的子集目前有 1000 多个，手写这些接口的包装代码需要花费大量的时间，而且这些接口的代码需要随着引擎的更新而更新，所以需要一个自动化的工具来生成这些接口的代码。</p>
<p>  所以我们的自动化工具需要完成的事，举个最简单的例子：</p>
<ul>
<li class="">a. 我有一个 C++ 接口：</li>
</ul>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">public</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">int32_t</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">getTargetFPS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#9CDCFE">#</span><span class="token macro property directive keyword" style="color:#C586C0">define</span><span class="token macro property" style="color:#9CDCFE"> </span><span class="token macro property macro-name" style="color:#9CDCFE">SharedApplication</span><span class="token macro property" style="color:#9CDCFE"> </span><span class="token macro property punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token macro property" style="color:#9CDCFE"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token macro property" style="color:#9CDCFE">    </span><span class="token macro property expression class-name" style="color:rgb(78, 201, 176)">Singleton</span><span class="token macro property expression operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token macro property expression" style="color:#9CDCFE">Application</span><span class="token macro property expression operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token macro property expression double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token macro property expression function" style="color:rgb(220, 220, 170)">shared</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre></div></div>
<ul>
<li class="">b. 变成一个 C 语言的导出接口：</li>
</ul>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">extern</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"C"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token class-name" style="color:rgb(78, 201, 176)">int32_t</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">application_get_target_fps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">return</span><span class="token plain"> SharedApplication</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">getTargetFPS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<ul>
<li class="">c. 再变成一个凹语言的导入接口：</li>
</ul>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token plain">#wa</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> dora application_get_target_fps</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">application_get_target_fps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> i32</span><br></span></code></pre></div></div>
<ul>
<li class="">d. 最终变成一个成熟的凹语言调用的接口：</li>
</ul>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">type</span><span class="token plain"> _App </span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token keyword" style="color:#C586C0">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> _App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">GetTargetFPS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> i32 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">application_get_target_fps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">global App </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> _App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<ul>
<li class="">e. 在凹语言程序中进行调用：</li>
</ul>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"dora"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> init </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token function" style="color:rgb(220, 220, 170)">println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">dora</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">GetTargetFPS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<p>  其中 b, c, d 这三步主要就是需要批量由工具自动完成的步骤。</p>
<p>  但是举的这个例子是最简单的情形，大家都知道 C++ 语言中的机制花样多得很。我们跨语言要传递的东西除了基础数据类型，还有对象、对象的继承关系、对象在继承链上的类型转换、字符串对象、存有各种类型数据和对象的数组、C++ 和凹语言互相调用的回调函数、枚举类型数据、对于函数还有静态函数、成员变量函数、类的静态成员函数等等。搞完了对象的传递，一个更加棘手的问题就是对象的生命周期要怎么管理，C++ 管 C++，凹语言管凹语言，然后跨语言之间还要互相引用对象互相管理。</p>
<p>  各种各样的细节这里讲不过来就请大家去看源码吧（不负责任）。</p>
<p>  篇幅不够平台不给推流也就白写了，这里就再介绍个比较有趣的绑定处理机制。就是关于跨语言调用回调函数的。大家都知道 C/C++ 的世界（以及很多语言的世界）里，函数调用传参数的核心是通过一个编译器生成的调用堆栈来在函数体中传入参数以及取出返回值。跨语言的时候通常两边语言机制的调用堆栈并不能直接互相访问，那么是不是可以通过自己编写一个两边语言都能访问的调用堆栈，用来模拟跨语言之间传递参数，以及获取返回值的函数回调调用呢？这个思路当然可以。</p>
<p>  比如我们写游戏循环通常会需要注册一个每个游戏帧里都被调用的 Update 更新函数。可能会有一个这样的 C++ 接口：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">GameScheduleUpdate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">const</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">function</span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token keyword" style="color:#C586C0">bool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">double</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain"> updateFunc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<p>  我们就先实现一个函数调用堆栈：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">CallStack</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">public</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">double</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">bool</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">double</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">popDouble</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">bool</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">popBool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<p>  提供 C 包装函数：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">extern</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"C"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">int64_t</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">new_call_stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">/* 创建 CallStack 对象 */</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">call_stack_push_bool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">int64_t</span><span class="token plain"> stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">int32_t</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">/* bool 入栈 */</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">int64_t</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">call_stack_pop_f64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">int64_t</span><span class="token plain"> stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">/* double 出栈 */</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">game_schedule_update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">int32_t</span><span class="token plain"> funcId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">int64_t</span><span class="token plain"> stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">shared_ptr</span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token keyword" style="color:#C586C0">void</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">deref</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">nullptr</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">funcId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">auto</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">            SharedWasmRuntime</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">deref</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">funcId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">auto</span><span class="token plain"> args </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">reinterpret_cast</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">CallStack</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">*</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token function" style="color:rgb(220, 220, 170)">GameScheduleUpdate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">funcId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> deref</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">double</span><span class="token plain"> deltaTime</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">            args</span><span class="token operator" style="color:rgb(212, 212, 212)">-&gt;</span><span class="token function" style="color:rgb(220, 220, 170)">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">deltaTime</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 给凹语言传参</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">            SharedWasmRuntime</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">invoke</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">funcId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 执行回调</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">            </span><span class="token keyword" style="color:#C586C0">return</span><span class="token plain"> args</span><span class="token operator" style="color:rgb(212, 212, 212)">-&gt;</span><span class="token function" style="color:rgb(220, 220, 170)">popBool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 从凹语言取返回值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<p>  在凹语言这边提供注册 Update 回调函数的接口：</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token plain">#wa</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> dora new_call_stack</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">new_call_stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> i64</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">#wa</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> dora call_stack_push_bool</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">call_stack_push_bool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> i64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> i32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">#wa</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> dora call_stack_pop_f64</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">call_stack_pop_f64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> i64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> f64</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">#wa</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> dora game_schedule_update</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">game_schedule_update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">funcId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> i32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> i64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> _Game</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">ScheduleUpdate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">update_func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">delta_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> f64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">bool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    stack </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">new_call_stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    func_id </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">PushFunction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        delta_time </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">call_stack_pop_f64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 从 C++ 取得传参</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        result </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">if</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">update_func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">delta_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 执行实际的回调</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">            result </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token function" style="color:rgb(220, 220, 170)">call_stack_push_bool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 给 C++ 传返回值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token function" style="color:rgb(220, 220, 170)">game_schedule_update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">func_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> stack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<p>  在凹程序中就可以这样使用清爽的程序接口啦：</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"dora"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">init</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    dora</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Game</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">ScheduleUpdate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">delta_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> f64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">bool</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token function" style="color:rgb(220, 220, 170)">println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">delta_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">return</span><span class="token plain"> </span><span class="token boolean" style="color:#569CD6">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<p>  在实际运行中，其实还要比看起来的方案更复杂一点，因为凹语言是一门运行在 WASM 虚拟机上的语言，两个语言的互动实际还要经过 WASM 虚拟机这个“中间商”来完成。实际执行回调的流程大概会像是这样：</p>
<!-- -->
<p>  其实这个图中还简化了一些东西，比如 C++ 程序与 WASM 虚拟机之间的调用，也是走了一套额外的通过 WASM 虚拟机模拟调用堆栈的流程。所以可以看到当前的方案对于跨语言函数回调的实现，还是有一定的性能损耗，未来也许会研究有没有办法直接访问复用 WASM 虚拟机的调用堆栈，来优化性能。</p>
<p>  然后再简单聊聊对象生命周期的管理的问题。如果不能从语言层面找到能自动并正确托管 C++ 对象生命周期的机制，那我们在新的编程语言环境中就只有手动管理对象的释放，比如需要满世界不能多不能少的准确安排调用一次<code>obj.Destroy()</code>的方法来释放对象，这种硬核刀耕火种的内存管理方式会让急着写游戏玩法脚本的我们累到奔溃。</p>
<p>  好在凹语言有个优势就是和引擎 C++ 这边的机制都同样是走了引用计数的方式。甚至有语义非常相似的，通过引用计数管理指针指向对象的机制，所以我们就只要这样做：</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四实践中遇到的困难">四、实践中遇到的困难<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E5%9B%9B%E5%AE%9E%E8%B7%B5%E4%B8%AD%E9%81%87%E5%88%B0%E7%9A%84%E5%9B%B0%E9%9A%BE" class="hash-link" aria-label="四、实践中遇到的困难的直接链接" title="四、实践中遇到的困难的直接链接" translate="no">​</a></h2>
<p>  原理先聊到这里，下面聊一下实践中遇到的难题。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="困难一凹语言作者告诉我别用这个语言">困难一：凹语言作者告诉我别用这个语言<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E5%9B%B0%E9%9A%BE%E4%B8%80%E5%87%B9%E8%AF%AD%E8%A8%80%E4%BD%9C%E8%80%85%E5%91%8A%E8%AF%89%E6%88%91%E5%88%AB%E7%94%A8%E8%BF%99%E4%B8%AA%E8%AF%AD%E8%A8%80" class="hash-link" aria-label="困难一：凹语言作者告诉我别用这个语言的直接链接" title="困难一：凹语言作者告诉我别用这个语言的直接链接" translate="no">​</a></h3>
<p>  要先说回为什么对凹语言这么感兴趣，而且实际上 Dora SSR 引擎中已经实现了 Rust 语言的 WASM 绑定，Rust 语言对于 C++ 老手的体验来讲什么都好，几乎快要“秒天秒地”。但是要用来快速开发和迭代游戏逻辑层的玩法的话，我其实是有些犯怵的。就像你就想好好写个作业，结果旁边坐了一个老师直勾勾地盯着你写的每一个字，不停的骂你，有时因为不够懂老师的规矩，结果导致做作业过程中增加了和老师争执以及妥协重写一遍作业的时间。</p>
<p>  凹语言完全走向了 Rust 语言的反面。类 Go 语言的设计，强调语言规则的极简。</p>
<p>  不整那么多有的没的语法智力挑战和强制要优雅美丽的编码方式。用完全没法花哨的极简语法集就快速糊你的业务逻辑。这个风格我也很喜欢，以至于在初期和凹语言核心作者交流时，被警告这个项目可能还不成熟，请不要报太大期望下，我说，吃螃蟹还是得吃，Rust 螃蟹（此处有 Rust logo）吃得，凹有什么吃不得呢。大不了遇到语言的 bug 我就参与贡献解决一下。然后困难二就来了，我真遇到了语言的 bug 就参与贡献了一下。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="困难二软件工程之天道难违">困难二：软件工程之天道难违<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E5%9B%B0%E9%9A%BE%E4%BA%8C%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E4%B9%8B%E5%A4%A9%E9%81%93%E9%9A%BE%E8%BF%9D" class="hash-link" aria-label="困难二：软件工程之天道难违的直接链接" title="困难二：软件工程之天道难违的直接链接" translate="no">​</a></h3>
<p>  其实说到这个事，我老实交代一下，Dora SSR 开源游戏引擎项目也有一摸一样的问题。研发开源软件的事，既然叫做软件研发，那自然得面对软件工程的现实问题。以前大家都喜欢吐槽开源项目就是种新颖的无酬劳众包测试（团伙型劳动力白嫖），要研发一个成熟稳定功能强大的软件，采取稳健的需求设计开发测试的实施路径，投入充足的人力时间都是必不可少的。作为个人业余时间的开源开发者，再是以一当十的天才，也很难以个人投入去匹配所需的资源成本去做出期望的完美软件。所以要用开源白嫖，错了，要用开源共建的方式，搞持久战和人民战争，才有可能性在去资本加持的模式下去实现一些奇观，创造出所有人平等可得的技术资产。</p>
<p>  然后我在做凹语言绑定过程中确实遇上了一些具体是语言编译器的 bug，刚上手几天就就给作者来了个 issue 5 连发。其中一个 issue 因为不修复我的代码就无法运行，只好去通读研究凹语言编译器的源码找到了修复方案。</p>
<p>  所以提了这个 issue：<a href="https://github.com/wa-lang/wa/issues/67" target="_blank" rel="noopener noreferrer" class="">https://github.com/wa-lang/wa/issues/67</a></p>
<p>  以及这个对应的修复 pr：<a href="https://github.com/wa-lang/wa/pull/68" target="_blank" rel="noopener noreferrer" class="">https://github.com/wa-lang/wa/pull/68</a></p>
<p>  其实我感觉开源项目往往会有个奇怪的规律，如果你有看到被提 issue 越多的项目，很可能你在亲自上手使用的时候遇到的问题就越少。用户试用发现并提交问题也是构建软件项目客观需要的劳动力投入。你帮助一个开源项目发现的问题越多，能带来的结果就是这个开源项目长期的问题会越少。这个互动模式是很健康的，也是开源软件项目的魅力所在，你不只是一个无关紧要旁观者，哪怕只是参与观测和试用也会是建设它的重要力量，最重要的是，建设结果也是和你共享的。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="困难三路在何方">困难三：路在何方<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E5%9B%B0%E9%9A%BE%E4%B8%89%E8%B7%AF%E5%9C%A8%E4%BD%95%E6%96%B9" class="hash-link" aria-label="困难三：路在何方的直接链接" title="困难三：路在何方的直接链接" translate="no">​</a></h3>
<p>  你有没有发现这篇文章还没有提到大家都喜欢的大模型？不蹭一下吗？</p>
<p>  因为在当下开发一门新语言大概率会和大模型辅助绝缘了（不是）。当然凹语言暂时还算好一点，毕竟是 Go like 的语言，差异化目前还不够大，为 Go 语言生成的代码，凹也能勉强改改用。很多人在想有 AI 大模型，编程开发已经没有价值了，那只是资方老板期待的平行宇宙。作为通过实践创造真实世界的开发者，这个世界是什么样，还不是得经由自己的感受去认知，并由自己的双手去直接创造的。作为 WASM 上原生语言的探索，我体会到凹的价值是很大的，比如我是没法上手去研究 Rust 语言那么复杂的工程是怎么实现编译到 WASM 并做交互的，但是研究凹的过程确实帮助到我快速上手了解到非常多的 WASM 知识细节。因为有了这样的实践体验，所以我能切身接受到作者们发起一门新的语言带来的实际价值。</p>
<p>  所以，在这里呼吁大家也一起来参与开启编程语言的创作浪潮吧。无论是创作 native，WASM，还是 Lua  虚拟机上的转译语言。用“一人一言”去构建一个由每一个个人主导而非自动生成的新世界。只要你敢发明新的编程语言，我都敢通过 Dora SSR 开源项目给你的作品也接入一个创作游戏的运行时，扩展你的作品边界。详情请进群咨询：512620381（Dora 引擎 Q 群非诈骗）</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五相关代码仓库链接">五、相关代码仓库链接<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2025/1/15/dora-wa#%E4%BA%94%E7%9B%B8%E5%85%B3%E4%BB%A3%E7%A0%81%E4%BB%93%E5%BA%93%E9%93%BE%E6%8E%A5" class="hash-link" aria-label="五、相关代码仓库链接的直接链接" title="五、相关代码仓库链接的直接链接" translate="no">​</a></h2>
<ul>
<li class="">Dora SSR 的凹语言开发包：<a href="https://github.com/IppClub/dora-wa" target="_blank" rel="noopener noreferrer" class="">https://github.com/IppClub/dora-wa</a></li>
<li class="">凹语言：<a href="https://github.com/wa-lang/wa" target="_blank" rel="noopener noreferrer" class="">https://github.com/wa-lang/wa</a></li>
<li class="">Dora SSR 开源游戏引擎：<a href="https://github.com/IppClub/Dora-SSR" target="_blank" rel="noopener noreferrer" class="">https://github.com/IppClub/Dora-SSR</a></li>
</ul>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="Dora SSR" term="Dora SSR"/>
        <category label="Wa-lang" term="Wa-lang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dora SSR 带来游戏开发新体验]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview"/>
        <updated>2024-08-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[对游戏引擎开发的一些思考]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="对游戏引擎开发的一些思考">对游戏引擎开发的一些思考<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E5%AF%B9%E6%B8%B8%E6%88%8F%E5%BC%95%E6%93%8E%E5%BC%80%E5%8F%91%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83" class="hash-link" aria-label="对游戏引擎开发的一些思考的直接链接" title="对游戏引擎开发的一些思考的直接链接" translate="no">​</a></h2>
<p>  曾几何时，每次游戏引擎的重大突破都会带来行业技术发展的飞跃：例如从 2D 到 3D 渲染，从简单的光照到实时光影和物理模拟。这些革新为游戏开发开创了无限可能，推动了整个行业的前进。如今，随着技术的成熟，颠覆性的创新也越来越少见。</p>
<!-- -->
<p>  现在，游戏引擎的开发更注重<strong>优化和改进现有技术</strong>，提升用户体验和开发效率。特别是在开源引擎项目中，整合和完善现有的开源库显得尤为重要。毕竟，开源开发者通常缺乏资源和人力，没有必要从头开发物理引擎、字体加载或动画模型运行时。换句话说，目前做开源游戏引擎开发可能很大程度的工作量是<strong>整合现有的成熟流行的第三方功能库</strong>。</p>
<p>  这种方法不仅提高了开发效率，也让游戏引擎更灵活，能更好地满足不同类型的游戏开发需求。通过复用现有的开源库，开发者可以专注于创新游戏玩法和内容，而不是重复造基础轮子。这样，开发游戏引擎更像是<strong>搭建一个服务平台</strong>，为开发者提供了满足各自需求的基础设施，让他们能更专注于创作。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dora-ssr-引擎的定位">Dora SSR 引擎的定位<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#dora-ssr-%E5%BC%95%E6%93%8E%E7%9A%84%E5%AE%9A%E4%BD%8D" class="hash-link" aria-label="Dora SSR 引擎的定位的直接链接" title="Dora SSR 引擎的定位的直接链接" translate="no">​</a></h2>
<p>  说到服务平台，我们在做的 Dora SSR 开源游戏引擎的定位是<strong>提供一个易于上手、跨设备兼容的游戏引擎及开发工具链</strong>。如果要与内置开发 IDE 的 Godot 引擎相比，Dora SSR 的不同之处在于，它<strong>内置的游戏编辑器</strong>是用 ReactJS 开发的 <strong>Web 应用</strong>。</p>
<p>  这意味着 Dora 的编辑器和运行时能够在不同平台上独立运行，甚至跨硬件设备运行。这样，开发中的游戏程序和 IDE 不会在同一个程序进程中互相影响，也不会互抢资源。最终，仍然可以像 Godot 一样，将运行时和开发工具一起打包成一个 App 或安装包，方便分发。使得准备游戏开发环境的难度就像安装一个手机 App 一样简单。</p>
<p>  不过，Dora SSR 目前还不支持完整的 3D 渲染功能，尽管游戏场景的节点对象有 Z 坐标和 XY 轴旋转属性，默认使用的是 3D 摄像机。但 3D 动画模型、材质管理以及完整的 3D 渲染管线尚未实现。由于项目维护者精力有限，我们也没有能力制作高级的 3D 美术资源和游戏作品，这也是我们暂时没有钞能力加持下的开源开发者的局限。</p>
<p>  可是，没能做到第一，那么喜欢的事就完全不要去做了么？</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="开源开源还是开源">开源、开源还是开源！<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E5%BC%80%E6%BA%90%E5%BC%80%E6%BA%90%E8%BF%98%E6%98%AF%E5%BC%80%E6%BA%90" class="hash-link" aria-label="开源、开源还是开源！的直接链接" title="开源、开源还是开源！的直接链接" translate="no">​</a></h2>
<p>  当然不是。做开源的游戏引擎，是因为对这项事业有着无尽的热爱。<strong>开源文化</strong>代表着共享、合作和创新，这种精神深深地吸引着我们。开源不仅是一种开发模式，更是一种信念——相信每个人都能为技术进步，对所热爱领域的发展，贡献一份力量，无论大小。</p>
<p>  在游戏领域，开源的意义尤为重大。通过开源，更多的开发者可以参与进来，共同完善和优化引擎，推动技术的不断进步。而且，开源让更多的人有机会学习和成长，无论是初学者还是资深开发者，都能从中受益。对于我来说，看到一个个开源项目因为大家的努力而变得更好，看到越来越多的人因为开源而找到自己的梦想，这是很令人激动的一件事。</p>
<p>  我设想一个更加<strong>开源开放</strong>的<strong>游戏创作</strong>的世界：在这个世界里，每一个有创意的人都可以自由地获取和使用各种资源，毫无阻碍地实现他们的想法。每一个开发者都可以自由分发和分享他们的成果，接受来自全球各地的反馈和建议。这样的开放环境不仅能加速技术的发展，也能培养更多优秀的开发者，推动整个行业的进步。作为一个游戏老饕，通过大家分享接力的努力，我也能在未来有更多有趣和特别的游戏作品的选择。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="那么就聊聊动手的事吧">那么就聊聊动手的事吧！<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E9%82%A3%E4%B9%88%E5%B0%B1%E8%81%8A%E8%81%8A%E5%8A%A8%E6%89%8B%E7%9A%84%E4%BA%8B%E5%90%A7" class="hash-link" aria-label="那么就聊聊动手的事吧！的直接链接" title="那么就聊聊动手的事吧！的直接链接" translate="no">​</a></h2>
<p>  Dora SSR 引擎目前版本（v1.5.1）的软件架构如下：</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/dora-ssr-architecture-9c099a74eb1b150796aea0c9b6aa6238.png" alt="Dora SSR 软件架构"></p><p>Dora SSR 软件架构</p><p></p>
<p>  总结起来，Dora SSR 的软件架构分为三个层次：<strong>硬件适配层、引擎核心功能层、以及用户接口层</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="硬件适配层">硬件适配层<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E7%A1%AC%E4%BB%B6%E9%80%82%E9%85%8D%E5%B1%82" class="hash-link" aria-label="硬件适配层的直接链接" title="硬件适配层的直接链接" translate="no">​</a></h3>
<p>  首先是硬件适配层，它确保 Dora SSR 能在各种操作系统和硬件平台上运行。无论是 Windows、Linux、macOS，还是移动设备上的 iOS 和 Android，Dora SSR 都能够通过 SDL2 和实现 RHI（Render Hardware Interface）技术框架 bgfx，实现跨平台兼容性。bgfx 是一个抽象层，它为底层的渲染接口技术（包括 OpenGL、Metal、DirectX 和 Vulkan 等）提供统一的接口。这些技术解决了对底层的<strong>操作系统接口</strong>和<strong>图形渲染接口</strong>的适配问题，使得引擎在不同的硬件环境中都能高效运行。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="引擎核心功能层">引擎核心功能层<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E5%BC%95%E6%93%8E%E6%A0%B8%E5%BF%83%E5%8A%9F%E8%83%BD%E5%B1%82" class="hash-link" aria-label="引擎核心功能层的直接链接" title="引擎核心功能层的直接链接" translate="no">​</a></h3>
<p>  其次是引擎核心功能层，这是 Dora SSR 的“心脏”。它包括多个子功能层级，分别负责不同的引擎功能：</p>
<ul>
<li class=""><strong>渲染层</strong>：包括 Line Renderer、Sprite Renderer、VG Renderer 和 ImGui Renderer，用于分类批量的处理各种图形渲染请求的渲染器。</li>
<li class=""><strong>功能层</strong>：涵盖 Physics（物理）、Assets（资源管理）、Graphic（图形）、Network（网络）、Audio（音频）和ML（机器学习）等基础功能模块。</li>
<li class=""><strong>游戏框架层</strong>：包含 Platformer Game（平台游戏）、AI（人工智能）、Unit（单位管理）和 Action（动作管理）等模块，为游戏逻辑和玩法提供支持。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="用户接口层">用户接口层<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E7%94%A8%E6%88%B7%E6%8E%A5%E5%8F%A3%E5%B1%82" class="hash-link" aria-label="用户接口层的直接链接" title="用户接口层的直接链接" translate="no">​</a></h3>
<p>  最后是用户接口层，这是开发者直接与引擎交互的部分。Dora SSR 提供了强大的 Web IDE 层，整合了其它开源项目的成果如 Monaco Editor（VSCode 的前端）、Code Wire（可视化脚本编辑器）、Yarn Editor（游戏剧本编辑器）、Spine Player（Spine2D 动画预览）和 TypeScript 编译器。这些工具集成在一起，为开发者提供了一个提供尽可能完善的功能的、易于使用的开发环境，让他们可以快速上手，专注于创意和内容的实现。</p>
<p>  另外用户接口层还包括用于加载、编译和运行开发者编写的游戏脚本代码的运行时和语言编译器，提供 Lua VM、WASM VM、YueScript 编译器、Teal 编译器和多种语言绑定等，从而能支持多种脚本语言，让开发者能够更灵活地选用进行游戏开发。</p>
<p>  Dora SSR 的架构设计试图考虑跨平台兼容性、功能模块化和用户体验，最后以其开源的方式，让更多的开发者能够参与进来，共同打造一个强大、灵活的游戏开发平台。努力通过层次分明、清晰可扩展的架构，Dora SSR 简化开发流程并为开发者提供了丰富的功能支持，来实现了让游戏开发变得更轻松、更有趣的目标。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="用户功能视角下的-dora-ssr-引擎">用户功能视角下的 Dora SSR 引擎<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E7%94%A8%E6%88%B7%E5%8A%9F%E8%83%BD%E8%A7%86%E8%A7%92%E4%B8%8B%E7%9A%84-dora-ssr-%E5%BC%95%E6%93%8E" class="hash-link" aria-label="用户功能视角下的 Dora SSR 引擎的直接链接" title="用户功能视角下的 Dora SSR 引擎的直接链接" translate="no">​</a></h3>
<p>  然后从用户功能的角度来看 Dora SSR 开源引擎，Dora SSR 引擎就是分为了两个部分，一个是引擎运行时，一个是 Web IDE。其中引擎运行时是可以完全分离 Web IDE 的程序和外置资源独立运行的。只要从发布的引擎中简单的删除 Web IDE 运行所需要脚本和资源，就能得到一个纯粹的 Dora SSR 运行时程序，并可以用来只加载开发好的游戏程序和资源打包为独立发布的游戏。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="dora-ssr-引擎运行的流程">Dora SSR 引擎运行的流程<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#dora-ssr-%E5%BC%95%E6%93%8E%E8%BF%90%E8%A1%8C%E7%9A%84%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="Dora SSR 引擎运行的流程的直接链接" title="Dora SSR 引擎运行的流程的直接链接" translate="no">​</a></h3>
<p>  Dora SSR 引擎执行的流程从数据流处理的角度可以很容易理解，用户编写的游戏脚本里基本上都是在做游戏逻辑数据的处理和提交的操作。当这些数据提交到了引擎核心模块后，会做进一步的数据转换、加工与合并处理，最终生成提交给 GPU 渲染需要的数据等形式，以不限于图形更新展示的方式完成游戏的反馈和交互。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="部分-web-ide-功能的展示">部分 Web IDE 功能的展示<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E9%83%A8%E5%88%86-web-ide-%E5%8A%9F%E8%83%BD%E7%9A%84%E5%B1%95%E7%A4%BA" class="hash-link" aria-label="部分 Web IDE 功能的展示的直接链接" title="部分 Web IDE 功能的展示的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>代码编辑器</strong></li>
</ul>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/1-1814ea2a8a51ee7069ed0f550e08f8d2.jpg" alt="Dora SSR 代码编辑器"></p><p>Dora SSR 代码编辑器</p><p></p>
<p>  Dora SSR 的 Web IDE 提供了完善的代码编辑器功能，支持多种编程语言和文件类型。在这张演示图中，我们可以看到用户可以编写 TypeScript 代码，使用 TSX 进行游戏对象的行为定义和控制。左侧的文件树展示了项目的资源结构，包括脚本、资源和配置文件等。代码编辑器具备语法高亮、自动补全等功能、文档跳转的功能，提升了开发效率。此外，右下角的小窗口展示了所关联的引擎运行时实时预览的效果，开发者做了文件修改就能<strong>即时查看</strong>代码的<strong>运行效果</strong>。</p>
<ul>
<li class=""><strong>Yarn Spinner 剧本编辑器</strong></li>
</ul>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/2-2990bda867454d1ce44807d0efdf3a0f.jpg" alt="Dora SSR 剧本编辑器"></p><p>Dora SSR 剧本编辑器</p><p></p>
<p>  Dora SSR 的 Web IDE 中集成了 Yarn Spinner 剧本编辑器，这为游戏开发者提供了直观高效的故事编写工具。在这张演示图中，可以看到 Yarn Spinner 编辑器的界面，用户正在编写一个包含决策点的互动剧本。中央的编辑窗口展示了当前正在编辑的剧本内容，支持富文本格式，并且可以通过简单的标签如 <code>&lt;&lt;jump&gt;&gt;</code> 实现剧情跳转。</p>
<p>  右侧的可视化节点图展示了剧本的流程，每个节点代表一个剧情片段，节点之间通过线条连接，清晰地展示了剧情的走向和决策路径。这种图形化的剧本编辑方式，使得开发者能够直观地设计和调整剧情流程。</p>
<p>  Yarn Spinner 的这些功能，不仅提升了游戏剧本编写测试的效率，还方便了复杂剧情的设计和管理，帮助 Dora SSR 的 Web IDE 成为了一个功能全面的游戏开发平台。</p>
<ul>
<li class=""><strong>Visual Script 编辑器</strong></li>
</ul>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/3-1603fcfe5317a389453642c43047242c.jpg" alt="Dora SSR 可视化脚本编辑器"></p><p>Dora SSR 可视化脚本编辑器</p><p></p>
<p>  Dora SSR 的 Web IDE 集成了 Visual Script 编辑器，这个功能主要面向<strong>编程初学者</strong>，特别是青少年，帮助他们顺利进行编程学习的过渡和上手体验。在这张演示图中，可以看到 Visual Script 编辑器的界面，采用了图形化的编程方式，通过拖拽和连接不同的节点来创建程序逻辑。</p>
<p>  左侧的面板显示了变量管理功能，用户可以轻松添加和管理变量。中央的工作区展示了各种节点，包括循环、条件判断和数组操作等。用户可以通过直观的方式将这些节点连接起来，构建复杂的程序逻辑。在右侧还有一个被折叠的面板，可以实时查看用户编辑的可视化脚本最终编译的，用于在引擎加载执行的 Teal 程序代码。</p>
<p>  这种图形化编程方式降低了编程的门槛，让初学者无需掌握复杂的语法就能理解和实现基本的编程概念。对于青少年来说，这种方式不仅增加了学习的趣味性，还能培养他们的逻辑思维和问题解决能力，帮助更多人轻松入门编程世界。</p>
<ul>
<li class=""><strong>Spine 动画预览</strong></li>
</ul>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/4-3f8ab5a8efa6201c4a27bd1bd2f4fcf4.jpg" alt="Dora SSR 动画预览"></p><p>Dora SSR 动画预览</p><p></p>
<p>  Dora SSR 的 Web IDE 中还集成了 Spine2D 动画模型预览功能。通过这个功能，开发者可以方便地查看和调整 Spine 动画模型，包括切换动画模型的皮肤和播放不同的动画。帮助大家在程序中正确的加载和播放 Spine 动画模型。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="在多种设备上开发游戏的用户体验">在多种设备上开发游戏的用户体验<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E5%9C%A8%E5%A4%9A%E7%A7%8D%E8%AE%BE%E5%A4%87%E4%B8%8A%E5%BC%80%E5%8F%91%E6%B8%B8%E6%88%8F%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C" class="hash-link" aria-label="在多种设备上开发游戏的用户体验的直接链接" title="在多种设备上开发游戏的用户体验的直接链接" translate="no">​</a></h2>
<p>  最后来聊聊用户体验，前面所说 Dora SSR 的目标是搭建游戏开发的环境像安装和使用 App 一样快捷和简单。这个 Dora 真的可以做到吗？</p>
<p>  我们已经在尝试在各种移动设备、掌机和嵌入式设备上运行了 Dora SSR，通过远程访问 Web IDE 来使用游戏开发和测试的功能。在树莓派，国产 MCU，手机上的各种高性能 SOC 上，Dora SSR 都能提供比较流畅的使用体验。甚至部分自带键盘轨迹球外设的小众移动设备上，我们也能同时运行引擎，并通过本地打开浏览器访问开发环境，把做游戏变成随时随地可及的娱乐活动。</p>
<p>  不过，为了确保良好的使用体验，我们建议在小屏设备上开发游戏时，至少使用一块更大的显示屏幕，带键盘的 Android 平板或是 iPad 来远程访问和使用 Web IDE 开发游戏，以获得更舒适的游戏开发体验。无论是在家中、咖啡馆还是户外，Dora SSR 都能为开发者提供随时随地的游戏开发环境，让创作不再受限于设备和地点。</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/dev-everywhere-1580ed46ea92ee7ed14ac91a39afbb68.jpg" alt="Dora SSR 跨平台开发"></p><p>Dora SSR 跨平台开发</p><p></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="加入我们的社区">加入我们的社区<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E5%8A%A0%E5%85%A5%E6%88%91%E4%BB%AC%E7%9A%84%E7%A4%BE%E5%8C%BA" class="hash-link" aria-label="加入我们的社区的直接链接" title="加入我们的社区的直接链接" translate="no">​</a></h2>
<p>  如果你对 Dora SSR 感兴趣，欢迎加入我们的社区，与我们一起探讨、交流、合作。可以通过以下方式找到我们：</p>
<ul>
<li class="">GitHub 项目地址：<a href="https://github.com/IppClub/Dora-SSR" target="_blank" rel="noopener noreferrer" class="">https://github.com/IppClub/Dora-SSR</a></li>
<li class="">Gitee 项目地址：<a href="https://gitee.com/pig/Dora-SSR" target="_blank" rel="noopener noreferrer" class="">https://gitee.com/pig/Dora-SSR</a></li>
<li class="">GitCode 项目地址：<a href="https://gitcode.com/ippclub/Dora-SSR" target="_blank" rel="noopener noreferrer" class="">https://gitcode.com/ippclub/Dora-SSR</a></li>
<li class="">QQ 群号：512620381</li>
</ul>
<p>  期待你的加入，一起推动开源游戏引擎的发展！</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="后续预告">后续预告<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/8/14/dora-ssr-overview#%E5%90%8E%E7%BB%AD%E9%A2%84%E5%91%8A" class="hash-link" aria-label="后续预告的直接链接" title="后续预告的直接链接" translate="no">​</a></h2>
<p>  在接下来的系列文章中，我们将深入介绍 Dora SSR 的各个程序模块，带你详细了解这个不断迭代发展的游戏引擎的内部工作原理和各种实现技巧，敬请关注我们的更新吧。</p>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="Dora SSR" term="Dora SSR"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[给前端同学看的跨平台游戏开发入门]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro"/>
        <updated>2024-04-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[&emsp;&emsp;大家好，我是一个游戏引擎技术探索者，同时也是一名做过不少前端开发工作的程序员。如果你想知道如何从编写网页到开发游戏，那你来对地方了！]]></summary>
        <content type="html"><![CDATA[<p>  大家好，我是一个游戏引擎技术探索者，同时也是一名做过不少前端开发工作的程序员。如果你想知道如何从编写网页到开发游戏，那你来对地方了！</p>
<p>  今天我们聊聊如何使用 Dora SSR，一个支持 TSX 且跨平台在 native 运行的游戏引擎，助你轻松跨入游戏开发的世界。不必担心，说到游戏引擎并不是啥高不可攀的技术，反而和我们熟悉的前端开发工具可以有惊人相似之处。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一游戏客户端开发也可以是一种前端开发">一、游戏客户端开发也可以是一种前端开发<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#%E4%B8%80%E6%B8%B8%E6%88%8F%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%BC%80%E5%8F%91%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%B8%80%E7%A7%8D%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91" class="hash-link" aria-label="一、游戏客户端开发也可以是一种前端开发的直接链接" title="一、游戏客户端开发也可以是一种前端开发的直接链接" translate="no">​</a></h2>
<p>  首先，让我们解释一下什么是游戏引擎。简单来说，游戏引擎就是一套工具和库的集合，帮助开发者构建游戏，管理图形、声音、物理计算或碰撞检测等。对于前端开发者来说，你可以把它想象成就是一种特殊的浏览器，专门用来运行游戏。</p>
<p>  Dora SSR 的游戏场景管理使用了类似于 HTML DOM 的树形结构，这对我们来说再熟悉不过了。想象一下，将 div 元素换成游戏中的各种对象，CSS 动画换成游戏动画，概念也差不多，代码写法上可能也差不多，是不是觉得有点意思了？</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二从-typescript-到-tsx前端技术在游戏中应用">二、从 TypeScript 到 TSX：前端技术在游戏中应用<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#%E4%BA%8C%E4%BB%8E-typescript-%E5%88%B0-tsx%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%A8%E6%B8%B8%E6%88%8F%E4%B8%AD%E5%BA%94%E7%94%A8" class="hash-link" aria-label="二、从 TypeScript 到 TSX：前端技术在游戏中应用的直接链接" title="二、从 TypeScript 到 TSX：前端技术在游戏中应用的直接链接" translate="no">​</a></h2>
<p>  许多前端开发者都熟悉 TypeScript 和 React 的 JSX 语法。在 Dora SSR 开源游戏引擎中，我们通过支持 TSX，提供了与前端开发编程模式相似的游戏开发接口。是的你没听错，就是那个 TSX。</p>
<p>  使用 TSX 开发游戏，意味着你可以利用已有的前端技术栈—组件、模块和其他现代前端技术，直接在游戏开发中复用这些概念。而且，Dora SSR 的性能优化确保了即使是在复杂的游戏场景中，也能保持流畅的运行。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三挑战-100-行代码以内教你写一个愤怒的小鸟like的游戏">三、挑战 100 行代码以内，教你写一个“愤怒的小鸟”like的游戏<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#%E4%B8%89%E6%8C%91%E6%88%98-100-%E8%A1%8C%E4%BB%A3%E7%A0%81%E4%BB%A5%E5%86%85%E6%95%99%E4%BD%A0%E5%86%99%E4%B8%80%E4%B8%AA%E6%84%A4%E6%80%92%E7%9A%84%E5%B0%8F%E9%B8%9Flike%E7%9A%84%E6%B8%B8%E6%88%8F" class="hash-link" aria-label="三、挑战 100 行代码以内，教你写一个“愤怒的小鸟”like的游戏的直接链接" title="三、挑战 100 行代码以内，教你写一个“愤怒的小鸟”like的游戏的直接链接" translate="no">​</a></h2>
<p>  好了，理论知识够多了，让我们来点实际操作吧。来看看如何在 Dora SSR 中用 100 行以内的 TSX 代码编写一个类似“愤怒的小鸟”的小游戏。当然，在开始之前还是要准备开发环境，做这个事用 Dora SSR 就很简单：我有一个<strong>安装包一装</strong>，我有一个<strong>浏览器一开</strong>，嗯，开始<strong>写代码</strong>运行吧。安装启动参见：<a href="https://dora-ssr.net/zh-Hans/docs/tutorial/quick-start" target="_blank" rel="noopener noreferrer" class="">Dora 启动！</a></p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/dora-on-android-61f4254f2bb8648cc2d994871d429301.jpg" alt="不小心装成了APK包在手机上？那就在同局域网下访问，直接在手机上进行开发调试吧"></p><p>不小心装成了APK包在手机上？那就在同局域网下访问，直接在手机上进行开发调试吧</p><p></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-编写最简单游戏场景">1. 编写最简单游戏场景<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#1-%E7%BC%96%E5%86%99%E6%9C%80%E7%AE%80%E5%8D%95%E6%B8%B8%E6%88%8F%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="1. 编写最简单游戏场景的直接链接" title="1. 编写最简单游戏场景的直接链接" translate="no">​</a></h3>
<p>  在编写实际的代码之前，我们可以先写一个有特别功能的注释，它可以告诉 Dora SSR 的 Web IDE 在我们按下 Ctrl + S 保存文件时，自动热更新运行的代码，以实现代码运行结果的实时预览功能。</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token comment" style="color:rgb(106, 153, 85)">// @preview-file on</span><br></span></code></pre></div></div>
<p>  然后，我们引入必要的库和组件。当然我们的代码编辑器也会提示辅助我们自动引入需要的模块，可以放到后面编码过程中再完成：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">React</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> toNode</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> useRef </span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'DoraX'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">Body</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">BodyMoveType</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">Ease</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">Label</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">Line</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">Scale</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">TypeName</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name" style="color:#4EC9B0">Vec2</span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token imports"> tolua </span><span class="token imports punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'Dora'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<p>  在 Dora SSR 中显示一个图片很简单，只要使用<code>&lt;sprite&gt;</code>标签，最后通过<code>toNode()</code>函数将标签实例化为一个游戏对象就可以了。</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token function" style="color:rgb(220, 220, 170)">toNode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">sprite</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">file</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">'</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">Image/logo.png</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">'</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">scaleX</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">scaleY</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<p>  好的，至此你已经基本掌握大部分 Dora SSR 游戏开发的诀窍了，开始做你自己的游戏吧（认真）。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-编写游戏箱子组件">2. 编写游戏箱子组件<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#2-%E7%BC%96%E5%86%99%E6%B8%B8%E6%88%8F%E7%AE%B1%E5%AD%90%E7%BB%84%E4%BB%B6" class="hash-link" aria-label="2. 编写游戏箱子组件的直接链接" title="2. 编写游戏箱子组件的直接链接" translate="no">​</a></h3>
<p>  接下来我们在游戏中碰撞的箱子会由 <code>Box</code> 组件定义，它接受 <code>num</code>、<code>x</code>、<code>y</code> 和 <code>children</code> 等属性：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">BoxProps</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	num</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">number</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	x</span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">number</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	y</span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">number</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	children</span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">any</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">any</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(220, 220, 170)">Box</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">props</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token maybe-class-name" style="color:#4EC9B0">BoxProps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token keyword" style="color:#C586C0">const</span><span class="token plain"> numText </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">num</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:rgb(220, 220, 170)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token keyword" style="color:#C586C0">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">		</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">body</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">type</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">BodyMoveType</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access maybe-class-name" style="color:#4EC9B0">Dynamic</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">scaleX</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">scaleY</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">x</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">props</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">x</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">y</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">props</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">y</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">tag</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">numText</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">rect-fixture</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">width</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">height</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">draw-node</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">				</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">rect-shape</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">width</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">height</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">fillColor</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0x8800ffff</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">borderWidth</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">1</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">borderColor</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0xff00ffff</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">draw-node</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">label</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">fontName</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">'</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">sarasa-mono-sc-regular</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">'</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">fontSize</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">40</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain">numText</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">label</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain">props</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">children</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">		</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">body</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<p>  我们使用仿 React 的函数组件的写法来完成我们箱子组件的定义，其中：</p>
<ul>
<li class=""><code>body</code> 组件的 <code>tag</code> 属性：用于存储箱子的分数。</li>
<li class=""><code>rect-fixture</code> ：定义了箱子的碰撞形状。</li>
<li class=""><code>draw-node</code> ：用于绘制箱子的外观。</li>
<li class=""><code>label</code> ：用于显示盒子的分数。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-创建-tsx-实例化后的对象引用">3. 创建 TSX 实例化后的对象引用<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#3-%E5%88%9B%E5%BB%BA-tsx-%E5%AE%9E%E4%BE%8B%E5%8C%96%E5%90%8E%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8" class="hash-link" aria-label="3. 创建 TSX 实例化后的对象引用的直接链接" title="3. 创建 TSX 实例化后的对象引用的直接链接" translate="no">​</a></h3>
<p>  使⽤ useRef 创建两个引⽤变量进行备用，分别指向⼩⻦和分数标签：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">const</span><span class="token plain"> bird </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">useRef</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">Body</span><span class="token generic-function generic class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">Type</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">const</span><span class="token plain"> score </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">useRef</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">Label</span><span class="token generic-function generic class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">Type</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-创建发射线">4. 创建发射线<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#4-%E5%88%9B%E5%BB%BA%E5%8F%91%E5%B0%84%E7%BA%BF" class="hash-link" aria-label="4. 创建发射线的直接链接" title="4. 创建发射线的直接链接" translate="no">​</a></h3>
<p>  发射线由 <code>line</code> 变量创建，并添加触摸（同时也是鼠标点击）的事件处理：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token maybe-class-name" style="color:#4EC9B0">Vec2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">zero</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> delta </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token maybe-class-name" style="color:#4EC9B0">Vec2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">zero</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">const</span><span class="token plain"> line </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">Line</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">toNode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">physics-world</span><span class="token tag" style="color:#569CD6"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag" style="color:#569CD6">		</span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">onTapBegan</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">touch </span><span class="token tag script language-javascript arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			start </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> touch</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">location</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			line</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">clear</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">		</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag" style="color:#569CD6">		</span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">onTapMoved</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">touch </span><span class="token tag script language-javascript arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			delta </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> delta</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">add</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">touch</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">delta</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			line</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">set</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token tag script language-javascript" style="color:#D4D4D4">start</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token tag script language-javascript" style="color:#D4D4D4"> start</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">add</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">delta</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">		</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag" style="color:#569CD6">		</span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">onTapEnded</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript keyword" style="color:#C586C0">if</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">!</span><span class="token tag script language-javascript" style="color:#D4D4D4">bird</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">current</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript keyword" style="color:#C586C0">return</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			bird</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">current</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">velocity</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> delta</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">mul</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript function" style="color:rgb(220, 220, 170)">Vec2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript number" style="color:#B5CEA8">10</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript number" style="color:#B5CEA8">10</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			start </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">Vec2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">zero</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			delta </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">Vec2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">zero</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			line</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">clear</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">		</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag" style="color:#569CD6">		</span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">onMount</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">world </span><span class="token tag script language-javascript arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			world</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">addChild</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">line</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">		</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag" style="color:#569CD6">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">		</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token comment" style="color:rgb(106, 153, 85)">/* ...在物理世界下创建其它游戏元素 ... */</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">physics-world</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<ul>
<li class="">在 <code>onTapBegan</code> 事件中，记录触摸开始的位置并清除发射线。</li>
<li class="">在 <code>onTapMoved</code> 事件中，计算触摸移动的距离并更新发射线。</li>
<li class="">在 <code>onTapEnded</code> 事件中，根据触摸移动的距离设置小鸟的发射速度并清除发射线。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-创建其它游戏元素">5. 创建其它游戏元素<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#5-%E5%88%9B%E5%BB%BA%E5%85%B6%E5%AE%83%E6%B8%B8%E6%88%8F%E5%85%83%E7%B4%A0" class="hash-link" aria-label="5. 创建其它游戏元素的直接链接" title="5. 创建其它游戏元素的直接链接" translate="no">​</a></h3>
<p>  接下来，我们以 <code>&lt;physics-world&gt;</code> 作为游戏场景的父级标签，在它下面继续创建游戏场景中的各个元素：</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-地面">5.1 地面<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#51-%E5%9C%B0%E9%9D%A2" class="hash-link" aria-label="5.1 地面的直接链接" title="5.1 地面的直接链接" translate="no">​</a></h4>
<p>  首先，我们使用 <code>body</code> 组件创建一个地面，并将其设置为静态刚体：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">body</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">type</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">BodyMoveType</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access maybe-class-name" style="color:#4EC9B0">Static</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">rect-fixture</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">centerY</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">-</span><span class="token tag script language-javascript number" style="color:#B5CEA8">200</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">width</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">2000</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">height</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">10</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">draw-node</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">		</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">rect-shape</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">centerY</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">-</span><span class="token tag script language-javascript number" style="color:#B5CEA8">200</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">width</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">2000</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">height</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">10</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">fillColor</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0xfffbc400</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">draw-node</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text"></span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">body</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><br></span></code></pre></div></div>
<ul>
<li class=""><code>type={BodyMoveType.Static}</code>：表明这是一个静态刚体，不会受到物理模拟的影响。</li>
<li class=""><code>rect-fixture</code>：定义地面碰撞形状为一个矩形。</li>
<li class=""><code>draw-node</code>：用于绘制地面的外观。</li>
<li class=""><code>rect-shape</code>：绘制一个矩形，颜色为黄色。</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-箱子">5.2 箱子<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#52-%E7%AE%B1%E5%AD%90" class="hash-link" aria-label="5.2 箱子的直接链接" title="5.2 箱子的直接链接" translate="no">​</a></h4>
<p>  接下来，我们使用之前写好的 <code>Box</code> 组件创建 5 个箱子，并设置不同的初始位置和分数，在创建时播放出场动画：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:#B5CEA8">10</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">20</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">30</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">40</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">50</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:rgb(220, 220, 170)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">num</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">		</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag class-name" style="color:rgb(78, 201, 176)">Box</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">num</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">num</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">x</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">200</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">y</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">-</span><span class="token tag script language-javascript number" style="color:#B5CEA8">150</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">+</span><span class="token tag script language-javascript" style="color:#D4D4D4"> i </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">*</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript number" style="color:#B5CEA8">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">sequence</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">				</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">delay</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">time</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">i </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">*</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">				</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">scale</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">time</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.3</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">start</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">stop</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">1</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">			</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">sequence</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">		</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag class-name" style="color:rgb(78, 201, 176)">Box</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<ul>
<li class=""><code>map</code> 函数：用于遍历分数数组从 10 到 50，并为每个分数创建一个需要小鸟撞击的箱子。</li>
<li class=""><code>Box</code> 组件：用于创建箱子，并传入以下属性：<!-- -->
<ul>
<li class=""><code>num={num}</code>：箱子的分数，对应数组中的数字。</li>
<li class=""><code>x={200}</code>：箱子的初始 x 轴位置，为 200。</li>
<li class=""><code>y={-150 + i * 100}</code>：箱子的初始 y 轴位置，根据创建序号递增。</li>
</ul>
</li>
<li class=""><code>sequence</code> 组件：用于创建要在父节点上播放的动画序列，包含以下动画：<!-- -->
<ul>
<li class=""><code>delay time={i * 0.2}</code>：延迟播放动画，延迟时间根据创建序号递增。</li>
<li class=""><code>scale time={0.3} start={0} stop={1}</code>：缩放动画，从不显示到完全显示，耗时 0.3 秒。</li>
</ul>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="53-小鸟">5.3 小鸟<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#53-%E5%B0%8F%E9%B8%9F" class="hash-link" aria-label="5.3 小鸟的直接链接" title="5.3 小鸟的直接链接" translate="no">​</a></h4>
<p>  最后，我们使用 <code>body</code> 组件创建小鸟，并设置碰撞形状、外观和分数标签：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">body</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">ref</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">bird</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">type</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">BodyMoveType</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access maybe-class-name" style="color:#4EC9B0">Dynamic</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">x</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">-</span><span class="token tag script language-javascript number" style="color:#B5CEA8">200</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">y</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">-</span><span class="token tag script language-javascript number" style="color:#B5CEA8">150</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag" style="color:#569CD6">	</span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">onContactStart</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">other </span><span class="token tag script language-javascript arrow operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">		</span><span class="token tag script language-javascript keyword" style="color:#C586C0">if</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">other</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">tag</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">!==</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript string" style="color:rgb(206, 145, 120)">''</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">&amp;&amp;</span><span class="token tag script language-javascript" style="color:#D4D4D4"> score</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">current</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript comment" style="color:rgb(106, 153, 85)">// 累加积分</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript keyword" style="color:#C586C0">const</span><span class="token tag script language-javascript" style="color:#D4D4D4"> sc </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript function" style="color:rgb(220, 220, 170)">parseFloat</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">score</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">current</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">text</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">+</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript function" style="color:rgb(220, 220, 170)">parseFloat</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">other</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">tag</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			score</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">current</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">text</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> sc</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">toString</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript comment" style="color:rgb(106, 153, 85)">// 清除被撞箱子上的分数</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript keyword" style="color:#C586C0">const</span><span class="token tag script language-javascript" style="color:#D4D4D4"> label </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> tolua</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">cast</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">other</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">children</span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">?.</span><span class="token tag script language-javascript" style="color:#D4D4D4">last</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">TypeName</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access maybe-class-name" style="color:#4EC9B0">Label</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript keyword" style="color:#C586C0">if</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript" style="color:#D4D4D4">label</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript" style="color:#D4D4D4"> label</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">text</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript string" style="color:rgb(206, 145, 120)">''</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			other</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access" style="color:#D4D4D4">tag</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript operator" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript string" style="color:rgb(206, 145, 120)">''</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			</span><span class="token tag script language-javascript comment" style="color:rgb(106, 153, 85)">// 播放箱子被撞的动画</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">			other</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(220, 220, 170)">perform</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript function" style="color:rgb(220, 220, 170)">Scale</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.2</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.7</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token tag script language-javascript" style="color:#D4D4D4"> </span><span class="token tag script language-javascript number" style="color:#B5CEA8">1.0</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">		</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag script language-javascript" style="color:#D4D4D4"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token tag script language-javascript" style="color:#D4D4D4">	</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">disk-fixture</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">radius</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">50</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">draw-node</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">		</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">dot-shape</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">radius</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">50</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">color</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0xffff0088</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">draw-node</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">label</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">ref</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript" style="color:#D4D4D4">score</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">fontName</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">'</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">sarasa-mono-sc-regular</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">'</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">fontSize</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">40</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text">0</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">label</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text">	</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:#569CD6">scale</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">time</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.4</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">start</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">0.3</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">stop</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript number" style="color:#B5CEA8">1.0</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag" style="color:#569CD6"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">easing</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token tag script language-javascript maybe-class-name" style="color:#4EC9B0">Ease</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token tag script language-javascript property-access maybe-class-name" style="color:#4EC9B0">OutBack</span><span class="token tag script language-javascript punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain-text"></span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:#569CD6">body</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><br></span></code></pre></div></div>
<ul>
<li class=""><code>ref={bird}</code>：使用 <code>ref</code> 创建引用变量，方便后续操控小鸟。</li>
<li class=""><code>type={BodyMoveType.Dynamic}</code>：表明这是一个动态刚体，会受到物理模拟的影响。</li>
<li class=""><code>onContactStart={(other) =&gt; {}}</code>：小鸟的物理体接触到其它物体时触发的回调处理函数。</li>
<li class=""><code>disk-fixture</code>：定义小鸟形状为一个圆盘。</li>
<li class=""><code>draw-node</code> ：用于绘制小鸟的外观。</li>
<li class=""><code>label</code> ：用于显示小鸟的累积分数。</li>
<li class=""><code>scale</code> ：用于播放小鸟的出场动画。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-完成游戏逻辑">6. 完成游戏逻辑<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#6-%E5%AE%8C%E6%88%90%E6%B8%B8%E6%88%8F%E9%80%BB%E8%BE%91" class="hash-link" aria-label="6. 完成游戏逻辑的直接链接" title="6. 完成游戏逻辑的直接链接" translate="no">​</a></h3>
<p>  至此，我们已经完成了小游戏的核心逻辑。你可以根据自己的想法进一步完善游戏逻辑和增加功能。完整的 demo 代码可以见这个链接：<a href="https://github.com/IppClub/Dora-Example/blob/master/Example/Birdy.tsx" target="_blank" rel="noopener noreferrer" class="">Dora-Example/Example/Birdy.tsx</a>。下面是一些运行效果的截图。</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/birdy1-4ae21702d205aae54fbb29507a4f3b4d.png" alt="拖拽屏幕发射了“愤怒的小鸟”"></p><p>拖拽屏幕发射了“愤怒的小鸟”</p><p></p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/birdy2-607933996611fd031ef52003f9447ba0.png" alt="高超的技巧，使我一击获得了所有得分"></p><p>高超的技巧，使我一击获得了所有得分</p><p></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四简单揭秘一下">四、简单揭秘一下<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#%E5%9B%9B%E7%AE%80%E5%8D%95%E6%8F%AD%E7%A7%98%E4%B8%80%E4%B8%8B" class="hash-link" aria-label="四、简单揭秘一下的直接链接" title="四、简单揭秘一下的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-是鹿还是马">1. 是鹿还是马<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#1-%E6%98%AF%E9%B9%BF%E8%BF%98%E6%98%AF%E9%A9%AC" class="hash-link" aria-label="1. 是鹿还是马的直接链接" title="1. 是鹿还是马的直接链接" translate="no">​</a></h3>
<p>  事实上我们写的这段游戏代码，在 Dora SSR 引擎的能力下是可以确保在跨 Linux、Android、iOS、macOS 和 Windows 获得一致的运行结果。但是为了运行这段代码，我们的 Dora SSR 引擎甚至都没有做 JavaScript 运行环境的支持……（你说什么？）</p>
<p>  是的，Dora SSR 的底层技术实现其实是基于 Lua 和 WASM 虚拟机作为脚本语言运行环境的。对 TypeScript 的支持其实是通过整合了 <a href="https://github.com/TypeScriptToLua/TypeScriptToLua" target="_blank" rel="noopener noreferrer" class="">TypescriptToLua</a> 这个编译器提供的。TSTL 通过重新编写了 TypeScript 语言编译器的后端，将 TS 和 TSX 的代码编译为了等价运行的 Lua 代码，从而使得 TS 代码可以在 Dora 上加载运行。在 Dora 自带的 Web IDE 的代码编辑器下，可以帮助大家做 TS 的语言检查和补全以及 Dora 内置库 API 的提示。最终的使用体验，大家就可以不用管最后是鹿还是马，只要代码能通过了 TS 的编译检查，拉出来那都是一样的跑啦。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-和-react-有关系吗">2. 和 React 有关系吗<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/25/tsx-dev-intro#2-%E5%92%8C-react-%E6%9C%89%E5%85%B3%E7%B3%BB%E5%90%97" class="hash-link" aria-label="2. 和 React 有关系吗的直接链接" title="2. 和 React 有关系吗的直接链接" translate="no">​</a></h3>
<p>  这个问题的答案目前是：可以有（所以截至发文前还没有）。React 最重要的能力是通过 Virtual DOM 和执行 Tree Diff 处理的过程来进行渲染组件和业务数据的状态同步，目前这个机制还没有在 Dora SSR 中实现，所以大家目前看到的用 TSX 编写出的类似 VDOM 的构建代码只会在运行时做一次性的游戏渲染对象的构建，往后都是底层 C++ 实现的引擎功能在负责继续处理。也许有一天我们会为游戏 UI 的开发，提供仿 React 通过执行 Tree Diff 做状态同步的能力，或是仿 SolidJS 基于 TSX 实现其它的渲染组件状态同步的机制。所以在这里也诚挚地邀请广大前端开发的朋友，加入我们，一起玩 Dora SSR 项目，一起研究怎么运用前端开发技术思想，为游戏开发也引入更多好用便捷的轮子吧。</p>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="TSX" term="TSX"/>
        <category label="TypeScript" term="TypeScript"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[给 Moonscript 重写编译器的故事]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale"/>
        <updated>2024-04-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Moonscript 是一门极为小众的编程语言]]></summary>
        <content type="html"><![CDATA[<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/tokyo-moon-b7e7e52a4ef04622c08ee55c8e67d577.jpg" alt="tokyo moon" height="300px"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="moonscript-是一门极为小众的编程语言">Moonscript 是一门极为小众的编程语言<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale#moonscript-%E6%98%AF%E4%B8%80%E9%97%A8%E6%9E%81%E4%B8%BA%E5%B0%8F%E4%BC%97%E7%9A%84%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80" class="hash-link" aria-label="Moonscript 是一门极为小众的编程语言的直接链接" title="Moonscript 是一门极为小众的编程语言的直接链接" translate="no">​</a></h2>
<p>  Moonscript 是一门编译成为 Lua 代码并在 Lua 虚拟机运行的编程语言。主要语法和特性借鉴于 Coffeescript。这门语言的优势在于语言简练、具有较强表达力的同时能保留尽可能高的可读性，在表达力和可读性之间取得一个比较好的平衡点。有较为克制不那么 corner case 的语法糖。用来写一些经常变化的业务逻辑非常省力，实践下来编写相同的游戏开发类的业务逻辑，用 Moonscript 比写原生的 Lua 能缩减到 1/2，甚至到 1/3 的代码量，更少的代码对减少 Bug 的产生或是问题排查也有很多帮助。另外这门语言还有一个重要特点，据 Discord 群里的老哥说，全世界范围内的活跃用户可能只有 20 多人。还有一个更重要的特点就是这是一门 Sailor Moon Themed 的编程语言。</p>
<!-- -->
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/moonscript-0f7963b0bd86484283e9e43ccd47841f.png" alt="logo里暗藏情怀" height="200px"></p><p>logo里暗藏情怀</p><p></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="开源和免费难以为继">开源和免费难以为继<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale#%E5%BC%80%E6%BA%90%E5%92%8C%E5%85%8D%E8%B4%B9%E9%9A%BE%E4%BB%A5%E4%B8%BA%E7%BB%A7" class="hash-link" aria-label="开源和免费难以为继的直接链接" title="开源和免费难以为继的直接链接" translate="no">​</a></h2>
<p>  Moonscript 的作者因使用这门语言开发了一些商业网站，如销售独立游戏的 itch.io，以及分享绘画作品的网站 streak.club。说为了保持这门语言的稳定性，从 2017 年开始暂缓了项目的维护，不再增加新特性，甚至 issue fix 也不积极了。当然生活不易，作者还开了 github sponsor 希望他开发的开源软件能获得更多支持。我们也没理由要求别人一直免费给大家做贡献。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="不爽就自己重写">不爽就自己重写<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale#%E4%B8%8D%E7%88%BD%E5%B0%B1%E8%87%AA%E5%B7%B1%E9%87%8D%E5%86%99" class="hash-link" aria-label="不爽就自己重写的直接链接" title="不爽就自己重写的直接链接" translate="no">​</a></h2>
<p>  当然，作为 Moonscript 粉丝的我对这样的状况是不能够接受的。原版 Moonscript 编译器是用 Moonscript 写的，核心是用 C 语言实现的 PEG 文法解析库解析 Moonscript 代码生成 AST 结构传到 Lua 环境中，再由 Moonscript 编译生成的 Lua 代码操作 AST 结构把Moonscript 代码翻译成 Lua 代码。这个方案还是挺浪费资源，C 语言实现的 parser 很高效，但是后续回到 Lua 环境创建大量 Lua 的数据结构，增加资源消耗和 Lua GC 时间其实并无必要，在数千行 Moonscript 代码的项目中，如果不做预编译，在运行时才动态加载 Moonscript 代码，会明显感觉到程序的长时间卡顿。另外用动态类型的语言来操作需要严格检查数据类型的 AST 结构，完全是动态语言开发的弱项。</p>
<p>  当然说得再多不如拿出代码有意义，所以我没有继承已有的 code base，而是直接用第二喜欢的编程语言 C++ 进行了完全的重写（第一喜欢的就是 Moonscript）。并在重写的同时顺便修复了各类作者未解决的问题，并引入一些缺失了几年的其它语言都已经用烂的编程特性。</p>
<p>  详见项目：<a href="https://yuescript.org/zh" target="_blank" rel="noopener noreferrer" class="">YueScript</a>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="transpilers-for-lua-和-peg-文法">Transpilers For Lua 和 PEG 文法<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale#transpilers-for-lua-%E5%92%8C-peg-%E6%96%87%E6%B3%95" class="hash-link" aria-label="Transpilers For Lua 和 PEG 文法的直接链接" title="Transpilers For Lua 和 PEG 文法的直接链接" translate="no">​</a></h2>
<p>  不过说到编译生成另一门编程语言的编译器，现在更准确的叫法是叫做转译器（transpiler）。Lua 语言因为语言设计的简洁，实现了只用做一次遍历的递归下降解析器，本身的编译时间极快。又因为大家各自编程喜好的不同，很多人就打起了开发其它编程语言转译成 Lua 的转译器，扩展 Lua 语言的开发能力的想法。除了 Moonscript 外现在已有各类从 Javascript、Typescript、Lisp、C、Python、Go 和C# 等等各种语言转译成 Lua 的实现。另外也有各种给 Lua 语言加上静态类型检查的想法。</p>
<p>  说到底还是因为大家的审美和个性化的需求的日益增长，以及硬件的发展解放了算力，让大家都不再纠结于程序文法复杂度以及程序编译期间各种开销的问题，解放了大家研发新编程语言的生产力。就如 Python 之父曾因为历史原因，在三十年前为了确保 parser 的执行效率，降低文本解析阶段的内存消耗，实现了 LL(1) 的文法，只要一个 token 的 look ahead 就足够完成文法解析。后来算力和内存提供的条件已经大大超过以前，便开始考虑采用对程序开发更加友好的PEG文法，通过使用足够多的缓存支持无限多次的文法匹配回溯（backtrace），提升解析器开发的灵活性，以增强未来 Python 语言演化的能力。</p>
<p>  原版 Moonscript 也是用 PEG 文法实现的。一般实现 PEG 支持的程序库都是提供通过 parser combinator 的形式编写解析器程序。我在 C++ 中先尝试了使用 meta programming 实现的在编译期构建 parser 的黑魔法库 PEGTL，结果未获得任何开发上的增益，调试困难就不用说了，如果文法有复杂度太高，或者左递归，直接编译期提示生成函数嵌套超过最大值，左递归报错是应该，正常的嵌套太深就只能尝试调大编译参数看能不能过编译了。好不容易调好了 parser 生成一看好几个M的 binary size，才发现这个库比起应用更多的只是炫技。最终我找到了 parserlib（<a href="https://github.com/axilmar/parserlib" target="_blank" rel="noopener noreferrer" class="">https://github.com/axilmar/parserlib</a> ）。运行时生成 parser，带有 AST 生成还提供一定程度的左递归文法自动解决功能，看了代码关于如何在 parse 的过程中创建 AST 的部分很精妙，就决定是它了。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="用-c-编写-transpiler-的优势">用 C++ 编写 Transpiler 的优势<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale#%E7%94%A8-c-%E7%BC%96%E5%86%99-transpiler-%E7%9A%84%E4%BC%98%E5%8A%BF" class="hash-link" aria-label="用 C++ 编写 Transpiler 的优势的直接链接" title="用 C++ 编写 Transpiler 的优势的直接链接" translate="no">​</a></h2>
<p>  有的人形容 Moonscript 是 Lua 上的一套宏系统，的确没错，很多 Moon 的语法其实就是加了能简写代码的 Lua 语法糖。Moon 转译到 Lua 只要做三步操作，第一步是解析代码生成 Moon AST，第二步是把 Moon AST 转换成对应的 Lua AST，最后一步把 Lua AST 转换成代码文本。用 C++ 操作 AST 结构的优势就是可以在编译期以及运行时以比较小的代价完成对 AST 结构的类型检查。</p>
<p>  并且到 C++17 版本 C++ 语言增加了很多新的编程特性，编程的表达力和抽象能力也已经变得更加强大。原版用 Moonscript 编写的 Moonscript 编译器用了近 5K 行代码，现在用 C++17 实现相同的业务功能也只用 5K 行多一点的代码量。Discord 群里另一位老哥也说他在 C++98 的年代写相同规模的项目预估代码量是不低于上万行的，C++17 已经带来了他没想到的语言进步。当然表达力、抽象力是增强了，用了一些黑魔法特性以后，生成的 binary size 也增大了很多。</p>
<p>  通过 C++ 的 meta programing 的能力，我们可以放心地写这样的代码：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token comment" style="color:rgb(106, 153, 85)">// 检查ast节点是Exp或ExpList</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">item</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token generic-function function" style="color:rgb(220, 220, 170)">is</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">Exp_t</span><span class="token generic-function generic class-name punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)"> ExpList_t</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// 检查某节点开始是否匹配某个ast结构分支</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// 并获取最后一个匹配的节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">auto</span><span class="token plain"> variable </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    node</span><span class="token operator" style="color:rgb(212, 212, 212)">-&gt;</span><span class="token generic-function function" style="color:rgb(220, 220, 170)">getByPath</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">ChainValue_t</span><span class="token generic-function generic class-name punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)"> Callable_t</span><span class="token generic-function generic class-name punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)"> Variable_t</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">auto</span><span class="token plain"> varName </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">variable</span><span class="token operator" style="color:rgb(212, 212, 212)">-&gt;</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// 用switch语句分别处理不同的ast结构</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// id作为编译期常量由编译器自动生成，无需人手工编号</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">node</span><span class="token operator" style="color:rgb(212, 212, 212)">-&gt;</span><span class="token function" style="color:rgb(220, 220, 170)">getId</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">case</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">id</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">While_t</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">auto</span><span class="token plain"> while_ </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">static_cast</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">While_t</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">*</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">break</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">case</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">id</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">For_t</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">auto</span><span class="token plain"> for_ </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(220, 220, 170)">static_cast</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token generic-function generic class-name" style="color:rgb(78, 201, 176)">For_t</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">*</span><span class="token generic-function generic class-name operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">        </span><span class="token keyword" style="color:#C586C0">break</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<p>  通过利用模板泛型参数的功能，可以将一些参数类型的检查放到编译期。如：</p>
<p><code>node-&gt;getByPath&lt;ChainValue_t, Callable_t&gt;()</code></p>
<p>  就要比类似</p>
<p><code>node-&gt;getByPath("ChainValue", "Callable")</code></p>
<p>  这样的写法少很多潜在的风险，同时进行了编译期参数检查，运行时类型匹配的两重功能，动态类型的语言是很难取代这样的优势的。在这些设施的帮助下，不用额外设计特别复杂的检查机制，错误地操作 AST 结构就会产生明确的编译报错或是运行时报错，让 C++ 写 transpiler 无比爽快和省心。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="方言中的方言yuescript-语言的生产应用">方言中的方言——YueScript 语言的生产应用<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/17/a-moon-script-tale#%E6%96%B9%E8%A8%80%E4%B8%AD%E7%9A%84%E6%96%B9%E8%A8%80yuescript-%E8%AF%AD%E8%A8%80%E7%9A%84%E7%94%9F%E4%BA%A7%E5%BA%94%E7%94%A8" class="hash-link" aria-label="方言中的方言——YueScript 语言的生产应用的直接链接" title="方言中的方言——YueScript 语言的生产应用的直接链接" translate="no">​</a></h2>
<p>  YueScript 在创作之初其实有一直绑定了一个开源的游戏引擎项目 Dora SSR (<a href="https://dora-ssr.net/" target="_blank" rel="noopener noreferrer" class="">https://dora-ssr.net</a> )，可以说 YueScript 的一个重要的创作目标，就是为了让支持 Lua 语言的 Dora SSR 开源游戏引擎用上升级版的 Moonscript 语言。结合 Dora SSR 的 Web IDE，我们还给 YueScript 语言稍微增加了一点点代码编辑器上的类型推导和代码补全的辅助能力。</p>
<p>  我特别喜欢在参加一些 Game Jam 活动的时候，和策划伙伴一顿头脑风暴，然后掏出 Dora SSR 引擎和 YueScript 就是一阵不考虑太多编程设计且“不计后果”的糊玩法编码。当然编程设计也不能说是完全没有，结合 Dora SSR 游戏引擎的消息系统机制 + YueScript 函数式风格编程的写法。Game Jam 里埋头花几个钟头写 1k 行代码左右，在一个函数内把游戏 demo 写完也是没有问题的。在 <a href="https://github.com/IppClub/Dora-SSR/tree/main/Assets/Script/Game" target="_blank" rel="noopener noreferrer" class="">Dora SSR 的仓库</a> 里也可以看到我们过往糊的各种 Game Jam 小游戏的 YueScript 源码。</p>
<p>  所以对 Lua 的方言 Moonscript 的方言 YueScript 语言的可用性，至少也是在 Dora SSR 项目中有过不少代码有在做验证啦。</p>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="YueScript" term="YueScript"/>
        <category label="Lua" term="Lua"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[来用 Rust 开发跨平台游戏吧]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev"/>
        <updated>2024-04-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[一、引言]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一引言">一、引言<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E4%B8%80%E5%BC%95%E8%A8%80" class="hash-link" aria-label="一、引言的直接链接" title="一、引言的直接链接" translate="no">​</a></h2>
<p>  自从童年时代深陷 Warcraft III 的 MOD 魔力之中，我就一直对游戏脚本语言怀有特殊的情感。回想那时，使用暴雪开发的 JASS 语言开发魔兽争霸3的游戏关卡，尽管从今天的角度看 JASS 是极其简陋的，主要特点为静态类型 + 无 GC 功能，但它在那个尚未形成行业标准的年代，代表了对游戏开发语言的一种大胆尝试。</p>
<!-- -->
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="为什么要使用脚本语言开发游戏">为什么要使用脚本语言开发游戏？<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8%E8%84%9A%E6%9C%AC%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E6%B8%B8%E6%88%8F" class="hash-link" aria-label="为什么要使用脚本语言开发游戏？的直接链接" title="为什么要使用脚本语言开发游戏？的直接链接" translate="no">​</a></h3>
<p>  游戏脚本语言的引入主要是为了提高开发测试的便捷性。如果直接使用 C++ 这样的底层语言，每更改一行代码，都可能需要耗费大量时间等待复杂工具链的编译与打包。而通过使用脚本语言，可以对实现游戏玩法的程序进行热加载执行，显著提升游戏的开发效率。</p>
<p>  随着时间的推移，如 Lua 和 JavaScript 这样的动态类型脚本语言已成为游戏开发中的常客。然而，随着编程语言的发展，我们有机会重新定义游戏脚本语言的新标准——既复古又革新，这就是 Rust + WASM 的组合。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二rust--wasm--dora-ssr重新定义游戏脚本开发">二、Rust + WASM + Dora SSR：重新定义游戏脚本开发<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E4%BA%8Crust--wasm--dora-ssr%E9%87%8D%E6%96%B0%E5%AE%9A%E4%B9%89%E6%B8%B8%E6%88%8F%E8%84%9A%E6%9C%AC%E5%BC%80%E5%8F%91" class="hash-link" aria-label="二、Rust + WASM + Dora SSR：重新定义游戏脚本开发的直接链接" title="二、Rust + WASM + Dora SSR：重新定义游戏脚本开发的直接链接" translate="no">​</a></h2>
<p>  通过结合 Rust 和 WASM，我们可以在不牺牲性能的前提下，直接在例如 Android 或 iOS 设备上进行游戏热更新和测试，且无需依赖传统的应用开发工具链。此外，借助 Dora SSR 开源游戏引擎的 Web IDE 接口，使用 Rust 编写的游戏代码可以一次编译后，在多种游戏设备上进行测试和运行。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="为何选择-rust">为何选择 Rust？<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E4%B8%BA%E4%BD%95%E9%80%89%E6%8B%A9-rust" class="hash-link" aria-label="为何选择 Rust？的直接链接" title="为何选择 Rust？的直接链接" translate="no">​</a></h3>
<p>  Rust 提供了无与伦比的内存安全保证，而且无需垃圾收集器（GC）的介入，这使得它非常适合游戏开发，尤其是在性能敏感的场景下。结合 WASM，Rust 不仅能够提供高性能的执行效率，还能保持跨平台的一致性和安全性。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="快速开始指南">快速开始指南<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B%E6%8C%87%E5%8D%97" class="hash-link" aria-label="快速开始指南的直接链接" title="快速开始指南的直接链接" translate="no">​</a></h3>
<p>  在开始开发之前，我们需要安装 Dora SSR 游戏引擎。该引擎支持多种平台，包括 Windows、Linux、macOS、iOS 和 Android。具体的安装步骤和要求，请参见官方快速开始指南：<a href="https://dora-ssr.net/zh-Hans/docs/tutorial/quick-start" target="_blank" rel="noopener noreferrer" class="">Dora SSR 快速开始</a>。</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/rusty-zh-0-10428e2aa126ca4641c6b31aace920a2.jpg" alt="在 macOS 上运行的 Dora SSR v1.3.17 版本"></p><p>在 macOS 上运行的 Dora SSR v1.3.17 版本</p><p></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步创建新项目">第一步：创建新项目<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%88%9B%E5%BB%BA%E6%96%B0%E9%A1%B9%E7%9B%AE" class="hash-link" aria-label="第一步：创建新项目的直接链接" title="第一步：创建新项目的直接链接" translate="no">​</a></h4>
<p>  在 Dora SSR 引擎的二进制程序启动以后，在浏览器中打开 Dora SSR 的 Web IDE，右键点击左侧游戏资源树，选择「新建」并创建名为「Hello」的新文件夹。</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/rusty-zh-1-0c8bb589a014c170a1ca5cfbfed2c00e.jpg" alt="在浏览器中访问 Dora SSR 的 Web IDE 并新建文件夹"></p><p>在浏览器中访问 Dora SSR 的 Web IDE 并新建文件夹</p><p></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步编写游戏代码">第二步：编写游戏代码<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E7%BC%96%E5%86%99%E6%B8%B8%E6%88%8F%E4%BB%A3%E7%A0%81" class="hash-link" aria-label="第二步：编写游戏代码的直接链接" title="第二步：编写游戏代码的直接链接" translate="no">​</a></h4>
<p>  然后在命令行中创建一个新的 Rust 项目：</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token plain">rustup target </span><span class="token function" style="color:rgb(220, 220, 170)">add</span><span class="token plain"> wasm32-wasip1</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">cargo</span><span class="token plain"> new hello-dora </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--name</span><span class="token plain"> init</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> hello-dora</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">cargo</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">add</span><span class="token plain"> dora_ssr</span><br></span></code></pre></div></div>
<p>  在 <code>src/main.rs</code> 中编写代码：</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">use</span><span class="token plain"> </span><span class="token namespace">dora_ssr</span><span class="token namespace punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:rgb(220, 220, 170)">main</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">  </span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">mut</span><span class="token plain"> sprite </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">match</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Sprite</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">with_file</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Image/logo.png"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token class-name" style="color:rgb(78, 201, 176)">Some</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">sprite</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token plain"> sprite</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token class-name" style="color:rgb(78, 201, 176)">None</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">return</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">  </span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">mut</span><span class="token plain"> sprite_clone </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> sprite</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">clone</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">  sprite</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">schedule</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">once</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:#C586C0">move</span><span class="token plain"> </span><span class="token closure-params closure-punctuation punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token closure-params keyword" style="color:#C586C0">mut</span><span class="token closure-params"> co</span><span class="token closure-params closure-punctuation punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">async</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">move</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#C586C0">in</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:#B5CEA8">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..=</span><span class="token number" style="color:#B5CEA8">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">rev</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">      </span><span class="token macro property" style="color:#9CDCFE">p!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"{}"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">      </span><span class="token macro property" style="color:#9CDCFE">sleep!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">co</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token macro property" style="color:#9CDCFE">p!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Hello World"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    sprite_clone</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">perform_def</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">ActionDef</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">sequence</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token macro property" style="color:#9CDCFE">vec!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">      </span><span class="token class-name" style="color:rgb(78, 201, 176)">ActionDef</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">scale</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:#B5CEA8">0.1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0.5</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">EaseType</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token class-name" style="color:rgb(78, 201, 176)">Linear</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">      </span><span class="token class-name" style="color:rgb(78, 201, 176)">ActionDef</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">scale</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:#B5CEA8">0.5</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0.5</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">EaseType</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token class-name" style="color:rgb(78, 201, 176)">OutBack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre></div></div>
<p>  构建生成 WASM 文件：</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token function" style="color:rgb(220, 220, 170)">cargo</span><span class="token plain"> build </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--release</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--target</span><span class="token plain"> wasm32-wasip1</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步上传并运行游戏">第三步：上传并运行游戏<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E7%AC%AC%E4%B8%89%E6%AD%A5%E4%B8%8A%E4%BC%A0%E5%B9%B6%E8%BF%90%E8%A1%8C%E6%B8%B8%E6%88%8F" class="hash-link" aria-label="第三步：上传并运行游戏的直接链接" title="第三步：上传并运行游戏的直接链接" translate="no">​</a></h4>
<p>  在 Dora SSR Web IDE 中，右键点击新创建的文件夹「Hello」，选择「上传」并上传编译好的 WASM 文件 <code>init.wasm</code>。</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/rusty-zh-2-033d4fc1743a2508d2ae10002ec00deb.jpg" alt="通过 Web IDE 上传文件，相比用辅助脚本操作可能要更方便"></p><p>通过 Web IDE 上传文件，相比用辅助脚本操作可能要更方便</p><p></p>
<p>  或者使用辅助脚本 <a href="https://github.com/IppClub/Dora-SSR/blob/main/Tools/dora-rust/dora-test/upload.py" target="_blank" rel="noopener noreferrer" class="">upload.py</a> 在 Rust 项目文件夹内上传 WASM 文件，命令如下，其中的 IP 参数为 Dora SSR 启动后显示的 Web IDE 地址，后一个参数为要上传目录的相对路径：</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token plain">python3 upload.py </span><span class="token string" style="color:rgb(206, 145, 120)">"192.168.3.1"</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Hello"</span><br></span></code></pre></div></div>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/rusty-3-01c1dec3d43cda223fa6690f4a92bc64.jpg" alt="使用脚本完成一键编译、上传和开始运行"></p><p>使用脚本完成一键编译、上传和开始运行</p><p></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四步发布游戏">第四步：发布游戏<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E5%8F%91%E5%B8%83%E6%B8%B8%E6%88%8F" class="hash-link" aria-label="第四步：发布游戏的直接链接" title="第四步：发布游戏的直接链接" translate="no">​</a></h4>
<p>  在编辑器左侧游戏资源树中，右键点击刚创建的项目文件夹，选择「下载」。</p>
<p>  等待浏览器弹出已打包项目文件的下载提示。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三怎么实现的">三、怎么实现的<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E4%B8%89%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0%E7%9A%84" class="hash-link" aria-label="三、怎么实现的的直接链接" title="三、怎么实现的的直接链接" translate="no">​</a></h2>
<p>  在 Dora SSR 中实现 Rust 语言开发支持和 WASM 运行时嵌入的过程是一次新的技术探索和尝试，主要包括三个关键步骤：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-接口定义语言idl的设计">1. 接口定义语言（IDL）的设计<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#1-%E6%8E%A5%E5%8F%A3%E5%AE%9A%E4%B9%89%E8%AF%AD%E8%A8%80idl%E7%9A%84%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="1. 接口定义语言（IDL）的设计的直接链接" title="1. 接口定义语言（IDL）的设计的直接链接" translate="no">​</a></h3>
<p>  要在 C++ 编写的游戏引擎上嵌入 WASM 运行时并支持 Rust 语言，首先需要设计一种接口定义语言（IDL），以便于不同编程语言之间的通信和数据交换。以下是一个 Dora SSR 设计的 WASM IDL 示例，可以看出是以源语言 C++ 的程序接口为基础，增加一些转换到 Rust 接口所需要的信息的标签，比如 object，readonly，optional 等。做跨语言的接口映射其中有一个难点是 C++ 的接口设计是面向对象的，但是 Rust 并没有提供完整的面向对象设计的能力，所以一部分的面向对象的接口需要在 Rust 上额外编写代码进行功能的模拟，所幸这部分语言差异并没有特别巨大，也不用很复杂的机制设计就能解决。</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token plain">object </span><span class="token keyword" style="color:#C586C0">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">EntityGroup</span><span class="token plain"> @ Group</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	readonly common </span><span class="token keyword" style="color:#C586C0">int</span><span class="token plain"> count</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	optional readonly common Entity</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	optional Entity</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">find</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">function</span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token keyword" style="color:#C586C0">bool</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">Entity</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">const</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token keyword" style="color:#C586C0">static</span><span class="token plain"> EntityGroup</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">create</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">VecStr components</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<p>  考虑到 C++ 的面向对象特性与 Rust 的设计哲学存在差异，我们在 Rust 中部分模拟了 C++ 中面向对象的行为，这需要在 Rust 中额外编写一些机制以对应 C++ 中的类和方法。这种处理方式虽然增加了一些开发工作，但保持了接口的整洁和系统的可维护性。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-生成胶水代码的程序">2. 生成胶水代码的程序<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#2-%E7%94%9F%E6%88%90%E8%83%B6%E6%B0%B4%E4%BB%A3%E7%A0%81%E7%9A%84%E7%A8%8B%E5%BA%8F" class="hash-link" aria-label="2. 生成胶水代码的程序的直接链接" title="2. 生成胶水代码的程序的直接链接" translate="no">​</a></h3>
<p>  第二步是编写一个程序，通过 IDL 生成 C++、WASM 和 Rust 之间互相调用的胶水代码。为了实现这一点，我们选择使用 Dora SSR 项目自创的 YueScript 语言。YueScript 是基于 Lua 的一门动态编程语言，它结合了 Lua 语言生态中的 lpeg 语法解析库来处理 IDL 的解析和胶水代码的生成。使用 YueScript 的好处是它继承了 Lua 的灵活性和轻量级，同时提供了更丰富的语法和功能，适合处理复杂的代码生成任务。以下是使用 PEG 文法编写的 IDL 解析器的代码节选。</p>
<div class="language-lua codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-lua codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token class-name" style="color:rgb(78, 201, 176)">Param</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token string" style="color:rgb(206, 145, 120)">"Param"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token class-name" style="color:rgb(78, 201, 176)">Param</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">V</span><span class="token string" style="color:rgb(206, 145, 120)">"Func"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Name</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">/</span><span class="token plain"> mark</span><span class="token string" style="color:rgb(206, 145, 120)">"callback"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">+</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Type</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Name</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">/</span><span class="token plain"> mark</span><span class="token string" style="color:rgb(206, 145, 120)">"variable"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	</span><span class="token class-name" style="color:rgb(78, 201, 176)">Func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Ct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"function&lt;"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Type</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Ct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"("</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">V</span><span class="token string" style="color:rgb(206, 145, 120)">"Param"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">","</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">V</span><span class="token string" style="color:rgb(206, 145, 120)">"Param"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">^</span><span class="token number" style="color:#B5CEA8">0</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">^</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:#B5CEA8">1</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">")"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token class-name" style="color:rgb(78, 201, 176)">Method</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Docs</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Ct</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">MethodLabel</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Type</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">C</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"operator=="</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">+</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"@"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Name</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">+</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Cc</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">false</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Ct</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"("</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">Param</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">","</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Param</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">^</span><span class="token number" style="color:#B5CEA8">0</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">^</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:#B5CEA8">1</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">")"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">C</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">"const"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token operator" style="color:rgb(212, 212, 212)">^</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:#B5CEA8">1</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">White</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">P</span><span class="token string" style="color:rgb(206, 145, 120)">";"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">/</span><span class="token plain"> mark</span><span class="token string" style="color:rgb(206, 145, 120)">"method"</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-嵌入-wasm-运行时和代码整合">3. 嵌入 WASM 运行时和代码整合<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#3-%E5%B5%8C%E5%85%A5-wasm-%E8%BF%90%E8%A1%8C%E6%97%B6%E5%92%8C%E4%BB%A3%E7%A0%81%E6%95%B4%E5%90%88" class="hash-link" aria-label="3. 嵌入 WASM 运行时和代码整合的直接链接" title="3. 嵌入 WASM 运行时和代码整合的直接链接" translate="no">​</a></h3>
<p>  最后一步是在游戏引擎中嵌入 WASM 运行时以及所生成的 C++ 胶水代码，完成代码的整合。对于 WASM 运行时，我们选择使用 WASM3，这是一个高性能、轻量级的 WebAssembly 解释器，它支持多种 CPU 架构，能够简化编译链的复杂性，并提高跨平台的兼容性。通过这种方式，Dora SSR 能够支持在各种架构的硬件设备上运行 Rust 开发的游戏，极大地提高了游戏项目的可访问性和灵活性。</p>
<p>  在整合过程中，我们发布了供 Rust 开发者使用的 crate 包，包含所有必要的接口和工具，以便开发者未来可以轻松地基于 Dora SSR 游戏引擎开发和再发布使用 Rust 语言编写的其它游戏模块。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四性能比较">四、性能比较<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E5%9B%9B%E6%80%A7%E8%83%BD%E6%AF%94%E8%BE%83" class="hash-link" aria-label="四、性能比较的直接链接" title="四、性能比较的直接链接" translate="no">​</a></h2>
<p>  Dora SSR 游戏引擎同时也提供了 Lua 脚本语言的支持。目前使用的是 Lua 5.5 版本的虚拟机，和 WASM3 也是一样的没有做 JIT 的实时机器码的生成而只是在虚拟机中解释执行脚本代码。所以我们可以为这两个相近的脚本方案做一些性能比较。</p>
<p>  在比较之前，我们可以大概判断，不考虑 Lua 语言执行 GC 的耗时，因为 Lua 语言本身的动态特性，C++ 映射到 Lua 的程序接口往往得在运行时做接口传入参数类型的实时检查，另外 Lua 对象的成员属性的访问查找也需要在运行时通过一个 hash 结构的表进行查找，这些都是静态类型的 Rust 语言 + WASM 虚拟机不需要付出的开销，或者只用付出更小的开销的场景。以下是一些基础的性能测试的案例，专门选取了 C++ 端没有做太多计算处理的接口，来比较跨语言调用传参的性能差异。</p>
<ul>
<li class="">Rust 测试代码</li>
</ul>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">mut</span><span class="token plain"> root </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">new</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> node </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">new</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">get_elapsed_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:#C586C0">in</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token number" style="color:#B5CEA8">10000</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	root</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">set_transform_target</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token macro property" style="color:#9CDCFE">p!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"object passing time: {} ms"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">get_elapsed_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1000.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">get_elapsed_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:#C586C0">in</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token number" style="color:#B5CEA8">10000</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	root</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">set_x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:#B5CEA8">0.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token macro property" style="color:#9CDCFE">p!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"number passing time: {} ms"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">get_elapsed_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1000.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">let</span><span class="token plain"> start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">get_elapsed_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:#C586C0">in</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token number" style="color:#B5CEA8">10000</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	root</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">set_tag</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Tag name"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token macro property" style="color:#9CDCFE">p!</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"string passing time: {} ms"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">get_elapsed_time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1000.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre></div></div>
<ul>
<li class="">Lua 测试代码</li>
</ul>
<div class="language-lua codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-lua codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token keyword" style="color:#C586C0">local</span><span class="token plain"> root </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">local</span><span class="token plain"> node </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">local</span><span class="token plain"> start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">elapsedTime</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> i </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">10000</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">do</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	root</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">transformTarget </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> node</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">end</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"object passing time: "</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">..</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">tostring</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">elapsedTime </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">..</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">" ms"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">elapsedTime</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> i </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">10000</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">do</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	root</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">x </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">end</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"number passing time: "</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">..</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">tostring</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">elapsedTime </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">..</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">" ms"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">start </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">elapsedTime</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">for</span><span class="token plain"> i </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">10000</span><span class="token plain"> </span><span class="token keyword" style="color:#C586C0">do</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">	root</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">tag </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Tag name"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token keyword" style="color:#C586C0">end</span><span class="token plain"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"string passing time: "</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">..</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">tostring</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">App</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">elapsedTime </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:#B5CEA8">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">..</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">" ms"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行结果">运行结果<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C" class="hash-link" aria-label="运行结果的直接链接" title="运行结果的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#D4D4D4;--prism-background-color:#212121"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#D4D4D4;background-color:#212121"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#D4D4D4"><span class="token plain">Rust + WASM:</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">object passing time: 0.63 ms</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">number passing time: 0.59 ms</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">string passing time: 3.54 ms</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">Lua:</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">object passing time: 6.73 ms</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">number passing time: 2.69 ms</span><br></span><span class="token-line" style="color:#D4D4D4"><span class="token plain">string passing time: 4.23 ms</span><br></span></code></pre></div></div>
<p>  可以看出，除了字符串类型的接口传参调用外，在 Dora SSR 中实现的其它类型的接口的 Lua 跨语言调用性能要比 WASM 跨语言调用几乎慢一个数量级。字符串类型的接口推断是因为性能消耗大头主要都是在字符串对象的拷贝上，跨语言调用的开销远比内存拷贝的开销小，所以结果差距不大。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五用户体验之谈">五、用户体验之谈<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E4%BA%94%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C%E4%B9%8B%E8%B0%88" class="hash-link" aria-label="五、用户体验之谈的直接链接" title="五、用户体验之谈的直接链接" translate="no">​</a></h2>
<p>  在游戏开发中引入 Rust 语言，我个人体验到了与传统所不同的生产力提升，特别是在与大型语言模型（如 ChatGPT）进行代码生成辅助方面。与传统的 C 或 C++ 相比，Rust 的严格编译器为游戏开发提供了一个更加稳固和安全的编程环境。</p>
<p>  比如使用大语言模型辅助编码时，在生成 C 或 C++ 甚至很多动态类型的语言时，尽管很多时候生成的代码可以通过编译，但在运行时往往仍隐藏着许多难以察觉的错误和缺陷。这些问题可能包括内存泄漏、指针或是引用误用等等，这些都是游戏开发中常见且难以调试的问题。然而，在 Rust 中，许多这类问题都可以在编译阶段被有效捕捉并修正，这得益于 Rust 的所有权和借用机制，以及其在类型安全和内存安全方面的设计优势。</p>
<p>  通过在 Dora SSR 游戏引擎中引入对 Rust 的支持，我发现编写游戏脚本不仅更加安全，也更加高效。这使得游戏开发不再是一个错误排查的过程，而是一个更加专注于创造和实现想象中游戏的过程。Rust 的这些优势，加上 WASM 的跨平台能力，极大地扩展了我们的游戏开发能力和可能性。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六结语">六、结语<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/4/15/rusty-game-dev#%E5%85%AD%E7%BB%93%E8%AF%AD" class="hash-link" aria-label="六、结语的直接链接" title="六、结语的直接链接" translate="no">​</a></h2>
<p>  选择 Dora SSR + Rust 作为游戏开发工具不仅是追求技术的前沿，也是对游戏开发流程的一次新的探索。在这里诚邀每一位热爱游戏开发的朋友加入我们的社区，一同探索这一激动人心的技术旅程。欢迎访问我们的 <a href="https://github.com/IppClub/Dora-SSR" target="_blank" rel="noopener noreferrer" class="">GitHub 仓库</a> 来了解更多信息，并参与到我们的开发中来。一起开创游戏开发的新纪元吧！</p>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="Rust" term="Rust"/>
        <category label="WASM" term="WASM"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[从编译器、游戏引擎到游戏掌机——我是这样做独立游戏的]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard"/>
        <updated>2024-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[引言]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="引言">引言<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard#%E5%BC%95%E8%A8%80" class="hash-link" aria-label="引言的直接链接" title="引言的直接链接" translate="no">​</a></h2>
<p>  自己开发制作游戏是一个儿时起就有的梦，特别是长时间接触魔兽争霸3世界编辑器后，我对游戏引擎和开发工具也有着特别的兴趣。学生时代接触编程以后，梦的外延开始扩散，不满足于使用各式编程语言做开发，开始维护一门自己喜欢的写游戏业务逻辑的编程语言 YueScript，因为学习图形学和作为学习项目重写 Cocos2d-x 有了 Dora SSR 游戏引擎。工作后因为对游戏掌机的喜爱，开始与伙伴合作研发自由开放的可编程游戏掌机设备——吉祥机，实现自己游戏梦终极的 Digital Freedom。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="游戏脚本语言的乐趣与挑战">游戏脚本语言的乐趣与挑战<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard#%E6%B8%B8%E6%88%8F%E8%84%9A%E6%9C%AC%E8%AF%AD%E8%A8%80%E7%9A%84%E4%B9%90%E8%B6%A3%E4%B8%8E%E6%8C%91%E6%88%98" class="hash-link" aria-label="游戏脚本语言的乐趣与挑战的直接链接" title="游戏脚本语言的乐趣与挑战的直接链接" translate="no">​</a></h2>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/3-a7fac222eef3422da6800af1f341c8e7.png" alt="编程语言游乐场！" width="600px"></p><p>编程语言游乐场！</p><p></p>
<p>  各式新的编程语言的学习是充满乐趣，对不同语言工具的接触也会带来不同的编程理念和程序设计思想。对于复杂多变的游戏玩法的脚本编程（Scripting）我也形成了自己编程偏好，即使用一门尽可能简洁和表达力强的编程语言来编写容易变化的业务逻辑，可以转译为 Lua 语言执行的 YueScript 就是满足这个需求的产物。后来随着使用自己的 Dora SSR 游戏引擎项目有了更多的游戏开发体验，又为 Dora SSR 游戏引擎引入了 Teal（为 Lua 语言添加静态类型检查能力的语言），Typescript（进一步增强代码编辑器提示和代码检查的语言），JSX 和 XML（提供描述性代码进行组件化开发的语言）等等。每一种脚本语言都能在特定的游戏开发场景发挥优势，并通过转译到最终运行的同样的Lua语言进行无缝的互通调用。不只是基于 Lua 语言的扩展，Dora SSR 游戏引擎还在尝试通过 WASM 虚拟机来支持更加多样的可以用做游戏脚本编程的语言，如 Rust 和准备支持的 C++ 和 Go 等，兼顾性能与引擎的运行时扩展能力。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="游戏引擎的创新之路">游戏引擎的创新之路<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard#%E6%B8%B8%E6%88%8F%E5%BC%95%E6%93%8E%E7%9A%84%E5%88%9B%E6%96%B0%E4%B9%8B%E8%B7%AF" class="hash-link" aria-label="游戏引擎的创新之路的直接链接" title="游戏引擎的创新之路的直接链接" translate="no">​</a></h2>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/2-3c0f6aac2b13b494cc22c47876094d4a.png" alt="随时随地用任何设备制作游戏！" width="600px"></p><p>随时随地用任何设备制作游戏！</p><p></p>
<p>  说到游戏引擎大家总是想到高性能高质量的图形渲染，搭建复杂的游戏场景。实际上作为独立游戏开发者，或是游戏制作的爱好者，并不是人人都有条件追求3A游戏的制作（钞能力）。我认为很多 2D 游戏或是 2D 混合 3D 效果的游戏也能表达展现十分有创意和独特的游戏作品。而且能运行自己制作游戏的终端最好是不受限制的，再进一步，也许能用于开发游戏的终端也可以是不受限制的。所以就有了 Dora SSR 游戏引擎的项目目标，在尽可能多的设备上为游戏开发爱好者提供便捷易用的环境甚至是游戏开发 IDE。一直以来游戏开发这件也成为了我的个人生活体验的一部分。哪怕只有碎片化的时间和手边随机可用作游戏开发和运行的设备，我也想有空就利用起来碎片化地写两行游戏代码，或是调试一个游戏功能，并把它变成了一种比较随性惬意的休闲活动。</p>
<p>  所以 Dora SSR 搭建了通过游戏引擎运行时内置用于游戏开发的 Web IDE 服务器，可以通过其它方便做输入的设备通过 Web 浏览器做访问，并实现直接在任意的终端运行设备上直接编写运行和调试游戏开发的代码。同时获得代码编辑器可视提示服务、以及使用其它游戏开发和资源管理的可视化工具。目前 Dora SSR 在努力之下已具备了在 Windows、macOS、iOS、Android、多个 Linux 发行版上进行游戏开发的能力。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="向着自由开放的游戏掌机梦想迈进">向着自由开放的游戏掌机梦想迈进<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard#%E5%90%91%E7%9D%80%E8%87%AA%E7%94%B1%E5%BC%80%E6%94%BE%E7%9A%84%E6%B8%B8%E6%88%8F%E6%8E%8C%E6%9C%BA%E6%A2%A6%E6%83%B3%E8%BF%88%E8%BF%9B" class="hash-link" aria-label="向着自由开放的游戏掌机梦想迈进的直接链接" title="向着自由开放的游戏掌机梦想迈进的直接链接" translate="no">​</a></h2>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/1-2dfb3c8ea227c9d6b7a1c2aa81ce5632.png" alt="开源开放？软件和硬件全都要！" width="600px"></p><p>开源开放？软件和硬件全都要！</p><p></p>
<p>  到此我觉得对游戏开发能力的自由和开放体验的追求还远不到尽头。作为喜好各式掌机的老玩家，在体验了诸多国产开源掌机的商业产品后，我感觉深深的不满足。用掌上游戏机玩游戏目前还是在卷硬件参数和外观设计来提供体验的差别，而我期待的掌机并不只是玩游戏上的体验，还应该是一个可以用来自由的开发、运行甚至发行自制游戏的设备。很多掌机厂商都有自己的商业化模式和获得盈利的闭环，所以不会允许硬件设备获得太多可编程定制的能力。于是和同样对硬件发烧的伙伴一起研究构建完全自由开放的掌机设备。并尽可能提供包括机器的计算核心、外设和外观均可进行模块化的定制和更换的能力（使科技不再以换壳为本）于是又有了“吉祥机”的项目。</p>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/auspice-gear-57b55973e700488b6381e04d6a82f0b9.png" alt="吉祥机 + Dora SSR 游戏引擎"></p><p>吉祥机 + Dora SSR 游戏引擎</p><p></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="回到制作游戏的初心">回到制作游戏的初心<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard#%E5%9B%9E%E5%88%B0%E5%88%B6%E4%BD%9C%E6%B8%B8%E6%88%8F%E7%9A%84%E5%88%9D%E5%BF%83" class="hash-link" aria-label="回到制作游戏的初心的直接链接" title="回到制作游戏的初心的直接链接" translate="no">​</a></h2>
<p align="center"><img src="https://ippclub.gitee.io/Dora-SSR/zh-Hans/assets/images/lsd-banner-ff13d49db769a7c066294fc221490e9b.jpg" alt="社区在做的开源独立游戏项目《灵数奇缘》"></p><p>社区在做的开源独立游戏项目《灵数奇缘》</p><p></p>
<p>  所以折腾了半天我的游戏到底做出来了没有呢？答案当然是做了，但没完全做出来啦。在生成式 AI 大模型进入彻底火爆前夕的2020年我们就想象了一个关于未来的 AI 的游戏故事，人的物质需求已经得到完全满足，生下来的目的只剩下了通过进行游戏娱乐，并通过采集过程数据给AI生产有创造力和展现智能的训练数据。人生的价值都是由未来的银行通过评估人的游戏活动所创造的智能数据的质量和价值，来进行货币分配而评定的。人类贡献的数据训练出的 AI 会帮助人完成一切的物质生产、到人类个体的养育和社会管理的工作。在这样的背景下，人还会有什么样的故事。最后游戏输出的价值观就是人生来就应该是改造世界的主体，而不是只会适应一切现状的被改造的客体。也呼应了我和我的伙伴们一直在追寻的东西，想要不被与生而来的一切所定义，就去靠自己的主动创造去重新定义一切。</p>
<p>  如果对我们在做的编程语言、游戏引擎、游戏掌机或是游戏项目感兴趣，欢迎 Star 我们的仓库或是进入我们的 Q 群聊聊。目前的项目都还在比较早起的阶段，但是会互相整合和验证迭代，关注我们也可以及时看到项目是怎么做的以及我们的进展。</p>
<p>  最后我们诚挚邀请每一位对游戏开发有热情的朋友加入我们，无论是贡献代码、提供意见还是分享我们的项目，您的每一份努力都能帮助我们共同实现游戏开发自由的梦想。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="项目地址">项目地址<a href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/2024/3/25/indie-game-made-so-hard#%E9%A1%B9%E7%9B%AE%E5%9C%B0%E5%9D%80" class="hash-link" aria-label="项目地址的直接链接" title="项目地址的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>游戏引擎：<a href="https://github.com/IppClub/Dora-SSR" target="_blank" rel="noopener noreferrer" class="">https://github.com/IppClub/Dora-SSR</a></p>
</li>
<li class="">
<p>YueScript语言：<a href="https://github.com/IppClub/YueScript" target="_blank" rel="noopener noreferrer" class="">https://github.com/IppClub/YueScript</a></p>
</li>
<li class="">
<p>《灵数奇缘》开源游戏项目：<a href="https://luv-sense-digital.readthedocs.io/" target="_blank" rel="noopener noreferrer" class="">https://luv-sense-digital.readthedocs.io</a></p>
</li>
</ul>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="Dora SSR" term="Dora SSR"/>
        <category label="YueScript" term="YueScript"/>
        <category label="Auspice Gear" term="Auspice Gear"/>
        <category label="Game LSD" term="Game LSD"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[🌈 Dora SSR - 从《绿野仙踪》到游戏世界的奇幻之旅]]></title>
        <id>https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/dora-ssr</id>
        <link href="https://ippclub.gitee.io/Dora-SSR/zh-Hans/blog/dora-ssr"/>
        <updated>2023-11-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[🌟]]></summary>
        <content type="html"><![CDATA[<p style="text-align:center">🌟</p>
<hr>
<p>  每个伟大的创造背后，往往隐藏着一个充满魔力的故事。Dora SSR 的灵感正是源自我童年时代最钟爱的故事之一——《绿野仙踪》。在这个经典故事中，小女孩多萝西与小狗托托，伴随着他们的新朋友——心灵缺失的铁皮人、缺乏智慧的稻草人和胆怯的狮子，共同踏上了一段既充满挑战又奇妙的冒险之旅。</p>
<p style="text-align:center">✨</p>
<hr>
<p>  Dora SSR 引擎的旅程，正如多萝西在《绿野仙踪》中的经历一般，是一次关于探索与发现的旅程。它不仅是一个技术产品，更是一个激发创意、实现梦想的平台。在这个开放的生态系统中，我们向往一个开源主义的世界，一个每个人都能自由贡献、共享知识的社区。我们期望每一位使用 Dora SSR 的开发者，都能像多萝西及其伙伴们那样，在游戏开发的征途中勇敢追梦，克服困难，发掘自我。</p>
<p style="text-align:center">🚀</p>
<hr>
<p>  在 Dora SSR 的世界中，我们鼓励开发者们像稻草人一样追求智慧、像铁皮人一样探寻心灵之爱、像狮子一样寻找勇气。每一款游戏都代表着一次全新的冒险，每一个创意都是对未知世界的一次探索。我们坚信，通过这个平台，每个人都能找到他们心中的“翡翠城”——梦想的实现之地。更重要的是，在这个开放的社区里，每一个创意和努力都将被尊重和分享，激发出无限的可能。</p>
<p style="text-align:center">🌍</p>
<hr>
<p>  Dora SSR 的力量，正如多萝西及其伙伴们一样，源自于其不断壮大的社区——一个充满创意、支持和协作的环境。我们的社区就是我们的“绿野仙踪”，在这里，每个人都能找到自己的声音和位置。开放源码的理念让每一个开发者都能参与进来，共同打造一个更加美好的世界。我们相信，只有在开放与合作中，才能真正实现创新的飞跃。</p>
<p style="text-align:center">🔥</p>
<hr>
<p>  我们的旅程才刚刚开始。Dora SSR 将持续成长和发展，如同《绿野仙踪》中的角色们一样，不断地学习、进步和超越。我们期待在这个平台上见证更多的创意和奇迹的诞生，并希望通过开放源码的力量，吸引更多志同道合的人们加入，共同书写未来的篇章。</p>
<p style="text-align:center">🤝</p>
<hr>
<p>  因此，让我们一起携手努力，在 Dora SSR 的奇幻旅程中续写我们自己的“绿野仙踪”故事！在这段旅程中，每个人都可以成为多萝西，每个创意都有潜力成为下一个奇迹。在开放的世界里，我们一起梦想，共同实现。</p>]]></content>
        <author>
            <name>李瑾</name>
            <uri>https://github.com/pigpigyyy</uri>
        </author>
        <category label="Dora SSR" term="Dora SSR"/>
        <category label="hello world" term="hello world"/>
    </entry>
</feed>