个人网站怎么做cps,中华室内设计协会,wordpress文字置顶插件,做网站找哪个软件用代码模拟p2战斗逻辑#xff0c;按流程进行步骤拆分#xff1a;
1.p2抽卡
2.p2召唤怪兽上场
3.p2战斗
其中战斗部分分为几种情况#xff1a;
情况一#xff1a;p2场上卡牌由大到小进行排序#xff0c;按序轮询可以攻击的卡牌#xff0c;然后攻击p1场上卡牌由大到小…用代码模拟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相关方法
templatediv refsceneRef classscene/div!-- 玩家区 --Player refplayerRef/!-- 手牌 --Hand refhandRef/!-- 卡组 --Deck refdeckRef/!-- 战域 --Site refsiteRef/!-- 墓地 --Graveyard refgraveyardRef/!-- 抽卡逻辑 --DrawCard refdrawCardRef :handRefhandRef/!-- 对话框 --Dialog refdialogRef handToSitehandToSite onCancelonCancel/!-- 阶段操作 --ul classstage-boxli v-ifcommonStore.$state.currentPlayerp1commonStore.$state.flowIndex1el-button typeprimary sizesmall click.stopnextFlow下一阶段/el-button/lili v-ifcommonStore.$state.currentPlayerp1commonStore.$state.flowIndex2el-button typedanger sizesmall round click.stopnextRound回合结束/el-button/li/uldiv classinfo-box!-- 当前操作玩家 --div classplayer{{ commonStore.$state.currentPlayer }}/div!-- 回合数 --div classround-boxround{{ commonStore.$state.round }}/div/div
/templatescript setup langts
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.jsonfontLoader.load(fonts/helvetiker_bold.typeface.json, (font: any) {commonStore.loadFont(font)resolve(true)});})
}// 初始化场景
const initScene async () {renderer.setSize( window.innerWidth, window.innerHeight );sceneRef.value.appendChild( renderer.domElement );scene.add(axesHelper)// addSceneBg()// camera.position.set( 5, 5, 5 );camera.position.set( 0, 6.5, 0 );camera.lookAt(0, 0, 0)// const glitchPass new GlitchPass();// composer.addPass( glitchPass );// const outputPass new OutputPass();// composer.addPass( outputPass );addPlane()animate();
}// scene添加动态背景
const addSceneBg () {const vertices [];for ( let i 0; i 5000; i ) {const x THREE.MathUtils.randFloatSpread( 1000 );const y THREE.MathUtils.randFloatSpread( 1000 );const z THREE.MathUtils.randFloatSpread( 1000 );vertices.push( x, y, z );}const particlesGeometry new THREE.BufferGeometry();particlesGeometry.setAttribute( position, new THREE.Float32BufferAttribute( vertices, 3 ) );// 设置点材质const pointsMaterial new THREE.PointsMaterial();// pointsMaterial.size 0.9;pointsMaterial.color.set(new THREE.Color(#fff));// 相机深度而衰减pointsMaterial.sizeAttenuation true;const points new THREE.Points(particlesGeometry, pointsMaterial);scene.add(points);// const texture new THREE.TextureLoader().load( textures/bg.jpg );// // const geometry new THREE.SphereGeometry( 1, 32, 16 );// const geometry new THREE.CircleGeometry( 6, 32 );// const material new THREE.MeshBasicMaterial({// map: texture// });// const sphere new THREE.Mesh( geometry, material );// sphere.name 场景背景// sphere.position.set(0, 0, 0)// sphere.rotateX(-90 * (Math.PI / 180)) // 弧度// scene.add( sphere );// texture.wrapS THREE.RepeatWrapping;// texture.wrapT THREE.RepeatWrapping;// scene.background texture
}// scene中添加plane几何体
const addPlane () {const geometry new THREE.PlaneGeometry( 20, 20);const material new THREE.MeshBasicMaterial( {color: new THREE.Color(gray), side: THREE.FrontSide, alphaHash: true,// alphaTest: 0,opacity: 0} );const plane new THREE.Mesh( geometry, material );plane.rotateX(-90 * (Math.PI / 180)) // 弧度plane.name 地面scene.add( plane );
}// 用requestAnimationFrame进行渲染循环
// let bgMesh scene.getObjectByName(场景背景)
// console.log(123, bgMesh)// 移动线纹理
let arrowTexture new THREE.TextureLoader().load(textures/arrow.png);
arrowTexture.wrapT THREE.RepeatWrapping;
arrowTexture.repeat.set(1, 4);
arrowTexture.center new THREE.Vector2(0.5, 0.5)
arrowTexture.rotation (-90 * (Math.PI / 180))
arrowTexture.needsUpdate true;const animate () {requestAnimationFrame( animate );if (arrowTexture) {arrowTexture.offset.y - 0.02; //更新箭头纹理偏移量}TWEEN.update()// let bgMesh scene.getObjectByName(场景背景)// if (bgMesh) {// bgMesh.rotation.z 0.0002// }// renderer.render( scene, camera );composer.render()
}// 场景跟随浏览器窗口大小自适应
const onWindowResize () {camera.aspect window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);
}// 初始化游戏
const initGame async () {// 初始化生命值commonStore.updateP1HP(4000)commonStore.updateP2HP(4000)// 初始化manacommonStore.updateP1Mana(6)commonStore.updateP2Mana(10)// 初始化游戏流程commonStore.updateFlowIndex(0)// 初始化游戏回合数commonStore.updateRound(1)// 确定先后手initFirst()// 初始化玩家initPlayer()// 初始化场地initSite()// 初始化墓地initGraveyard()// 初始化卡组await initDeck()// 初始化手牌await initHand()// 绑定手牌事件onHandEvent()// 执行游戏流if (commonStore.$state.currentPlayer p1) {// p1Flow()p1DrawCardEvent()} else {p2DrawCardEvent(1)}// // await p2DrawCardEvent(1)// let p2_handGroup scene.getObjectByName(p2_handGroup)// let cards p2_handGroup.children.filter((v: any) v.userData.type 怪兽)// p2HandToSite(cards[0])
}// 确定先后手
const initFirst () {let index Math.random() * 10if (index 0) { // p1先手commonStore.updateCurrentPlayer(p1)console.log(p1先手)} else { // p1后手commonStore.updateCurrentPlayer(p2)console.log(p2先手)}
}// 初始化玩家
const initPlayer () {playerRef.value.init()
}// 初始化场地
const initSite () {siteRef.value.init()
}// 初始化墓地
const initGraveyard () {graveyardRef.value.init()
}// 初始化卡组
const initDeck () {return new Promise((resolve, reject) {let p1Deck: any []let p2Deck: any []// 洗牌p1TestDeck.sort(() {return Math.random() - 0.5})p2TestDeck.sort(() {return Math.random() - 0.5})p1TestDeck.forEach((v: any, i: any) {let obj CARD_DICT.find((b: any) b.card_id v)if (obj) {p1Deck.push({card_id: v,name: ${obj.name}_${i}})}})p2TestDeck.forEach((v: any, i: any) {let obj CARD_DICT.find((b: any) b.card_id v)if (obj) {p2Deck.push({card_id: v,name: ${obj.name}_${i}})}})// console.log(p1Deck, newDeck)commonStore.updateP1Deck(p1Deck)commonStore.updateP2Deck(p2Deck)nextTick(() {handRef.value.init()deckRef.value.init()resolve(true)})})
}// 初始化手牌
const initHand () {let p1 new Promise((resolve, reject) {let cardNumber 4let _number 0let p1Deck JSON.parse(JSON.stringify(commonStore.$state.p1Deck))let deckGroup scene.getObjectByName(p1_deckGroup)let position new THREE.Vector3(0, 0.005 * p1Deck.length, 0)let _interval setInterval(async() {// console.log(123, p1Deck)if (_number cardNumber) {let obj p1Deck[p1Deck.length - 1]p1Deck.splice(p1Deck.length-1, 1)commonStore.updateP1Deck(p1Deck)// 修改卡组await editDeckCard(deckGroup, obj, remove)await renderDeckText(deckGroup, ${commonStore.$state.p1Deck.length}, commonStore.$state._font, position)// 手牌区添加手牌handRef.value.addP1HandCard(obj, deckGroup)} else {clearInterval(_interval)resolve(true)}_number}, 200)})let p2 new Promise((resolve, reject) {let cardNumber 4let _number 0let p2Deck JSON.parse(JSON.stringify(commonStore.$state.p2Deck))let deckGroup scene.getObjectByName(p2_deckGroup)let position new THREE.Vector3(0, 0.005 * p2Deck.length, 0)let _interval setInterval(async() {// console.log(123, p1Deck)if (_number cardNumber) {let obj p2Deck[p2Deck.length - 1]p2Deck.splice(p2Deck.length-1, 1)commonStore.updateP2Deck(p2Deck)// 修改卡组await editDeckCard(deckGroup, obj, remove)await renderDeckText(deckGroup, ${commonStore.$state.p2Deck.length}, commonStore.$state._font, position)// 手牌区添加手牌handRef.value.addP2HandCard(obj, deckGroup)} else {clearInterval(_interval)resolve(true)}_number}, 200)})return new Promise((resolve, reject) {Promise.all([p1, p2]).then((res: any) {resolve(true)})})
}// p1抽牌事件
const p1DrawCardEvent () {setTimeout(() {if (commonStore.$state.p1Deck.length 0) {alert(你输了)window.location.reload()return}let p1_deckGroup scene.getObjectByName(p1_deckGroup)let pos1 p1_deckGroup.userData.positionlet pos2 new THREE.Vector3(0, 2, 0)if (p1_deckGroup.position.x ! pos2.x) {drawCardRef.value.drawCardAnimate1(p1_deckGroup, pos1, pos2)}}, 300)
}// p2抽牌事件
const p2DrawCardEvent (cardNumber: any) {return new Promise((resolve, reject) {let _number 0let p2Deck JSON.parse(JSON.stringify(commonStore.$state.p2Deck))if (p2Deck.length 0) {alert(你赢了)window.location.reload()return}let deckGroup scene.getObjectByName(p2_deckGroup)let position new THREE.Vector3(0, 0.005 * p2Deck.length, 0)let _interval setInterval(async() {// console.log(123, p1Deck)if (_number cardNumber) {let obj p2Deck[p2Deck.length - 1]p2Deck.splice(p2Deck.length-1, 1)commonStore.updateP2Deck(p2Deck)// 修改卡组await editDeckCard(deckGroup, obj, remove)await renderDeckText(deckGroup, ${commonStore.$state.p2Deck.length}, commonStore.$state._font, position)// 手牌区添加手牌handRef.value.addP2HandCard(obj, deckGroup)} else {clearInterval(_interval)// 更新flowIndexcommonStore.updateFlowIndex(1)// p2玩家手牌召唤上场逻辑轮询手牌中Mana最大且不超过此时p2Mana的卡牌直到能上场的都上场后进行下一阶段function p2FindHandToSiteCards() {let p2_handGroup scene.getObjectByName(p2_handGroup)let cards p2_handGroup.childrenlet mana commonStore.$state.p2Manalet card p2FindHandToSiteCard(cards, mana)if (card card.userData.type 怪兽) {p2HandToSite(card)nextTick(() {let p2SiteCards scene.children.filter((v: any) v.userData v.userData.areaType (v.userData.areaType.indexOf(对方怪兽区)-1))if (commonStore.$state.p2Mana 0 p2SiteCards.length 3) {setTimeout(function() {p2FindHandToSiteCards()}, 400)} else {// 执行p2战斗阶段console.log(执行p2战斗阶段)nextTick(() {p2SiteCards.forEach((v: any) {v.userData.AttackFrequency 1})p2FightEvent()})}})} else {// 执行p2战斗阶段console.log(执行p2战斗阶段)nextTick(() {let p2SiteCards scene.children.filter((v: any) v.userData v.userData.areaType (v.userData.areaType.indexOf(对方怪兽区)-1))p2SiteCards.forEach((v: any) {v.userData.AttackFrequency 1})p2FightEvent()})}}p2FindHandToSiteCards()resolve(true)}_number}, 200)})
}// p2卡牌上场事件
const p2HandToSite (card: any) {let sitePlane scene.getObjectByName(对方战域Plane)let userData card.userDataif (userData.type 怪兽) {let meshes sitePlane.children.filter((v: any) v.name.indexOf(对方怪兽区) -1 v.userData.empty true)if (meshes.length 0) {let _mesh nulllet m1 meshes.find((v: any) v.name.indexOf(1) -1)let m2 meshes.find((v: any) v.name.indexOf(2) -1)let m3 meshes.find((v: any) v.name.indexOf(3) -1)if (m2) {_mesh m2} else if (m1) {_mesh m1} else if (m3) {_mesh m3}let p2_handGroup scene.getObjectByName(p2_handGroup)// card.rotateX(180 * (Math.PI / 180)) // 弧度renderSiteCard(p2_handGroup, card, _mesh)}}
}// p2战斗事件
const p2FightEvent () {commonStore.updateFlowIndex(2)let p1SiteCards scene.children.filter((v: any) (v.userData v.userData.areaType v.userData?.areaType?.indexOf(己方怪兽区) -1))let p2SiteCards scene.children.filter((v: any) (v.userData v.userData.areaType v.userData?.areaType?.indexOf(对方怪兽区) -1))console.log(222, p1SiteCards,p2SiteCards )if (p2SiteCards.length 0) {if (p1SiteCards.length 0) {function p2CardAttack() {// 遍历p2可以攻击的cardlet p2CanAttackCards p2SiteCards.filter((v: any) v.userData.AttackFrequency 0)if (p2CanAttackCards.length 0) {p2CanAttackCards.sort((a: any, b: any) {return b.userData._ATK - a.userData._ATK})let p2ATK Number(p2CanAttackCards[0].userData._ATK)let p1AttackedCards p1SiteCards.filter((v: any) Number(v.userData._ATK) p2ATK) // 找出p1可以被p2攻击的卡牌即当前选中的p2卡牌的攻击力大于等于p1卡牌{if (p1AttackedCards.length 0) {p1AttackedCards.sort((a: any, b: any) {return a.userData._ATK - b.userData._ATK})// let _selectedCard scene.children.find((v: any) v.name p2CanAttackCards[0].name (v.userData.areaType v.userData.areaType.indexOf(对方怪兽区) -1))// let _selectedTargetCard scene.children.find((v: any) v.name p1AttackedCards[0].name (v.userData.areaType v.userData.areaType.indexOf(己方怪兽区) -1))selectedCard.value p2CanAttackCards[0]selectedTargetCard.value p1AttackedCards[0]// console.log(666, selectedCard.value, selectedTargetCard.value)nextTick(() {fight()setTimeout(function() {let p2CanAttackCards p2SiteCards.filter((v: any) v.userData.AttackFrequency 0)if (p2CanAttackCards.length 0) {p2FightEvent()}}, 1000)})} else {selectedCard.value nullselectedTargetCard.value null// 如果不能攻击则将这回合攻击次数归0p2CanAttackCards[0].userData.AttackFrequency 0nextRound()}} else {fight()}}p2CardAttack()} else {// 直接攻击let p2CanAttackCards p2SiteCards.filter((v: any) v.userData.AttackFrequency 0)if (p2CanAttackCards.length 0) {selectedCard.value p2CanAttackCards[0]fight()setTimeout(function() {let p2CanAttackCards p2SiteCards.filter((v: any) v.userData.AttackFrequency 0)if (p2CanAttackCards.length 0) {p2FightEvent()}}, 1000)}}}// 如果p2所有卡牌攻击次数都为0则回合结束let p2CanAttackCards p2SiteCards.filter((v: any) v.userData.AttackFrequency 0)if (p2CanAttackCards.length 0) {setTimeout(() {nextRound()}, 500)}
}// 鼠标按下事件
const onMousedown (ev: any) {// console.log(222, ev.target)// 判断是否点击到canvas上if(!(ev.target instanceof HTMLCanvasElement)){return;}// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to 1)let clientX ev.clientX || ev.changedTouches[0].pageXlet clientY ev.clientY || ev.changedTouches[0].pageYlet point transPos(clientX, clientY)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );// 点击卡组事件// onP1DeckEvent()// 鼠标选中场上卡牌事件onSelectSiteCard()
}// 鼠标移动事件
const onMousemove (ev: any) {// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to 1)pointer.x ev.clientX || ev.changedTouches[0].pageXpointer.y ev.clientY || ev.changedTouches[0].pageY// 画线if (selectedCard.value (commonStore.$state.flowIndex 2)) {drawLine()}
}// 鼠标抬起事件
const onMouseup (ev: any) {let lineMesh scene.getObjectByName(移动线)if (lineMesh) {scene.remove(lineMesh)}fight()
}// 鼠标选中场上卡牌事件
const onSelectSiteCard () {if (commonStore.$state.flowIndex ! 2) { // 非战斗阶段不进行该操作return}if (commonStore.$state.round 1) { // 第一回合不能进行攻击return}let p1Cards scene.children.filter((v: any) v.userData?.areaType?.indexOf(己方怪兽区) -1)if (p1Cards.length 0) {return}let arr raycaster.intersectObjects(p1Cards, true)if (arr.length 0) {// 找到对应卡牌let _selectedCard: any arr[0].objectif (_selectedCard.name 攻击力) {_selectedCard _selectedCard.parent}if (_selectedCard.userData.AttackFrequency 0) { // 如果该卡攻击次数小于等于0那么跳过return}selectedCard.value _selectedCard}}// 画线
const drawLine () {let mesh scene.getObjectByName(移动线)if (mesh) {scene.remove(mesh)}let startPos new THREE.Vector3(0, 0, 0)selectedCard.value.getWorldPosition(startPos)let point transPos(pointer.x, pointer.y)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );let plane scene.getObjectByName(地面)let arr raycaster.intersectObject(plane)if (arr.length 0) {// let pos new THREE.Vector3(0, 0, 0)// arr[0].object.getWorldPosition(pos)let point arr[0].pointlet curve new THREE.CatmullRomCurve3([new THREE.Vector3(startPos.x, startPos.y 0.2, startPos.z),new THREE.Vector3(point.x, point.y 0.2, point.z)]);let tubeGeometry new THREE.TubeGeometry(curve, 80, 0.08);const material new THREE.MeshBasicMaterial({map: arrowTexture,side: THREE.BackSide, //显示背面transparent: true,// color: new THREE.Color(#ff6347)});const _mesh new THREE.Mesh( tubeGeometry, material );_mesh.name 移动线scene.add(_mesh);}// 获取目标对象getTargetMesh()
}// 获取目标对象
const getTargetMesh () {let p2Cards scene.children.filter((v: any) v.userData?.areaType?.indexOf(对方怪兽区) -1)if (p2Cards.length 0) {selectedTargetCard.value nullreturn}let arr raycaster.intersectObjects(p2Cards, true)if (arr.length 0) {let _selectedTargetCard: any arr[0].objectif (_selectedTargetCard.name 攻击力) {_selectedTargetCard _selectedTargetCard.parent}selectedTargetCard.value _selectedTargetCard} else {selectedTargetCard.value null}
}// 战斗
const fight () {if (commonStore.$state.flowIndex ! 2) {return}if (selectedCard.value) { // 攻击次数减1let AttackFrequency JSON.parse(JSON.stringify(selectedCard.value.userData.AttackFrequency))if (AttackFrequency 0) {AttackFrequency--} else {AttackFrequency 0}selectedCard.value.userData.AttackFrequency AttackFrequency}// console.log(fight, selectedCard.value, selectedTargetCard.value)if (selectedCard.value selectedTargetCard.value) { // 如果selectedCard和selectedTargetCard都存在// 移除卡牌const removeCard async (card: any) {if (card.children card.children.length 0) {card.children.forEach((v: any) {card.remove(v)})}let areaType card.userData.areaTypelet isP1 areaType.indexOf(己方) -1let graveyardGroup nulllet graveyardGroupPos new THREE.Vector3(0, 0, 0)let cards []card.material.forEach((v: any) {v.transparent falsev.opacity 1v.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}}}let _selectedCard selectedCard.valuelet _selectedTargetCard selectedTargetCard.valuecardAttack(selectedCard.value, selectedTargetCard.value, () {// console.log(888, Number(selectedCard.value.userData.ATK), Number(selectedTargetCard.value.userData.ATK))if (Number(_selectedCard.userData.ATK) Number(_selectedTargetCard.userData.ATK)) {cardDestroy(_selectedTargetCard, () {removeCard(_selectedTargetCard)// 削减血量let isP1 _selectedTargetCard.userData.areaType.indexOf(己方) -1if (isP1) {let p1HP JSON.parse(JSON.stringify(commonStore.$state.p1HP))p1HP - (Number(_selectedCard.userData.ATK) - Number(_selectedTargetCard.userData.ATK))if (p1HP 0) {p1HP 0}commonStore.updateP1HP(p1HP)} else {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 isP1 _selectedCard.userData.areaType.indexOf(己方) -1if (isP1) {let p1HP JSON.parse(JSON.stringify(commonStore.$state.p1HP))p1HP - (Number(_selectedCard.userData.ATK) - Number(_selectedCard.userData.ATK))if (p1HP 0) {p1HP 0}commonStore.updateP1HP(p1HP)} else {let p2HP JSON.parse(JSON.stringify(commonStore.$state.p2HP))p2HP - (Number(_selectedCard.userData.ATK) - Number(_selectedCard.userData.ATK))if (p2HP 0) {p2HP 0}commonStore.updateP2HP(p2HP)}})}})selectedCard.value nullselectedTargetCard.value null} else if (selectedCard.value) { // 如果只存在selectedCard// 直接攻击let _selectedCard: any selectedCard.valuelet areaType _selectedCard.userData.areaTypelet isP1 areaType.indexOf(己方) -1let cards []if (isP1) {let plane scene.getObjectByName(对方战域Plane)let arr raycaster.intersectObjects(plane.children)if (arr.length 0) {return}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.ATKif (p2HP 0) {p2HP 0}commonStore.updateP2HP(p2HP)} else {let p1HP JSON.parse(JSON.stringify(commonStore.$state.p1HP))p1HP - _selectedCard.userData.ATKif (p1HP 0) {p1HP 0}commonStore.updateP1HP(p1HP)}})}selectedCard.value null
}// 手牌事件
const onHandEvent () {let handGroup scene.getObjectByName(p1_handGroup)const dragControls new DragControls( handGroup.children, camera, renderer.domElement );dragControls.addEventListener( dragstart, function ( event: any ) {if (commonStore.$state.currentPlayer p1 commonStore.$state.flowIndex 1) {dragControls.enabled trueevent.object.position.y 0.04} else {dragControls.enabled false}});dragControls.addEventListener( drag, function ( event: any ) {if (commonStore.$state.currentPlayer p1 commonStore.$state.flowIndex 1) {dragControls.enabled trueevent.object.position.y 0.04} else {dragControls.enabled false}});dragControls.addEventListener( dragend, function ( event: any ) {if (commonStore.$state.currentPlayer p1 commonStore.$state.flowIndex 1) {dragControls.enabled trueevent.object.position.y - 0.04// 如果mana不够则不能上场if (commonStore.$state.p1Mana event.object?.userData.Mana) {handRef.value.backPosition(event.object)return}let p1SitePlane scene.getObjectByName(己方战域Plane)let point transPos(pointer.x, pointer.y)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );const intersects raycaster.intersectObjects(p1SitePlane.children);if (intersects.length 0) {dialogRef.value.init({type: handToSite,obj: event.object,message: 是否上场该卡牌})} else {handRef.value.backPosition(event.object)}} else {dragControls.enabled false}});
}// 手牌移入己方战域
const handToSite (data: any) {let sitePlane scene.getObjectByName(己方战域Plane)// console.log(data)let userData data.userDataif (userData.type 怪兽) {let meshes sitePlane.children.filter((v: any) v.name.indexOf(己方怪兽区) -1 v.userData.empty true)if (meshes.length 0) {let _mesh nulllet m1 meshes.find((v: any) v.name.indexOf(1) -1)let m2 meshes.find((v: any) v.name.indexOf(2) -1)let m3 meshes.find((v: any) v.name.indexOf(3) -1)if (m2) {_mesh m2} else if (m1) {_mesh m1} else if (m3) {_mesh m3}let p1_handGroup scene.getObjectByName(p1_handGroup)renderSiteCard(p1_handGroup, data, _mesh)}}
}// 绘制场上卡牌
const renderSiteCard async (handGroup: any, data: any, mesh: any) {let position new THREE.Vector3(0, 0, 0)mesh.getWorldPosition(position)mesh.userData.empty falselet oldMesh handGroup.children.find((v: any) v.name data.name)let newMesh oldMesh.clone()newMesh.userData.areaType mesh.name // 用来记录卡牌在哪个区域怪兽区、墓地、手牌、卡组、场地等newMesh.scale.set(0.8, 0.8, 0.8)if (handGroup.name p1_handGroup) {// 更新manalet mana JSON.parse(JSON.stringify(commonStore.$state.p1Mana))mana - newMesh.userData.ManacommonStore.updateP1Mana(mana)// handRef.value.removeP1HandCard(oldMesh)} else if (handGroup.name p2_handGroup) {// 更新manalet mana JSON.parse(JSON.stringify(commonStore.$state.p2Mana))mana - newMesh.userData.ManacommonStore.updateP2Mana(mana)// handRef.value.removeP2HandCard(oldMesh)newMesh.rotateX(180 * (Math.PI / 180)) // 弧度newMesh.rotateY(180 * (Math.PI / 180)) // 弧度}scene.add(newMesh)newMesh.position.set(position.x, position.y, position.z)await renderSiteCardText(handGroup, newMesh, commonStore.$state._font)// 创建伽马校正通道// const gammaPass new ShaderPass(GammaCorrectionShader)// composer.addPass( gammaPass );// const outlinePass new OutlinePass(new THREE.Vector2( window.innerWidth, window.innerHeight ), scene, camera); // 模糊// outlinePass.edgeStrength 1.0; // 调整边缘强度// outlinePass.edgeGlow 1.0; // 边缘发光强度// outlinePass.usePatternTexture false; // 是否使用纹理// outlinePass.visibleEdgeColor.set(0xffffff); // 设置边缘颜色// outlinePass.hiddenEdgeColor.set(0x000000); // 设置隐藏边缘的颜色// outlinePass.selectedObjects [newMesh.children[0]]// composer.addPass( outlinePass );// console.log(123, newMesh)
}// 下一阶段
const nextFlow () {let flowIndex JSON.parse(JSON.stringify(commonStore.$state.flowIndex))flowIndexcommonStore.updateFlowIndex(flowIndex)
}// 回合结束
const nextRound () {// 切换玩家let player commonStore.$state.currentPlayerif (player p1) {commonStore.updateCurrentPlayer(p2)} else {commonStore.updateCurrentPlayer(p1)}console.log(333, commonStore.$state.currentPlayer)// 重置流程commonStore.updateFlowIndex(0)// 重置manacommonStore.updateP1Mana(6)commonStore.updateP2Mana(10)// 回合数增加let round JSON.parse(JSON.stringify(commonStore.$state.round))roundcommonStore.updateRound(round)// 重置怪兽攻击次数let p1SiteCards scene.children.filter((v: any) v.userData v.userData.areaType (v.userData.areaType.indexOf(己方怪兽区)-1))// let p2SiteCards scene.children.filter((v: any) v.userData v.userData.areaType (v.userData.areaType.indexOf(对方怪兽区)-1))if (p1SiteCards.length 0) {p1SiteCards.forEach((v: any) {v.userData.AttackFrequency 1})}// if (p2SiteCards.length 0) {// p2SiteCards.forEach((v: any) {// v.userData.AttackFrequency 1// })// }// 重新执行游戏流if (commonStore.$state.currentPlayer p1) {p1DrawCardEvent()} else {p2DrawCardEvent(1)}
}// 取消
const onCancel (data: any) {handRef.value.backPosition(data)
}
/scriptstyle langscss scoped
.scene {position: fixed;top: 0;left: 0;width: 100%;height: 100vh;
}
.stage-box {position: fixed;top: 50%;right: 4px;z-index: 10;margin-top: -20px;display: flex;align-items: center;justify-content: center;flex-wrap: wrap;list-style: none;// max-width: 200px;// width: 40%;height: 40px;li {// margin: 6px;}
}
.info-box {position: fixed;top: 50%;left: 4px;z-index: 10;// display: flex;// flex-wrap: wrap;align-items: center;margin-top: -20px;height: 40px;color: #fff; div {line-height: 20px;}
}
/style
页面效果如下 这里输了是因为卡组没牌了。。。
其实到这里基本已经实现了和电脑简单对战的游玩基本的游戏架构初步完成剩下的就是往这个框里添加各种卡牌逻辑比如基础的加攻减攻恢复血量等等以及优化一些战斗效果和交互逻辑、UI美化等。