共计 3956 个字符,预计需要花费 10 分钟才能阅读完成。
《跳一跳》是微信小游戏里第一款制作精良,也是十分受大家青睐的游戏。这里以一个跳一跳 MVP(最简可行版本)版本为例,让大家理解『如何用 Oasis 开发一款 Web 3D 游戏』这一过程。最终的成果如下:
大家能够在:https://stackblitz.com/edit/o… 克隆我的项目到本地启动。)
咱们把外围的局部分成三大部分,场景 、 角色 和游戏逻辑,前面的教程会以这三大部分为主,实现一个跳一跳的最小可用版本(并非残缺的游戏)。下图是外围模块的剖析:
第一期咱们筹备制作最根本的场景,实现灯光,相机,根本底座的摆放。
在具体进入开发之前,咱们须要先把整个我的项目工程搭建好。
工程搭建
咱们先应用 create-oasis-app 创立我的项目。
应用命令的第一步须要装置 Node.js。如果已装置 Node.js(version >= 12.0.0) 能够执行命令创立 oasis 模板:
npm init @oasis-engine/oasis-app
因为咱们无需额定开发前端局部,所以间接应用 Vanilla 模板即可。上面是调用命令的过程。
当执行实现后,咱们进入到我的项目中的 terminal 里,执行:
npm install
在装置完依赖后再应用:
npm run dev
启动 dev 服务器,过程如下图所示:
再关上 http://localhost:3000 即可看到:
阐明工程搭建曾经实现。此时我的项目目录如下:
|-jump-game | |
|-index.html // HTML 文件 | |
|-main.js // 入口 js 文件 | |
|-package.json // 工程形容文件 | |
|-src | |
| |-index.ts // oasis 局部代码 |
根本场景搭建
引擎和场景初始化
咱们用 IDE 关上我的项目,找到 /src/index.ts
如上面代码所示:
import {Camera, Vector3, WebGLEngine, DirectLight} from "oasis-engine"; | |
// 初始化引擎 | |
const engine = new WebGLEngine("canvas"); | |
// 依据页面设置 canvas 大小 | |
engine.canvas.resizeByClientSize(); | |
const zeroVector = new Vector3(0, 0, 0); | |
// 设置背景色 | |
const scene = engine.sceneManager.activeScene; | |
scene.background.solidColor.setValue(208 / 255, 210 / 255, 211 / 255, 1); | |
scene.ambientLight.diffuseSolidColor.setValue(0.5, 0.5, 0.5, 1); | |
// 创立根节点 | |
const rootEntity = scene.createRootEntity(); | |
const cameraEntity = rootEntity.createChild("camera"); | |
cameraEntity.transform.setPosition(-100, 100, 100); | |
const camera = cameraEntity.addComponent(Camera); | |
// 初始化相机 | |
camera.isOrthographic = true; | |
cameraEntity.transform.lookAt(zeroVector); | |
// 初始化灯光 | |
const directLightEntity = rootEntity.createChild("directLight"); | |
const directLight = directLightEntity.addComponent(DirectLight); | |
directLight.intensity = 0.5; | |
directLightEntity.transform.setPosition(10, 30, 20); | |
directLightEntity.transform.lookAt(zeroVector); | |
engine.run(); |
此段代码创立了引擎,场景,并且初始化了相机,灯光。相机应用正交相机,朝向原点。间接光也设置为朝向原点。
实现以上步骤能够场景里还是一片灰色,咱们来给场景增加底座生成和相机挪动的逻辑。
场景底座初始化
咱们通过创立一个 SceneScript.ts
来做场景整体的治理,并且在 rootEntity
上增加 SceneScript
:
const sceneScript = rootEntity.addComponent(SceneScript);
脚本是 Oasis Engine 十分外围的概念,是一种非凡的组件,组件又是挂载在实体(Entity)上的,来给引擎提供拓展的能力。更多对于实体和组件概念请查看:《实体与组件》文档。
接下来,在 SceneScript
的 onAwake
生命周期中创立一个 ground 实体,用来摆放跳一跳的底座。onAwake
生命周期函数是在挂载的实体被激活时调用,个别用来搁置一下初始化的代码。引擎中还有许多生命周期的钩子函数用来帮忙开发者编写业务逻辑,更多脚本生命周期能够查看:《脚本》。
同时创立 TableManager
对象来管制底座的生成。
onAwake() {this.ground = this.entity.createChild("ground"); | |
this.tableManager = new TableManager(this._engine, this.ground); | |
} |
咱们在 TableManager
里创立能够复用的材质(Material)和网格(Mesh)。创立一个 3D 物体的渲染,须要用到 MeshRenderer
网格渲染器组件,设置好材质和网格即可。
因为是 MVP 版本,我这里只用一个红色的立方体 Table 作为示意:
import { | |
BlinnPhongMaterial, | |
Engine, | |
Entity, | |
MeshRenderer, | |
ModelMesh, | |
PrimitiveMesh, | |
} from "oasis-engine"; | |
import {Config} from "./Config"; | |
export class TableManager { | |
// 底座的 Mesh | |
private cuboidMesh: ModelMesh; | |
// 底座的材质 | |
private cuboidMaterial: BlinnPhongMaterial; | |
constructor(engine: Engine, private sceneEntity: Entity) { | |
// 创立根本网格 | |
this.cuboidMesh = PrimitiveMesh.createCuboid( | |
engine, | |
Config.tableSize, | |
Config.tableHeight, | |
Config.tableSize | |
); | |
// 创立根本材质 | |
this.cuboidMaterial = new BlinnPhongMaterial(engine); | |
// 设置材质色彩 | |
this.cuboidMaterial.baseColor.setValue(1, 0, 0, 1); | |
} | |
// 创立一个方块的底座 | |
createCuboid(x: number, y: number, z: number) { | |
// 创立渲染实体 | |
const cuboid = this.sceneEntity.createChild("cuboid"); | |
const renderEntity = cuboid.createChild("render"); | |
// 设置坐标 | |
renderEntity.transform.setPosition(0, Config.tableHeight / 2, 0); | |
cuboid.transform.setPosition(x, y, z); | |
// 创立 MeshRenderer 组件 | |
const renderer = renderEntity.addComponent(MeshRenderer); | |
// 设置网格 | |
renderer.mesh = this.cuboidMesh; | |
// 设置设置材质 | |
renderer.setMaterial(this.cuboidMaterial); | |
return {entity: cuboid, size: Config.tableSize}; | |
} | |
// 革除所有底座 | |
clearAll() {this.sceneEntity.clearChildren(); | |
} | |
} |
咱们能够看到下面的的 tableSize
和 tableHeight
都是在 GameConfig
里定义的,咱们也须要创立一个 Config.ts
来设置游戏配置:
export module Config { | |
export const tableHeight = 5 / 3; | |
export const tableSize = 8 / 3; | |
} |
咱们通过把配置收敛到对立文件里,不便配置的批改。
咱们再到 SceneScript
中增加 reset
办法:
reset() { | |
// 革除所有的底座 | |
this.ground.clearChildren(); | |
// 初始化的第一个底座 | |
this.tableManager.createCuboid(-2.5, 0, 0); | |
// 初始化的第二个底座 | |
this.tableManager.createCuboid(4.2, 0, 0); | |
} |
reset
办法是之后每次游戏开始时和完结后都须要调用的办法。下面的几个数值都是理论开发中调试出的后果,相对来说比拟靠近实在的游戏。
咱们在 index.ts
调用 sceneScript.reset()
即可看到成果:
总结
这篇文章讲了一下跳一跳的简略场景搭建,波及到的知识点有:
- Oasis 工程搭建
- 组件零碎架构
- 脚本生命周期
- 3D 场景的搭建
-
- 相机
- 灯光
- 网格渲染器
下一期会带来场景的逻辑局部:底座生成和相机挪动的局部。
本次教程代码可参考 feat/init 分支。
本文由 mdnice 多平台公布