本文给大家介绍笔者所在团队自研的 JS 游戏引擎是如何管理模型资源的,这里预告一波儿如何用 JS 游戏引擎实现 PID 算法,下面是基于 PID 实现的两轴飞行器定高效果:
需求描述
模型是什么?模型就是 ECSM 架构中的 Model,笔者在 JS 游戏引擎 - 物体编辑器 这篇文章里介绍了 ECSM 架构,提到将 Model 抽象为一种资源,独立于引擎进行管理,那么具体是怎么抽象和管理的呢?
需求分析
先来看看使用 Model 的基本流程:开发者制作 Model,游戏引擎加载 Model,游戏引擎使用 Model 创建 Entity。这里面涉及到几个关键问题:
- 开发者制作的是什么?也就是 Model 以什么形式存在?
- 游戏引擎从哪里加载 Model?也就是 Model 是怎么存储的?
- 游戏引擎怎样加载 Model?
- 游戏引擎怎么运行 Model?也就是 Model 在内存里的状态是什么?
- Model 需要版本管理吗?
- 需要设计 Model 的加载策略吗?
方案设计
定义形式
Model 用于描述 Entity 的具体内容,简单来说就是游戏引擎创建一个 Entity 时所依赖的一段 js 代码,通过这段代码,我们可以为 Entity 添加各种 Component。因此 Model 存在形式的核心就是 js 脚本。
这里借鉴 npm 包的概念,我们定义 Model 的实际存在形式为单文件夹,该文件夹下包含一个主文件和其它资源文件。主文件也是入口文件,通常为 index.js,其它资源文件可能是图片、JSON 文件等,为主文件所引用。
Car/
|--index.js
|--light.png
|--shine.json
明确存储
怎么存储 Model?通常的思路是使用一个存储服务,然而我们的产品是 小世界,这是一个基于 SolidJS 的纯前端应用,它的底层使用了团队自研的 JS 游戏引擎,现阶段我们还未计划引入后端服务。
其实 Model 本质上就是一种静态资源,在这个意义上,一个 Model 和一张图片没有区别,我们完全可以把 Model 放到静态资源服务器上,具体操作就是把 Model 放到项目工程的静态资源目录下,比如 public。
public/
|--models/
|--Car/
|--index.js
|--light.png
|--shine.json
加载方式
游戏引擎只需要加载 Model 的主文件 index.js,而加载 js 文件考虑两种方式:
- 使用 xhr 或 fetch API 获取 js 文本,然后通过 eval 或 Function 执行该文本;
const modelContent = await fetch('/public/models/Car/index.js');
const model = eval