vue3+threejs新手从零开发卡牌游戏(二十):添加卡牌被破坏进入墓地逻辑

本文主要是介绍vue3+threejs新手从零开发卡牌游戏(二十):添加卡牌被破坏进入墓地逻辑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在game目录下新建graveyard文件夹存放墓地相关代码:

game/graveyard/p1.vue,这里主要设置了墓地group的位置:

<template><div></div>
</template><script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, defineComponent, getCurrentInstance, nextTick } from 'vue'
import { useCommonStore } from "@/stores/common.ts"
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { Card } from "@/views/game/Card.ts"
import { CARD_DICT } from "@/utils/dict/card.ts"
import { transPos, renderDeckText } from "@/utils/common.ts"// 引入threejs变量
const {proxy} = getCurrentInstance()
const THREE = proxy['THREE']
const scene = proxy['scene']
const camera = proxy['camera']
const renderer = proxy['renderer']
const TWEEN = proxy['TWEEN']const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();const commonStore = useCommonStore()// 墓地group
const deckGroup = new THREE.Group()
deckGroup.name = "p1_graveyardGroup"
scene.add(deckGroup)const init = () => {setDeckPos()
}// 设置墓地位置
const setDeckPos = () => {nextTick(() => {let sitePlane = scene.getObjectByName("己方战域Plane")let siteDeckMesh = sitePlane.getObjectByName("己方墓地")let pos = new THREE.Vector3(0, 0, 0)siteDeckMesh.getWorldPosition(pos)deckGroup.position.set(pos.x, pos.y, pos.z)deckGroup.userData["position"] = posdeckGroup.scale.set(0.8, 0.8, 0.8) // 缩放})
}defineExpose({init,
})
</script><style lang="scss" scoped>
</style>

然后在utils/common.ts文件中添加修改墓地和渲染墓地文字的方法(参考卡组相关方法):


// 修改墓地
const editGraveyardCard = (group:any, mesh: any, type: any) => {return new Promise((resolve, reject) => {let text = group.children.find((v: any) => v.name === "墓地数量")let shadowText = group.children.find((v: any) => v.name === "墓地数量阴影")// console.log(22, group.children, commonStore.$state.p1Deck)if (type === "remove") { // 删除墓地中的卡牌let child = group.children.find((v: any) => v.name === mesh.name)if (child) {group.remove(child)}}group.remove(text)group.remove(shadowText)group.children.forEach((v: any, i: any) => {v.position.set(0, 0.005 * i, 0)})resolve(true)})
}
export { editGraveyardCard }// 渲染墓地文字
const renderGraveyardText = (group: any, text: any, font: any, position: any) => {return new Promise((resolve, reject) => {const geometry = new TextGeometry( `${text}`, {font,size: 0.4,height: 0,curveSegments: 4,bevelEnabled: true,bevelThickness: 0,bevelSize: 0,bevelSegments: 0});geometry.center()const material = new THREE.MeshBasicMaterial({ color: new THREE.Color("white"),alphaHash: true})const mesh = new THREE.Mesh( geometry, material ) ;mesh.position.set(position.x, position.y + 0.01, position.z)// mesh.position.set(0, 0.005 * commonStore.$state.p1Deck.length + 0.01, 0)mesh.rotateX(-90 * (Math.PI / 180)) // 弧度mesh.name = "墓地数量"// 阴影let shadowGeometry = geometry.clone()shadowGeometry.translate(0.02, 0.02, 0);let shadowMaterial = new THREE.MeshBasicMaterial({color: new THREE.Color("black"),alphaHash: true});let shadowMesh = new THREE.Mesh(shadowGeometry, shadowMaterial);shadowMesh.position.set(position.x, position.y, position.z)// shadowMesh.position.set(0, 0.005 * commonStore.$state.p1Deck.length, 0)shadowMesh.rotateX(-90 * (Math.PI / 180)) // 弧度shadowMesh.name = "墓地数量阴影"group.add(mesh)group.add(shadowMesh)resolve(true)})
}
export { renderGraveyardText }

然后我们修改game/index.vue中的fight战斗方法,卡牌被破坏后不直接将其从scene中移除,而且改为进入墓地:

// 战斗
const fight = () => {if (selectedCard.value && selectedTargetCard.value) {let _selectedCard: any = selectedCard.valuelet _selectedTargetCard: any = selectedTargetCard.valueif (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)})}console.log(321, card)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}}}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 = nullselectedTargetCard.value = null}
}

页面效果如下:

附:
game/index.vue完整代码:

<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"/>
</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 } 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"
import { resolve } from 'dns';// 引入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();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 () => {// 初始化玩家initPlayer()// 初始化场地initSite()// 初始化墓地initGraveyard()// 初始化卡组await initDeck()// 初始化手牌await initHand()// 绑定手牌事件onHandEvent()// 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 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)})})
}// p2抽牌事件
const p2DrawCardEvent = (cardNumber: any) => {return new Promise((resolve, reject) => {let _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)})
}// 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)}}
}// 鼠标按下事件
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) {drawLine()}
}// 鼠标抬起事件
const onMouseup = (ev: any) => {let lineMesh = scene.getObjectByName("移动线")if (lineMesh) {scene.remove(lineMesh)}fight()
}// 鼠标选中场上卡牌事件
const onSelectSiteCard = () => {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) {selectedCard.value = arr[0].object// drawLine()}}// 画线
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) {selectedTargetCard.value = arr[0].object} else {selectedTargetCard.value = null}
}// 战斗
const fight = () => {if (selectedCard.value && selectedTargetCard.value) {let _selectedCard: any = selectedCard.valuelet _selectedTargetCard: any = selectedTargetCard.valueif (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)})}console.log(321, card)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}}}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 = nullselectedTargetCard.value = null}
}// 点击卡组事件
const onP1DeckEvent = () => {if (commonStore.$state.p1Deck.length <= 0) {return}let p1_deckGroup = scene.getObjectByName("p1_deckGroup")let arr = raycaster.intersectObject(p1_deckGroup, true)if (arr.length <= 0) {return}let pos1 = p1_deckGroup.userData.positionlet pos2 = new THREE.Vector3(0, 2, 0)// console.log(444, pos1, pos2)if (p1_deckGroup.position.x !== pos2.x) {drawCardRef.value.drawCardAnimate1(p1_deckGroup, pos1, pos2)}
}// 手牌事件
const onHandEvent = () => {let handGroup = scene.getObjectByName("p1_handGroup")const dragControls = new DragControls( handGroup.children, camera, renderer.domElement );dragControls.addEventListener( 'dragstart', function ( event: any ) {event.object.position.y += 0.04});dragControls.addEventListener( 'drag', function ( event: any ) {event.object.position.y += 0.04});dragControls.addEventListener( 'dragend', function ( event: any ) {event.object.position.y -= 0.04let 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)}});
}// 手牌移入己方战域
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") {handRef.value.removeP1HandCard(oldMesh)} else if (handGroup.name === "p2_handGroup") {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 onCancel = (data: any) => {handRef.value.backPosition(data)
}
</script><style lang="scss" scoped>
.scene {position: fixed;top: 0;left: 0;width: 100%;height: 100vh;
}
</style>

这篇关于vue3+threejs新手从零开发卡牌游戏(二十):添加卡牌被破坏进入墓地逻辑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/860692

相关文章

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

基于Java开发一个极简版敏感词检测工具

《基于Java开发一个极简版敏感词检测工具》这篇文章主要为大家详细介绍了如何基于Java开发一个极简版敏感词检测工具,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录你是否还在为敏感词检测头疼一、极简版Java敏感词检测工具的3大核心优势1.1 优势1:DFA算法驱动,效率提升10

使用Python实现一个简易计算器的新手指南

《使用Python实现一个简易计算器的新手指南》计算器是编程入门的经典项目,它涵盖了变量、输入输出、条件判断等核心编程概念,通过这个小项目,可以快速掌握Python的基础语法,并为后续更复杂的项目打下... 目录准备工作基础概念解析分步实现计算器第一步:获取用户输入第二步:实现基本运算第三步:显示计算结果进