cocos creator 3.x 手搓背包拖拽装备

 项目背景:

游戏背包 需要手动 拖拽游戏装备到 装备卡槽中,看了下网上资料很少。手搓了一个下午搞定,现在来记录下实现步骤;

功能拆分:

一个完整需求,我们一般会把它拆分成 几个小步骤分别造零件。等都造好了我们就能 装配到一起 形成一个完成功能。以下是对上面功能的 步骤拆分:

  1. 背包详情的展示,点击背包中的物品 展示一个详情页面(因为 是在 ScrollView 中拖拽 ScrollView 的元素 会造成 ScrollView 滚动)所有我们直接拖拽 详情页面中的元素就能 避免对 ScrollView 的影响。(如果没有详情可以 先生成一个一样的元素放置的 ScrollView 外层)
  2. 实现 拖拽元素,本身是对 拖拽事件的监听 来完成对元素位置的设置。这里有个知识点 触点坐标 到 世界坐标的转换
  3. 能拖拽元素了 那么我们就需要把 元素放在对应的位置, 实际上就是在拖拽的时候 判断两个元素的位置,根据需求我们这里是直接判断的 元素的 x坐标;来判断拖拽元素 是否到了 对应的卡槽;
  4. 既然能判断到那个具体卡槽了,我们停止拖拽,那就装备到对应的卡槽,要是没有到卡槽位置,我们隐藏拖拽元素 返回 (假装什么也没发生)

1.背包装备详情

点击装备展示,对应详情信息,应为装备位置不固定,

  1. 展示的时候就需要 通过 背包元素的 位置 来计算详情页面展示的位置
  2. 并且如果是 在边缘位置还要修改要展示的位置,然后修正位置信息后 在做展示

这里有一个技术点就是 坐标位置的转换

想要对比两个节点元素 或者 参照当前节点 设置另一个节点位置信息(不在同一个父节点的时候) 需要把他们转换在 同一个坐标系及(参照同一个父节点)

 

问题: 由于图中的 粉色ScrollView item  和 详情不是在用一个坐标参照中, 如果我们直接获取 item 位置 赋值给 详情元素 那肯定无法让他们两位置一直;

 

解决问题思路:

  先计 算出 item 世界坐标,然后再把这个坐标转化到 详情页面的局部坐标他们世界坐标一直,局部坐标不一致

同为 cocos creator 坐标转换需要使用 使用节点父元素计算:

https://docs.cocos.com/creator/3.8/api/zh/class/UITransform?id=convertToWorldSpaceARicon-default.png?t=N7T8http://convertToWorldSpaceAR

ItemworldPositon = item.parent.getComponent(UITransform).convertToWorldSpaceAR(item.getPosition());详情面板位置 =  详情面板.parent.getComponent(UITransform).convertToNodeSpaceAR(                  ItemworldPositon)
  • convertToNodeSpaceAR
    /*** @en* Converts a Point to node (local) space coordinates.** @zh* 将一个 UI 节点世界坐标系下点转换到另一个 UI 节点 (局部) 空间坐标系,这个坐标系以锚点为原点。* 非 UI 节点转换到 UI 节点(局部) 空间坐标系,请走 Camera 的 `convertToUINode`。** @param worldPoint @en Point in world space.*                   @zh 世界坐标点。* @param out @en Point in local space.*            @zh 转换后坐标。* @returns @en Return the relative position to the target node.*          @zh 返回与目标节点的相对位置。* @example* ```ts* const newVec3 = uiTransform.convertToNodeSpaceAR(cc.v3(100, 100, 0));* ```*/
    convertToNodeSpaceAR(worldPoint: math.Vec3, out?: math.Vec3): math.Vec3;
  • convertToWorldSpaceAR
    /*** @en* Converts a Point in node coordinates to world space coordinates.** @zh* 将距当前节点坐标系下的一个点转换到世界坐标系。** @param nodePoint @en Point in local space.*                  @zh 节点坐标。* @param out @en Point in world space.*            @zh 转换后坐标。* @returns @en Returns the coordinates in the UI world coordinate system.*          @zh 返回 UI 世界坐标系。* @example* ```ts* const newVec3 = uiTransform.convertToWorldSpaceAR(3(100, 100, 0));* ```*/
    convertToWorldSpaceAR(nodePoint: math.Vec3, out?: math.Vec3): math.Vec3;
 /*** 坐标计算* @param target ScrollView 中被点击的 item 元素 * @param item  数据*/
public setData(target: Node, item: CoachCharacterItem) {//console.log('target.getPosition():', target.getPosition());//当前节点本地坐标转世界坐标、//世界坐标转到 对应的 节点坐标let vec: Vec3 = this.rootParemt.getComponent(UITransform).convertToNodeSpaceAR(target.parent.getComponent(UITransform).convertToWorldSpaceAR(target.getPosition()));console.log(vec)//修正位置if (vec.x < 400) {vec.x += 250;} else {vec.x -= 250;}if (vec.y > 140) {vec.y = 140;} else if (vec.y < -100) {vec.y = -100;}this.node.setPosition(vec);this.node.active = true;
}

2.拖拽元素

我们给详情页面添加 拖拽事件的监听:

这里有个技术点 tuochMove 中获取到的坐标实际上是 触点坐标, 我们需要将这个坐标 转化到 UI坐标才能对 UI元素赋值

//添加监听事件
onLoad() {this.node.on(Node.EventType.TOUCH_START, this.touchStart, this);this.node.on(Node.EventType.TOUCH_MOVE, this.touchMove, this);this.node.on(Node.EventType.TOUCH_END, this.touchEnd, this)this.node.on(Node.EventType.TOUCH_CANCEL, this.touchCancel, this)
}//展示只有 在拖拽情况下才显示的 元素 equipmentFly
touchStart(event: EventTouch) {//Log.trace('touchStart');//展示 拖拽 元素 equipmentFlythis.equipmentFly.node.active = true;
}//获取 触点坐标位置
touchMove(event: EventTouch) {//更新 拖拽元素位置this.equipmentFly.updatePosition(event.getLocation());
}//结束拖拽 隐藏拖拽元素
touchCancel(event: EventTouch) {//console.log('touchCancel');//隐藏 拖拽 元素 equipmentFlythis.equipmentFly.node.active = false;//执行 拖拽完毕的判断逻辑this.equipmentFly.onConfirm();//重置拖拽元素的位置this.equipmentFly.resetPostion(new Vec3(0, 50));}
//结束拖拽
touchEnd(event: EventTouch) {//console.log('touchEnd');//隐藏 拖拽 元素 equipmentFlythis.equipmentFly.node.active = false;//执行 拖拽完毕的判断逻辑this.equipmentFly.onConfirm();//重置拖拽元素的位置this.equipmentFly.resetPostion(new Vec3(0, 50));
}
//隐藏详情面板
public hideNoticePanel() {this.equipmentFly.node.active = false;this.equipmentFly.resetPostion(new Vec3(0, 50));this.node.active = false;
}
触点坐标转换UI坐标的实现:

触点坐标转 UI 坐标需要通过  camera.screenToWorld(触点坐标)

Cocos Creator APIDescriptionicon-default.png?t=N7T8https://docs.cocos.com/creator/3.8/api/zh/class/renderer.scene.Camera?id=screenToWorld大概逻辑整理如下:

  1. 拿到 拖拽 事件传递的 触点坐标
  2. 触点坐标 通过 camera 转 世界坐标
  3. 世界坐标转 UI局部坐标赋值 拖拽元素坐标    这样就能实现 拖拽元素随着手指滑动而移动

//拿到摄像机
onLoad() {//获取摄像机this.camera = find('Canvas/Camera').getComponent(Camera);//获取卡槽1 的 世界坐标this.vec3WorldBattle = this.nodeWearBattle.parent.getComponent(UITransform).convertToWorldSpaceAR(this.nodeWearBattle.getPosition());//获取卡槽1 的 世界坐标this.vec3WorldReward = this.nodeWearReward.parent.getComponent(UITransform).convertToWorldSpaceAR(this.nodeWearReward.getPosition());}/*** 触点坐标转换 * 最后使用UI坐标赋值* @param vec */
updatePosition(vec: Vec2) {this.vec3Pos.x = vec.x;this.vec3Pos.y = vec.y;//触点坐标转 世界坐标this.vec3WorldNode = this.camera.screenToWorld(this.vec3Pos);// 世界坐标转 UI局部坐标this.vec3new = this.node.parent.getComponent(UITransform).convertToNodeSpaceAR(this.vec3WorldNode);this.node.position = this.vec3new;//计算 拖拽元素 和 两个卡槽的 x轴距离 这里  distance 为 50个单位if (Math.abs(this.vec3WorldNode.x - this.vec3WorldBattle.x) < this.distance) {//距离到了 通知界面展示 卡槽1 选中框this.coachCharacterEquipmentView.onPreview(this.equipment, 0);} else if (Math.abs(this.vec3WorldNode.x - this.vec3WorldReward.x) < this.distance) {       //距离到了 通知界面展示 卡槽2 选中框this.coachCharacterEquipmentView.onPreview(this.equipment, 1);} else {//这里处理 距离都没到的逻辑 移除选中框 以及 从 已经选中状态到 没选中状态的切换this.coachCharacterEquipmentView.onPreview(null, -1);}}

3.卡槽判定

通过上面的代码我们已经可以实现,拖转元素到 卡槽函数的调用:

//计算 拖拽元素 和 两个卡槽的 x轴距离 这里  distance 为 50个单位
if (Math.abs(this.vec3WorldNode.x - this.vec3WorldBattle.x) < this.distance) {//距离到了 通知界面展示 卡槽1 选中框this.coachCharacterEquipmentView.onPreview(this.equipment, 0);
} else if (Math.abs(this.vec3WorldNode.x - this.vec3WorldReward.x) < this.distance) {//距离到了 通知界面展示 卡槽2 选中框this.coachCharacterEquipmentView.onPreview(this.equipment, 1);
} else {//这里处理 距离都没到的逻辑 移除选中框 以及 从 已经选中状态到 没选中状态的切换this.coachCharacterEquipmentView.onPreview(null, -1);
}
因为我们一个卡槽有多个 装备位置,需要响应的装备展示 对应的卡槽;
this.coachCharacterEquipmentView.onPreview(data,soltIndex);

函数onPreview 当到对应的卡槽就把数据传递过去,具体不够就传 null,过去

卡槽现实的我们就略过去;

 

卡槽数据的确认:

这个环节就对应的是 到对应的卡槽,并且松手:

上面的代码中我们已经加过监听了;通过实践发现 即便我同时监听了 TOUCH_END  和 TOUCH_CANCEL 他也只有一个会执行;所有我两个都加了

所以一来逻辑就清晰了:

  1. 当拖拽元素到卡槽中的时候,我们已经传递参数过去了,并且 我们当拖出 卡槽的时候还把数据 赋值为  null,
  2. 当我们停止拖拽的时候 判断下 传递过去的 数据是否为 null,
  3. 如果为 null  则说明 没有在卡槽中停止 拖拽,不为空则为 在卡槽中停止的拖拽
touchCancel(event: EventTouch) {//console.log('touchCancel');this.equipmentFly.node.active = false;this.equipmentFly.onConfirm();this.equipmentFly.resetPostion(new Vec3(0, 50));}
touchEnd(event: EventTouch) {//console.log('touchEnd');this.equipmentFly.node.active = false;this.equipmentFly.onConfirm();this.equipmentFly.resetPostion(new Vec3(0, 50));
}

到这里基本上级功能都实现了。而且我们的 距离判断逻辑只有在 拖拽时候才会执行,应该说性能还不错!

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

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

相关文章

openresty(Nginx) 隐藏 软件包名称 版本号 升级新版本

1 访问错误或者异常的URL 2 修改配置&#xff0c;重新编译&#xff0c;升级 #修改版本等 vim ./bundle/nginx-1.13.6/src/core/nginx.h #define nginx_version 1013006 #define NGINX_VERSION "1.13.6" #define NGINX_VER "openresty/&q…

计算机网络学习笔记——应用层

一、应用层概述 二、客户/服务器方式(C/S方式)和对等方式(P2P方式) 客户/服务器(Client/Server&#xff0c;C/S)方式 服务器总是处于运行状态&#xff0c;并等待客户的服务请求。服务器具有固定端口号(例如HTTP服务器的默认端口号为80)&#xff0c;而运行服务器的主机也具有固…

UVa11604 General Sultan

UVa11604 General Sultan 题目链接题意分析AC 代码 题目链接 UVA - 11604 General Sultan 题意 给出一些0和1组成的模式串&#xff0c;问是否存在一个串使得有多种方案将这个串分解成模式串。    给一个包含n&#xff08;n≤100&#xff09;个符号的二进制编码方式&#xff…

自学SPSS,有哪些教学视频或书籍推荐?

书籍推荐 经过长达八年的不断迭代与优化&#xff0c;SPSSAU的用户群体已经远超简单的数据分析层面&#xff0c;而是逐步深入到了学术研究的精髓之中。如今&#xff0c;无论是在SCI、EI等国际权威学术期刊&#xff0c;还是北大核心期刊、CSSCI等国内顶尖学术期刊上&#xff0c;…

leetCode.87. 扰乱字符串

leetCode.87. 扰乱字符串 题目思路&#xff08;该方法以前可以过&#xff0c;现在对时间复杂度的要求严格了许多&#xff0c;不能过去&#xff09;&#xff1a; 这里显示&#xff0c;能够让我自己后期复习的时候&#xff0c;可以掌握最基本的做法&#xff08;尽管不能通过全部样…

wangEditor富文本实现自定义插入数据(手把手)

插件版本如下: vue2版本 “@wangeditor/editor”: “^5.1.23”, “@wangeditor/editor-for-vue”: “^1.0.2”, 文件截图如下: 一、plugins/index.js 入口文件,整合模块导出外部使用 import withMention from ./plugin import renderElemConf from ./render-elem import …

重庆耶非凡科技选品师项目大揭秘:成功背后的故事与经验

在电商行业迅猛发展的今天&#xff0c;选品师这一职业愈发受到市场的关注。重庆耶非凡科技有限公司凭借其专业的选品团队和科学的选品方法&#xff0c;成为众多商家关注的焦点。那么&#xff0c;该公司的选品师项目是否真的有成功的案例呢?接下来&#xff0c;我们将从多个角度…

深度学习——卷积神经网络

卷积神经网络 1.导入需要的包2.数据导入与数据观察3.卷积层4.汇聚层最大汇聚 平均汇聚全局平均汇聚 5.搭建卷积神经网络进行手写数字识别导入并对数据进行预处理搭建卷积神经网络 6.利用函数式API与子类API搭建复杂神经网络残差层 1.导入需要的包 numpy as np: NumPy是一个用于…

Pytorch深度学习实践笔记4(b站刘二大人)

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;pytorch深度学习 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 视频来自【b站刘二大人】 1 反向传播 Back propaga…

FFMPEG+ANativeWinodow渲染播放视频

前言 学习音视频开发&#xff0c;入门基本都得学FFMPEG&#xff0c;按照目前互联网上流传的学习路线&#xff0c;FFMPEGANativeWinodow渲染播放视频属于是第一关卡的Boss&#xff0c;简单但是关键。这几天写了个简单的demo&#xff0c;可以比较稳定进行渲染播放&#xff0c;便…

【运维】Linux 端口管理实用指南,扫描端口占用

在 Linux 系统中&#xff0c;你可以使用以下几种方法来查看当前被占用的端口&#xff0c;并检查 7860 到 7870 之间的端口&#xff1a; 推荐命令&#xff1a; sudo lsof -i :7860-7870方法一&#xff1a;使用 netstat 命令 sudo netstat -tuln | grep :78[6-7][0-9]这个命令…

全球痛风年轻化趋势明显 别嘌醇制剂需求增多

全球痛风年轻化趋势明显 别嘌醇制剂需求增多 别嘌醇制剂包括片剂和缓释胶囊两种剂型&#xff0c;别嘌醇片剂吸收快&#xff0c;可能会出现胃肠道反应&#xff1b;别嘌醇缓释胶囊释放比较缓慢&#xff0c;作用更持久&#xff0c;对胃肠道损害比较小。别嘌醇制剂是抑制尿酸合成的…

Java内存空间

Java内存空间划分 Java虚拟机在执行Java程序的过程中会把他管理的内存划分为若干个不同的数据区域&#xff0c;如图所示1.7和1.8两个版本的Java内存空间划分。 JDK1.7: JDK1.8: 线程私有&#xff1a; 程序计数器虚拟机栈本地方法栈 线程共享 &#xff1a; 堆方法区直接内…

股价飙升:AI PC大变革,联想的“联想时刻”正在缔造?

按照产业的传导逻辑&#xff0c;在颠覆式技术到来之时&#xff0c;当引发这场变革的最核心技术及产品真正进入了产品化、商业化阶段&#xff0c;此时直触需求端的终端厂商&#xff0c;其成长性估算将得到市场的重新预估。 眼下AI PC之于联想就是如此。 5月27日&#xff0c;联…

mysql中InnoDB的统计数据

大家好。我们知道&#xff0c;mysql中存在许多的统计数据&#xff0c;比如通过SHOW TABLE STATUS 可以看到关于表的统计数据&#xff0c;通过SHOW INDEX可以看到关于索引的统计数据&#xff0c;那么这些统计数据是怎么来的呢&#xff1f;它们是以什么方式收集的呢&#xff1f;今…

vscode:如何解决”检测到include错误,请更新includePath“

vscode:如何解决”检测到include错误&#xff0c;请更新includePath“ 前言解决办法1 获取includePath路径2 将includePath路径添加到指定文件3 保存 前言 配置vscode是出现如下错误&#xff1a; 解决办法 1 获取includePath路径 通过cmd打开终端&#xff0c;输入如下指令&a…

【第8章】SpringBoot之单元测试

文章目录 前言一、准备1. 引入库2. 目录结构 二、测试代码1. SpringBoot3ApplicationTests2.测试结果 总结 前言 单元测试是SpringBoot项目的一大利器&#xff0c;在SpringBoot我们可以很轻松地测试我们的接口。 一、准备 1. 引入库 <dependency><groupId>org.s…

Java基于saas模式云MES制造执行系统源码Spring Boot + Hibernate Validation什么是MES系统?

Java基于saas模式云MES制造执行系统源码Spring Boot Hibernate Validation 什么是MES系统&#xff1f; MES制造执行系统&#xff0c;通过互联网技术实现从订单下达到产品完成的整个生产过程进行优化管理。能有效地对生产现场的流程进行智能控制&#xff0c;防错防呆防漏&…

大模型时代的具身智能系列专题(五)

stanford宋舒然团队 宋舒然是斯坦福大学的助理教授。在此之前&#xff0c;他曾是哥伦比亚大学的助理教授&#xff0c;是Columbia Artificial Intelligence and Robotics Lab的负责人。他的研究聚焦于计算机视觉和机器人技术。本科毕业于香港科技大学。 主题相关作品 diffusio…

【FISCO BCOS 3.0】一、新版本搭链介绍

目录 一、区块链种类的变化 二、搭链演示 1.单群组区块链&#xff08;Air版本&#xff09; 2.多群组区块链&#xff08;Pro版本&#xff09; 3.可扩展区块链&#xff08;Max版本&#xff09; FISCO BCOS的发展速度如日中天&#xff0c;对于稳定的2.0版本而言&#xff0c;偶…