首先将双方玩家的HP存入store中,stores/common.ts代码如下:
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCommonStore = defineStore('common', () => {
const _font = ref() // 字体
const p1HP = ref(4000) // 己方HP
const p2HP = ref(4000) // 对方HP
const p1Deck = ref([] as any) // 己方卡组
const p2Deck = ref([] as any) // 对方卡组
const p1Hand = ref([] as any) // 己方手牌
const p2Hand = ref([] as any) // 对方手牌
const p1SiteCards = ref([] as any) // 己方场上卡牌
const p2SiteCards = ref([] as any) // 对方场上卡牌
// 加载字体
function loadFont(data: any) {
_font.value = data
}
// 更新己方HP
function updateP1HP(data: any) {
p1HP.value = data
}
// 更新对方HP
function updateP2HP(data: any) {
p2HP.value = data
}
// 更新己方卡组
function updateP1Deck(data: any) {
p1Deck.value = data
}
// 更新对方卡组
function updateP2Deck(data: any) {
p2Deck.value = data
}
// 更新己方手牌
function updateP1Hand(data: any) {
p1Hand.value = data
}
// 更新己方手牌
function updateP2Hand(data: any) {
p2Hand.value = data
}
// 更新己方场上卡牌
function updateP1SiteCards(data: any) {
p1SiteCards.value = data
}
// 更新对方场上卡牌
function updateP2SiteCards(data: any) {
p2SiteCards.value = data
}
return {
_font,
p1HP,
p2HP,
p1Deck,
p2Deck,
p1Hand,
p2Hand,
p1SiteCards,
p2SiteCards,
loadFont,
updateP1HP,
updateP2HP,
updateP1Deck,
updateP2Deck,
updateP1Hand,
updateP2Hand,
updateP1SiteCards,
updateP2SiteCards,
}
}, {
persist: true
})
然后思考下血量相关逻辑,这里只做两个简单的处理:
1.卡牌战斗后的攻击力差值导致的血量削减
2.卡牌直接攻击玩家导致的血量削减
所以我们修改game/index.vue中的fight方法,补充了直接攻击和卡牌战斗后差值导致的血量变化逻辑:
// 战斗
const fight = () => {
if (selectedCard.value && selectedTargetCard.value) { // 如果selectedCard和selectedTargetCard都存在
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
}
// 移除卡牌
const removeCard = async (card: any) => {
if (card.children && card.children.length > 0) {
card.children.forEach((v: any) => {
card.remove(v)
})
}
let areaType = card.userData.areaType
let isP1 = areaType.indexOf("己方") > -1
let graveyardGroup = null
let graveyardGroupPos = new THREE.Vector3(0, 0, 0)
let cards = []
card.material.forEach((v: any) => {
v.transparent = false
v.opacity = 1
v.alphaTest = 0.1;
})
card.rotateX(180 * (Math.PI / 180)) // 弧度
if (isP1) {
card.userData.areaType = "己方墓地"
graveyardGroup = scene.getObjectByName("p1_graveyardGroup")
graveyardGroup.getWorldPosition(graveyardGroupPos)
card.position.set(graveyardGroupPos.x, graveyardGroupPos.y, graveyardGroupPos.z)
cards = scene.children.filter((v: any) => v.userData?.areaType === "己方墓地")
} else {
card.userData.areaType = "对方墓地"
graveyardGroup = scene.getObjectByName("p2_graveyardGroup")
graveyardGroup.getWorldPosition(graveyardGroupPos)
card.position.set(graveyardGroupPos.x, graveyardGroupPos.y, graveyardGroupPos.z)
cards = scene.children.filter((v: any) => v.userData?.areaType === "对方墓地")
}
// 修改墓地
let position = new THREE.Vector3(0, 0.005 * cards.length, 0)
await editGraveyardCard(graveyardGroup, card, "remove")
await renderGraveyardText(graveyardGroup, `${cards.length}`, commonStore.$state._font, position)
if (isP1) {
let sitePlane = scene.getObjectByName("己方战域Plane")
let mesh = sitePlane.children.find((v: any) => v.name === areaType)
if (mesh) {
mesh.userData.empty = true
}
} else {
let sitePlane = scene.getObjectByName("对方战域Plane")
let mesh = sitePlane.children.find((v: any) => v.name === areaType)
if (mesh) {
mesh.userData.empty = true
}
}
}
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)
let p2HP = JSON.parse(JSON.stringify(commonStore.$state.p2HP))
p2HP -= (Number(_selectedCard.userData.ATK) - Number(_selectedTargetCard.userData.ATK))
if (p2HP < 0) {
p2HP = 0
}
commonStore.updateP2HP(p2HP)
})
} else if (Number(_selectedCard.userData.ATK) === Number(_selectedTargetCard.userData.ATK)) {
cardDestroy(_selectedCard, () => {
removeCard(_selectedCard)
})
cardDestroy(_selectedTargetCard, () => {
removeCard(_selectedTargetCard)
})
} else {
cardDestroy(_selectedCard, () => {
removeCard(_selectedCard)
let p1HP = JSON.parse(JSON.stringify(commonStore.$state.p1HP))
p1HP -= (Number(_selectedTargetCard.userData.ATK) - Number(_selectedCard.userData.ATK))
if (p1HP < 0) {
p1HP = 0
}
commonStore.updateP1HP(p1HP)
})
}
})
selectedCard.value = null
selectedTargetCard.value = null
} else if (selectedCard.value) { // 如果只存在selectedCard
// 直接攻击
let _selectedCard: any = selectedCard.value
console.log(333, _selectedCard)
if (selectedCard.value.name === "攻击力") {
_selectedCard = _selectedCard.value.parent
}
let areaType = _selectedCard.userData.areaType
let isP1 = areaType.indexOf("己方") > -1
let cards = []
if (isP1) {
cards = scene.children.filter((v: any) => v.userData?.areaType?.indexOf("对方怪兽区") > -1)
} else {
cards = scene.children.filter((v: any) => v.userData?.areaType?.indexOf("己方方怪兽区") > -1)
}
if (cards.length > 0) {
return
}
cardDirectAttack(scene, _selectedCard, () => {
if (isP1) {
let p2HP = JSON.parse(JSON.stringify(commonStore.$state.p2HP))
p2HP -= _selectedCard.userData.ATK
if (p2HP < 0) {
p2HP = 0
}
commonStore.updateP2HP(p2HP)
} else {
let p1HP = JSON.parse(JSON.stringify(commonStore.$state.p1HP))
p1HP -= _selectedCard.userData.ATK
if (p1HP < 0) {
p1HP = 0
}
commonStore.updateP1HP(p1HP)
}
})
}
}
然后在utils/common.ts中添加一个卡牌直接攻击特效的方法,和卡牌战斗动效差不多,修改下移动终点的位置即可:
// 卡牌直接攻击特效
const cardDirectAttack = (scene: any, card: any, callback: any) => {
// 获取card1世界坐标
let pos1 = new THREE.Vector3(0, 0, 0)
card.getWorldPosition(pos1)
// 获取card2世界坐标
let pos2 = new THREE.Vector3(0, 0, 0)
let isP1 = card.userData.areaType.indexOf("己方") > -1
let mesh = null
if (isP1) {
let sitePlane = scene.getObjectByName("对方战域Plane")
mesh = sitePlane.children.find((v: any) => v.name === "对方战术2")
mesh.getWorldPosition(pos2)
} else {
let sitePlane = scene.getObjectByName("己方战域Plane")
mesh = sitePlane.children.find((v: any) => v.name === "己方战术2")
mesh.getWorldPosition(pos2)
}
// 动画1:移动到对方卡面前
const twA = new TWEEN.Tween({
x: pos1.x,
y: pos1.y,
z: pos1.z,
card,
})
twA.to({
x: pos2.x,
y: pos2.y + 0.1,
z: pos2.z,
}, 300)
twA.easing(TWEEN.Easing.Quadratic.Out)
twA.onUpdate((obj: any) => {
obj.card.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,
card,
})
twB.to({
x: pos1.x,
y: pos1.y,
z: pos1.z,
}, 400)
twB.easing(TWEEN.Easing.Quadratic.In)
twB.onUpdate((obj: any) => {
obj.card.position.set(obj.x, obj.y, obj.z)
})
twB.onComplete(function() {
//动画结束:关闭允许透明,恢复到模型原来状态
// TWEEN.remove(twA)
// callback && callback()
})
twA.chain(twB)
twA.start();
}
export { cardDirectAttack }
页面效果如下: