用代码模拟p2战斗逻辑,按流程进行步骤拆分:
1.p2抽卡
2.p2召唤怪兽上场
3.p2战斗
其中战斗部分分为几种情况:
情况一:p2场上卡牌由大到小进行排序,按序轮询可以攻击的卡牌,然后攻击p1场上卡牌由大到小攻击力最高的同时攻击力不超过当前p2卡牌的那个,如果p2场上最大的攻击力不能突破p1场上卡牌,那就不攻击并将该卡牌攻击次数置为0,进行下一个循环,当p2场上所以卡牌攻击次数均为0时,认为战斗阶段结束,可以进行下一个回合。
情况二:p1场上卡牌已经全部被破坏,而此时p2场上还有卡牌未行动,那么此时卡牌可以直接攻击p1玩家。
情况三:p2战斗阶段时,p1场上怪兽区没有卡牌时,全员即可轮询直接攻击p1玩家。
修改utils/common.ts:
// 卡牌攻击特效
const cardAttack = (card1: any, card2: any, callback: any) => {
console.log("cardAttack", card1, card2)
let isP1 = card1.userData.areaType.indexOf("己方") > -1
// 获取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: isP1 ? pos2.z + 1.4 * 0.8 : pos2.z - 0.7 * 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: isP1 ? pos2.z + 1.4 * 0.8 : pos2.z - 0.7 * 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 }
// p2玩家手牌召唤上场逻辑
const p2FindHandToSiteCard = (cards: any, mana: any) => {
let newCards = cards.filter((v: any) => v.userData.Mana <= mana)
console.log("p2玩家手牌召唤上场逻辑", cards, newCards)
if (newCards.length > 0) {
newCards.sort((a: any, b: any) => {
return a.Mana - b.Mana
})
return newCards[0]
}
return null
}
export { p2FindHandToSiteCard }
game/index.vue(由于涉及代码较多,所以直接贴上该文件全部代码,主要部分看p2DrawCardEvent相关方法):
<template>
<div ref="sceneRef" class="scene"></div>
<!-- 玩家区 -->
<Player ref="playerRef"/>
<!-- 手牌 -->
<Hand ref="handRef"/>
<!-- 卡组 -->
<Deck ref="deckRef"/>
<!-- 战域 -->
<Site ref="siteRef"/>
<!-- 墓地 -->
<Graveyard ref="graveyardRef"/>
<!-- 抽卡逻辑 -->
<DrawCard ref="drawCardRef" :handRef="handRef"/>
<!-- 对话框 -->
<Dialog ref="dialogRef" @handToSite="handToSite" @onCancel="onCancel"/>
<!-- 阶段操作 -->
<ul class="stage-box">
<li v-if="commonStore.$state.currentPlayer==='p1'&&commonStore.$state.flowIndex==1">
<el-button type="primary" size="small" @click.stop="nextFlow">下一阶段</el-button>
</li>
<li v-if="commonStore.$state.currentPlayer==='p1'&&commonStore.$state.flowIndex===2">
<el-button type="danger" size="small" round @click.stop="nextRound">回合结束</el-button>
</li>
</ul>
<div class="info-box">
<!-- 当前操作玩家 -->
<div class="">player:{
{ commonStore.$state.currentPlayer }}</div>
<!-- 回合数 -->
<div class="round-box">round:{
{ commonStore.$state.round }}</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, defineComponent, getCurrentInstance, nextTick } from 'vue'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 轨道控制器
import { DragControls } from 'three/addons/controls/DragControls.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { GlitchPass } from 'three/addons/postprocessing/GlitchPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { useCommonStore } from "@/stores/common.ts"
import { transPos, editDeckCard, renderDeckText, editGraveyardCard, renderGraveyardText, renderSiteCardText, cardAttack, cardDestroy, cardDirectAttack, p2FindHandToSiteCard } from "@/utils/common.ts"
import { Card } from "./Card.ts"
import { CARD_DICT } from "@/utils/dict/card.ts"
import { p1TestDeck, p2TestDeck} from "@/utils/deck/test.ts"
import Hand from "./hand/index.vue"
import Deck from "./deck/index.vue"
import Site from "./site/index.vue"
import Player from "./player/index.vue"
import Graveyard from "./graveyard/index.vue"
import DrawCard from "@/components/DrawCard.vue"
import Dialog from "@/components/Dialog.vue"
// 引入threejs变量
const {proxy} = getCurrentInstance()
const THREE = proxy['THREE']
const scene = proxy['scene']
const camera = proxy['camera']
const renderer = proxy['renderer']
const composer = proxy['composer']
const TWEEN = proxy['TWEEN']
// 后期处理
const renderPass = new RenderPass( scene, camera );
composer.addPass( renderPass );
//
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
const commonStore = useCommonStore()
// 场景ref
const sceneRef = ref()
const playerRef = ref()
const siteRef = ref()
const handRef = ref()
const deckRef = ref()
const graveyardRef = ref()
const drawCardRef = ref()
const dialogRef = ref()
const selectedCard = ref() // 选中的场上card
const selectedTargetCard = ref() // 选中的目标场上card
// 坐标轴辅助
const axesHelper = new THREE.AxesHelper(5);
// 创建轨道控制器
// const orbitControls = new OrbitControls( camera, renderer.domElement );
// 字体加载器
const fontLoader = new FontLoader();
watch(() => commonStore.$state.p1HP, () => {
if (commonStore.$state.p1HP <=0) {
// alert("你输了")
// window.location.reload()
}
})
watch(() => commonStore.$state.p2HP, () => {
if (commonStore.$state.p2HP <=0) {
// alert("你赢了")
// window.location.reload()
}
})
onMounted(async () => {
await initResource()
initScene()
initGame()
// 鼠标按下
window.addEventListener('touchstart', onMousedown)
window.addEventListener('touchmove', onMousemove)
window.addEventListener('touchend', onMouseup)
// window.addEventListener('click', onMousedown)
// 监听浏览器窗口变化进行场景自适应
window.addEventListener('resize', onWindowResize, false);
})
// 资源加载
const initResource = () => {
// 字体加载
return new Promise((resolve, reject) => {
// Microsoft YaHei_Regular
// fonts/helvetiker_regular.typeface.json
fontLoader.load('fonts/helvetiker_bold.typeface.json', (font: any) => {
commonStore.loadFont(font)
resolve(true)
});
})
}
// 初始化场景
const initScene = async () => {
renderer.setSize( window.innerWidth