Babylon实例:用Babylon.js实现手动操作的汉诺塔

演示效果

Babylon.js 汉诺塔

核心代码

监听鼠标选中事件,记录圆盘对象和初始位置,方便在操作错误的情况下重置圆盘位置

scene.onPointerDown = function (evt, pickResult) {
  if (
    pickResult.pickedMesh &&
    pickResult.pickedMesh.name.startsWith('disk')
  ) {
    const newPositionX = pickResult.pickedMesh.position.x
    const towerIndex = towers.findIndex(
      (tower) => Math.abs(tower.tower.position.x - newPositionX) < 1
    )
    if (towerIndex != -1) {
      const stack = diskStacks[towerIndex]
      const topDisk = stack.length > 0 ? stack[stack.length - 1] : null
      if (topDisk && topDisk.name === pickResult.pickedMesh.name) {
        draggingDisk = pickResult.pickedMesh
        originalPosition = draggingDisk.position.clone() // 记录圆盘的原始位置
        const pickPoint = getWorldPositionFromCanvas(
          scene.pointerX,
          scene.pointerY
        )
        if (pickPoint) {
          offset = pickPoint.subtract(draggingDisk.position)
        }
        // 禁用相机旋转
        camera.detachControl(canvas)
      }
    }
  }
}

监听鼠标移动事件,动态更新拖拽圆盘的位置

scene.onPointerMove = function () {
  if (draggingDisk) {
    const pickPoint = getWorldPositionFromCanvas(
      scene.pointerX,
      scene.pointerY
    )
    if (pickPoint) {
      draggingDisk.position = pickPoint.subtract(offset)
    }
  }
}

监听鼠标抬起事件,在抬起时,比较塔最上面圆盘的索引和拖拽的索引,如果满足放置条件则放在目标塔上

scene.onPointerUp = function () {
   if (draggingDisk) {
     const newPositionX = draggingDisk.position.x
     const towerIndex = towers.findIndex(
       (tower) => Math.abs(tower.tower.position.x - newPositionX) < 1
     )

     if (towerIndex !== -1) {
       const stack = diskStacks[towerIndex]
       const currentHeight = stack.length * 0.5 + 0.25

       // 检查目标塔的顶部圆盘
       const topDisk = stack.length > 0 ? stack[stack.length - 1] : null
       const draggingDiskDiameter = draggingDisk.metadata.index // 计算直径
       const topDiskDiameter = topDisk ? topDisk.metadata.index : Infinity // 计算直径

       if (!topDisk || draggingDiskDiameter < topDiskDiameter) {
         // 确保圆盘可以放置在目标塔上
         draggingDisk.position.x = towers[towerIndex].tower.position.x
         draggingDisk.position.y = currentHeight
         draggingDisk.position.z = towers[towerIndex].tower.position.z

         // 更新圆盘的塔映射
         const originalTowerIndex = diskToStackMap.get(draggingDisk)
         diskStacks[originalTowerIndex] = diskStacks[
           originalTowerIndex
         ].filter((disk) => disk !== draggingDisk)
         diskToStackMap.set(draggingDisk, towerIndex)
         stack.push(draggingDisk)
       } else {
         // 如果圆盘不能放置,回到原位置
         resetDiskPosition(draggingDisk, originalPosition)
       }
     } else {
       // 如果未选择有效塔,回到原位置
       resetDiskPosition(draggingDisk, originalPosition)
     }

     draggingDisk = null
     // 重新启用相机旋转
     camera.attachControl(canvas, true)
   }
 }
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值