共计 2841 个字符,预计需要花费 8 分钟才能阅读完成。
近期在尝试着学习写一些 3D 小游戏,分享一下成绩。
严格上说还算不上残缺的游戏,感兴趣的敌人能够观摩一下。
- 预览地址:https://luosijie.github.io/ga…
- git 仓库:https://github.com/luosijie/g…
- 语言:TypeScript
- 框架:Babylon
筹备
在这里用到的惟一素材:小飞机
是在 Blender 软件了外面简略设计的
Blender 是一个收费开源的建模软件
如果感兴趣,这里举荐 B 站上的一个 入门教程
上面是我的一些步骤
- 应用简略的几何元素构建出飞机模型
- 制作 2 个小动画:螺旋桨旋转 和 机身摇摆
- 导出 .glb 格局模型
模型导入到 Babylon 的代码如下
次要用到 2 个参数 meshes 和 animationGroups
{animationGroups: (2) [AnimationGroup, AnimationGroup] | |
geometries: (9) [Geometry, Geometry, Geometry, Geometry, Geometry] | |
lights: [] | |
meshes: (10) [Mesh, Mesh, Mesh, Mesh, Mesh, Mesh, Mesh, Mesh, Mesh, Mesh] | |
particleSystems: [] | |
skeletons: [] | |
transformNodes: (5) [TransformNode, TransformNode, TransformNode] | |
__proto__: Object |
代码
在这个我的项目次要实现一下几个环节
- 根本场景的搭建
- 飞机追随鼠标的静止
- 粒子的生成和静止
- 飞机与粒子的碰撞
飞机模型的加载
// 加载飞机模型 | |
private async loadPlane(): Promise<any> { | |
// 新建一个通明元素 包裹模型 | |
const container = MeshBuilder.CreateBox('plane-container', { width: 1, depth: 2, height:1}, this.scene) | |
container.isVisible = false; | |
// 调整到与模型重合的地位 | |
container.bakeTransformIntoVertices(Matrix.Translation(0, 1.2, 0.8)) | |
container.rotation.y = -Math.PI / 2 | |
container.position.x = 0.6 | |
// 加载飞机模型 | |
const glb = await SceneLoader.ImportMeshAsync(null, './public/', 'plane.glb', this.scene) | |
const root = glb.meshes[0] | |
console.log('glb', glb) | |
// 绑定父子关系 | |
root.parent = container | |
return { | |
mesh: container, | |
fly: () => {glb.animationGroups[0].play(true) | |
glb.animationGroups[1].play(true) | |
}, | |
stop: () => {glb.animationGroups[0].stop(), | |
glb.animationGroups[1].stop()} | |
} | |
} |
飞机模型的静止追随
- 鼠标挪动时获取 鼠标坐标 和 飞机 坐标
- 飞机坐标 须要 3 维坐标 到 屏幕坐标 的转化
- 让 飞机坐标 往 鼠标坐标 挪动
... | |
// 获取鼠标坐标存储 | |
this.scene.onPointerObservable.add(info => {const { event} = info | |
// 存储鼠标坐标数据 | |
if (event.type === 'pointermove') { | |
this.pointerPos = { | |
x: event.x, | |
y: event.y | |
} | |
} | |
}) | |
... | |
/** Loop 中更新 plane 坐标 */ | |
private updatePlane(): void { | |
// 设置平滑系数 - 一直尝试失去到数值 | |
const smoothing = 2000 | |
// 获取 plane 屏幕坐标 | |
const originPos = this.WorldToScreen(this.plane.mesh.position) | |
if (this.pointerPos.x && this.pointerPos.y) { | |
// 计算鼠标地位 和 plane 地位得间隔 | |
const deltaX = (this.pointerPos.x - originPos.x) / smoothing | |
const deltaY = (this.pointerPos.y - originPos.y) / smoothing | |
// plane 朝鼠标的方向挪动 | |
this.plane.mesh.position.x += deltaX | |
this.plane.mesh.position.y -= deltaY | |
} | |
} |
生成粒子
/** | |
* 生成粒子数据 | |
* 每个间隔时间生成粒子:并插入到 particles 中 | |
*/ | |
private initParticles(): void { | |
// 限度 scene 最多的粒子为 90 | |
const LIMIT = 90 | |
this.particles = [] | |
setInterval(() => {if (this.particles.length > LIMIT || this.state !== State.GAME) return | |
// 创立粒子 | |
const particle = this.createParticle() | |
// 随机搁置粒子 | |
particle.position.x = 20 + Math.random() * 20 | |
particle.position.y = -10 + Math.random() * 20 | |
particle.position.z = 0 | |
// 粒子插入 particles 中:不便前面更新操作 | |
this.particles.push(particle) | |
}, 300) | |
} |
更新粒子静止 并检测 是否与飞机碰撞
/** Loop 中更新 plane 坐标 */ | |
private updatePlane(): void { | |
// 设置平滑系数 - 一直尝试失去到数值 | |
const smoothing = 2000 | |
// 获取 plane 屏幕坐标 | |
const originPos = this.WorldToScreen(this.plane.mesh.position) | |
if (this.pointerPos.x && this.pointerPos.y) { | |
// 计算鼠标地位 和 plane 地位得间隔 | |
const deltaX = (this.pointerPos.x - originPos.x) / smoothing | |
const deltaY = (this.pointerPos.y - originPos.y) / smoothing | |
// plane 朝鼠标的方向挪动 | |
this.plane.mesh.position.x += deltaX | |
this.plane.mesh.position.y -= deltaY | |
} | |
} |
其余
我的项目的次要流程就是这些了
还有其余的一些,比方:
- 场景的搭建
- 相机的解决
- 灯光的解决
- 游戏状态的解决
欢送到 GitHub 查看残缺代码
谢谢浏览
喜爱的话,点赞 star 反对
正文完