机械拆装-基于Unity-装配功能的实现

目录

1. 装配场景的相机控制

2. 鼠标拖拽和旋转功能的实现

  2.1 鼠标拖拽

  2.2 物体旋转

3. 零件与装配位置的对应关系

4. 轴向装配的准备位置

5. 装配顺序的实现

  5.1 标签提示

  5.2 定义一个变量记录步骤数值



1. 装配场景的相机控制

   开始装配功能时,需要将相机调节成适合于装配的移动方式,万一鼠标拖拽零件时镜头游移到其他地方会相当不舒服。

  在本应用中的做法是,建立一个空节点,让镜头始终跟随这个节点移动,类似于第三人称控制器,控制镜头在这个节点周围的有限位置。

  

  需要将相机设置为这个固定节点的子节点,并且调整好高度和角度。效果如下:

  

  

  相机控制代码如下:  

public class CameraControl : MonoBehaviour
{//使用鼠标左键点击画面调整角度public GameObject mainPerson;//跟随点private float distance;//相机和主角点的距离private Quaternion Cam_rotation;  //相机的旋转角度public bool isClickRotate=true;  //判断是否有旋转命令private float xAngle,yAngle;private Vector2 inputPos;private Vector3 resultPos;private Ray ray;public float rotationSpeed=80;  //旋转速度public float yAngleMin=3, yAngleMax=80;public float lerp = 5; //位置跟随的范围void Start(){distance = Vector3.Distance(mainPerson.transform.position, transform.position);Cam_rotation = transform.rotation;  //记录相机初始角度//计算相机初始与X、Y轴的角度xAngle = Vector3.Angle(Vector3.right, transform.right);yAngle = Vector3.Angle(Vector3.up, transform.up);}void Update(){//或者使用lateUpdate()if(!isClickRotate){//如果点击到了零件,就不再让相机旋转return;}else{isClickRotate = Input.GetMouseButton(0);inputPos.x = Input.GetAxis("Mouse X");inputPos.y = Input.GetAxis("Mouse Y");if (isClickRotate){xAngle += inputPos.x * rotationSpeed * Time.deltaTime;yAngle -= inputPos.y * rotationSpeed * Time.deltaTime;yAngle = Mathf.Clamp(yAngle, yAngleMin, yAngleMax);Cam_rotation = Quaternion.Euler(yAngle, xAngle, 0);transform.rotation = Quaternion.Lerp(transform.rotation, Cam_rotation, Time.deltaTime * 5);}resultPos = mainPerson.transform.position - (Cam_rotation * Vector3.forward * distance);transform.position = Vector3.Lerp(transform.position, resultPos, Time.deltaTime * lerp);}//镜头缩放if (Input.GetAxis("Mouse ScrollWheel") != 0){//鼠标滚动滑轮if (Input.GetAxis("Mouse ScrollWheel") < 0){//范围值限定if (Camera.main.fieldOfView <= 100)Camera.main.fieldOfView += 2;if (Camera.main.orthographicSize <= 20)Camera.main.orthographicSize += 0.5F;}//Zoom in  if (Input.GetAxis("Mouse ScrollWheel") > 0){//范围值限定if (Camera.main.fieldOfView > 2)Camera.main.fieldOfView -= 2;if (Camera.main.orthographicSize >= 1)Camera.main.orthographicSize -= 0.5F;}}}
}

2. 鼠标拖拽和旋转功能的实现

  2.1 鼠标拖拽

  查了一下各路大仙的做法,使用协程方法的效果比较好,由于鼠标拖动是比较耗时的工作,不可能在一帧执行时间内完成,因此使用协程方法建立一个新线程,不影响主线程的执行。代码如下:

public class onMouseDrag3d : MonoBehaviour
{//偏移值private Vector3 _Offset;//当前物体对应的屏幕坐标private Vector3 _ScreenPos;private void Start(){StartCoroutine(OnMouseDrag());}private IEnumerator OnMouseDrag(){//当前物体对应的屏幕坐标_ScreenPos = Camera.main.WorldToScreenPoint(transform.position);//偏移值=物体的世界坐标,减去转化之后的鼠标世界坐标(z轴的值为物体屏幕坐标的z值)_Offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, _ScreenPos.z));//当鼠标左键点击while (Input.GetMouseButton(0)){//物体当前坐标transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y, _ScreenPos.z)) + _Offset;//等待固定更新,且循环执行yield return new WaitForFixedUpdate();}}
}

  将这个代码挂在需要移动的物体上,能够实现移动的效果。

  2.2 物体旋转

    将下面的旋转脚本挂在物体上,并且需要将物体的层设置为“WorkPiece"层。

public class onMouseRotate : MonoBehaviour
{    //旋转所需的参数//上下旋转最大角度限制public int yMinLimit = -20;public int yMaxLimit = 80;//旋转速度public float xSpeed = 250.0f;//左右旋转速度public float ySpeed = 120.0f;//上下旋转速度//旋转角度private float x = 0.0f;private float y = 0.0f;private void Update(){RaycastHit hit;//射线检测需要旋转的物体Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);Physics.Raycast(ray, out hit, 100, LayerMask.GetMask("WorkPiece")); //零件需要加入WorkPiece层if (Input.GetMouseButton(1)&&hit.collider!=null){//旋转的判断条件为射线接触到物体,且按下了鼠标右键x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;y = ClampAngle(y, yMinLimit, yMaxLimit);//欧拉角转化为四元数target.transform.rotation = Quaternion.Euler(y, x, 0);} }//角度范围值限定static float ClampAngle(float angle, float min, float max){if (angle < -360)angle += 360;if (angle > 360)angle -= 360;return Mathf.Clamp(angle, min, max);}
}

3. 零件与装配位置的对应关系

  在一个装配场景中,零件数量从几个到上百个不等,因此,需要根据零件数量定义数据表,如数据表、数组或二维数组、字典等数据形式,必要时需要用数据库存储零件信息。这里使用相对容易理解的数组,设置三个数组,分别存储零件、零件位置和提示标签,让这三者的下标一致作为对应标记。

  

  并且可以在初始化时Start() ,使用for循环给每个零件挂上拖拽和旋转的脚本

        for (int i = 0; i < 14; i++){   //将所有零件挂上onMouseDrag3d脚本workPiece[i].AddComponent<onMouseDrag3d>();if (i == 0)workPiece[i].GetComponent<pieceToPlace>().ifBase = true;//第一个零件为基准零件(主轴),其他为轴向装配零件}

4. 轴向装配的准备位置

  在主轴一端设置一个轴向准备位置,以便于轴向装配的零件,自由移动到这个位置后,锁定其他两轴,仅沿着轴向装配。(拆卸场景相反)

  

  实现思想是:当零件被自由拖拽,移动到的位置和这个准备位置的距离,小于一定数值时,将这个准备位置的角度和位置赋值给零件。(装配到最终位置也是这么实现的)

  var offset = Vector3.Distance(transform.position, piecePlace.transform.position);if (offset <= 0.75f){//在两者距离较接近时让两者重叠transform.position = piecePlace.transform.position;  //位置一致transform.rotation = piecePlace.transform.rotation;  //方向一致}

  之后仅仅让零件在x方向上被拖动,将上面的协程方法修改为如下,其中正负方向和坐标轴需要根据实际情况而定。

  private IEnumerator OnMouseDragX(){//X方向拖拽//当前物体对应的屏幕坐标_ScreenPos = Camera.main.WorldToScreenPoint(transform.position);//偏移值_Offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, _ScreenPos.z));//当鼠标左键点击while (Input.GetMouseButton(0)){//修改:y、z方向不变transform.position = Camera.main.ScreenToWorldPoint(new Vector3(-Input.mousePosition.x,transform.position.y, transform.position.z)) + Offset;//等待固定更新,且循环执行yield return new WaitForFixedUpdate();}}

5. 装配顺序的实现

  5.1 标签提示

  使用UI制作标签,包含Canvas和Text,其中画布Canvas设置为WorldSpace,相机设置为主相机。

    

  这些标签起到在场景中提示拆装顺序的作用:

  5.2 定义一个变量记录步骤数值

   比如,可以定义一个记录步骤的整型变量,初始值为0,用这个整型变量与零件的数组下标进行比较,如果选取一个零件的下标与步骤变量相符时,可以顺利实现装配,并且变量值+1;当两者不符合时,则提示装配顺序有误。

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

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

相关文章

在大型项目中,怎样有效地组织和管理 SCSS 文件结构以提高开发效率?

在大型项目中&#xff0c;组织和管理 SCSS 文件结构是非常重要的&#xff0c;可以提高开发效率和代码的可维护性。下面是一些有效的方法&#xff1a; 使用模块化和层次化的文件结构&#xff1a;将 SCSS 文件按照模块进行组织&#xff0c;每个模块包含相关的样式规则。可以使用文…

vector与list的简单介绍

1. 标准库中的vector类的介绍&#xff1a; vector是表示大小可以变化的数组的序列容器。 就像数组一样&#xff0c;vector对其元素使用连续的存储位置&#xff0c;这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素&#xff0c;并且与数组中的元素一样高效。但与数…

1975react社区问答管理系统开发mysql数据库web结构node.js编程计算机网页源码

一、源码特点 react 社区问答管理系统是一套完善的完整信息管理类型系统&#xff0c;结合react.js框架和node.js后端完成本系统&#xff0c;对理解react node编程开发语言有帮助系统采用node框架&#xff08;前后端分离&#xff09;&#xff09;&#xff0c;系统具有完整的源…

【代码随想录训练营】【Day 63】【单调栈-2】| Leetcode 42, 84

【代码随想录训练营】【Day 63】【单调栈-2】| Leetcode 42, 84 需强化知识点 单调栈强化 题目 42. 接雨水 注意 python 数组反序用法 result [::-1] class Solution:def trap(self, height: List[int]) -> int:# n len(height)# leftMax, rightMax [0] * n, [0] * …

golang 垃圾回收

gc不回收什么 GC 不负责回收栈中的内存栈是一块专用内存&#xff0c;专门为了函数执行而准备的&#xff0c;存储着函数中的局部变量以及调用栈栈中的数据可以通过简单的编译器指令自动清理&#xff0c;也就不需要通过 GC 来回收了 垃圾回收算法 主流的两类垃圾回收算法有两种&a…

Spring Boot中的安全漏洞防护

Spring Boot中的安全漏洞防护 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot应用中有效防护安全漏洞。随着软件应用程序的复杂…

6种ETL计算引擎介绍

目录 一、ETL计算引擎定义 二、ETL计算引擎的功能和特性 三、6种ETL计算引擎 1、MapReduce 2、Tez 3、Spark 4、Flink 5、ClickHouse 6、Doris 一、ETL计算引擎定义 ETL&#xff08;Extract, Transform, Load&#xff09;计算引擎是用于执行ETL过程中数据转换阶段的关键组件之一…

mac如何压缩视频大小不改变画质,mac怎么压缩视频软件

在数字时代&#xff0c;视频已成为信息传递和娱乐消遣的重要媒介。然而&#xff0c;视频带来的愉悦体验背后&#xff0c;是日益增长的存储和分享压力。大视频文件不仅占用大量存储空间&#xff0c;上传和下载也变得异常缓慢。那么&#xff0c;如何才能有效压缩视频&#xff0c;…

ERROR: No matching distribution found for numpy

1.原因&#xff1a; 出现这两行英文是因为原先输入pip install numpy的方式不安全&#xff0c;不被信任所以无法下载。 2.解决方法&#xff1a; 改成以下命令执行&#xff1a; pip install numpy -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun…

2025年中国国际新能源汽车技术零部件及服务展览会

中国国际新能源汽车技术零部件及服务展览会&#xff0c;从设计到制造、从使用到服务&#xff0c;精准“链”接新能源汽车全产业链的技术供应商和汽车制造商&#xff0c;专业面向新能源造车供应链的行业盛会。2024展会回顾&#xff1a;在展会的3天里&#xff0c;有62家车企核心供…

共享拼购:创新商业模式引领小用户基数下的销售奇迹“

在瞬息万变的商业蓝海中&#xff0c;一个新颖且深具潜力的策略正悄然改变着游戏规则&#xff0c;它巧妙地避开了传统路径的束缚&#xff0c;以微妙却深远的调整&#xff0c;开辟出了一条通往成功的独特航道。我的一位合作伙伴&#xff0c;正是这一策略的实践者&#xff0c;他在…

数据库设计(实战项目)-1个手机号多用户身份

一. 背景&#xff1a; 该需求是一个互联网医院的预约单场景&#xff0c;护士在小程序上申请患者查房预约单&#xff0c;医生在小程序上对预约单进行接单&#xff0c;护士开始查房后填写查房小结&#xff0c;客户需要对用户信息进行授权&#xff0c;医生查房后进行签字&#xff…

数字媒体技术基础之:DNG 文件

DNG&#xff08;Digital Negative&#xff09;文件是一种用于存储原始图像数据的文件格式&#xff0c;由 Adobe Systems 于2004年开发并推广。DNG 是一种开放的、非专利的原始图像格式&#xff0c;旨在为不同相机制造商提供一个统一的存储格式。DNG 文件保存了原始的、未处理的…

springboot+vue下载文件一篇就够了

前台代码 export function downLoad(id) {var url = baseURL + `/api/admin/system/promotion/downLoad/${id}`axios({method: get,url: url,responseType: blob,headers: { Authori-Zation: getToken() }}).then(async (res) => {// 从 Content-Disposition 头部解析文件名…

C++时区转换

#include <iostream> #include "cctz/civil_time.h" #include "cctz/time_zone.h"// 时区转换库 // https://github.com/google/cctzint test() {for (cctz::civil_day d(2016, 2, 1); d < cctz::civil_month(2016, 3); d) {std::cout << &…

【设计模式】设计模式学习线路与总结

文章目录 一. 设计原则与思想二. 设计模式与范式三. 设计模式进阶四. 项目实战 设计模式主要是为了改善代码质量&#xff0c;对代码的重用、解耦以及重构给了最佳实践&#xff0c;如下图是我们在掌握设计模式过程中需要掌握和思考的内容概览。 一. 设计原则与思想 面向对象编…

ELK企业内部日志分析系统(1)

ELKKafkaFilebeat企业内部日志分析系统(1) Elasticsearch集群部署 1.部署环境 IP地址主机名配置系统版本192.168.222.129es12核4GRockyLinux192.168.222.130es22核3GRockyLinux192.168.222.131es32核3GRockyLinux 2.配置主机名解析和主机名 #关闭防火墙与selinux #更改主机…

k8s 使用 helm 文件部署 8.12.2 es 分角色集群

文章目录 [toc] 环境介绍添加 helm 仓库下载 elasticsearch chart 包配置 secret 文件tls 证书用户名和密码 部署 master 节点部署 ingest 节点部署 data 数据节点创建 pv 和 pvc 节点验证部署 kibana配置 secret 文件用户名和密码随机密钥 创建 kibana_login 用户下载 kibana …

qt6 获取百度地图(一)

需求分析&#xff1a; 要获取一个地图&#xff0c; 需要ip 需要根据ip查询经纬度 根据经纬度查询地图 另外一条线是根据输入的地址 查询ip 根据查询到的ip查地图‘ 最后&#xff0c;要渲染地图 上面这这些动作&#xff0c;要进行http查询&#xff1a; 为此要有三个QNet…

机器学习与AI大数据的融合:开启智能新时代

在当今这个信息爆炸的时代&#xff0c;大数据和人工智能&#xff08;AI&#xff09;已经成为推动社会进步的强大引擎。作为AI核心技术之一的机器学习&#xff08;Machine Learning, ML&#xff09;&#xff0c;与大数据的深度融合正引领着一场前所未有的科技革命&#xff0c;不…