Three.js 学习笔记 - 实现跳一跳小游戏中的棋子

一. 分析棋子的形状

明确一下需要画的棋子的形状:

它的整个组成是这样的:

在开始之前先去创建如下文件

  • 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()
}
复制代码

最终效果:

GitHub地址

下一篇就实现棋子的动画旋转,跳跃

转载于:https://juejin.im/post/5d033dc66fb9a07ed36ea65f

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值