You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity3D板球游戏投球逻辑:计算无抬升发射角度实现定点落地

解决方案:无上升轨迹的投球逻辑

核心公式推导

定义关键参数:

  • h:发射点与目标点的竖直高度差(发射点y坐标 - 目标点y坐标,正值)
  • d:发射点与目标点的水平距离(x/z平面上的直线距离)
  • v0:初始速度大小
  • g:重力加速度(Unity中默认取Physics.gravity.y的绝对值,即9.81)

我们需要让初始速度的竖直分量向下(或水平),确保球发射后不会升高。推导过程以向下为正方向,最终转换为Unity的y轴向上坐标系:

  1. 运动时间t由水平距离和水平速度分量vx决定:t = d / vx
  2. 竖直方向位移满足:h = vy * t + 0.5 * g * t²(vy为向下的速度分量)
  3. 结合速度大小关系vx² + vy² = v0²,代入化简得到关于k = vy/vx的一元二次方程:
    (g*d²/(2*v0²)) * k² + d*k + (g*d²/(2*v0²) - h) = 0
    
  4. 解此方程,取非负根(保证vy向下,无上升阶段):
    a = g*d²/(2*v0²)
    b = d
    c = a - h
    discriminant = b² - 4*a*c
    k = [-b + sqrt(discriminant)]/(2*a)
    
  5. 转换为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:36:26