Roguelike In Rust 03: 实体和组件

对于游戏开发者,可能或多或少听说过或者使用过 ECS 的结构。现在大多数游戏使用的还是面向对象的模式,面向对象编程并没有什么问题,但是在游戏开发过程中,当游戏不断的超出原有的设计时,从整个工程的扩展来说,ECS 拥有更好的扩展性。 下面是一个面向对象的例子 BaseEntity Monster MeleeMob OrcWarrior ArcherMob OrcArcher BaseEntity 是一个基类,包含了基本的数据和代码,用于表示地图上的一个实体。Monster 是一个怪物,MeleeMob 是一个近战单位,它会发现近处的目标,然后干掉它。ArcherMob 是一个可以远程攻击的单位。完成这样一个实体逻辑,可能首先需要按照不同的单位,将逻辑分开,并且抽出共同的逻辑,放到基类中。如果这时增加了一个兽人的逻辑,它即可以近战,又可以远程,并且在完成某些任务时,会变得更友好,怎么办?那就改逻辑呗,继续抽象,分离和整理代码。有很多已经上线的游戏是这样做的。但是,如果使用 ECS,这样的扩展会变得更加容易。 Entity Component 的模式会消除面向对象模式中的层级结构,取而代之的是使用 Components 来描述一切东西,例如一个兽人,一只狼,一瓶药水等等。Component 只是数据,给一个实体,添加多个 Component。 例如,我们可以创建一个实体,然后赋予它一些 Components,Position,Renderable,MelleAI,RangedAI,Hostile,Friendly 等等。对于近战单位,可以给它 MelleAI,Renderable 等。对于远程单位,可以给它 RangedAI,Renderable。对于兽人,在完成任务前,它有 Hostile 组件,而完成任务后,会变得更加友好,那就移除 Hostile 然后添加 Friendly。可以按照游戏逻辑随意地去组合。 ECS 中的 “S” 叫做 System。System 会从 Components 中读取数据,然后执行自己的逻辑代码。例如在单位的显示逻辑中,用于显示的 System 会从单位的 Position 和 Renderable 组件中拿取数据,然后用于在地图上显示实体。 对于小型游戏来说,在使用 ECS 时可能会感觉比面向对象写了更多的代码,前期确实是这样,但是对于后期添加逻辑,ECS 就变得容易了很多。 使用 ECS 很重要的一点就是要知道 ECS 只是处理组合的一种方式,但并不是唯一的方式。对于实现功能来说,并没有什么唯一的方式,在了解了原理后,按照自己的习惯和喜好来就行。 接着上一节的 hellorust 工程,使用 Specs 库 cargo add specs cargo add specs-derive Cargo.toml...

February 3, 2022 · 6 min · fred

Roguelike In Rust 02: Hello Rust

Rust 算是一个新兴的语言,近两年非常火了,但是他首次出现是在 2010 年。Rust 有非常好用的工具 cargo 和 rustup。 如果要学习 Rust 这门编程语言,也有很多优秀的教程。 The Rust Programming Language Book Learn Rust by Example 24 Days of Rust Rust’s Ownership Model for Javascript Developers Rust 编辑器可以使用 VSCode 在终端中使用命令 cargo new hellorust 可以创建一个名为 hellorust 的工程。src/main.rs 是起始文件。Cargo.toml 是工程的配置文件,里面包含了一些其他库的引用信息。 此时 src/main.rs 的代码如下 fn main() { println!("Hello, world!"); } fn 是函数的关键字 main 是主函数名,也就是整个程序的起始函数。 println! 是一个打印宏 使用命令 cargo run 可以编译并运行工程。 一些有用的 cargo 命令 cargo init 初始化一个新的工程 cargo build 会下载所有的依赖库,并且编译整个项目 cargo update 会根据 Cargo....

February 2, 2022 · 1 min · fred

Roguelike In Rust 01: 前言

这个教程是免费和开源的,所有的代码都使用 MIT 协议,可以无限制的免费使用。希望这个系列的教程可以帮助大家做出更优秀的游戏。 每一年,有一些大神都会在 r/roguelikedev 上启动一个周二教程系列,以此来鼓励更多的程序员加入 Roguelike 游戏开发者行列中。大多数的编程语言已经被使用过了,所以在今年,我决定使用 Rust。我不是很想用默认的引擎 libtcod,所以我自己写了一个,名为 RLTK。刚开始的时候并不是很好,但是也让我学到了很多,如果你有兴趣,代码在此 -> rustyroguelike 上面的 rustyroguelike 代码是使用 Python 和 libtcod 来实现的。 我一直很想使用一下 Entity Component System。而 Rust 有一个很好的库 Specs。我已经在之前的游戏中使用过 ECS 的理念,所以再次使用 ECS,一切就很自然了。在 reddit 上,ECS 也是一个一直以来有争议的方向。所以我希望这次的教程可以让大家理解 ECS 的利弊。 注意:这个系列的教程并不是面向 Rust 0 基础的朋友,至少要有一点 Rust 的语言基础才行。 萌一小栈 欢迎关注微信公众号 萌一小栈,博客文章同步推送

February 2, 2022 · 1 min · fred

Gameplay 02 游戏中的跳跃

游戏中的跳跃,就是以某一个速度起跳,克服重力。而以不同的速度,起跳的最高点是不一样的,很难去量化,所以我们可以定义每次起跳的最大高度,然后求出起跳速度,即可做到一切可控。 自由落体公式 $h = \frac{1}{2}gt^2$。速度 $v = gt$,这个是瞬时速度,但是自由落体的速度是均匀变化的,所以平均速度就是下落高度中间时刻的速度,所以才得出 $h = \frac{1}{2}gt^2$。 我们的目标是求出跳跃的速度。 首先,假设我们以一个初始速度 $j$ 来跳跃,这个是一个向上的速度,但是因为重力的存在,所以我们的跳跃速度会因为重力的向下抵消,而逐渐趋向于 0。当 $j$ 慢慢被抵消到 0 时,我们也就达到了以 $j$ 这个速度来跳跃所能到达的最大高度。 对于任意时刻 $t$,速度 $v = j - gt$,当 $j - gt = 0$ 时,也就是我们所能到达的最大高度。所以,到达最大高度的时间为 $t = \frac{j}{g}$。 根据上面的公式,我们可以知道,在以 $j$ 来跳跃的整个过程中,任意时刻的高度为 $h = jt - \frac{gt^2}{2}$。 由于我们上面已经知道了,在 $t = \frac{j}{g}$ 时,我们将达到最大跳跃高度。将 $\frac{j}{g}$ 带入到任意时刻的高度公式中 $h = jt - \frac{gt^2}{2}$。我们可以得到 $h = j(\frac{j}{g}) - \frac{g(\frac{j}{g})^2}{2}$。 化简上面的公式将得到 $h = \frac{j^2}{g} - \frac{\frac{j^2}{g}}{2} = \frac{j^2}{g} - \frac{j^2}{2g} = \frac{j^2}{2g}$。...

January 22, 2022 · 1 min · fred

This Week In Moeif 30

下个周计划去做个小手术,把额头上的小脂肪瘤干掉,应该可以直接在门诊做。上海的医保也可以直接用了。 从下一期开始,我要考虑一下改变一下周记的模板,看看如何改成内容叠加式,这样最后就知道这一年干了什么。 ...

January 16, 2022 · 1 min · fred

This Week In Moeif 29

这周主要在加速开发码农游戏,其他的事情都暂缓了。 这周注册了一个新的域名,国内的,这样可以备案,可是域名拼错了…,不过也无所谓,反正不对外,只是在代码中使用。似乎找到了一个国内和国内访问腾讯云都很快的方法,就是国内直连,国外使用 Cloudflare 加速,等后面有了服务器的逻辑可以测一下。 考虑了一下下一个项目的事情,准备下一个项目海外版增加内购,国内还是暂时以广告为主,暂时这样计划着。 看了一下Godot,编辑器确实很快,但是从产品开发上,还是Unity更保险一些,一方面比较熟悉,一方面各种支持和资源很丰富。目前确实没有转引擎的必要。 项目进度 游戏码农:那些打工的日子 这周完成了资产模块的逻辑和UI,投资模块的逻辑和UI。投资模块的价格数据,使用了市场上真实的数据,目前只加了一个数据源,后面会再加几个,增加可靠性。另外,这个项目的软著终于有动静了,目前处于待发放的状态,也就是通过了,估计下周能邮出。 本周电影 这周忙到没时间看电影 本周书籍 《愿你迷路到我身旁》 《游戏设计艺术》(阅读中) 下周初步计划 继续逻辑编写

January 9, 2022 · 1 min · fred

Gameplay 01 游戏开发中的平滑移动

这篇博客,聊一聊在游戏开发中,控制角色或者其他物体的平滑移动。现实中,一个物体,从静止加速到匀速运动状态,或者从匀速运动状态变为静止状态,都会有一个过程。就像人走路,或者汽车开动。 一个物体在运动状态下,会有一个速度变量,也就是我们期望的速度。而从静止到运动状态的过程,会有一个加速度。 而游戏开发中,要做到一个物体平滑的运动,也就是模拟出这个从静止,通过加速度,达到期望速度的过程。 游戏是按帧运行的,在初始的时候,目标运动速度为0,随着每一帧的流逝,目标速度会不断累加一帧中的加速度,当累加到期望速度时,则会以期望速度来运动。 代码如下,这里是在 Unity 中实现的,但是原理对于所有游戏引擎通用 using System.Collections; using System.Collections.Generic; using UnityEngine; public class MovingSphere : MonoBehaviour { // 用户设定最大期望速度 [SerializeField, Range(0f, 100f)] private float maxSpeed = 10f; // 用户设定最大加速度 [SerializeField, Range(0f, 100f)] private float maxAcceleration = 10f; // 当前的运动速度 private Vector3 velocity; // Update is called once per frame void Update() { // 通过读取用户输入,来确定期望速度向量(向量包含了大小和方向) Vector2 playerInput; playerInput....

January 6, 2022 · 1 min · fred

This Week In Moeif 28

现在已经 2022 年了,本来想跨年夜去外滩,看了一下新闻,好像也没什么活动,就在家里待着了。这个周又开始运动了,跑步加跳绳,保持健康。这周是单调的一周。这周还把博客使用 Cloudflare 加速了,能明显感觉也访问速度的提升。 项目进度 游戏码农:那些打工的日子 这周完成了外卖和自己做饭界面的UI及逻辑,下周开始添加学习内容的模块。这周的内容比较单调,好像也没做什么特别的事情。软件著作权还没有下来,这次真是好慢。 本周电影 寂静之海 고요의 바다 (2021) 本周书籍 《愿你迷路到我身旁》(阅读中) 下周初步计划 继续逻辑编写

January 2, 2022 · 1 min · fred

This Week In Moeif 27

又是一周结束了,时间过的好快啊。这周在焦虑和烦躁中度过。上海也开启了冬天模式,很冷,还没有取暖设备,买了一个取暖器,也做不到整屋加热,不过还好距离过年也就剩一个多月了,可以回北方了。好像已经两个周没有出去跑步了… ...

December 26, 2021 · 1 min · fred

This Week In Moeif 26

对于下一个游戏产品,有了一点点的方向,还没有深入去考虑。 ...

December 20, 2021 · 1 min · fred