Unity3D板球游戏投球逻辑:计算无抬升发射角度实现定点落地
解决方案:无上升轨迹的投球逻辑
核心公式推导
定义关键参数:
h:发射点与目标点的竖直高度差(发射点y坐标 - 目标点y坐标,正值)d:发射点与目标点的水平距离(x/z平面上的直线距离)v0:初始速度大小g:重力加速度(Unity中默认取Physics.gravity.y的绝对值,即9.81)
我们需要让初始速度的竖直分量向下(或水平),确保球发射后不会升高。推导过程以向下为正方向,最终转换为Unity的y轴向上坐标系:
- 运动时间
t由水平距离和水平速度分量vx决定:t = d / vx - 竖直方向位移满足:
h = vy * t + 0.5 * g * t²(vy为向下的速度分量) - 结合速度大小关系
vx² + vy² = v0²,代入化简得到关于k = vy/vx的一元二次方程:(g*d²/(2*v0²)) * k² + d*k + (g*d²/(2*v0²) - h) = 0 - 解此方程,取非负根(保证
vy向下,无上升阶段):a = g*d²/(2*v0²) b = d c = a - h discriminant = b² - 4*a*c k = [-b + sqrt(discriminant)]/(2*a) - 转换为Unity坐标系的速度分量(y轴向上,所以
vy为负):
水平方向的方向向量由发射点到目标点的水平方向确定,最终速度向量为:vx = v0 / sqrt(1 + k²) vy = -k * vx(dirX * vx, vy, dirZ * vx),其中dirX和dirZ是水平方向的单位向量分量。
Unity C# 实现脚本
挂载在球对象上的脚本,需确保球带有Rigidbody组件:
using UnityEngine; public class CricketBallLauncher : MonoBehaviour { [SerializeField] private float initialSpeed = 20f; [SerializeField] private Transform targetPoint; private Rigidbody rb; private void Awake() { rb = GetComponent<Rigidbody>(); } public void LaunchBall() { if (targetPoint == null) { Debug.LogError("Target point not assigned!"); return; } // 计算水平方向向量与距离、竖直高度差 Vector3 horizontalDir = targetPoint.position - transform.position; horizontalDir.y = 0; float d = horizontalDir.magnitude; float h = transform.position.y - targetPoint.position.y; if (d <= 0.01f) { Debug.LogError("Target is too close horizontally!"); return; } if (h < 0) { Debug.LogError("Target is higher than launch point!"); return; } float g = Mathf.Abs(Physics.gravity.y); float a = (g * d * d) / (2 * initialSpeed * initialSpeed); float b = d; float c = a - h; float discriminant = b * b - 4 * a * c; if (discriminant < 0) { Debug.LogError("No valid trajectory: initial speed is too low to reach target!"); return; } // 计算速度分量 float k = (-b + Mathf.Sqrt(discriminant)) / (2 * a); float vx = initialSpeed / Mathf.Sqrt(1 + k * k); float vy = -k * vx; // 构建最终发射速度向量 Vector3 horizontalUnitDir = horizontalDir.normalized; Vector3 launchVelocity = new Vector3(horizontalUnitDir.x * vx, vy, horizontalUnitDir.z * vx); // 重置球状态并施加速度 rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; rb.AddForce(launchVelocity, ForceMode.VelocityChange); } }
注意事项
- 目标点必须低于或等于发射点高度(
h ≥ 0),否则无法实现无上升轨迹。 - 若初始速度过小,会出现判别式为负的情况,此时无法到达目标,需增大初始速度。
- 脚本使用Unity默认重力,如需自定义重力,可修改
g的值并调整rb.useGravity的设置。
内容的提问来源于stack exchange,提问作者harshit joshi
相关产品推荐
相关产品推荐

