vue3+threejs新手从零开发卡牌游戏(十九):添加战斗事件

接上一节实现画线后,现在可以根据鼠标移动位置判断是否选中了对方区域怪兽卡牌:

修改game/index.vue代码,在画线方法中添加获取目标对象方法:


const selectedCard = ref() // 选中的场上card
const selectedTargetCard = ref() // 选中的目标场上card


// 画线
const drawLine = () => {
  ...
  // 获取目标对象
  getTargetMesh()
}

// 获取目标对象
const getTargetMesh = () => {
  let p2Cards = scene.children.filter((v: any) => v.userData?.areaType?.indexOf("对方怪兽区") > -1)
  if (p2Cards.length <= 0) {
    selectedTargetCard.value = null
    return
  }
  let arr = raycaster.intersectObjects(p2Cards, true)
  if (arr.length > 0) {
    selectedTargetCard.value = arr[0].object
  } else {
    selectedTargetCard.value = null
  }
}

然后我们设计卡牌战斗逻辑:

1.卡牌移动到对方卡牌的位置进行碰撞,然后退回到原位置

2.两张卡牌比较大小,攻击力高的存活,攻击力低的被破坏

我们在utils/common.ts添加卡牌攻击和卡牌被破坏的动效(这里就是简单修改了卡牌的透明度):



// 卡牌攻击特效
const cardAttack = (card1: any, card2: any, callback: any) => {
  // 获取card1世界坐标
  let pos1 = new THREE.Vector3(0, 0, 0)
  card1.getWorldPosition(pos1)
  // 获取card2世界坐标
  let pos2 = new THREE.Vector3(0, 0, 0)
  card2.getWorldPosition(pos2)

  // 动画1:移动到对方卡面前
  const twA = new TWEEN.Tween({
    x: pos1.x,
    y: pos1.y,
    z: pos1.z,
    card1,
  })
  twA.to({
    x: pos2.x,
    y: pos2.y + 0.1,
    z: pos2.z + 1.4 * 0.8,
  }, 300)
  twA.easing(TWEEN.Easing.Quadratic.Out)
  twA.onUpdate((obj: any) => {
    obj.card1.position.set(obj.x, obj.y, obj.z)
  })
  twA.onComplete(function() {
    //动画结束:关闭允许透明,恢复到模型原来状态
    TWEEN.remove(twA)
    callback && callback()
  })
  // 动画2:退回到原位置
  const twB = new TWEEN.Tween({
    x: pos2.x,
    y: pos2.y + 0.1,
    z: pos2.z + 1.4 * 0.8,
    card1,
  })
  twB.to({
    x: pos1.x,
    y: pos1.y,
    z: pos1.z,
  }, 400)
  twB.easing(TWEEN.Easing.Quadratic.In)
  twB.onUpdate((obj: any) => {
    obj.card1.position.set(obj.x, obj.y, obj.z)
  })
  twB.onComplete(function() {
    //动画结束:关闭允许透明,恢复到模型原来状态
    // TWEEN.remove(twA)
    // callback && callback()
  })
  twA.chain(twB)
  twA.start();
}
export { cardAttack }


// 卡牌被破坏动效
const cardDestroy = (card: any, callback: any) => {
  const tw = new TWEEN.Tween({
    opacity: 0.5,
    card
  })
  tw.to({opacity: 0.0}, 500)
  tw.easing(TWEEN.Easing.Quadratic.InOut)
  tw.onUpdate((obj: any) => {
    if (obj.card?.material && obj.card.material.length > 0) {
      obj.card.material.forEach((v: any) => {
        v.transparent = true
        v.opacity = obj.opacity
        v.alphaTest = 0.1;
      })
    }
  })
  tw.onComplete(function() {
    //动画结束:关闭允许透明,恢复到模型原来状态
    callback && callback()
  })
  tw.start();
}
export { cardDestroy }

然后我们在game/index.vue代码中引用(里面有一个判断mesh名称是否是攻击力,这个攻击力其实指的是卡牌的攻击力文字,因为鼠标移动也可能选到卡牌的文字上,所以需要找到它的parent即可以找到对应的卡牌):

// 鼠标抬起事件
const onMouseup = (ev: any) => {
  ...
  fight()
}

// 战斗
const fight = () => {
  if (selectedCard.value && selectedTargetCard.value) {
    let _selectedCard: any = selectedCard.value
    let _selectedTargetCard: any = selectedTargetCard.value
    if (selectedCard.value.name === "攻击力") {
      _selectedCard = _selectedCard.value.parent
    }
    if (selectedTargetCard.value.name === "攻击力") {
      _selectedTargetCard = _selectedTargetCard.value.parent
    }

    // 移除卡牌
    function removeCard(card: any) {
      if (card.children && card.children.length > 0) {
        card.children.forEach((v: any) => {
          card.remove(v)
        })
      }
      scene.remove(card)
    }

    cardAttack(_selectedCard, _selectedTargetCard, () => {
      console.log(888, Number(_selectedCard.userData.ATK), Number(_selectedTargetCard.userData.ATK))
      if (Number(_selectedCard.userData.ATK) > Number(_selectedTargetCard.userData.ATK)) {
        cardDestroy(_selectedTargetCard, () => {
          removeCard(_selectedTargetCard)
        })
      } else if (Number(_selectedCard.userData.ATK) === Number(_selectedTargetCard.userData.ATK)) {
        cardDestroy(_selectedCard, () => {
          removeCard(_selectedCard)
        })
        cardDestroy(_selectedTargetCard, () => {
          removeCard(_selectedTargetCard)
        })
      } else {
        cardDestroy(_selectedCard, () => {
          removeCard(_selectedCard)
        })
      }
    })
    selectedCard.value = null
    selectedTargetCard.value = null
  }
}

页面效果如下:

  • 24
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用Vue3和Three.js渲染室内地图有几个主要步骤。 首先,你需要准备好室内地图的数据。这可以是一个包含房间、墙壁、家具等元素的3D模型文件,如OBJ或GLTF格式。你还可以考虑将地图数据转换为JSON格式,并使用自定义脚本生成3D对象。 接下来,在Vue3中创建一个Three.js的场景(Scene)。你可以使用Vue Composition API来创建一个自定义的Vue组件,该组件将负责Three.js的初始化和场景的绘制。在这个组件中,你将使用Three.js的PerspectiveCamera来设置透视投影相机,并使用OrbitControls插件来实现用户交互控制。 然后,你需要加载地图数据并将其转换为Three.js的3D对象。你可以使用Three.js提供的加载器(Loader)来加载3D模型文件。完成加载后,你可以将模型添加到场景中,并设置其位置、旋转等属性。 最后,你可以根据需要添加光源、阴影效果、材质等来提高渲染效果。你可以通过创建Three.js的光源对象,如DirectionalLight或SpotLight,来模拟现实世界的光照。你可以使用Three.js的材质(Material)来定义模型的外观和反射属性,如颜色、贴图等。 通过以上步骤,你可以在Vue3应用中使用Three.js渲染室内地图。不过,请注意,使用Three.js进行复杂的渲染可能对性能有一定要求,你可能需要优化性能,如使用LOD(多级细分)模型、合并几何体等技术来提高性能并避免卡顿。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清岚_lxn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值