• 【Unity】两种方式实现弹跳平台/反弹玩家(玩家触发与物体自身触发事件实现蹦床的物理效果)


    一、声明

    只实现物理反弹的效果,不实现蹦床会有的视觉拉伸效果,请自行找相关代码

    二、实现

    经过我的实践,我发现要想实现一个平台反弹的效果,要么就选择给player添加一个物理材质(平台加了没用),
    在这里插入图片描述

    但是这样会造成一个问题,如果我们要弄一个3d控制器的游戏,那么没理由让玩家什么情况下都要弹起来吧。

    2.1 老手操作

    因此参考这篇优质文章https://blog.csdn.net/LLLLL__/article/details/117266549
    我们可以给玩家移动代码中添加如下的代码 :
    注意

    • 应避免使用contacts[0],因为它会产生内存垃圾。改用 GetContact GetContacts,即other.GetContact(0).normal
    	private Vector3 lastDir;
    	private void LateUpdate()
        {
            lastDir = rb.velocity;
        }
    
        private void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.tag == "Wall")
            {
                Vector3 reflexAngle = Vector3.Reflect(lastDir, other.contacts[0].normal);
                rb.velocity = reflexAngle.normalized * lastDir.magnitude;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.2 新手操作

    下面的选择则是挂载到我们的平台上。
    注意
    playerRigidbody是在OnCollisionEnter方法中声明的,因此它的作用范围仅限于OnCollisionEnter方法,这会导致编译错误。
    要解决这个问题,可以将playerRigidbody声明为类级别的字段,以便在整个类中都能访问它。
    同时,还需要在OnCollisionEnter方法中获取到playerRigidbody

    using UnityEngine;
    
    public class Bounch_Platform : MonoBehaviour
    {
        private Vector3 lastDir;
        private Rigidbody playerRigidbody; // 声明为类级别字段
    
        private void OnCollisionEnter(Collision other)
        {
            // 检测是否碰到了玩家(假设玩家有一个标签为 "Player")
            if (other.gameObject.CompareTag("Player"))
            {
                playerRigidbody = other.gameObject.GetComponent<Rigidbody>(); // 获取玩家的刚体
                if (playerRigidbody != null)
                {
                    Vector3 reflexAngle = Vector3.Reflect(lastDir, other.GetContact(0).normal);
                    // 应用反射角度来实现弹跳
                    playerRigidbody.velocity = reflexAngle.normalized * lastDir.magnitude;
                }
            }
        }
    
        private void LateUpdate()
        {
            if (playerRigidbody != null)
            {
                lastDir = playerRigidbody.velocity;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    三、额外注意事项

    3.1 使用触发事件的问题

    • 注意碰撞体Collider和碰撞Collision不是同一个东西,有些人可能会考虑使用触发事件(假设已经点了is trigger),去完成这个反弹效果。
    • 但是请注意了,如果在unity中的实现,如果分开碰撞体和刚体组件就会造成这个触发问题(如下图

    ![请添加图片描述](https://img-blog.csdnimg.cn/66c8be7923574efcbfe620180a10ec42.png

    Tip
    我们实现物理移动,rigidbody组件是一定要选择跟我们的脚本挂载到同一个游戏对象,碰撞体在什么位置反而无所谓,只是不要想着可以通过GetComponentInChildrenGetComponentInParent取巧解决上面的结构问题,这样会造成不必要的工作量。

    3.2 老手和新手操作的区别点

    游戏是由事件驱动的,比如OnCollisionEnterOnTriggerEnter,对涉及到碰撞的事件可以通过以下两种方法实现:

    • 玩家触发,通过对tag的识别,更好的理解就是:我碰到小明,所以小明叫了我
    • 物体自身触发事件,也是对tag的识别,但是由物体自己主导,可以理解成:小明被我碰到了,所以叫了我

    老手的操作并不代表这一定好,只是这样更适合更加小型的项目,更方便我们聚合tag在一起,而如果我们选择把一个物体当成一个模块,意味着可以复用这些类型的预制体。

    一旦使用老手的操作,如果遇到需要改动或者弃用某些对象,可能会影响到相关的事件的判断,而且unity也对tags改名操作和弃用操作也不智能,选择新手的方式无疑更好。

    四、最终效果

    请添加图片描述

  • 相关阅读:
    mac os + python 新建环境 github仓库
    STM32实战总结:HAL之I2C
    机器学习day3
    十二条后端开发经验分享,纯干货
    深度清洁,清洗小物件的好助手——希亦CG超声波清洗机体验
    【小程序】常见系统API | 页面分享 | 位置信息 | 本地存储
    HotReload for unity支持的代码修改
    2022年最新吉林水利水电施工安全员模拟试题题库及答案
    每日三题 9.29
    视频转换器WinX HD Video Converter mac中文特点介绍
  • 原文地址:https://blog.csdn.net/kokool/article/details/133553177