【unity】用代码实现“碰到障碍后 运动对象的运动方向如何改变(反弹/滑行)”

想要实现的效果:

例1:飞出的弹丸,碰到墙壁后,反弹。【↘️| 】——>【↙️| 】

例2:向右下方【↘️】移动的对象,碰到右侧的墙壁 【↘️| 】 后,继续沿着着墙壁向下方移动【↓ | 】

 

为什么要用代码实现?

确实,一般来说使用刚体和碰撞器(Dynamic模式)的话Unity会负责物理碰撞的部分。 

但我的实现是用Kinematic X Static。敌人使用Kinematic 是因为需要控制他们各自不同的运动方式,所以碰到障碍物要绕行/滑行/反弹的话需要自己手动实现。

一、计算反射向量

无论要实现哪个效果都需要一个很重要的函数:根据入射向量,计算反射向量。(见下图)

原本的运动方向是inDirection,再提供一个碰撞法线inNormal,就可以得到反射向量啦。

 

用法很简单:

Vector3 reflectDir = Vector3.Reflect(OrgDir, normal);//OrgDir是原本的运动方向向量,normal是碰撞表面的法线

那么,碰撞表面的法线inNormal要怎样得到?

我只记录我有在使用的两种方式,应该可以满足大部分需求。

1.有发生实际碰撞:

在脚本中使用碰撞检测,可以得到碰撞点信息:

protected ContactPoint2D contactPoint;//用这个变量保存碰撞点信息

protected void OnCollisionEnter2D(Collision2D collision)
{
     contactPoint = collision.GetContact(0); //这个函数用来获取发生碰撞的点。因为它可能会是一个点的集合,我只需要一个就可以了,所以取第一个。
}

contackPoint.normal 就是法线。

reflectDir = Vector2.Reflect(orgDir, contactPoint.normal);

 2.未发生实际碰撞

有一些情况需要在发生实际碰撞之前,先去检测会不会发生碰撞(未雨绸缪)。

比如对象看到运动方向前面有障碍物,它会提前绕行,而不是撞到以后再改变运动方向。

这种情况可以使用Cast函数,unity提供了多种Cast函数。比如:

关于射线的更多内容可以参考这个⬇️,不再这篇多做赘述。【Unity2D】射线·碰撞投射·方法总结_unity raycasthit2d-CSDN博客文章浏览阅读4.8k次,点赞6次,收藏24次。射线:Physics2D.Raycast( )必须参数:起点、方向可选参数:距离、Z轴深度、过滤条件(检测哪些层、是否检测触发碰撞器等)out 参数:RaycastHit2D[ ] (存放碰撞返回的结果)返回值:int (表示碰撞结果的个数)/ RaycastHit2D(射线碰撞的结果)备注:如果射线从碰撞体内部发出,可以使用collider2d.Raycast( )方法手册链接:Physics2D-Raycast - Unity 脚本 API与碰撞体相关的射线/投射:._unity raycasthit2dhttps://blog.csdn.net/yjy99yjy999/article/details/124551072?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171535726816800213068639%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171535726816800213068639&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-124551072-null-null.nonecase&utm_term=cast&spm=1018.2226.3001.4450这里我使用了 Rigidbody2D.Cast 函数。

    //用一个数组保存投射的结果,这里我设定数组长度为10个    
    RaycastHit2D[] hits = new RaycastHit2D[10];

    //检测对象运动方向上有没有障碍物,检测距离为dist,n表示检测到的碰撞数量
    //contactFilter_obstacle 是提前设定好的过滤条件,如何设置要根据需求而定
    public bool HasObstacle(Vector2 orgDir, float dist)
    {
        int n = m_rigidbody.Cast(orgDir, contactFilter_obstacle, hits, dist);
        return n != 0;
    }

Cast函数将碰撞结果保存在 hits 数组中,hits[0].normal 就是我们需要的法线。

二、对象碰撞后的运动方向

有了反射向量就很简单了。

要实现例1反弹效果的话,直接使用反射向量即可。

要实现例2贴墙继续走的话,用 OrgDir + ReflectDir 即可。注意实现时,要保持同之前运动相同的速度,就需要一些细节了,比如这样:

//入射与反射向量相加后,把向量归一化。再乘以原本要移动的距离。避免对象的运动速度骤减或突然翻倍
return (orgDir + reflectDir).normalized * moveLength;
  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Unity3D中使用集群算法模拟鱼群运动,可以按照以下步骤编写代码: 1. 创建一个鱼的预制体(Prefab),包含鱼的模型和相应的脚本组件。 2. 在鱼的脚本中,添加以下代码: ```csharp using UnityEngine; public class Fish : MonoBehaviour { public Transform target; // 集群中心点 public float cohesionWeight = 1f; // 聚集权重 public float alignmentWeight = 1f; // 对齐权重 public float separationWeight = 1f; // 分离权重 public float maxSpeed = 2f; // 最大速度 public float maxForce = 0.1f; // 最大力 private Rigidbody rb; private void Start() { rb = GetComponent<Rigidbody>(); } private void Update() { Vector3 cohesionForce = Vector3.zero; Vector3 alignmentForce = Vector3.zero; Vector3 separationForce = Vector3.zero; int cohesionCount = 0; int alignmentCount = 0; int separationCount = 0; foreach (Collider collider in Physics.OverlapSphere(transform.position, 5f)) // 选择附近的鱼 { if (collider.gameObject != gameObject) { Fish otherFish = collider.gameObject.GetComponent<Fish>(); if (otherFish != null) { cohesionForce += otherFish.transform.position; cohesionCount++; alignmentForce += otherFish.rb.velocity; alignmentCount++; if (Vector3.Distance(transform.position, otherFish.transform.position) < 1f) // 如果太近,远离 { separationForce += transform.position - otherFish.transform.position; separationCount++; } } } } if (cohesionCount > 0) { cohesionForce /= cohesionCount; cohesionForce = (cohesionForce - transform.position).normalized; } if (alignmentCount > 0) { alignmentForce /= alignmentCount; alignmentForce = alignmentForce.normalized; } if (separationCount > 0) { separationForce /= separationCount; separationForce = separationForce.normalized; } Vector3 totalForce = cohesionForce * cohesionWeight + alignmentForce * alignmentWeight + separationForce * separationWeight; Vector3 clampedForce = Vector3.ClampMagnitude(totalForce, maxForce); rb.AddForce(clampedForce); // 限制速度 rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed); } } ``` 3. 在场景中实例化多只鱼预制体,并将它们添加到场景中。 4. 调整鱼的脚本中的各种参数,如聚集权重、对齐权重、分离权重、最大速度和最大力等,以获得期望的集群运动效果。 5. 运行游戏,观察鱼的集群运动效果。 这段代码实现了鱼使用集群算法进行群体运动。在Update方法中,鱼会计算与其他鱼之间的距离,并根据距离和设定的参数计算聚集、对齐和分离的力,然后将这些力施加到鱼的刚体上,使其产生运动。你可以根据自己的需求调整参数以获得期望的集群运动效果。希望对你有所帮助!如果有更多问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值