前言
最近一直在学ThreeJS,看到别人做出那么多炫酷的效果,觉得太厉害了,于是决定从一些简单的效果开始做。所以打算借这个小游戏来认真的来学习一下ThreeJS
。
正文
"推箱子" 游戏最早是由日本游戏开发者Hiroyuki Imabayashi于1982年开发和发布的。这款游戏的日本名为 "Sokoban"(倉庫番),意为 "仓库管理员"。"推箱子" 游戏的目标是在游戏区域内将箱子移动到指定的位置,通常通过推箱子来完成。游戏逻辑并不复杂,正好可以用来练练手。
初始化场景
游戏场景主要分为四个部分:场景底部面板、仓库边界、箱子、推箱子的人。
首先肯定是初始化场景,需要完成场景、相机、灯光、控制器的创建。场景、渲染器都是常规创建就行,相机的话因为我们游戏场景的范围是 10*10,所以相机需要稍微调整一下。
ts
const fov = 60
const aspect = this.sizes.width / this.sizes.height
this.camera = new PerspectiveCamera(fov, aspect, 0.1)
this.camera.position.copy(
new Vector3(
this.gridSize.x / 2 - 2,
this.gridSize.x / 2 + 4.5,
this.gridSize.y + 1.7
)
)
gridSize
表示游戏场景的范围,暂时设置为 10*10 的网格,后面随着游戏关数不同,复杂度的变化,整体游戏范围肯定会越来越大。 灯光我们需要创建两个灯光,一个平行光,一个环境光,光的颜色都设置为白色就行,平行光需要添加一些阴影的参数。
ts
const ambLight = new AmbientLight(0xffffff, 0.6)
const dirLight = new DirectionalLight(0xffffff, 0.7)
dirLight.position.set(20, 20, 20)
dirLight.target.position.set(this.gridSize.x / 2, 0, this.gridSize.y / 2)
dirLight.shadow.mapSize.set(1024, 1024)
dirLight.shadow.radius = 7
dirLight.shadow.blurSamples = 20
dirLight.shadow.camera.top = 30
dirLight.shadow.camera.bottom = -30
dirLight.shadow.camera.left = -30
dirLight.shadow.camera.right = 30
dirLight.castShadow = true
this.scene.add(ambLight, dirLight)
threeJs的场景初始完之后,接着需要创建游戏场景的底部平面。
游戏场景平面我们用PlaneGeometry
来创建,接着将平面沿着x轴旋转90度,调整为水平方向,并且给平面添加网格辅助AxesHelper
,方便我们在游戏移动的过程中找准位置。
ts
private createScenePlane() {
const { x, y } = this.gridSize
const planeGeometry = new PlaneGeometry(x * 50, y * 50)
planeGeometry.rotateX(-Math.PI * 0.5)
const planMaterial = new MeshStandardMaterial({ color: theme.groundColor })
const plane = new Mesh(planeGeometry, planMaterial)
plane.position.x = x / 2 - 0.5
plane.position.z = y / 2 - 0.5
plane.position.y = -0.5
plane.receiveShadow = true
this.scene.add(plane)
}
private createGridHelper() {
const gridHelper = new GridHelper(
this.gridSize.x,
this.gridSize.y,
0xffffff,
0xffffff
)
gridHelper.position.set(
this.gridSize.x / 2 - 0.5,
-0.49,
this.gridSize.y / 2 - 0.5
)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.3
this.scene.add(gridHelper)
}
接着我们创建一个可以推动箱子的人物,我们用RoundedBoxGeometry
来创建身体,再创建两个SphereGeometry当做眼睛,最后再用RoundedBoxGeometry创建一个嘴巴,就简单的完成了一个任务。
ts
export default class PlayerGraphic extends Graphic {
constructor() {
const NODE_GEOMETRY = new RoundedBoxGeometry(0.8, 0.8, 0.8, 5, 0.1)
const NODE_MATERIAL = new MeshStandardMaterial({
color: theme.player
})
const headMesh = new Mesh(NODE_GEOMETRY, NODE_MATERIAL)
headMesh.name = PLAYER
const leftEye = new Mesh(
new SphereGeometry(0.16, 10, 10),
new MeshStandardMaterial({
color: 0xffffff
})
)
leftEye.scale.z = 0.1
leftEye.position.x = 0.2
leftEye.position.y = 0.16
leftEye.position.z = 0.46
const leftEyeHole = new Mesh(
new SphereGeometry(0.1, 100, 100),
new MeshStandardMaterial({ color: 0x333333 })
)
leftEyeHole.position.z += 0.08
leftEye.add(leftEyeHole)
const rightEye = leftEye.clone()
rightEye.position.x = -0.2
const mouthMesh = new Mesh(
new RoundedBoxGeometry(0.4, 0.15, 0.2, 5, 0.05),
new MeshStandardMaterial({
color: '#5f27cd'
})
)
mouthMesh.position.x = 0.0
mouthMesh.position.z = 0.4
mouthMesh.position.y = -0.2
headMesh.add(leftEye, rightEye, mouthMesh)
headMesh.lookAt(headMesh.position.clone().add(new Vector3(0, 0, 1)))
super(headMesh)
}
}
创建出来的人物长这样。