【Unity How】如何让物体跟随平台移动或旋转?

embedded/2024/12/3 3:18:11/

先看下最终要实现的效果:

当查找这个问题的资料时,发现多数的方案都是将物体设置为平台的子对象

但是如果平台是非均匀缩放时,物体在移动或旋转时就会发生变形。

参考:Unity中父对象是非均匀缩放时出现倾斜或剪切现象

那有没有其他方法呢?

其实我们也可以不将物体设置为平台的子对象,而是通过管理刚体的实现。

先看代码:

using UnityEngine;
using System.Collections.Generic;// CarryRigidbodies类负责让一系列Rigidbody对象跟随Unity GameObject移动。
public class CarryRigidbodies : MonoBehaviour
{// 存储所有应随本GameObject移动的Rigidbody对象的列表。public List<Rigidbody> rigidbodies = new List<Rigidbody>();// 存储上一帧物体的位置,用于计算移动距离。public Vector3 LastPosition;// 缓存当前GameObject的Transform组件。Transform _transform;// Start方法在脚本实例被激活时调用一次。void Start(){_transform = transform; // 初始化_transform为当前GameObject的Transform。LastPosition = _transform.position; // 初始化LastPosition为当前位置。}// LateUpdate在每一帧的Update函数调用之后调用。void LateUpdate(){// 如果列表中有Rigidbody对象,则处理它们的移动。if(rigidbodies.Count > 0){// 遍历所有的Rigidbody。for(int i = 0; i < rigidbodies.Count; i++){Rigidbody rb = rigidbodies[i];// 计算自上一帧以来的位置变化。Vector3 velocity = _transform.position - LastPosition;// 将位置变化应用到每个Rigidbody上。rb.transform.Translate(velocity, _transform);}}// 更新LastPosition为当前帧的位置。LastPosition = _transform.position;}// 当发生碰撞开始时调用。private void OnCollisionEnter(Collision other) {// 尝试从碰撞对象中获取Rigidbody组件。Rigidbody rb = other.collider.GetComponent<Rigidbody>();if(rb != null){// 如果存在Rigidbody,则添加到列表中。Add(rb);}    }// 当碰撞结束时调用。private void OnCollisionExit(Collision other) {// 尝试从碰撞对象中获取Rigidbody组件。Rigidbody rb = other.collider.GetComponent<Rigidbody>();if(rb != null){// 如果存在Rigidbody,则从列表中移除。Remove(rb);}    }// 添加一个Rigidbody到列表中,如果它尚未存在于列表中。void Add(Rigidbody rb){if(!rigidbodies.Contains(rb)){rigidbodies.Add(rb);}}// 从列表中移除一个Rigidbody,如果它存在于列表中。void Remove(Rigidbody rb){if(rigidbodies.Contains(rb)){rigidbodies.Remove(rb);}}
}

上面脚本的核心实现原理是通过监听一个物体的位置变化,并将这个变化应用到与其相连的其他物体上,使得这些物体可以同步移动。这里面涉及的核心概念和方法包括:

位置追踪

  1. 脚本通过记录物体的当前位置和上一帧的位置来计算位置的变化量(即位移向量)。这个位置变化量反映了物体在每一帧之间的移动。

同步位移

  1. 使用Unity的Transform.Translate方法,将计算出的位移向量应用到所有附着的Rigidbody上。这个方法允许物体根据相对于其自身或另一个变换(在此案例中是脚本所依附的物体的变换)的位移向量进行移动。
  2. 在LateUpdate方法中执行这个位移同步,是因为LateUpdate在所有Update方法之后执行,可以获取到所有物体的最终位置更新后,再统一进行位移操作,确保同步性和位置的准确性。

碰撞侦测与动态列表管理

  1. 使用OnCollisionEnter和OnCollisionExit方法动态地管理附着的Rigidbody列表。这两个方法在Unity物理引擎处理碰撞的开始和结束时被调用。
  2. 当一个物体开始与脚本附着的物体碰撞时,OnCollisionEnter被触发,脚本检查碰撞物体是否有Rigidbody组件,如果有,则加入到管理列表中。
  3. 当碰撞结束时,OnCollisionExit触发,对应的Rigidbody从列表中移除。

性能考虑

  1. 脚本中使用了变量_transform来缓存所附加GameObject的Transform组件的引用,这是为了减少在每次调用时重复获取这个组件的开销,优化性能。

那如何实现物体跟随平台同步旋转呢?

为了让附着的物体能够随着平台同步旋转,我们需要修改代码以跟踪平台的旋转变化,并将这些变化应用到所有附着的Rigidbody上。这可以通过计算每帧的旋转差异并应用这个差异来实现。下面是如何改进原有代码来支持旋转同步的详细步骤:

1. 添加跟踪旋转的变量: 在类中增加一个变量来存储上一帧的旋转:

public Quaternion LastRotation;

2. 初始化旋转变量: 在Start方法中初始化这个变量:

void Start()
{_transform = transform;LastPosition = _transform.position;LastRotation = _transform.rotation;
}

3. 计算旋转差异并应用: 在LateUpdate方法中,计算旋转的差异并应用到所有的Rigidbody上:

void LateUpdate()
{if (rigidbodies.Count > 0){Vector3 velocity = _transform.position - LastPosition;Quaternion rotationDelta = _transform.rotation * Quaternion.Inverse(LastRotation);for (int i = 0; i < rigidbodies.Count; i++){Rigidbody rb = rigidbodies[i];rb.transform.Translate(velocity, Space.World);rb.transform.rotation = rotationDelta * rb.transform.rotation;}}LastPosition = _transform.position;LastRotation = _transform.rotation;
}

这段代码中,旋转差异rotationDelta是通过计算当前旋转与上一帧旋转的相对旋转得到的。这个旋转差异然后应用于所有附着的Rigidbody上,更新它们的旋转状态。

通过这种方式,任何附着的Rigidbody不仅会随着平台的移动而移动,也会随着平台的旋转而旋转,实现完全的同步。这对于制作需要物体随着移动平台旋转和平移的游戏场景(如旋转的平台或转盘等)非常有用。


http://www.ppmy.cn/embedded/142497.html

相关文章

(4)CHATGPT-3和GPT-4是生成式AI的一部分吗?

文章目录 前言ChatGPT-3 和 GPT-4被认为是生成式AI的原因后续 前言 ChatGPT-3 和 GPT-4 都是大型语言模型&#xff08;LLMs&#xff09;&#xff0c;也是生成式AI&#xff08;生成式人工智能&#xff09;的例子。它们属于一类称为transformers的模型&#xff0c;特别擅长处理数…

使用ECharts创建带百分比标注的环形图

在数据可视化领域&#xff0c;环形图是一种非常有效的图表类型&#xff0c;它能够清晰地展示各部分与整体的关系。今天&#xff0c;我们将通过ECharts来创建一个带百分比标注的环形图&#xff0c;并详细解释如何实现这一效果。 1. 数据准备 首先&#xff0c;我们定义了一些基础…

D82【python 接口自动化学习】- pytest基础用法

day82 pytest初体验 学习日期&#xff1a;20241128 学习目标&#xff1a;pytest基础用法 -- pytest初体验 学习笔记&#xff1a; 文件命名规范 py测试文件必须以test_开头&#xff08;或_test结尾&#xff09;测试方法必须以test开头测试类必须以Test开头&#xff0c;并且…

(免费送源码)计算机毕业设计原创定制:Java+ssm+JSP+Ajax SSM棕榈校园论坛的开发

摘要 随着计算机科学技术的高速发展,计算机成了人们日常生活的必需品&#xff0c;从而也带动了一系列与此相关产业&#xff0c;是人们的生活发生了翻天覆地的变化&#xff0c;而网络化的出现也在改变着人们传统的生活方式&#xff0c;包括工作&#xff0c;学习&#xff0c;社交…

【二分查找】力扣 34. 在排序数组中查找元素的第一个和最后一个位置

一、题目 二、思路 将题目转化为求解 target 和 target 1 的查找。分别采用最基础的二分查找即可。 三、题解 class Solution {public int[] searchRange(int[] nums, int target) {int n nums.length;int start lowerBound(nums, target);if (start n || nums[start] !…

家庭记账本小程序

私信我获取源码和万字论文&#xff0c;制作不易&#xff0c;感谢点赞支持。 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户…

【2025最新计算机毕业设计】基于SpringBoot+Vue文化创意展示与交流平台【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

MySQL索引与分区:性能优化的关键

在开发过程中&#xff0c;随着数据量的不断增长&#xff0c;MySQL 查询的性能问题会逐渐显现。特别是在大数据量下&#xff0c;查询变得越来越慢&#xff0c;甚至可能导致系统崩溃。为了优化查询&#xff0c;MySQL 提供了 分区&#xff08;Partitioning&#xff09; 和 索引&am…