在本文中,我将谈谈我在Rust中开发小型游戏的个人经历。 创建工作版本大约需要24小时(我主要在晚上或周末工作)。 游戏还远远没有结束,但我认为这种体验会很有用。 我将告诉您我从中学到的知识以及从头开始制作游戏时的一些观察。
Skillbox建议:两年实践课程“我是PRO Web开发人员” 。
我们提醒您: 对于所有“ Habr”读者来说,使用“ Habr”促销代码注册任何Skillbox课程时均可享受10,000卢布的折扣。
为什么生锈?
我选择这种语言是因为我听到了很多关于它的好东西,并且看到它在游戏开发领域越来越流行。 在编写游戏之前,我几乎没有在Rust中开发简单应用程序的经验。 这足以在编写游戏时感到一定的自由。
为什么是游戏,又是什么样的游戏?
制作游戏很有趣! 由于更多原因,我希望这样做,但是对于“家庭”项目,我选择的主题与我的日常工作不太相关。 什么样的游戏? 我想做一些类似网球模拟器的事情,将城市天际线,动物园大亨,监狱建筑师和网球本身结合在一起。 总的来说,结果是一场有关网球学院的比赛,人们来此比赛。
技术培训
我想使用Rust,但是我不完全知道我需要如何“从头开始”。 我不想编写像素着色器并使用拖放功能,所以我一直在寻找最灵活的解决方案。
找到了我与您分享的有用资源:
我探索了几个Rust游戏引擎,最终选择了Piston和ggez。 在上一个项目中工作时,我遇到了他们。 最后,我选择了ggez,因为它似乎更适合实现小型2D游戏。 对于新手开发人员(或第一次与Rust合作的人),Piston的模块化结构过于复杂。
游戏结构
我花了一些时间思考这个项目的架构。 第一步是建造“土地”,人民和网球场。 人们必须在法院四处走动并等待。 玩家必须具备随着时间而提高的技能。 另外,应该有一个允许您添加新朋友和法院的编辑器,但这不再是免费的。
考虑一切,我开始工作。
游戏创作
开始于:圆圈和抽象我以ggez为例,在屏幕上画了一个圆圈。 好厉害 现在是一些抽象。 在我看来,忽略游戏对象的想法真是太好了。 必须按照此处指示的方式渲染和更新每个对象:
这段代码使我获得了一个极好的对象列表,可以在同样出色的循环中更新和渲染这些对象。
mpl event::EventHandler for MainState { fn update(&mut self, context: &mut Context) -> GameResult<()> {
main.rs是必需的,因为它包含所有代码行。 我花了一些时间来分离文件并优化目录结构。 这是所有事情的开始:
资源->这是所有资产所在的位置(图片)
src
-实体
-game_object.rs
-circle.rs
-main.rs->主循环人,楼层和图像下一步是创建一个Person游戏对象并加载图像。 一切都应基于大小为32 * 32的图块。
网球场研究了网球场的外观后,我决定用4 * 2的瓷砖制作它们。 最初,可以制作此大小的图像,或者一起制作8个单独的图块。 但是后来我意识到只需要两个唯一的磁贴,这就是为什么。
总共,我们有两个这样的图块:1和2。
球场的每个部分都由图块1或图块2组成。它们可以照常布置,也可以上下颠倒180度。
主要施工方式(组装)在设法完成网站,人物和地图的渲染之后,我意识到还需要一种基本的构建模式。 它的实现是这样的:按下按钮时,将选择对象,然后单击将其放置在正确的位置。 因此,按钮1允许您选择一个球场,按钮2允许您选择一个球员。
但是您仍然需要记住1和2的含义,因此我添加了线框,以便清楚地选择了哪个对象。 这是它的外观。
有关架构和重构的问题现在我有几个游戏对象:人,法院和地板。 但是,为了使线框起作用,您需要告诉对象的每个实体,对象本身是否处于演示模式,或者是否简单绘制了框架。 这不是很方便。
在我看来,我需要重新考虑体系结构,以便发现一些限制:
- 显示和更新自身的实体的存在是一个问题,因为该实体将无法“知道”其应呈现的内容-图像和线框;
- 缺少用于在各个实体之间交换属性和行为的工具(例如is_build_mode属性或呈现行为)。 可以使用继承,尽管在Rust中没有正常的实现方法。 我真正需要的是布局。
- 需要一种实体之间相互作用的工具来将人员分配到法院;
- 实体本身是数据和逻辑的混合,很快就失去了控制。
我进行了进一步的研究,发现了ECS架构-实体组件系统 ,该系统在游戏中普遍使用。 以下是ECS的优势:
- 数据与逻辑分离;
- 布局而不是继承;
- 面向数据的体系结构。
ECS具有三个基本概念:
- 实体-标识符所指的对象类型(可以是玩家,球或其他东西);
- 组件-实体由它们组成。 一个示例是渲染组件,布局等。 它是一个数据仓库;
- 系统-它们同时使用对象和组件,还包含基于此数据的行为和逻辑。 一个示例是一个渲染系统,该系统使用要渲染的组件在所有实体上进行迭代并参与渲染。
经过研究,很明显,ECS解决了以下问题:
- 对实体的系统组织使用布局而不是继承;
- 消除由于控制系统导致的代码哈希;
- 使用is_build_mode之类的方法将线框的逻辑存储在渲染系统中的同一位置。
这是实施ECS之后发生的事情。
资源->这是所有资产所在的位置(图片)
src
-组件
-position.rs
-人
-Tennis_court.rs
-floor.rs
-wireframe.rs
-mouse_tracked.rs
-资源
-mouse.rs
-系统
-rendering.rs
-constants.rs
-utils.rs
-world_factory.rs->世界工厂函数
-main.rs->主循环分配人到法院
ECS使生活更轻松。 现在,我有了一种系统的方法,将数据添加到实体并基于该数据添加逻辑。 反过来,这使得有可能通过法院组织人员的分配。
我做了什么:
- 向Person添加有关分配法院的数据;
- 向TennisCourt添加了有关分布式人员的数据;
- 添加了CourtChoosingSystem,该系统使您可以分析人员和站点,找到可用的法院并向其分发玩家;
- 添加了PersonMovementSystem系统,该系统搜索分配给法院的人员,如果不在现场,则在必要时将其发送给人员。
总结一下
我非常喜欢这款简单的游戏。 而且,我很高兴用Rust编写它,因为:
- Rust提供了您所需的东西;
- 他有出色的文档,Rust非常优雅。
- 恒久性很酷;
- 您不必求助于克隆,复制或其他类似操作,而我在C ++中经常这样做;
- 选件非常方便工作,还可以完美地处理错误。
- 如果可以编译该项目,则99%的项目可以正常运行,并且完全可以完成。 在我看来,编译器错误消息是我所看到的最好的消息。
Rust上的游戏开发才刚刚开始。 但是已经有一个稳定而庞大的社区致力于向所有人开放Rust。 因此,我乐观地看待语言的未来,期待我们共同工作的结果。
Skillbox建议: