一. 项目目录
|- 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