vue3+threejs新手从零开发卡牌游戏(十六):初始化对方手牌

添加对方手牌区时注意位置调整,以及手牌应该是背面朝上,加个rotateX翻转即可,其他代码和p1.vue代码一致,game/hand/p2.vue代码如下:

<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 { Card } from "@/views/game/Card.ts"
import { CARD_DICT } from "@/utils/dict/card.ts"
import { transPos } 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 handGroup = new THREE.Group()
handGroup.name = "p1_handGroup"
scene.add(handGroup)const _width = ref()const init = () => {setHandPos()
}// 设置手牌区位置
const setHandPos = () => {nextTick(() => {let plane = scene.getObjectByName("地面")let point1 = transPos(window.innerWidth * 0.35, 10) // 手牌区起始位置的屏幕坐标let point2 = transPos(window.innerWidth - 10, 10) // 手牌区结束位置的屏幕坐标let x1 = 0 // 手牌区起始位置的世界x坐标let x2 = 0 // 手牌区结束位置的世界x坐标// raycaster.setFromCamera( point1, camera );const intersects1 = raycaster.intersectObject( plane );if (intersects1.length > 0) {let point = intersects1[0].point// 由于卡牌几何体大小设置的是(1, 0.005, 1.4),所以我们对应进行偏移// handGroup.position.set(point.x, point.y, point.z)handGroup.position.set(point.x + 0.5, point.y, point.z + 0.7)x1 = handGroup.position.x}// raycaster.setFromCamera( point2, camera );const intersects = raycaster.intersectObject( plane );if (intersects.length > 0) {let point = intersects[0].pointx2 = point.x + 0.5}// 用绝对值相加得到手牌区长度_width.value = Math.abs(x1) + Math.abs(x2)})
}// 添加手牌
const addHandCard = (obj: any, origin: any) => {let position = origin.position// console.log(666, deckGroupPos)let cardObj = CARD_DICT.find((v: any) => v.card_id === obj.card_id)if (cardObj) {let card = new Card(cardObj)let mesh = card.init()mesh.name = obj.namemesh.position.set(position.x, position.y, position.z)mesh.rotateX(180 * (Math.PI / 180)) // 弧度mesh.material.forEach((v: any) => {// v.alphaHash = truev.transparent = true})scene.add( mesh );updateCardPos(mesh)}
}// 移除手牌
const removeHandCard = (mesh: any) => {handGroup.remove(mesh)// 计算叠放间距let space = ((_width.value - 1) / (handGroup.children.length - 1)) <= 1 ? (_width.value - 1) / (handGroup.children.length - 1) : 1handGroup.children.forEach((v: any, i: any) => {v.position.set(i * space, 0.005 * i, 0)v.userData = {...v.userData,oriPos: new THREE.Vector3(i * space, 0.005 * i, 0)}})
}// 回到手牌原位置
const backPosition = (mesh: any) => {let oriPos = mesh.userData.oriPosconst tw = new TWEEN.Tween({x: mesh.position.x,y: mesh.position.y,z: mesh.position.z,mesh})tw.to({x: oriPos.x,y: oriPos.y,z: oriPos.z,}, 200)tw.easing(TWEEN.Easing.Quadratic.Out)tw.onUpdate((obj: any) => {obj.mesh.position.set(obj.x, obj.y, obj.z)})tw.onComplete(function() {TWEEN.remove(tw)})tw.start();
}// 更新卡牌位置
const updateCardPos = (mesh: any) => {const tw = new TWEEN.Tween({x: mesh.position.x,y: mesh.position.y,z: mesh.position.z,opacity: 0.9,mesh})tw.to({x: handGroup.position.x,y: handGroup.position.y,z: handGroup.position.z,opacity: 0}, 200)tw.easing(TWEEN.Easing.Quadratic.Out)tw.onUpdate((obj: any) => {obj.mesh.position.set(obj.x, obj.y, obj.z)obj.mesh.material.forEach((v: any) => {v.opacity = obj.opacity})})tw.onComplete(function() {//动画结束:关闭允许透明,恢复到模型原来状态TWEEN.remove(tw)scene.remove( mesh );mesh.material.forEach((v: any) => {v.transparent = falsev.opacity = 1})handGroup.add(mesh)// 计算叠放间距let space = ((_width.value - 1) / (handGroup.children.length - 1)) <= 1 ? (_width.value - 1) / (handGroup.children.length - 1) : 1handGroup.children.forEach((v: any, i: any) => {v.position.set(i * space, 0.005 * i, 0)v.userData = {...v.userData,oriPos: new THREE.Vector3(i * space, 0.005 * i, 0)}})})tw.start();
}defineExpose({init,addHandCard,removeHandCard,backPosition
})
</script><style lang="scss" scoped>
</style>

修改game/hand/index.vue,添加p2添加手牌方法:

<!-- 手牌区 -->
<template><P1 ref="p1Ref"/><P2 ref="p2Ref"/>
</template><script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, defineComponent, getCurrentInstance, nextTick } from 'vue'
import P1 from "./p1.vue"
import P2 from "./p2.vue"const p1Ref = ref()
const p2Ref = ref()onMounted(() => {// init()
})const init = () => {p1Ref.value.init()p2Ref.value.init()
}const addP1HandCard = (obj: any, origin: any) => {p1Ref.value.addHandCard(obj, origin)
}const addP2HandCard = (obj: any, origin: any) => {p2Ref.value.addHandCard(obj, origin)
}const removeHandCard = (mesh: any) => {p1Ref.value.removeHandCard(mesh)
}const backPosition = (mesh: any) => {p1Ref.value.backPosition(mesh)
}defineExpose({init,addP1HandCard,addP2HandCard,backPosition,removeHandCard
})
</script><style lang="scss" scoped>
</style>

然后修改下game/index.vue的初始化手牌方法:

// 初始化手牌
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)})})
}

页面效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/774343.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STL的基本概念

一、STL的诞生 长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西 C的面向对象和泛型编程思想&#xff0c;目的就是复用性的提升 面向对象的三大特性(简单理解) 封装&#xff1a;把属性和行为抽象出来作为一个整体来实现事和物 继承&#xff1a;子类继承父类&a…

目前可用的免费云服务器整理汇总

随着云计算技术的飞速发展&#xff0c;越来越多的企业和个人开始关注并使用云服务器。为了吸引用户上云&#xff0c;各大云服务商纷纷推出了免费云服务器&#xff0c;供用户免费试用。本文将为大家整理汇总目前市场上可用的免费云服务器&#xff0c;以便大家更好地选择适合自己…

GIS与Python机器学习:开创地质灾害风险评价新纪元

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

Unity编辑器功能 将选中的文件夹复制一份到其他文件夹

[MenuItem("Ab包工具/将选中的文件移动到StreamingAssets文件夹下")] public static void MoveFireToStreamA() { //得到选中文件的数组 Object[] selectobj Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets); i…

Django之Web应用架构模式

一、Web应用架构模式 在开发Web应用中,有两种模式 1.1、前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示。前端与后端的耦合度很高 1.2、前后端分离 在前后端分离的应用模式中,后端仅返…

【物联网开源平台】tingsboard安装与编译

别看这篇了&#xff0c;这篇就当我的一个记录&#xff0c;我有空我再写过一篇&#xff0c;编译的时候出现了一个错误&#xff0c;然后我针对那一个错误执行了一个命令&#xff0c;出现了绿色的succes,我就以为整个tingsboard项目编译成功了&#xff0c;后面发现的时候&#xff…

Redis 教程系列之Redis 发布订阅(十五)

Redis 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式&#xff1a;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。 Redis 客户端可以订阅任意数量的频道。 下图展示了频道 channel1 &#xff0c; 以及订阅这个频道的三个客户端 —— client2 、 client5 和 cl…

【业界动态】数字孪生到底意味着什么

什么是数字孪生&#xff1f;它可以理解为一种技术&#xff0c;也可以理解为某种生态。数字孪生即指将物理实体映射至虚拟空间&#xff0c;进而协助完成预测、决策等动作。随着互联网的建设与发展&#xff0c;数字孪生在未来又会如何落地&#xff1f; 一、数字孪生到底是什么&am…

抗干扰段码屏驱动芯片/ LCD液晶屏驱动/仪器仪表液晶驱动IC-VK1C21D/DA FAE支持

产品型号&#xff1a;VK1C21D/DA 产品品牌&#xff1a;永嘉微电/VINKA 封装形式&#xff1a;SOP28/SSOP28 可定制裸片&#xff1a;DICE(COB邦定片)&#xff1b;COG(邦定玻璃用) 工程服务&#xff0c;技术支持&#xff01; 概述&#xff1a; VK1C21D/DA是一个点阵式存储映射…

【C/C++】C++中的四种强制类型转换

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

保姆级指导0基础如何快速搭建“对话机器人”类ChatGPT

参考了CDSN上的文章&#xff0c;但发现不work&#xff0c; 不是这里有问题&#xff0c;就是那里有问题&#xff0c;查阅了大量的资料&#xff0c;做了无数次试验&#xff0c;终于整理出来了一个完整的教程&#xff0c;保可用&#xff0c;保真~~~~~如果各位遇到什么问题&#xf…

Python中lambda函数使用方法

在Python中&#xff0c;lambda 关键字用于创建匿名函数&#xff08;无名函数&#xff09;&#xff0c;这些函数的特点是简洁、一次性使用&#xff0c;并且通常用于只需要一行表达式的简单场景。下面是lambda函数的基本结构和使用方法&#xff1a; 基本语法&#xff1a; lambd…

Python更改Word文档的页面大小

页面大小确定文档中每个页面的尺寸和布局。在某些情况下&#xff0c;您可能需要自定义页面大小以满足特定要求。在这种情况下&#xff0c;Python可以帮助您。通过利用Python&#xff0c;您可以自动化更改Word文档中页面大小的过程&#xff0c;节省时间和精力。本文将介绍如何使…

【PLC】PROFIBUS(二):总线协议DP、PA、FMS

1、总线访问协议 (FDL) 1.1、多主通信 多个主设备间&#xff0c;使用逻辑令牌环依次向从设备发送命令。 特征&#xff1a; 主站间使用逻辑令牌环、主从站间使用主从协议主站在一个限定时间内 (Token Hold Time) 对总线有控制权从站只是响应一个主站的请求它们对总线没有控制…

Java八股文(SpringCloud Alibaba)

Java八股文のSpringCloud Alibaba SpringCloud Alibaba SpringCloud Alibaba Spring Cloud Alibaba与Spring Cloud有什么区别&#xff1f; Spring Cloud Alibaba是Spring Cloud的衍生版本&#xff0c;它是由Alibaba开发和维护的&#xff0c;相比于Spring Cloud&#xff0c;它在…

OpenCV4.9在iOS中安装

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;使用CUDA 为Tegra构建OpenCV-CSDN博客 下一篇&#xff1a; 警告&#xff01; 本教程可以包含过时的信息。 所需软件包 CMake 2.8.8 或更高版本Xcode 4.2 或更高版本 从 G…

flask_Restful数据解析参数设置

add_argument 方法参数详解 add_argument方法可以指定这个字段的名字&#xff0c;这个字段的数据类 型等&#xff0c;验证错误提示信息等&#xff0c;具体如下&#xff1a; default&#xff1a;默认值&#xff0c;如果这个参数没有值&#xff0c;那么将使用这个参数 指定的默认…

短信系统开发注意事项|网页版短信后台

在开发短信系统时&#xff0c;有一些重要的注意事项需要考虑&#xff0c;以确保系统的稳定性、安全性和功能完整性。以下是一些开发短信系统时需要注意的事项&#xff1a; 合规性和法律要求&#xff1a;确保短信系统的开发符合当地法律法规和通信行业规定&#xff0c;包括用户隐…

【LVGL-文件系统移植】

LVGL-文件系统移植 ■ LVGL-文件系统移植■ 示例一&#xff1a;■ 示例二&#xff1a;视频实例■ 综合示例&#xff1a; ■ LVGL-文件系统移植 ■ 示例一&#xff1a; 在这里插入代码片■ 示例二&#xff1a;视频实例 在这里插入代码片■ 综合示例&#xff1a; /***********…

Rust基本类型

数值类型 整数类型 无符号整数只能取正数和0&#xff0c;有符号整数可以取正数负数和0。isize和usize类型取决于程序运行的计算机CPU类型&#xff0c;若CPU是32位的&#xff0c;则这两个类型是32位的&#xff0c;若CPU是64位的&#xff0c;则它们是64位的。rust整型 默认使用…