【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

这篇具有很好参考价值的文章主要介绍了【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目标

玩家控制的大立方体 碰到小立方体时变成一样的大小,与小立方体分离后变为原来大小

实现过程

首先创建一个Cube,改个名称,作为玩家控制的大立方体
然后创建几个小立方体,标签设置为 Cube,可以改个颜色,方便区分
然后给玩家挂上 下文的脚本,设置一下移动和旋转的速度
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

直接变小,发现Bug

挂在玩家身上的脚本代码是这样的:

// 这是段有Bug的代码
using UnityEngine;

public class PlayerController_00 : MonoBehaviour
{
    private Rigidbody rb;
    private MeshRenderer meshRenderer;

    [Header("Move")]
    private Vector3 moveDir;            // 移动方向
    private Quaternion quaternionDir;   // 旋转朝向
    public float moveSpeed;             // 移动速度
    public float rotateSpeed;           // 旋转速度
                                           
    [Header("Change Scale")]               
    private Vector3 originScale;        // 初始比例

    private void Awake()
    {
        rb = GetComponent<Rigidbody>();                // 获取刚体组件
        meshRenderer = GetComponent<MeshRenderer>();   // 获取渲染器
        originScale = transform.localScale;            // 获取玩家的初始比例
    }

    private void FixedUpdate()
    {
        // 获取水平、前后方向的输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // 获取移动方向向量
        moveDir.Set(horizontal, 0, vertical);
        // 归一化向量
        moveDir.Normalize();
        // 随移方向旋转朝向
        quaternionDir = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, moveDir, rotateSpeed * Time.deltaTime, 0));

        // 用刚体移动和旋转
        rb.MovePosition(rb.position + moveDir * moveSpeed * Time.deltaTime);
        rb.MoveRotation(quaternionDir);
    }

    private void OnCollisionEnter(Collision collision)
    {
    	// 小立方体的标签为 Cube
        if (collision.gameObject.CompareTag("Cube"))
        {
            // 将玩家的比例设为碰撞目标的比例
            transform.localScale = collision.transform.localScale;

            // 为了看的更清楚,改为红色
            meshRenderer.material.color = Color.red;
        }
    }

    private void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Cube"))
        {
            // 将玩家比例设为初值
            transform.localScale = originScale;

            // 改为白色
            meshRenderer.material.color = Color.white;
        }
    }
}
//这是段有Bug的代码

像这样如果碰撞瞬间直接变小,会立刻与小立方体分离,然后瞬间恢复原来大小,然后会继续碰撞,出现如下Bug
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

变小的瞬间,改变位置

想解决这个Bug,可以让玩家控制的方块在碰到小立方体的一瞬间直接贴住小立方体,那么就要得到变小瞬间的落点
直接计算落点比较麻烦
这里提供一种比较容易理解的方法:
Unity API 提供了Collider.ClosestPoint 方法,可以帮我们在碰撞时找到小立方体上距离玩家的最近点,然后可以根据碰撞最近点计算出 玩家下一刻的落点

为了方便理解,我将计算过程拆成两步,分别是平面上的位移竖直方向的位移

平面上的位移

平面上碰撞的角度大致分为四种,这些情况全部可以用通过 .ClosestPoint() 获得碰撞最近点的位置来计算落点位置
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

竖直方向上的位移

竖直方向也就是Y轴,如果你创建的小立方体并不是很小,那么靠自由下落也可以,这一步可以忽略
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

以下为碰撞瞬间的代码片段:

    //碰撞瞬间
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Cube"))
        {
            // 获取目标物体比例
            float targetScale = collision.transform.localScale.x;
            // 获取目标物体与玩家的最近点
            Vector3 collisionPoint = collision.collider.ClosestPoint(rb.position);
            // 最近点投影在平面上的点
            Vector3 collisionPointOnGround = new Vector3(collisionPoint.x, 0, collisionPoint.z);
            // 先将玩家的比例设为碰撞目标的比例
            transform.localScale = collision.transform.localScale;
            // 目标相对位置的向量(与小立方体在平面上的相对位置)
            Vector3 targetPointOnGround = new Vector3(rb.position.x, 0, rb.position.z) - collisionPointOnGround;
            Debug.Log(targetPointOnGround);
            // Y轴偏移量,可以不加,让物体自由下落
            float offsetY = -(originScale.x - targetScale) * 0.5f;

            // 最后变换位置 = 平面上的最近点坐标 + 平面上的目标相对位置 - Y轴的偏移量
            rb.position = collisionPointOnGround + targetPointOnGround * targetScale + new Vector3(0, offsetY, 0);
        }
    }

撞到后保持紧贴,离开时慢慢恢复大小

要实现这个效果,需要对玩家控制的方块做一些修改
首先创建一个空物体,重置其Transform,创建一个Cube作为其子物体
将本文最后的完整代码的脚本 挂在这个空物体上
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)
然后设置一下Cube的位置
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

完整代码

using UnityEngine;

public class PlayerController_02 : MonoBehaviour
{
    public GameObject cube;
    private Rigidbody rb;
    private SphereCollider sphereCollider;
    private MeshRenderer meshRenderer;

    [Header("Move")]
    private Vector3 moveDir;            // 移动方向
    private Quaternion quaternionDir;   // 旋转朝向
    public float moveSpeed;             // 移动速度
    public float rotateSpeed;           // 旋转速度

    [Header("Change Scale")]
    private Vector3 originScale;        // 初始比例
    private float targetScale;          // 目标物体比例
    private float baseDistance;         // 碰撞方块离开后的变换距离
    private float tempDistance;         // 与碰撞目标的当前距离
    private bool startChange;           // 是否开始根据距离做比例调整


    private void Awake()
    {
        rb = GetComponent<Rigidbody>();                     // 获取刚体组件
        sphereCollider = GetComponent<SphereCollider>();    // 获取触发器
        meshRenderer = cube.GetComponent<MeshRenderer>();   // 获取渲染器
        originScale = cube.transform.lossyScale;            // 获取玩家的初始比例
        baseDistance = sphereCollider.radius;               // 设置变换距离
    }

    private void FixedUpdate()
    {
        // 获取水平、前后方向的输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // 获取移动方向向量
        moveDir.Set(horizontal, 0, vertical);
        // 归一化向量
        moveDir.Normalize();
        // 随移方向旋转朝向
        quaternionDir = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, moveDir, rotateSpeed * Time.deltaTime, 0));

        // 用刚体移动和旋转
        rb.MovePosition(rb.position + moveDir * moveSpeed * Time.deltaTime);
        rb.MoveRotation(quaternionDir);
    }

    //碰撞瞬间
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Cube"))
        {
            // 获取目标物体比例
            targetScale = collision.transform.localScale.x;
            // 获取目标物体与玩家的最近点
            Vector3 collisionPoint = collision.collider.ClosestPoint(rb.position);
            // 最近点投影在平面上的点
            Vector3 collisionPointOnGround = new Vector3(collisionPoint.x, 0, collisionPoint.z);
            // 先将玩家的比例设为碰撞目标的比例
            cube.transform.localScale = collision.transform.localScale;
            // 目标相对位置的向量(与小立方体在平面上的相对位置)
            Vector3 targetPointOnGround = new Vector3(rb.position.x, 0, rb.position.z) - collisionPointOnGround;
            Debug.Log(targetPointOnGround);
            // Y轴偏移量
            float offsetY = -(originScale.x - targetScale) * 0.5f;

            // 最后变换位置 = 平面上的最近点坐标 + 平面上的目标相对位置 - Y轴的偏移量
            rb.position = collisionPointOnGround + targetPointOnGround * targetScale + new Vector3(0, offsetY, 0);
        }
    }

    //在贴住的过程中
    private void OnCollisionStay(Collision collision)
    {
        if (collision.gameObject.CompareTag("Cube"))
        {
            startChange = false;
            // 和Cube相撞时,玩家速度设为0,避免被挤开
            rb.velocity = Vector3.zero;
            // 将玩家的比例设为碰撞目标的比例
            cube.transform.localScale = collision.transform.localScale;

            // 为了看的更清楚,改为红色
            meshRenderer.material.color = Color.red;
        }
    }

    //分离瞬间
    private void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Cube"))
        {
            // 和Cube分离时,可以开始变换比例
            startChange = true;
        }
    }

    private void OnTriggerStay(Collider other)
    {
        if (other.CompareTag("Cube") && startChange)
        {
            // 获取玩家和目标物体在平面上的位置
            Vector2 playerPos = new Vector2(rb.position.x, rb.position.z);
            Vector2 targetPos = new Vector2(other.transform.position.x, other.transform.position.z);
            // 获取在平面上的距离,- targetScale * 1.5f是为预留一部分空间,避免距离过近时出现不停碰撞的Bug
            tempDistance = Vector2.Distance(playerPos, targetPos) - targetScale * 1.5f;

            // 计算需要变换比例的部分,限制在 0 到 1 - targetScale 之间
            float tempScale = Mathf.Clamp(tempDistance / baseDistance * (1 - targetScale), 0, 1 - targetScale);
            // 玩家当前的比例 = 初始比例 * 目标缩放值 + 根据距离计算的动态值
            cube.transform.localScale = originScale * targetScale + originScale * tempScale;

            // 改为黄色
            meshRenderer.material.color = Color.yellow;
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Cube"))
        {
            startChange = false;
            // 将玩家比例设为初值
            cube.transform.localScale = originScale;

            // 改为白色
            meshRenderer.material.color = Color.white;
        }
    }
}

关于分离时慢慢恢复大小的讲解详见视频

最终效果

【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)
【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)

感谢观看!文章来源地址https://www.toymoban.com/news/detail-501615.html

到了这里,关于【Unity】碰撞后缩小比例并与碰撞目标紧贴(吸附效果)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity】拖拽放置模型时 为什么出现有时候有紧贴地面和有时候随机再空中的情况

    👨‍💻个人主页 :@元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶‍🌫️收录于专栏 :unity细节和bug 😶‍🌫️优质专栏 ⭐【软件设计师高频考点暴击】 解决了点个赞,关注下吧✅ ⭐【2023unity游戏制作-mango的冒险】-开始画面API制作 ⭐【

    2024年02月10日
    浏览(53)
  • Mediapipe手势识别,并与unity通信

    Mediapipe是goole的一个开源项目,支持跨平台的常用ML方案,详情请戳下面链接 MediaPipe Mediapipe底层封装了手势识别的具体实现内容,而在Python中搭建完环境后经过很简单的调用就能够实现手势识别 环境如下: pip install mediapipe pip install opencv-python 简单的实现,代码很少,代码如

    2024年02月11日
    浏览(38)
  • 全网最详细的鼠标点击效果与禁用页面缩小放大

    🌏 博客首页: 水香木鱼 📑 文章摘要: 鼠标点击效果   vue2 💌 春波寄语: 故木秀于林,风必摧之;堆出于岸,流必湍之;行高于人,众必非之。 在public的index.html 内 body 下 添加即可。 在public的index.html 内 body 下 添加即可。 在utils文件夹下创建 coreSocialistValues.js 文件,并

    2024年01月23日
    浏览(53)
  • QGraphicsView 如何实现百度地图按照鼠标点进行放大缩小效果

    前段时间用了QGraphicsView做了一些工作,然而如何实现QGraphicsView的放大缩小的效果也很简单,照鼠标某一点进行缩放,仅靠以下代码对view进行缩放会导致view上的item在放大缩小的过程中跑偏了。 我们看一下仅靠以上代码实现的放大缩小的效果。 从下图中我们看到把图中小矩形

    2024年02月05日
    浏览(59)
  • uniapp图片放大缩小预览,并支持图片拖动附效果图

    效果图: 放大缩小和拖动是根据 movable-area 组件来实现的,小程序和uniapp都支持这个组件。 movable-area | 微信开放文档 微信开发者平台文档 https://developers.weixin.qq.com/miniprogram/dev/component/movable-area.html 实现思路: 默认显示默认大小的图片,点击图片执行yulan事件从而显示放大缩

    2024年02月11日
    浏览(50)
  • 用C++模拟的弹簧系统,可展示弹簧的振动和碰撞效果

    以下是一个使用C++和OpenGL库的示例代码,绘制了一个基于物理模拟的弹簧系统,展示了弹簧的振动和碰撞效果: 以上代码通过使用OpenGL库创建了一个基于物理模拟的弹簧系统。系统中的粒子通过弹簧相互连接

    2024年02月13日
    浏览(38)
  • Unity纹理优化:缩小包体

    Android打包apk大小约:475M 查看打包日志:Console→Open Editor Log; 或者依赖第三方插件:build reports tool(在unity store里可以下载); 经过排查后,发现项目中纹理占比很高(82.8%),而且美术说图片从tga换成了更小的png,包体理应会变小,但是替换后并没有变化,甚至还大了3M,就

    2023年04月17日
    浏览(37)
  • Unity 鼠标控制 UI 放大、缩小、拖拽

    2024年02月12日
    浏览(59)
  • blender模型导入Unity朝向、比例问题测试及解决办法

    先进行测试(全部都先Ctrl+A应用全部变换): 1.模型正面朝向Y-  ,导出FBX时未勾选“应用变换”→Unity内X旋转为-89.98,朝向( Unity内Z轴正方向 )正常,比例全为100   2.模型正面朝向Y-  ,导出FBX时勾选“应用变换”→Unity内全部旋转为0,朝向正常,比例全为1(正常) 3.模

    2024年02月16日
    浏览(41)
  • Unity 2d - 基础 - 碰撞(一) - 针对性碰撞

    问题: 在开发过程中经常会遇到物体碰撞的问题,比如玩家的角色遇到敌人后碰撞掉血,子弹碰到敌人后消失等等。 一般我们会选择添加刚体与碰撞盒来处理此类问题,但添加碰撞盒后,玩家的多个单位之间也会形成碰撞,在横版2D游戏中就很致命了,如图:  要处理此问题

    2024年02月16日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包