vue3+threejs新手从零开发卡牌游戏(十五):创建对方场地和对方卡组

首先创建对方场地,game/site/p2.vue和p1.vue代码一样,注意把里面的命名“己方”修改成“对方”,game/site/index.vue代码如下,用rotateZ翻转一下即可得到镜像的对方场地:


// 添加战域plane
const addSitePlane = () => {
  return new Promise((resolve, reject) => {
    // 设置战域大小和位置
    let plane = scene.getObjectByName("地面")
    let point = transPos(0, 0) // 战域起始位置的屏幕坐标
    // 
    raycaster.setFromCamera( point, camera );
    const intersects = raycaster.intersectObject( plane );
    if (intersects.length > 0) {
      let point = intersects[0].point
      // 进行裁剪
      // let x = Math.abs(point.x) * 2 - 2.4
      // let y = Math.abs(point.z) * 2 - 4
      let x = Math.abs(point.x) * 2
      let y = Math.abs(point.z) - 2

      // 添加p1战域
      const p1SitePlane = new THREE.Group()
      p1SitePlane.name = "己方战域Plane"
      p1SitePlane.position.set(0, 0, 0.3)
      p1SitePlane.rotateX(-90 * (Math.PI / 180)) // 弧度
      p1SitePlane.userData["width"] = x
      p1SitePlane.userData["height"] = y
      scene.add(p1SitePlane)

      // 添加p2战域
      const p2SitePlane = new THREE.Group()
      p2SitePlane.name = "对方战域Plane"
      p2SitePlane.position.set(0, 0, -0.3)
      p2SitePlane.rotateX(-90 * (Math.PI / 180)) // 弧度
      p2SitePlane.rotateZ(-180 * (Math.PI / 180)) // 弧度
      p2SitePlane.userData["width"] = x
      p2SitePlane.userData["height"] = y
      scene.add(p2SitePlane)
      resolve(true)
    }
  })
}

页面效果如下:

然后添加对方卡组,game/deck/p2.vue代码和p1.vue代码一样,注意把里面的命名“己方”修改成“对方”,game/deck/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 { 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 = "p2_deckGroup"
scene.add(deckGroup)

const init = () => {
  setDeckPos()
  addDeckWireframe()
  commonStore.$state.p2Deck.forEach((v: any, i: any) => {
    let obj = CARD_DICT.find((b: any) => b.card_id === v.card_id)
    if (obj) {
      let card = new Card(obj)
      let mesh = card.init()
      mesh.position.set(0, 0.005 * i, 0)
      mesh.rotateX(180 * (Math.PI / 180)) // 弧度
      mesh.name = v.name
      mesh.userData._ATK = mesh.userData.ATK // _ATK用于实时计算当前攻击力
      deckGroup.add( mesh );
    }
  })

  let position = new THREE.Vector3(0, 0.005 * commonStore.$state.p2Deck.length, 0)
  renderDeckText(deckGroup, `${commonStore.$state.p2Deck.length}`, commonStore.$state._font, position)

}

// 设置卡组位置
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"] = pos
    deckGroup.scale.set(0.8, 0.8, 0.8) // 缩放
    // let plane = scene.getObjectByName("地面")
    // let point = transPos(window.innerWidth - 15, window.innerHeight - 15) // 卡组起始位置的屏幕坐标
    // // 
    // raycaster.setFromCamera( point, camera );
    // const intersects1 = raycaster.intersectObject( plane );
    // if (intersects1.length > 0) {
    //   let point = intersects1[0].point
    //   // deckGroup.position.set(point.x, point.y, point.z)
    //   deckGroup.position.set(point.x - 0.5, point.y, point.z - 0.7)
    //   // 记录卡组位置
    //   let position = new THREE.Vector3(point.x - 0.5, point.y, point.z - 0.7)
    //   deckGroup.userData["position"] = position
    // }
  })
}

// 绘制卡组区域线框
const addDeckWireframe = () => {
  nextTick(() => {
    const edges = new THREE.EdgesGeometry( deckGroup.children[0].geometry );
    const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
    deckGroup.add(line);
  })
}

defineExpose({
  init,
})
</script>

<style lang="scss" scoped>
</style>

这里封装下测试卡组,分成p1和p2两个测试卡组:

// p1测试卡组
const p1TestDeck = [
  "YZ-01",
  "YZ-02",
  "YZ-03",
  "YZ-04",
  "YZ-01",
  "YZ-02",
  // "YZ-03",
  // "YZ-04",
  // "YZ-01",
  // "YZ-02",
  // "YZ-03",
  // "YZ-04",
]

export { p1TestDeck }

// p2测试卡组
const p2TestDeck = [
  // "YZ-01",
  // "YZ-02",
  // "YZ-03",
  // "YZ-04",
  // "YZ-01",
  // "YZ-02",
  "YZ-03",
  "YZ-04",
  "YZ-01",
  "YZ-02",
  "YZ-03",
  "YZ-04",
]
export { p2TestDeck }

然后在game/index.vue代码调用,修改初始化卡组方法:


// 初始化卡组
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)
    })
  })
}

页面效果如下:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode 76 最小覆盖子串 java版

官网链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09; 1. 问题&#xff1a; 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 …

【项目管理——时间管理】【自用笔记】

1 项目时间管理&#xff08;进度管理&#xff09;概述 过程&#xff1a;&#xff08;2—6&#xff09;为规划过程组&#xff0c;7为监控过程组 题目定义&#xff1a;项目时间管理又称为进度管理&#xff0c;是指确保项目按时完成所需的过程。目标&#xff1a;时间管理的主要目标…

FlyControls 是 THREE.js 中用于实现飞行控制的类,它用于控制摄像机在三维空间中的飞行。

demo演示地址 FlyControls 是 THREE.js 中用于实现飞行控制的类&#xff0c;它用于控制摄像机在三维空间中的飞行。 入参&#xff1a; object&#xff1a;摄像机对象&#xff0c;即要控制的摄像机。domElement&#xff1a;用于接收用户输入事件的 HTML 元素&#xff0c;通常…

蓝桥杯刷题8

1. 世纪末的星期 import java.util.Calendar; public class Main {public static void main(String[] args) {Calendar calendar Calendar.getInstance();for(int year 1999;year<100000;year100){calendar.set(Calendar.YEAR,year);calendar.set(Calendar.MONTH,11);cale…

力扣hot100:207. 课程表

这是一道拓扑排序问题&#xff0c;也可以使用DFS判断图中是否存在环。详情请见&#xff1a;官方的BFS算法请忽略&#xff0c;BFS将问题的实际意义给模糊了&#xff0c;不如用普通拓扑排序思想。 数据结构&#xff1a;图的拓扑排序与关键路径 拓扑排序&#xff1a; class Sol…

手撕算法-三数之和

描述 分析 排序双指针直接看代码。 代码 public static List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> res new ArrayList<>();for(int k 0; k < nums.length - 2; k){if(nums[k] > 0) break; …

通讯录管理系统实现(C++版本)

1.菜单栏的设置 &#xff08;1&#xff09;我么自定义了一个showmenu函数&#xff0c;用来打印输出我们的菜单栏&#xff1b; &#xff08;2&#xff09;菜单栏里面设置一些我们的通讯录里面需要用到的功能&#xff0c;例如增加联系人&#xff0c;删除联系人等等 2.退出功能…

【Python系列】Python 中 YAML 文件与字典合并的实用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

MySQL数据库------------探索高级SQL查询语句

目录 一、常用查询 1.1按关键字排序 1.2简单的select条件查询(where) 二、排序 2.1升序排列 2.2降序排序 三、order by 查询结果排序 ①order by还可以结合where进行条件过滤&#xff0c;筛选地址是哪里的学生按分数降序排列 ②查询学生信息先按hobbyid降序排列&#…

面试官问我 ,try catch 应该在 for 循环里面还是外面?

首先 &#xff0c; 话说在前头&#xff0c; 没有什么 在里面 好 和在外面好 或者 不好的 一说。 本篇文章内容&#xff1a; 使用场景 性能分析 个人看法 1. 使用场景 为什么要把 使用场景 摆在第一个 &#xff1f; 因为本身try catch 放在 for循环 外面 和里面 &#…

(一)whatsapp 语音通话基本流程

经过了一整年的开发测试&#xff0c;终于将whatsapp 语音通话完成&#xff0c;期间主要参考webrtc的源码来实现.下面简要说一下大致的步骤 XMPP 协商 发起或者接受语音通话第一步是发起XMPP 协商&#xff0c;这个协商过程非常重要。下面是协商一个包 <call toxxxs.whatsap…

2024 年广西职业院校技能大赛高职组《云计算应用》赛项赛题第 4 套

#需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; 某企业根据自身业务需求&…

背包DP模板

01背包 01背包-1 #include <bits/stdc.h> using namespace std;const int N 1e5 10; int n, m, f[N][N], v[N], w[N];int main() {cin >> n >> m;for (int i 1; i < n; i) {cin >> v[i] >> w[i];}for (int i 1; i < n; i) {for (int…

构建多语言数字资产交易平台和秒合约系统:从概念到实现

多语言交易所开发定制秒合约平台币数字所网站制作一条龙搭建 第一步&#xff1a;需求分析 在开始搭建多语言交易所和秒合约平台之前&#xff0c;需要进行详细的需求分析&#xff0c;包括以下几个方面&#xff1a; 功能需求&#xff1a;确定交易所需要提供的功能&#xff0c;包…

要创建企业百度百科,需要注意以下技巧和原则。

&#xfffd;&#xfffd;&#xfffd;词条内容技巧 词条排版必须美观&#xff0c;内容分段&#xff0c;然后制作副标题。例如&#xff0c;一个企业的名称分为小标题&#xff0c;如企业介绍、企业文化、企业发展、企业历史和企业新闻。这不仅可以给读者一个良好的阅读&#xf…

Learn OpenGL 30 SSAO

SSAO 我们已经在前面的基础教程中简单介绍到了这部分内容&#xff1a;环境光照(Ambient Lighting)。环境光照是我们加入场景总体光照中的一个固定光照常量&#xff0c;它被用来模拟光的散射(Scattering)。在现实中&#xff0c;光线会以任意方向散射&#xff0c;它的强度是会一…

python 第一次作业

因为笔者有一些 c/c 语言的基础&#xff0c;所以应该学 python 会稍微简单一些 格式化输出的时候&#xff0c;保留2位小数的格式是 # 假设输出 a &#xff0c;并且 a 保留 2 位小数 print(%.2f%a)输入 输入的时候所有的输入都是字符串类型&#xff0c;我们需要进行类型转换 …

RHCE- 4-Web服务器(2)

基于https协议的静态网站 概念解释 超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息。 HTTP协议以明文方式发送内容&#xff0c;不提供任何方式的数据加密&#xff0c;如果攻击者截取了Web浏览器和网站服务器之间的传输报文&#xff0c;就可以直接读懂其中…

应用层协议 - HTTP

文章目录 目录 文章目录 前言 1 . 应用层概要 2. WWW 2.1 互联网的蓬勃发展 2.2 WWW基本概念 2.3 URI 3 . HTTP 3.1 工作过程 3.2 HTTP协议格式 3.3 HTTP请求 3.3.1 URL基本格式 3.3.2 认识方法 get方法 post方法 其他方法 3.3.2 认识请求报头 3.3.3 认识请…

day8 ARM

main.c #include"key_inc.h"//封装延时函数void delay(int ms){int i,j;for(i0;i<ms;i){for(j0;j<2000;j){}}}int main(){//按键中断的初始化key1_it_config();key2_it_config();key3_it_config();while(1){printf("in main pro\n");delay(1000);}re…