一. 分析棋子的形状
明确一下需要画的棋子的形状:
它的整个组成是这样的:
在开始之前先去创建如下文件
- coordinate_config.js是坐标的配置,因为棋子的初始坐标和第一个块的坐标是相同的,所以把这些重复的坐标提取出来,方便以后的维护
- piece.js 就是棋子的类
coordinate_config.js
export const initCoordinates = { x: -15, y: 0, z: 0 }
复制代码
game_page.js作如下修改
import { initCoordinates } from '../../configs/coordinate_config'
const box = new Box(initCoordinates.x, initCoordinates.y, initCoordinates.z)
复制代码
然后把第一个方块给隐藏了,改变一下相机位置:
camera.js
cameraInstance.position.set(0, 0, 0) // 设置相机位置
复制代码
game_page.js
// 把下面这句代码注释了
// this.renderer.scene.add(box.instance)
复制代码
现在看到的应该就是这样:
二. 实现棋子的上半部分的八面几何体
piece.js
import { initCoordinates } from '../../configs/coordinate_config'
class Piece {
constructor () {
this.radius = 2
this.pieceContainer = null
this.head = null
this.color = 0xff0000
}
init () {
this.pieceContainer = new THREE.Object3D() // 创建容器
this.pieceContainer.position.set( // 设置容器位置
initCoordinates.x,
initCoordinates.y,
initCoordinates.z
)
this.head = this.createHead()
this.pieceContainer.add(this.head) // 将物体加入容器中
}
createHead () {
const head = new THREE.Mesh(
new THREE.OctahedronGeometry(this.radius),
new THREE.MeshPhongMaterial({ color: this.color })
)
head.castShadow = true
return head
}
}
export default new Piece()
复制代码
因为棋子是组装起来的,所以这里使用了new THREE.Object3D()
,new THREE.Object3D()
就是一个容器,你可以将其他的物体放在这个容器中,就可以对组合好的物体进行整体操作,有点类似DOM中的createDocumentFragment
。
对game_page.js做如下修改(仅仅是添加,不要把之前的代码删了)
import piece from '../objects/piece.js'
export default class GamePage {
/* 省略之前的代码 */
constructor () {
this.piece = piece
}
init () {
this.addPiece()
}
addPiece () {
this.piece.init()
this.renderer.scene.add(this.piece.pieceContainer)
}
}
复制代码
效果:
三. 实现棋子的下半部分
根据上面分析,棋子的下半部分由3个物体组成,所以下半部分还是准备使用一个new THREE.Object3D
把这三个包起来
-
实现饼状物体
饼状物体可以认为是一个球体压扁了,这里使用
new THREE.SphereGeometry
实现:在piece.js添加:
class Piece { constructor () { this.body = null } init () { this.body = this.createBody() this.pieceContainer.add(this.body) } createBody () { const body = new THREE.Object3D() const topGeometry = new THREE.SphereGeometry(this.radius * 1.2, 20, 20) topGeometry.scale(1, 0.3, 1) const top = new THREE.Mesh( topGeometry, new THREE.MeshPhongMaterial({ color: this.color }) ) top.position.y = -2 * this.radius top.castShadow = true body.add(top) return body } } export default new Piece() 复制代码
效果:
代码里的这些物体的大小,缩放,偏移量都是一点一点试出来的,应该有更科学的计算方法吧,但是我没有找到相关的文章或是教程。
-
实现第一个圆柱体
第一个圆柱体就是上大下小的圆柱
在piece.js添加:
class Piece { createBody () { const middle = new THREE.Mesh( new THREE.CylinderGeometry(this.radius * 1.2, this.radius, this.radius * 1.2, 20, 20), new THREE.MeshPhongMaterial({ color: this.color }) ) middle.position.y = -2.7 * this.radius middle.castShadow = true body.add(middle) } } 复制代码
效果:
-
实现最后一个圆柱体
在piece.js添加:
class Piece { createBody () { const bottom = new THREE.Mesh( new THREE.CylinderGeometry(this.radius, this.radius * 1.4, this.radius * 3, 20, 20), new THREE.MeshPhongMaterial({ color: this.color }) ) bottom.position.y = -4.8 * this.radius bottom.castShadow = true body.add(bottom) } } 复制代码
-
将棋子整个上移,让它刚好在块的上面
在piece.js修改:
class Piece { init () { this.pieceContainer.position.set( initCoordinates.x, initCoordinates.y + this.radius * 8.75, // 修改 initCoordinates.z ) } 复制代码
效果:
将视角还原,把第一个方块渲染出来:
camera.js
cameraInstance.position.set(-10, 10, 10) // 设置相机位置 复制代码
game_page.js
this.renderer.scene.add(box.instance) 复制代码
效果:
感觉上面的八面体有点小,算了,不要在意这些细节。
完整的代码:
import { initCoordinates } from '../../configs/coordinate_config' class Piece { constructor () { this.radius = 2 this.pieceContainer = null this.head = null this.body = null this.color = 0xff0000 } init () { this.pieceContainer = new THREE.Object3D() this.pieceContainer.position.set( initCoordinates.x, initCoordinates.y + this.radius * 8.75, initCoordinates.z ) this.head = this.createHead() this.body = this.createBody() this.pieceContainer.add(this.head) this.pieceContainer.add(this.body) } createHead () { const head = new THREE.Mesh( new THREE.OctahedronGeometry(this.radius), new THREE.MeshPhongMaterial({ color: this.color }) ) head.castShadow = true return head } createBody () { const body = new THREE.Object3D() const topGeometry = new THREE.SphereGeometry(this.radius * 1.2, 20, 20) topGeometry.scale(1, 0.3, 1) const top = new THREE.Mesh( topGeometry, new THREE.MeshPhongMaterial({ color: this.color }) ) const middle = new THREE.Mesh( new THREE.CylinderGeometry(this.radius * 1.2, this.radius, this.radius * 1.2, 20, 20), new THREE.MeshPhongMaterial({ color: this.color }) ) const bottom = new THREE.Mesh( new THREE.CylinderGeometry(this.radius, this.radius * 1.4, this.radius * 3, 20, 20), new THREE.MeshPhongMaterial({ color: this.color }) ) top.position.y = -2 * this.radius middle.position.y = -2.7 * this.radius bottom.position.y = -4.8 * this.radius top.castShadow = true middle.castShadow = true bottom.castShadow = true body.add(top) body.add(middle) body.add(bottom) return body } } export default new Piece() 复制代码
三. 八面几何体旋转
在piece.js 新增
class Piece {
update () {
this.head.rotation.y += 0.06
}
}
复制代码
在game_page.js新增
render () {
this.piece && this.piece.update()
}
复制代码
最终效果:
下一篇就实现棋子的动画旋转,跳跃