近期在嘗試着學習寫一些3D小遊戲,分享一下成果。
嚴格上說還算不上完整的遊戲,感興趣的朋友能夠觀摩一下。
在這裏用到的惟一素材:小飛機
是在 Blender 軟件了裏面簡單設計的
git
Blender 是一個免費開源的建模軟件
若是感興趣,這裏推薦B站上的一個 入門教程github
主要用到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
在這個項目主要實現一下幾個環節dom
// 加載飛機模型 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() } } }
... // 獲取鼠標座標存儲 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中更新粒子數據 */ private updateParticles(): void { // 定義粒子移動速度 const SPEED = 0.15 this.particles.forEach((e, index) => { // 粒子差很少離開屏幕後,回收重製到初始位置 if (e.position.x < -20) { e.position.x = 20 + Math.random() * 20 } e.position.x -= SPEED // 檢測粒子是否和 plane 發生碰撞 const collided = e.intersectsMesh(this.plane.mesh) if (collided) { this.particles.splice(index, 1) e.dispose() if (e.name === 'sphere') { this.score++ this.updateScore() console.log('collided') } } }) }
項目的主要流程就是這些了
還有其餘的一些,好比:async
歡迎到GitHub查看完整代碼ide
喜歡的話,點贊 star 支持