Unity 2D开发中如何根据距爆炸中心距离计算刚体作用力乘数
Unity 2D火箭跳跃动态爆炸力实现
问题原因
当前代码的力计算逻辑存在三个核心错误:
CalculateForceMultiplier直接返回距离值,逻辑反向:距离越远返回值越大,施加的力反而越高,和「近大远小」的预期完全相反- 弹射方向向量
launchPos未做归一化处理:向量本身的长度已经包含了距离信息,会导致力值计算重复叠加距离因子,数值完全不受控 - 缺少爆炸有效范围限制:力值没有上下限约束,手感无法稳定调优
实现思路
参考《军团要塞2》《雷神之锤》的火箭跳跃手感,采用范围钳制+比例衰减+可选非线性曲线的计算逻辑:
- 新增爆炸有效半径参数,超出半径的目标不受爆炸力
- 将玩家与爆炸点的距离钳制在
0~爆炸半径区间内,避免异常值 - 对弹射方向向量做归一化,仅保留方向信息,力的大小完全由输入参数控制
- 计算距离占爆炸半径的比例,用
1-距离比例得到基础衰减值,支持通过指数调整衰减曲线:- 指数为1时是线性衰减,力随距离均匀下降
- 指数大于1时是非线性衰减,贴脸推力拉满、距离稍远时力快速下降,匹配经典FPS火箭跳的爽感
修正后完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class HandleExplosion : MonoBehaviour { [SerializeField] float launchSpeed; [SerializeField] float explosionTime; [Header("爆炸力参数")] [Tooltip("爆炸有效作用半径")] [SerializeField] float explosionRadius = 4f; [Tooltip("衰减指数,1为线性,值越大近点推力越强、远距离衰减越快,经典火箭跳推荐1.5~2.5")] [SerializeField] float falloffExponent = 2f; private void Start() { StartCoroutine(DeleteExplosion()); } private void OnCollisionEnter2D(Collision2D player) { if (player.gameObject.CompareTag("Player")) { Rigidbody2D playerRb = player.gameObject.GetComponent<Rigidbody2D>(); // 计算从爆炸点指向玩家的方向,归一化后仅保留方向 Vector2 launchDir = (player.transform.position - transform.position).normalized; float forceMultiplier = CalculateForceMultiplier(player); // 施加冲量 playerRb.AddForce(launchDir * launchSpeed * forceMultiplier, ForceMode2D.Impulse); } } float CalculateForceMultiplier(Collision2D player) { // 计算两点距离 float distance = Vector2.Distance(player.transform.position, transform.position); // 将距离钳制在有效范围内,避免超出半径后出现负数、零距离除0等异常 distance = Mathf.Clamp(distance, 0f, explosionRadius); // 计算基础衰减比例 float falloffRatio = 1 - (distance / explosionRadius); // 应用指数曲线后返回最终乘数,范围固定在0~1之间 return Mathf.Pow(falloffRatio, falloffExponent); } IEnumerator DeleteExplosion() { yield return new WaitForSeconds(explosionTime); Destroy(gameObject); } }
调参参考
- 想要更接近《雷神之锤》的爽快手感:把
falloffExponent调到22.5,`explosionRadius`设为3.54.5,适当调高launchSpeed,贴脸弹射高度会非常高,距离爆炸点1个单位以上推力快速下降 - 想要更写实的爆炸效果:把
falloffExponent设为1,采用线性衰减即可 - 如果需要实现范围爆炸(不需要碰撞接触,只要在半径内就受推力),把
OnCollisionEnter2D的逻辑移到Start里,用Physics2D.OverlapCircleAll检测半径内所有带Player标签的物体逐一施加力即可
内容的提问来源于stack exchange,提问作者licco-twentythree
相关产品推荐
相关产品推荐

