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.rhkb.cn/news/336512.html

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

相关文章

MGR集群模拟故障切换

说明&#xff1a; 1、MGR集群搭建起来&#xff0c;但不知道是否能进行启动切换&#xff0c;故要手动模拟故障并且验证 2、停止主库master服务&#xff0c;登录mysql查看MGR是否进行自动切换。 3、主库切换完成以后&#xff0c;手动将宕机的服务器添加到MGR集群中。 一、模拟故障…

【Unity AR开发插件】五、运行示例程序

专栏 本专栏将介绍如何使用这个支持热更的AR开发插件&#xff0c;快速地开发AR应用。 链接&#xff1a; Unity开发AR系列 热更数据制作&#xff1a;制作热更数据-AR图片识别场景 插件简介 通过热更技术实现动态地加载AR场景&#xff0c;简化了AR开发流程&#xff0c;让用户可…

Java整合ELK实现日志收集 之 Elasticsearch、Logstash、Kibana

简介 Logstash&#xff1a;用于收集并处理日志&#xff0c;将日志信息存储到Elasticsearch里面 Elasticsearch&#xff1a;用于存储收集到的日志信息 Kibana&#xff1a;通过Web端的可视化界面来查看日志&#xff08;数据可视化&#xff09; Logstash 是免费且开放的服务器端数…

视频智能分析平台LntonAIServer视频监控管理平台裸土检测算法的重要性与应用

随着科技的飞速发展&#xff0c;人工智能技术在各个领域的应用越来越广泛。其中&#xff0c;LntonAIServer裸土检测算法作为一种先进的技术手段&#xff0c;已经在农业、环境保护等领域取得了显著的成果。本文将探讨LntonAIServer裸土检测算法的重要性及其在实际应用中的优势。…

鸿蒙应用模型:【Stage模型开发】概述

Stage模型开发概述 基本概念 下图展示了Stage模型中的基本概念。 图1 Stage模型概念图 [AbilityStage] 每个Entry类型或者Feature类型的HAP在运行期都有一个AbilityStage类实例&#xff0c;当HAP中的代码首次被加载到进程中的时候&#xff0c;系统会先创建AbilityStage实例…

【NumPy】全面解析subtract函数:高效数组减法指南

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

推荐系统学习笔记(三)

swing召回通道 Q&#xff1a;假如重合的用户是一个小圈子&#xff1a;在一个群里&#xff0c;毫无关联的笔记也会被同时交互 solve&#xff1a;降低小圈子权重--------------swing的主要目的------------给用户加权 相似度&#xff1a; a是人工参数&#xff0c;overlap降低小…

零基础小白本地部署大疆上云api(个人记录供参考)

文章目录 运行前准备前后端项目运行1.前端项目&#xff1a; 后端项目运行必须先依靠emqx运行必须先依靠redis运行修改后端项目的application.yml文件 运行前准备 1.保证电脑又node.js环境&#xff0c;可以正常使用npm 2.Java的jdk必须是11及以上版本否则无效 3.下载好emqx,red…

神经网络与深度学习——第14章 深度强化学习

本文讨论的内容参考自《神经网络与深度学习》https://nndl.github.io/ 第14章 深度强化学习 深度强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;RL&#xff09;&#xff0c;也叫增强学习&#xff0c;是指一类从与环境交互中不断学习的问题以及解决这类问题…

工程项目管理系统的Java实现:高效协同与信息共享

在当今的工程领域&#xff0c;项目管理的高效协同和信息共享是提升工作效率、降低成本的关键。本文将向您介绍一款基于Java技术构建的工程项目管理系统&#xff0c;该系统采用前后端分离的先进技术框架&#xff0c;功能全面&#xff0c;能够满足不同角色的需求&#xff0c;从项…

linux的磁盘分区与管理

磁盘分区与管理 识别磁盘 一块硬盘的“艺术”之旅&#xff08;硬盘空间使用&#xff0c;经历的步骤&#xff09; •识别硬盘 > 分区规划 > 格式化 > 挂载使用 Unix/Linux的基本哲学理念&#xff1a;一切皆文件 /dev:存放设备&#xff08;键盘、鼠标、光驱、硬盘……

攀爬二叉树,发现新的美

二叉树 什么是二叉树? 二叉树的基础概念? 性质? 问题? 文章目录 二叉树一、二叉树的概念(一)认识二叉树(二)二叉树的性质 二、遍历二叉树1.前序遍历2.中序遍历3.后序遍历4.层序遍历 三丶创建二叉树总结 一、二叉树的概念 (一)认识二叉树 二叉树是一种非线性的数据结构,…

SFOS2:组件介绍

一、前言 在sailfish os application的开发过程中&#xff0c;几乎是困难重重&#xff0c;因为我暂未找到具有完整性、指导性、易懂性的开发文档&#xff0c;特别是组件的使用&#xff0c;现决定将自己的探究结果记录下来。因此&#xff0c;这篇文章只会具有参考价值&#xff0…

UI自动化测试最佳设计模式POM

当使用Selenium进行UI自动化测试时&#xff0c;Page Object Model&#xff08;POM&#xff09;是一种最佳实践的设计模式。POM的核心思想是通过将页面封装成对象&#xff0c;使得测试代码更加清晰、可维护和可重用。 POM的主要组成部分包括页面对象类、元素定位方式和操作方法…

从 0 开始实现一个博客系统 (SSM 项目)

相关技术 Spring Spring Boot Spring MVC MyBatis Html Css JS pom 文件我就不放出来了, 之前用的 jdk8 做的, MySQL 用的 5.7, 都有点老了, 你们自己看着配版本就好 实现功能 用户注册 - 密码加盐加密 (md5 加密)前后端用户信息存储 - 令牌技术用户登录 - (使用 拦截…

python清洗苹果产量数据:从字符串到整型的转化

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、使用普通方法清洗数据 1. 创建字典并遍历 2. 示例代码 3. 结果展示 三、使…

vscode 插件-01基础

翻译 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 适用于 VS Code 的中文&#xff08;简体&#xff09;语言包 远程连接 Remote Development Remote Development是vscode的远程编程与调试的插件&#xff0c;使用这个插件可以在很多情况下代替vim…

一篇文章搞懂二叉树

文章目录 DP 树叶的度树的度节点的层次节点的祖先节点的子孙双亲节点或父节点 树的表示孩子兄弟表示法双亲表示法树和非树树的应用 二叉树满二叉树完全二叉树推论二叉树的存储以数组的方式以链表的方式堆(Heap)堆的分类大根堆和小根堆的作用 二叉树的遍历DFS和BFS DP 动态规划…

Java Object类方法介绍

Object作为顶级类&#xff0c;所有的类都实现了该类的方法&#xff0c;包括数组。 查询Java文档&#xff1a; 1、object.eauqls(): 其作用与 有些类似。 &#xff1a; 是一个比较运算符&#xff0c;而不是一个方法。 ①可以判断基本类型&#xff0c;也可以判断引用类型。 ②若…

c++编程(15)——list的模拟实现

欢迎来到博主的专栏——c编程 博主ID&#xff1a;代码小豪 文章目录 前言list的数据结构list的默认构造尾插与尾删iterator插入和删除构造、析构、赋值copy构造initializer_list构造operator 析构函数 前言 受限于博主当前的技术水平&#xff0c;暂时还不能模拟实现出STL当中用…