【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;
        }
    }

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;
        }
    }
}

三、额外注意事项

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改名操作和弃用操作也不智能,选择新手的方式无疑更好。

四、最终效果

请添加图片描述

继续优化

最近看了很多codemonkey完整的付费的和免费教程,完全学到了人家几年的unity开发经验,废话不多说我们继续。

前面我实现的基本操作离不开tag,然而实际的游戏开发中我们应该要避免使用tag

小小码奴,你也不希望你未来会被成千上万个tag包围吧

那么好,我们修改的思路是什么,如果不用tag的话?

那么该怎么实现上面的步骤?

其实很简单,因为判断的依据是tag,就下面这段代码

if (other.gameObject.CompareTag("Player"))

无论是否把判断交给了弹跳平台,物体与物体之间的接触本质上就是碰撞,那么这玩意其实就好改了,不就是原来判断是否是tag,然后OnCollisionEnter接触。

现在变成是否可以射线检测碰撞嘛,你可以考虑直接物体下面搞多一条射线Physics.Raycast,如果想来个全身接触用个Physics.CapsuleCast函数就够了。

弹跳平台只用实现弹跳的功能,而玩家需要考虑的东西可就多了。

玩家判断完已经有物体碰撞接触了,还需要考虑是否得用上掩码图层特别判断,更麻烦的还要想想怎么优化弹跳的效果

if (Physics.Raycast(transform.position, moveDir, out RaycastHit raycastHit, JumpEffect_Distance, layerMasker)) {
    Debug.Log(raycastHit.transform);
    if(raycastHit.transform.TryGetComponent(out Bounch_Platform bounchPlatform)) {
        //bounchPlatform.实现弹跳功能的函数
    }
}

弹跳这项操作可以抽象成交互,游戏中的交互有很多,那么也就不限于弹跳,只要改动上面的这段逻辑,就适用所有要实现的交互功能。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值