Three.js 学习笔记 - 跳一跳小游戏基本场景搭建

|- libs    // 第三方库
|  
|- configs // 场景中物体的配置
|
|- public  // 公共资源
|
|- src     // 源码
|
|- game.js  // 小游戏入口
|
|- game.json // 小游戏配置
|
|- project.config.json // 项目配置
|
|- README.md   // 项目说明
复制代码

game.js,game.json,project.config.json 这三个文件通过微信开发者工具会自动创建,只需要把game.js中原有的内容清空即可。

引入Three.js的源码和微信提供的Adapter

地址:

现在目录看起来应该是这样

二. 基本游戏场景搭建

  • 将THREE挂载到GameGlobal上

    在game.js中:

    import './libs/weapp-adapter'
    import * as THREE from './libs/three'
    
    GameGlobal.THREE = THREE
    复制代码

    GameGlobal是小游戏的全局对象,类似于浏览器的window,这样就不用在用到three.js的时候再去引用了,引入weapp-adapte也会有一个canvas对象,所有的绘制都会在这个canvas上进行。

  • 创建renderer目录

    该目录用于存放Three.js渲染的相关的代码

  • 编写场景相关代码

    scene.js

    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

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章