Three.js 學習筆記 - 跳一跳小遊戲基本場景搭建

一. 項目目錄

|- libs    // 第三方庫
|  
|- configs // 場景中物體的配置
|
|- public  // 公共資源
|
|- src     // 源碼
|
|- game.js  // 小遊戲入口
|
|- game.json // 小遊戲配置
|
|- project.config.json // 項目配置
|
|- README.md   // 項目說明
複製代碼

game.js,game.json,project.config.json 這三個文件經過微信開發者工具會自動建立,只須要把game.js中原有的內容清空便可。html

引入Three.js的源碼和微信提供的Adaptergit

地址:github

如今目錄看起來應該是這樣json

二. 基本遊戲場景搭建

  • 將THREE掛載到GameGlobal上

    在game.js中:canvas

    import './libs/weapp-adapter'
    import * as THREE from './libs/three'
    
    GameGlobal.THREE = THREE
    複製代碼

    GameGlobal是小遊戲的全局對象,相似於瀏覽器的window,這樣就不用在用到three.js的時候再去引用了,引入weapp-adapte也會有一個canvas對象,全部的繪製都會在這個canvas上進行。api

  • 建立renderer目錄

    該目錄用於存放Three.js渲染的相關的代碼瀏覽器

  • 編寫場景相關代碼

    scene.jsbash

    const scene = () => {
        const sceneInstance = new THREE.Scene()
        const axesHelper = new THREE.AxesHelper(100)
        sceneInstance.add(axesHelper)
    
        return sceneInstance
    }
    
    export default scene
    複製代碼

    new THREE.AxesHelper(AxesHelper)是座標系的輔助函數,將它添加到場景中就能夠看到座標軸了,文檔:AxesHelper微信

  • 編寫相機相關代碼

    camera.js微信開發

    const camera = () => {
        const ratio = window.innerHeight / window.innerWidth
        const size = 30
        // 設置相機可看到範圍
        const cameraInstance = new THREE.OrthographicCamera(
            -size, size, size * ratio, -size * ratio, -100, 85
        )
    
        cameraInstance.position.set(0, 0, 0) // 設置相機位置
        cameraInstance.lookAt(new THREE.Vector3(0, 0, 0)) // 設置相機位置從0, 0, 0望向0, 0, 0
    
        return cameraInstance
    }
    
    export default camera
    複製代碼
    • new THREE.OrthographicCamera是正交相機,關於它的參數上一篇有說過,這裏就不說了,說一下它的幾個參數的是怎麼計算的:

    相機可視寬度是我指定的,根據上圖,如今的相機可視寬度是60,若是想要相機看到場景中的物體不變形,那麼相機可視範圍的尺寸就要和整個canvas(畫布)的尺寸成正比:

    畫布高 / 畫布寬 = 相機可視高 / 相機可視寬
    
    相機可視高 = 相機可視高 * 畫布高 / 畫布寬
    複製代碼

    相機近平面這裏給了負值,目的是渲染相機後面的場景,可理解爲讓相機更接近物體

  • 編寫渲染器相關代碼:

    import camera from './camera'
    import scene from './scene'
    
    class Renderer {
        constructor () {
            this.camera = null
            this.scene = null
        }
        init () {
            this.camera = camera()
            this.scene = scene()
            this.instance = new THREE.WebGLRenderer({
                canvas,
                antialias: true  // 開啓抗鋸齒
            })
        }
    
        render () {
            this.instance.render(this.scene, this.camera)
        }
    }
    
    export default new Renderer()
    複製代碼

    修改game.js

    import './libs/weapp-adapter'
    import * as THREE from './libs/three'
    import renderer from './src/renderer/index'
    
    GameGlobal.THREE = THREE
    renderer.init()
    renderer.render()
    複製代碼

    這時候在開發者工具中就能夠看到座標系了:

    根據文檔:紅色表明 X 軸. 綠色表明 Y 軸. 藍色表明 Z 軸.

    目前並不能看到z軸,只須要改一下相機位置便可:

    在camera.js修改:

    cameraInstance.position.set(-10, 10, 10) // 以前是0,0,0
    複製代碼
  • 渲染一個立方體

    新建如下文件

    • block_config.js文件是立方體的基本配置

    • game 目錄存放整個遊戲不一樣層之間的控制文件

      • game -> controller.js 負責view層和model層的通信,暫時尚未model層
      • game -> view.js 負責頁面的相關邏輯
    • objects 目錄存放遊戲場景中的物體

      • objects -> block 遊戲中塊的類
    • pages 遊戲頁面,叫頁面可能不太合適,就理解爲遊戲的不一樣狀態,好比遊戲開始,結束等

    編寫塊的相關代碼:

    • block_config.js

      export default {
          width: 16,
          height: 10
      }
      複製代碼
    • base.js

      import blockConfig from '../../../configs/block_config'
      
      export default class BaseBlock {
          constructor (type) {
              this.type = type
              this.height = blockConfig.height
              this.width = blockConfig.width
          }
      }
      複製代碼
    • box.js

      import Base from './base'
      
      class Box extends Base {
          constructor (x, y, z) {
              super('box')
              this.instance = null
              this.x = x
              this.y = y
              this.z = z
              this.create()
          }
          create () {
              const geometry = new THREE.BoxGeometry(this.width, this.height,         this.width)
              const material = new THREE.MeshBasicMaterial({
                  color: 0xffffff
              })
              this.instance = new THREE.Mesh(geometry, material)
              this.instance.position.set(this.x, this.y, this.z)
          }
      }
      
      export default Box
      複製代碼

      new THREE.BoxGeometry是three.js提供的渲染立方體的方法,這裏的三個參數分別爲:

      • 寬度,物體在x軸的長度
      • 長度,物體在y軸的長度
      • 深度,物體在z軸的長度
    • game_page.js

      import renderer from '../renderer/index'
      import Box from '../objects/block/box'
      
      export default class GamePage {
          constructor () {
              this.renderer = renderer
          }
          init () {
              this.renderer.init()
              this.addBlock()
              this.render()
          }
          addBlock () {
              const box = new Box(-15, 0, 0)
              this.renderer.scene.add(box.instance)
          }
          render () {
              this.renderer.render()
              requestAnimationFrame(() => { this.render() })
          }
      }
      複製代碼
    • 完善controller.js 和 view.js的邏輯

      view.js

      import GamePage from '../pages/game_page'
      
      class GameView {
          constructor () {
              this.gamePage = null
          }
          initGamePage () {
              this.gamePage = new GamePage()
              this.gamePage.init()
          }
      }
      
      export default new GameView()
      
      複製代碼

      controller.js

      import gameView from './view'
      
      class GameController {
          constructor () {
              this.gameView = gameView
          }
      
          initPages () {
              this.gameView.initGamePage()
          }
      }
      
      export default new GameController()
      複製代碼
    • 修改game.js

      import './libs/weapp-adapter'
      import * as THREE from './libs/three'
      import controller from './src/game/controller'
      
      GameGlobal.THREE = THREE
      controller.initPages()
      複製代碼

    這時候去看開發者工具,應該會渲染出一個白色的立方體

    可是仔細看圖中紅框部位鋸齒仍是挺明顯的,去官方論壇搜索了一下,找到了解決方案,要手動的設置一下canvas的寬高:

    修改renderer -> index.js文件

    /* 省略以前的代碼 */
    init () {
        this.camera = camera()
        this.scene = scene()
        /* 新增代碼 */
        const { width, height } = canvas   
        if (window.devicePixelRatio) {
            canvas.height = height * window.devicePixelRatio
            canvas.width = width * window.devicePixelRatio
        }
        /* 新增代碼結束 */
        this.instance = new THREE.WebGLRenderer({
            canvas,
            antialias: true
        })
    }
    複製代碼

    這時候再去看,鋸齒就消失了

  • 渲染一個圓柱體

    新建 cylinder.js

    import Base from './base'
    
    export default class Cylinder extends Base {
        constructor (x, y, z) {
            super('cylinder')
            this.x = x
            this.y = y
            this.z = z
            this.create()
        }
        create () {
            const geometry = new THREE.CylinderGeometry(
                this.width / 2, this.width / 2, this.height, 120
            )
            const material = new THREE.MeshBasicMaterial({
                color: 0xffffff
            })
            this.instance = new THREE.Mesh(geometry, material)
            this.instance.position.set(this.x, this.y, this.z)
        }
    }
    複製代碼

    new THREE.CylinderGeometry 是three.js提供繪製圓柱體的方法,這裏的三個參數分別是:

    • 圓柱的頂部半徑 — 圓柱的底部半徑
    • 圓柱的高度 — 圓柱側面周圍的分段數,分段數去看官網的例子就能明白,它的圓是經過三角形畫出來的,因此當三角形的數量足夠多時,在人眼看來就是一個圓了。

    修改game_page.js

    import Cylinder from '../objects/block/cylinder' // 新增
    
    /* 省略以前代碼 */
    
    addBlock () {
        const box = new Box(-15, 0, 0)
        const cylinder = new Cylinder(20, 0, 0)  // 新增
        this.renderer.scene.add(box.instance)
        this.renderer.scene.add(cylinder.instance) // 新增
    }
    複製代碼

    修改完以後再去看看開發者工具

這樣一個基本的場景就行了,可是還缺燈光,陰影,背景,下一篇在寫。。

完整的代碼在這裏GitHub

相關文章
相關標籤/搜索