ThreeJS实现推箱子小游戏【一】

前言

最近一直在学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)
  }
}

创建出来的人物长这样。

相关推荐
Chikaoya3 小时前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
我认不到你5 小时前
antd proFromSelect 懒加载+模糊查询
前端·javascript·react.js·typescript
奔跑草-1 天前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
新星_1 天前
构造函数类型
typescript
Sword991 天前
【ThreeJs原理解析】第2期 | 旋转、平移、缩放实现原理
前端·three.js·源码阅读
清灵xmf1 天前
TypeScript 中的 ! 和 ? 操作符
前端·javascript·typescript·?·
葫芦鱼1 天前
怎么打造一个舒适的nodejs开发环境
前端·typescript
小白菜学前端1 天前
Threejs 材质贴图、光照和投影详解
前端·3d·three.js
前端要努力2 天前
深入解析 TypeScript 的 unknown 和 any:安全性与灵活性的平衡
前端·typescript
破浪前行·吴2 天前
使用@react-three/fiber,@mkkellogg/gaussian-splats-3d加载.splat,.ply,.ksplat文件
前端·react.js·three.js