当前位置:网站首页>用 Oasis 开发一个跳一跳(一)—— 场景搭建
用 Oasis 开发一个跳一跳(一)—— 场景搭建
2022-06-24 15:34:00 【HuSong】
《跳一跳》是微信小游戏里第一款制作精良,也是非常受大家喜爱的游戏。这里以一个跳一跳 MVP(最简可行版本) 版本为例,让大家了解『如何用 Oasis 开发一款 Web 3D 游戏』这一过程。最终的效果如下:
大家可以在: https://stackblitz.com/edit/oasis-jump-aeuowy?file=src/index.ts 体验和尝试修改代码。(BTW:如果访问不了或太慢,可以自行到 https://github.com/gz65555/jump-game/tree/feat/game 克隆项目到本地启动。)
我们把核心的部分分成三大部分,场景、角色和游戏逻辑,后面的教程会以这三大部分为主,实现一个跳一跳的最小可用版本(并非完整的游戏)。下图是核心模块的分析:

第一期我们准备制作最基本的场景,完成灯光,相机,基本底座的摆放。
在具体进入开发之前,我们需要先把整个项目工程搭建好。
工程搭建
我们先使用 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() 即可看到效果:

总结
这篇文章讲了一下跳一跳的简单场景搭建,涉及到的知识点有:
下一期会带来场景的逻辑部分:底座生成和相机移动的部分。
本次教程代码可参考 feat/init 分支。
边栏推荐
- The future of robots -- deep space exploration
- Software test [high frequency] interview questions sorted out by staying up late (latest in 2022)
- How to implement SQLSERVER database migration in container
- 【Kubernetes】1
- Crmeb multi merchant system applet authorization problem solving paste
- PHP export data as excel table
- 我与“Apifox”的网络情缘
- 60 个神级 VS Code 插件!!
- The catch-up of domestic chips has scared Qualcomm, the leader of mobile phone chips in the United States, and made moves to cope with the competition
- Industry cases of successful digital transformation
猜你喜欢

打破内存墙的新利器成行业“热搜”!持久内存让打工人也能玩转海量数据+高维模型

60 个神级 VS Code 插件!!
![[my advanced OpenGL learning journey] learning notes of OpenGL coordinate system](/img/21/48802245fea2921fd5e4a9a2d9ad18.jpg)
[my advanced OpenGL learning journey] learning notes of OpenGL coordinate system

我与“Apifox”的网络情缘

运营商5G用户渗透远远比4G慢,5G的普及还得看中国广电

Remote connection raspberry pie in VNC Viewer Mode

nifi从入门到实战(保姆级教程)——环境篇

The equipment is connected to the easycvr platform through the national standard gb28181. How to solve the problem of disconnection?

SIGGRAPH 2022 | 真实还原手部肌肉,数字人双手这次有了骨骼、肌肉、皮肤

Here comes Wi Fi 7. How strong is it?
随机推荐
Solution to the problem that FreeRTOS does not execute new tasks
At? Let's blow the air conditioner together!
Security Analysis on mining trend of dogecoin, a public cloud
Istio practical skill: enable accesslog locally
如何轻松实现在线K歌房,与王心凌合唱《山海》
Vim编辑器的最常用的用法
安裝ImageMagick7.1庫以及php的Imagick擴展
[tke] multiple ingress controllers are used in the cluster
国产最长寿的热销手机,苹果也不是对手,总算让国产手机找回面子
Learning these 10 kinds of timed tasks, I'm a little floating
asciinema 搭配 asciicast2gif 实现高效的命令行终端录制能力
FreeRTOS新建任务不执行问题解决办法
一文详解JackSon配置信息
Easy installation of Jenkins
A full set of tutorials for interviewers from Android manufacturers teach you: prepare for the interview and get the offer smoothly!
Crmeb multi merchant system applet authorization problem solving paste
Mongodb introductory practical tutorial: learning summary directory
10 hands-free idea plug-ins. These codes do not need to be written (the second bullet)
MySQL 开发规范
leetcode 139. Word Break 單詞拆分(中等)