# 04 碰撞与互动

本节将学习3个事件API

  1. onVoxelContact() 触碰方块

  2. onInteract() 与实体互动

  3. onEntityContact() 触碰实体


1.用onVoxelContact触碰方块事件,做一个欢迎灯

(点击->高清B站视频) (opens new window)


相关代码如下:

world.onVoxelContact(({ x, y, z, voxel }) => {
    const voxelName = voxels.name(voxel);  // 将方块id转换名称
    if (voxelName === 'board5'){              // 如果方块名称是 5号木板
        voxels.setVoxel(46, 11, 52, 'lantern_02');       // 在门口顶部生成一个灯箱

        const meshScale = 1/16 //默认模型方块大小倍数为地图方块的1/16
        const man = world.createEntity({
            mesh:'mesh/人物.vb',
            position:[44, 14, 52],
            meshScale:[meshScale,meshScale,meshScale],//xyz放大倍数
            fixed:true,//固定
        });
        man.say('欢迎回家')
        world.sound('audio/欢迎回家.mp3')
    }
});

2.用onInteract与实体互动事件,做一个电灯开关

(点击->高清B站视频) (opens new window)


相关的代码如下:
const lampSwitch = world.querySelector('#灯开关-1') 
// 用查看实体面板获得开关的实体名, 通过实体名查询得到开关实体。注意查询实体名要前置#号

lampSwitch.enableInteract = true // 允许灯开关被玩家触发交互
lampSwitch.interactRadius = 2 // 交互半径
lampSwitch.interactHint = lampSwitch.id // 交互提示文本内容改为实体名字
lampSwitch.interactColor = new Box3RGBColor(0,1,0) // 交互提示文本绿色

lampSwitch.onInteract(()=>{ // 在游戏中走近开关按E键触发
  lampSwitch.meshOrientation = lampSwitch.meshOrientation.rotateZ(Math.PI)  // 开关实体旋转180度(PI表示180度), 模拟开关上下切换
  lampSwitch.sound('audio/开关灯声音.mp3') // 添加开关灯的音效
  floor1ToggleLamps() // 反复开关1楼灯光
})

let floor1LampIsOn = true // 1楼灯的开关状态
function floor1ToggleLamps() { // 定义 反复开关1楼灯光 的函数
  if(floor1LampIsOn){
    // 换成 地砖方块模拟关灯
    voxels.setVoxel(37,12,64,'carpet_07')
    voxels.setVoxel(37,12,59,'carpet_07')
    voxels.setVoxel(28,12,65,'carpet_07')
    voxels.setVoxel(28,12,59,'carpet_07')
  }else{
    // 换成 灯箱方块模拟开灯
    voxels.setVoxel(37,12,64,'lantern_01')
    voxels.setVoxel(37,12,59,'lantern_01')
    voxels.setVoxel(28,12,65,'lantern_01')
    voxels.setVoxel(28,12,59,'lantern_01')
  }
  floor1LampIsOn = !floor1LampIsOn // 反复反转 开关状态
}
world.placeVoxelSound = '' // 关掉方块替换时的默认声音

3.升降电梯

const elevator = world.querySelector('#电梯地板-1') // 获取电梯地板实体
elevator.collides = true // 电梯开启碰撞检测
elevator.fixed = true // 电梯不受外力影响

world.onEntityContact(({entity, other})=>{  
  // 实时监测整个世界的实体碰撞事件。entity指被碰撞的实体, other则是主动撞过来的实体

  if(entity.id=='电梯地板-1' && other.isPlayer){ // 如果 玩家踏上了电梯
    if(entity.position.y<14){ // 如果玩家y低于2楼地板, 则判定玩家在1楼
      entity.velocity.y = 0.1 // 电梯持续上移 
      world.say(other.player.name+' 坐电梯上楼')
    }
  }
})

world.onTick(()=>{ // 实时检测电梯位置, 进行检测是否到达1楼或2楼
  if(elevator.position.y>14){ // 如果电梯y坐标高于2楼的地板, 电梯到达2楼
    elevator.position.y = 14 // 复位到2楼的准确位置
    elevator.velocity.y = 0 // 电梯停止移动
  }
})