Unity 抛物线

几何抛物线

cs 复制代码
using UnityEngine;
namespace GameLogic
{
    /// <summary>
    /// 几何抛物线
    /// </summary>
    public class GeometryParabola : MonoBehaviour
    {
        public Vector3 target = Vector3.zero;
        [Range(1, 256)]
        [SerializeField] int resolution = 50; // 轨迹分辨率
        [Range(3.25f, 6.8f)]
        [SerializeField] float height = 3.25f; // 抛物线高度
        [Range(0.5f, 40f)]
        [SerializeField] float moveSpeed = 23.4f; // 移动速度

        private Vector3[] parabolaPoints;
        private float currentDistance = 0f;
        private float totalDistance = 0f;
        private bool isMoving = false;
        private float startTime = 0f; // 开始移动的时间
        
        [Header("超时回收设置")]
        [SerializeField] private float maxLifetime = 15f; // 最大生存时间(秒)
        private float currentLifetime = 0f;

        /// <summary>
        /// UFO到达终点时的回调(由对象池调用者设置)
        /// </summary>
        public System.Action OnComplete;

        private const float MinHeight = 3.25f;
        private const float MaxHeight = 6.8f;
        private void Start()
        {
            // 不再自动启动,由Initialize方法控制
        }

        private void Update()
        {
            if (isMoving)
            {
                // 更新生存时间
                currentLifetime += Time.deltaTime;
                
                // 检查是否超时
                if (currentLifetime >= maxLifetime)
                {
                    Debug.LogWarning($"[UFO超时回收] UFO已存活{currentLifetime:F2}秒,超过最大生存时间{maxLifetime}秒,强制回收");
                    isMoving = false;
                    ReturnToPool();
                    return;
                }
                
                MoveAlongParabola();
            }
        }

        public void SetData(float distance,float axisAngle,float _height,float _moveSpeed)
        {
            target = TargetPosition(distance, axisAngle);
            height = RangeMapper.MapRangeClamped(_height, 1.5f, 3.0f, MinHeight, MaxHeight);
            moveSpeed = _moveSpeed;
        }
        private Vector3 TargetPosition(float distance,float angleDegrees)
        {
            // 当前位置
            Vector3 currentPosition = transform.position;
            // 通过四元数旋转forward向量
            Quaternion qua = Quaternion.Euler(0, angleDegrees, 0);
            Vector3 forwardDir = qua * transform.forward;
            Vector3 targetPosition = currentPosition + forwardDir * distance;

            // 可视化
            Debug.DrawLine(currentPosition, targetPosition, Color.red, 2f);
            return targetPosition;
        }
        public void StartMovement()
        {
            currentDistance = 0f;
            currentLifetime = 0f; // 重置生存时间计时器
            isMoving = true;
            startTime = Time.time;

            // 生成抛物线点
            GenerateParabolaPoints();
            
            Debug.Log($"[UFO启动] UFO开始移动,最大生存时间: {maxLifetime}秒");
        }

        /// <summary>
        /// 预测飞盘在指定时间后的位置(用于碰撞预判)
        /// </summary>
        public Vector3 PredictPositionAtTime(float time)
        {
            if (!isMoving || parabolaPoints == null || parabolaPoints.Length < 2)
                return transform.position;

            // 计算从开始到指定时间的距离
            float predictedDistance = currentDistance + (moveSpeed * time);
            
            // 计算进度百分比
            float t = Mathf.Clamp01(predictedDistance / totalDistance);
            
            // 返回预测位置
            return GetPositionOnParabola(t);
        }

        /// <summary>
        /// 获取飞盘当前速度(基于轨迹切线方向)
        /// </summary>
        public Vector3 GetCurrentVelocity()
        {
            if (!isMoving || parabolaPoints == null || parabolaPoints.Length < 2)
                return Vector3.zero;

            float t = Mathf.Clamp01(currentDistance / totalDistance);
            
            // 获取当前位置和稍后位置来计算速度方向
            Vector3 currentPos = GetPositionOnParabola(t);
            Vector3 nextPos = GetPositionOnParabola(Mathf.Min(t + 0.01f, 1f));
            
            Vector3 direction = (nextPos - currentPos).normalized;
            return direction * moveSpeed;
        }

        /// <summary>
        /// 获取飞盘半径(用于碰撞检测)
        /// </summary>
        public float GetDiscRadius()
        {
            SphereCollider sphereCol = GetComponent<SphereCollider>();
            if (sphereCol != null)
                return sphereCol.radius * transform.localScale.x;

            // 默认半径
            return 0.15f;
        }

        /// <summary>
        /// 是否正在移动
        /// </summary>
        public bool IsMoving()
        {
            return isMoving;
        }

        /// <summary>
        /// 获取轨迹点数组(用于高级预测)
        /// </summary>
        public Vector3[] GetParabolaPoints()
        {
            return parabolaPoints;
        }

        /// <summary>
        /// 获取当前进度(0-1)
        /// </summary>
        public float GetProgress()
        {
            if (totalDistance <= 0) return 0;
            return Mathf.Clamp01(currentDistance / totalDistance);
        }

        private void GenerateParabolaPoints()
        {
            if (target == Vector3.zero) return;
            Vector3 pos0 = transform.position;
            Vector3 pos1 = target;

            float deltaX = (pos1.x - pos0.x) / resolution;
            float deltaZ = (pos1.z - pos0.z) / resolution;

            float p, a, b, c = pos1.y - pos0.y;
            float h = c <= height ? height : c;
            parabolaPoints = new Vector3[resolution + 1];

            if (Mathf.Approximately(c, 0))
            {
                a = (pos0.x - pos1.x) * 0.5f;
                b = -a;
                p = a * a / (-4 * h);

                if (Mathf.Approximately(p, 0))
                {
                    // 直线情况
                    GenerateStraightLine();
                    return;
                    p = 0.1f; // 设置一个小的p值

                }
            }
            else
            {
                p = pos0.x - pos1.x;
                p /= Mathf.Sqrt(4 * h) + Mathf.Sqrt(4 * (h - c));
                p *= -p;

                if (Mathf.Approximately(p, 0))
                {
                    // 直线情况
                    GenerateStraightLine();
                    return;
                    p = 0.1f; // 

                }

                a = deltaX >= 0 ? -Mathf.Sqrt(4 * p * -h) : Mathf.Sqrt(4 * p * -h);
                b = deltaX >= 0 ? Mathf.Sqrt(4 * p * (c - h)) : -Mathf.Sqrt(4 * p * (c - h));
            }

            // 生成抛物线点
            parabolaPoints[0] = pos0;
            parabolaPoints[resolution] = pos1;
            float currentDistance = 0f;
            for (int i = 1; i < resolution; i++)
            {
                float x = a + (deltaX * i);
                float y = x * x / (4 * p) + h;

                float normalizedX = pos0.x + x - a;
                float normalizedZ = pos0.z + (deltaZ * i);
                float normalizedY = pos0.y + y;

                parabolaPoints[i] = new Vector3(normalizedX, normalizedY, normalizedZ);


                #region 10米处的高度
                // 计算当前点到前一个点的距离
                float segmentDistance = Vector3.Distance(parabolaPoints[i - 1], parabolaPoints[i]);
                currentDistance += segmentDistance;
                //Debug.Log($"currentDistance : {currentDistance}");
                // 在10米处打印高度
                if (Mathf.Abs(currentDistance - 10f) < 1f) // 使用更精确的范围
                {
                    Debug.Log($"在10米处: 点{i}, 世界高度={normalizedY:F2}米, 局部高度={y:F2}, 累计距离={currentDistance:F2}米");
                    // 如果想要更精确的10米点,可以插值计算
                    float exact10mDistance = 10f;
                    if (i > 0)
                    {
                        float overshoot = currentDistance - exact10mDistance;
                        if (overshoot > 0 && overshoot < segmentDistance)
                        {
                            float t = 1f - (overshoot / segmentDistance);
                            Vector3 exact10mPoint = Vector3.Lerp(parabolaPoints[i - 1], parabolaPoints[i], t);
                            Debug.Log($"精确10米点: 位置={exact10mPoint}, 高度={exact10mPoint.y:F2}米");
                        }
                    }
                }
                #endregion
            }

            // 计算总距离
            totalDistance = 0f;
            for (int i = 1; i < parabolaPoints.Length; i++)
            {
                totalDistance += Vector3.Distance(parabolaPoints[i - 1], parabolaPoints[i]);
            }
        }
        /*  private void GenerateParabolaPoints()
          {
              if (target == Vector3.zero) return;
              Vector3 pos0 = transform.position;
              Vector3 pos1 = target;

              parabolaPoints = new Vector3[resolution + 1];

              // 计算水平距离
              Vector3 horizontalDir = new Vector3(pos1.x - pos0.x, 0, pos1.z - pos0.z);
              float horizontalDistance = horizontalDir.magnitude;
              horizontalDir.Normalize();

              // 控制点(抛物线顶点)
              Vector3 controlPoint = (pos0 + pos1) * 0.5f;
              controlPoint.y = Mathf.Max(pos0.y, pos1.y, height) + 1.0f;

              // 生成抛物线点(贝塞尔曲线)
              for (int i = 0; i <= resolution; i++)
              {
                  float t = i / (float)resolution;

                  // 二次贝塞尔曲线
                  float u = 1 - t;
                  float tt = t * t;
                  float uu = u * u;

                  Vector3 point = uu * pos0;
                  point += 2 * u * t * controlPoint;
                  point += tt * pos1;

                  parabolaPoints[i] = point;
              }

              // 计算总距离
              totalDistance = 0f;
              for (int i = 1; i < parabolaPoints.Length; i++)
              {
                  totalDistance += Vector3.Distance(parabolaPoints[i - 1], parabolaPoints[i]);
              }
          }*/

        private void GenerateStraightLine()
        {
            parabolaPoints = new Vector3[2];
            parabolaPoints[0] = transform.position;
            parabolaPoints[1] = target;
            totalDistance = Vector3.Distance(parabolaPoints[0], parabolaPoints[1]);
        }


        private void MoveAlongParabola()
        {
            if (parabolaPoints == null || parabolaPoints.Length < 2) return;

            // 更新当前距离
            currentDistance += moveSpeed * Time.deltaTime;

            // 计算进度百分比
            float t = Mathf.Clamp01(currentDistance / totalDistance);

            // 根据进度获取抛物线上的位置
            Vector3 newPosition = GetPositionOnParabola(t);

            // 更新飞碟位置
            transform.position = newPosition;

            // 计算并应用朝向
            if (t < 0.99f)
            {
                Vector3 nextPosition = GetPositionOnParabola(t + 0.01f);
                Vector3 direction = (nextPosition - newPosition).normalized;

                if (direction != Vector3.zero)
                {
                    transform.rotation = Quaternion.LookRotation(direction);
                }
            }

            // 检查是否到达终点
            if (t >= 1f)
            {
                isMoving = false;
                transform.position = target;
                ReturnToPool();
                Debug.Log("Reached destination!");
            }
        }
      
        /// <summary>
        /// 回收UFO到对象池(通过回调)
        /// </summary>
        private void ReturnToPool()
        {
            OnComplete?.Invoke();
            OnComplete = null;
        }

        private Vector3 GetPositionOnParabola(float t)
        {
            if (parabolaPoints == null || parabolaPoints.Length < 2)
                return transform.position;

            // 将t值映射到轨迹点的索引
            float segmentLength = 1f / (parabolaPoints.Length - 1);
            int segmentIndex = Mathf.FloorToInt(t / segmentLength);

            if (segmentIndex >= parabolaPoints.Length - 1)
                return parabolaPoints[parabolaPoints.Length - 1];

            // 计算在段内的插值参数
            float segmentT = (t - (segmentIndex * segmentLength)) / segmentLength;

            // 线性插值
            return Vector3.Lerp(parabolaPoints[segmentIndex], parabolaPoints[segmentIndex + 1], segmentT);
        }

  

        // 可视化轨迹点(用于调试)
        private void OnDrawGizmos()
        {
            if (parabolaPoints == null || parabolaPoints.Length < 2) return;

            Gizmos.color = Color.green;
            for (int i = 0; i < parabolaPoints.Length - 1; i++)
            {
                Gizmos.DrawSphere(parabolaPoints[i], 0.1f);
                Gizmos.DrawLine(parabolaPoints[i], parabolaPoints[i + 1]);
            }
            Gizmos.DrawSphere(parabolaPoints[parabolaPoints.Length - 1], 0.1f);
        }
    }
    public class RangeMapper 
    {

        /// <summary>
        /// 将一个值从一个范围映射到另一个范围
        /// </summary>
        public static float MapRange(float value, float inMin, float inMax, float outMin, float outMax)
        {
            // 先将输入值标准化到0-1范围
            float normalized = Mathf.InverseLerp(inMin, inMax, value);
            // 再映射到输出范围
            float result = Mathf.Lerp(outMin, outMax, normalized);

            // 四舍五入到小数点后一位
            return Mathf.Round(result * 100f) / 100f;
        }

        /// <summary>
        /// 带自动限制的版本
        /// </summary>
        public static float MapRangeClamped(float value, float inMin, float inMax, float outMin, float outMax)
        {
            // 限制输入值在原始范围内
            float clampedValue = Mathf.Clamp(value, inMin, inMax);
            float mappedValue = MapRange(clampedValue, inMin, inMax, outMin, outMax);

            // 四舍五入到小数点后一位
            return Mathf.Round(mappedValue * 100f) / 100f;
        }
    }
}

物理抛物线

cs 复制代码
using UnityEngine;
namespace GameLogic
{
  
    public class MultipleDirLauncher : DicsusLauncherBase
    {
        [Header("目标参数")]
        [SerializeField] private float targetDistance = 10f;  // 10米处检测高度
        [SerializeField] private float minHeight = 1.5f;     // 最小高度
        [SerializeField] private float maxHeight = 3.0f;     // 最大高度
        [SerializeField] private float heightTolerance = 0.15f; // 高度允许误差

        [SerializeField] private float targetRange = 76f;    // 目标射程
        [SerializeField] private float rangeTolerance = 1f;  // 射程允许误差

        [Header("物理参数")]
        [SerializeField] private float customGravity = 9.81f;      // 自定义重力加速度

        [Header("发射控制")]
        [SerializeField] private float launchHeight = 12f;    // 垂直发射角度(度)
        [SerializeField] private float horizontalAngle = 0f; // 水平发射方向角(度),正值向右,负值向左
        [SerializeField] private float initialVelocity = 0f;  // 计算出的初速度
        [SerializeField] private float configuredSpeed = 0f;  // 外部设置的初速度

        [Header("飞行姿态控制")]
        [SerializeField] private float flightPitchAngle = 0f; // 飞行过程中的俯仰角度(相对于水平面,-45° 到 45°)
        [SerializeField] private float rotationSmoothness = 5f; // 旋转平滑度
        [SerializeField] private bool maintainFlightPitch = true; // 是否保持飞行俯仰角

        [Header("回收控制")]
        [SerializeField] private float groundHeight = 0f;    // 地面高度
        [SerializeField] private float recycleDelay = 0.5f;  // 落地后延迟回收时间

        [Header("调试显示")]
        [SerializeField] private bool showTrajectory = true;
        [SerializeField] private int trajectoryPoints = 50;
        [SerializeField] private Color trajectoryColor = Color.yellow;

        private Rigidbody rb;
        private Vector3 lastVelocity = Vector3.zero;
        private float originalCustomGravity;
        private bool hasSlowMotionGravity;

        private Vector3 launchStartPosition = Vector3.zero;
        private bool isLaunched = false;
        private float launchTime = 0f; // 发射时间
        bool isInit = false;
        private const float MinHeight = 8f;
        private const float MaxHeight = 20f;
        
        // 记录外部设置的目标高度(10米处)
        private float targetHeightAt10m = 2.25f; // 默认中间值

        void Start()
        {
            Initialize();
            //LaunchDisc();
        }
        void Initialize() 
        {
            if (isInit)
                return;
            isInit = true;
            rb = GetComponent<Rigidbody>();
            if (rb == null)
            {
                rb = gameObject.AddComponent<Rigidbody>();
            }

            SetupPhysics();
            launchStartPosition = transform.position;
        }
        void FixedUpdate()
        {
            // 应用自定义重力
            if (isLaunched)
            {
                rb.AddForce(Vector3.down * customGravity, ForceMode.Acceleration);
                RecordTrajectoryFrame(rb);
                
                if (maintainFlightPitch)
                {
                    MaintainFlightPitch();
                }
            }
        }
        /// <summary>
        /// 重置飞碟状态
        /// </summary>
        public void ResetDisc()
        {
            isLaunched = false;
            rb.velocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            transform.position = launchStartPosition;
            transform.rotation = Quaternion.identity;
        }
        /// <summary>
        /// 保持飞行过程中的俯仰角
        /// 限制:飞碟前向量与速度方向的夹角必须在 -45° 到 45° 范围内
        /// </summary>
        private void MaintainFlightPitch()
        {
            if (rb.velocity.magnitude > 0.1f)
            {
                // 计算目标方向(速度方向 + 俯仰角调整)
                Vector3 velocityDir = rb.velocity.normalized;
                
                // 获取水平方向
                Vector3 horizontalVelocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
                
                if (horizontalVelocity.magnitude > 0.1f)
                {
                    // 计算水平朝向
                    Vector3 horizontalDir = horizontalVelocity.normalized;
                    
                    // 应用俯仰角调整
                    Quaternion horizontalRotation = Quaternion.LookRotation(horizontalDir);
                    Quaternion desiredRotation = horizontalRotation * Quaternion.Euler(flightPitchAngle, 0f, 0f);
                    
                    // 计算期望的前向量
                    Vector3 desiredForward = desiredRotation * Vector3.forward;
                    
                    // 计算前向量与速度方向的夹角
                    float angleToVelocity = Vector3.SignedAngle(
                        new Vector3(velocityDir.x, 0, velocityDir.z).normalized,  // 速度的水平分量
                        new Vector3(desiredForward.x, 0, desiredForward.z).normalized,  // 前向量的水平分量
                        Vector3.up
                    );
                    
                    // 限制夹角在 -45° 到 45° 之间
                    if (Mathf.Abs(angleToVelocity) > 45f)
                    {
                        // 如果超出范围,调整俯仰角使夹角不超过45°
                        float correction = Mathf.Sign(angleToVelocity) * (Mathf.Abs(angleToVelocity) - 45f);
                        float adjustedPitch = flightPitchAngle - correction;
                        desiredRotation = horizontalRotation * Quaternion.Euler(adjustedPitch, 0f, 0f);
                        
                        if (Time.frameCount % 30 == 0)
                        {
                            Debug.Log($"[FlyingDiscLauncher] 夹角超限:{angleToVelocity:F1}° -> 调整俯仰角:{flightPitchAngle:F1}° -> {adjustedPitch:F1}°");
                        }
                    }
                    
                    // 平滑旋转到目标方向
                    rb.rotation = Quaternion.Slerp(rb.rotation, desiredRotation,
                                                  rotationSmoothness * Time.fixedDeltaTime);
                }
            }
        }
        void SetupPhysics()
        {
            rb.useGravity = false;  // 关闭Unity重力,使用自定义重力
            rb.drag = 0f;
            rb.angularDrag = 0.05f;
        }

        /// <summary>
        /// 计算满足76米射程所需初速度
        /// </summary>
        float CalculateVelocityForRange(float angleDeg, float range)
        {
            float angleRad = angleDeg * Mathf.Deg2Rad;
            float sin2Theta = Mathf.Sin(2f * angleRad);

            if (sin2Theta <= 0.001f)
            {
                Debug.LogWarning("角度太小或接近0/90度,射程公式不适用");
                return 0f;
            }

            float originalVelocity = Mathf.Sqrt((customGravity * range) / sin2Theta);
            return originalVelocity;
        }

        /// <summary>
        /// 计算在10米处的高度
        /// </summary>
        float CalculateHeightAt10m(float angleDeg, float velocity)
        {
            float angleRad = angleDeg * Mathf.Deg2Rad;
            float x = 10f;

            float term1 = x * Mathf.Tan(angleRad);
            float term2 = (customGravity * x * x) / (2f * velocity * velocity * Mathf.Cos(angleRad) * Mathf.Cos(angleRad));

            return term1 - term2;
        }

        /// <summary>
        /// 自动选择合适角度满足高度约束
        /// </summary>
        float FindOptimalAngle(float desiredHeight = 2.25f)
        {
            // 使用公式: y = tanθ * (10 - 100/R)
            float R = targetRange;
            float k = 10f - 100f / R;

            // 所需tanθ
            float tanTheta = desiredHeight / k;
            float angle = Mathf.Atan(tanTheta) * Mathf.Rad2Deg;

            return angle;
        }

        /// <summary>
        /// 验证参数是否在允许范围内
        /// </summary>
        bool ValidateParameters(float angleDeg, float velocity)
        {
            // 计算10米处高度
            float heightAt10m = CalculateHeightAt10m(angleDeg, velocity);

            // 计算射程
            float angleRad = angleDeg * Mathf.Deg2Rad;
            float range = (velocity * velocity * Mathf.Sin(2f * angleRad)) / customGravity;

            // 检查高度约束
            float minAllowedHeight = minHeight - heightTolerance;
            float maxAllowedHeight = maxHeight + heightTolerance;
            bool heightValid = (heightAt10m >= minAllowedHeight) && (heightAt10m <= maxAllowedHeight);

            // 检查射程约束
            float minRange = targetRange - rangeTolerance;
            float maxRange = targetRange + rangeTolerance;
            bool rangeValid = (range >= minRange) && (range <= maxRange);

          /*  Debug.Log($"角度: {angleDeg:F2}°, 速度: {velocity:F2} m/s");
            Debug.Log($"10米处高度: {heightAt10m:F2}m, 允许范围: [{minAllowedHeight:F2}, {maxAllowedHeight:F2}] - {(heightValid ? "通过" : "不通过")}");
            Debug.Log($"射程: {range:F2}m, 允许范围: [{minRange:F2}, {maxRange:F2}] - {(rangeValid ? "通过" : "不通过")}");*/

            return heightValid && rangeValid;
        }

    

        /// <summary>
        /// 获取飞盘当前速度
        /// </summary>
        public Vector3 GetCurrentVelocity()
        {
            return rb != null ? rb.velocity : Vector3.zero;
        }

        /// <summary>
        /// 获取飞盘半径(用于碰撞检测)
        /// </summary>
        public float GetDiscRadius()
        {
            // 假设飞盘是圆形,返回碰撞体半径
            SphereCollider sphereCol = GetComponent<SphereCollider>();
            if (sphereCol != null)
                return sphereCol.radius * transform.localScale.x;

            // 默认半径
            return 0.15f;
        }

        /// <summary>
        /// 是否已发射
        /// </summary>
        public bool IsLaunched()
        {
            return isLaunched;
        }

        /// <summary>
        /// 发射飞碟
        /// </summary>
        public override void LaunchDisc()
        {
            Initialize();
            isLaunched = true;
            launchTime = Time.time;
            launchStartPosition = transform.position;
            
            ApplyConfiguredSpeed();

            // 设置速度
            float verticalAngleRad = launchHeight * Mathf.Deg2Rad;
            float horizontalAngleRad = horizontalAngle * Mathf.Deg2Rad;

            // 计算速度分量
            float verticalSpeed = initialVelocity * Mathf.Sin(verticalAngleRad);
            float horizontalSpeed = initialVelocity * Mathf.Cos(verticalAngleRad);

            // 根据水平角度计算X和Z方向速度
            lastVelocity = new Vector3(
                horizontalSpeed * Mathf.Sin(horizontalAngleRad),  // X方向:左右
                verticalSpeed,                                     // Y方向:上下
                horizontalSpeed * Mathf.Cos(horizontalAngleRad)   // Z方向:前后
            );
            rb.velocity = lastVelocity;
            SetTrajectoryMotionParams(p =>
            {
                p.initialVelocity = lastVelocity;
                p.initialSpeed = lastVelocity.magnitude;
                p.horizontalSpeed = horizontalSpeed;
                p.verticalSpeed = verticalSpeed;
                p.customGravity = customGravity;
                p.drag = rb.drag;
                p.angularDrag = rb.angularDrag;
                p.launchAngle = launchHeight;
                p.horizontalAngle = horizontalAngle;
                p.pitchAngle = flightPitchAngle;
                p.calculatedGravity = customGravity;
            });

            // 计算并打印实际的10米处高度
            float actualHeightAt10m = CalculateHeightAt10m(launchHeight, initialVelocity);
            
            // 计算理论飞行时间和射程
            float flightTime = (2f * verticalSpeed) / customGravity;
            float theoreticalRange = horizontalSpeed * flightTime;
            
            /*Debug.Log($"[PhysicsParabola] 发射参数:");
            Debug.Log($"  - 垂直角度: {launchHeight:F2}°, 水平角度: {horizontalAngle:F2}°");
            Debug.Log($"  - 初速度: {initialVelocity:F2} m/s (水平: {horizontalSpeed:F2} m/s, 垂直: {verticalSpeed:F2} m/s)");
            Debug.Log($"  - 重力: {customGravity:F2} m/s²");
            Debug.Log($"  - 10米处高度: {actualHeightAt10m:F2}m (目标: {targetHeightAt10m:F2}m)");
            Debug.Log($"  - 理论飞行时间: {flightTime:F2}s");
            Debug.Log($"  - 理论射程: {theoreticalRange:F2}m (目标: {targetRange:F2}m)");*/

            // 验证最终参数(仅用于调试,不再自动调整)
            ValidateParameters(launchHeight, initialVelocity);
        }

        /// <summary>
        /// 设置高度
        /// </summary>
        public override void SetHeight(float height)
        {
            // 记录目标高度(10米处)
            targetHeightAt10m = height;
            
            // 根据目标高度计算发射角度
            launchHeight = MapRangeClamped(height, 1.5f, 3.0f, MinHeight, MaxHeight);
            
            // 重要:根据新角度重新计算所需的重力值,确保射程为76米
            // 使用迭代法找到满足两个约束的重力值:
            // 1. 射程 = 76米
            // 2. 10米处高度 = targetHeightAt10m
            
            float bestGravity = 9.81f;
            float minError = float.MaxValue;
            
            // 在合理范围内搜索重力值(5 ~ 50 m/s²),使用更精细的步长
            for (float testGravity = 5f; testGravity <= 50f; testGravity += 0.1f)
            {
                // 临时设置重力
                float tempGravity = testGravity;
                
                // 计算该重力下满足76米射程的速度
                float angleRad = launchHeight * Mathf.Deg2Rad;
                float sin2Theta = Mathf.Sin(2f * angleRad);
                if (sin2Theta <= 0.001f) continue;
                
                float testVelocity = Mathf.Sqrt((tempGravity * targetRange) / sin2Theta);
                
                // 计算10米处高度
                float x = 10f;
                float term1 = x * Mathf.Tan(angleRad);
                float term2 = (tempGravity * x * x) / (2f * testVelocity * testVelocity * Mathf.Cos(angleRad) * Mathf.Cos(angleRad));
                float heightAt10m = term1 - term2;
                
                // 计算误差
                float error = Mathf.Abs(heightAt10m - targetHeightAt10m);
                
                if (error < minError)
                {
                    minError = error;
                    bestGravity = tempGravity;
                }
            }
            
            // 应用找到的最佳重力值
            customGravity = bestGravity;
            
            // 验证结果
            float finalVelocity = CalculateVelocityForRange(launchHeight, targetRange);
            float finalHeightAt10m = CalculateHeightAt10m(launchHeight, finalVelocity);
            
         /*   Debug.Log($"[PhysicsParabola] 设置目标高度: {targetHeightAt10m:F2}m");
            Debug.Log($"[PhysicsParabola] 计算结果: 角度={launchHeight:F2}°, 重力={customGravity:F2} m/s², 初速度={finalVelocity:F2} m/s");
            Debug.Log($"[PhysicsParabola] 验证: 10米处高度={finalHeightAt10m:F2}m (误差: {Mathf.Abs(finalHeightAt10m - targetHeightAt10m):F4}m)");*/
        }

        /// <summary>
        /// 设置发射方向
        /// </summary>
        public override void SetHorizontalAngle(float angle)
        {
            horizontalAngle = Mathf.Clamp(angle, -45f, 45f);
            //Debug.Log($"水平角度设置为: {horizontalAngle}°");
        }

        private static float MapRangeClamped(float value, float inMin, float inMax, float outMin, float outMax)
        {
            if (Mathf.Approximately(inMin, inMax))
                return outMin;

            float t = Mathf.InverseLerp(inMin, inMax, value);
            return Mathf.Lerp(outMin, outMax, t);
        }

        /// <summary>
        /// 设置飞行俯仰角(限制在 -45° 到 45° 之间)
        /// </summary>
        public override void SetPitchAngle(float angle)
        {
            flightPitchAngle = Mathf.Clamp(angle, -45f, 45f);
           // Debug.Log($"[FlyingDiscLauncher] 飞行俯仰角设置为: {flightPitchAngle}°");
        }

        /// <summary>
        /// 设置初速度,由DicsusShooterV2统一控制
        /// </summary>
        public override void SetSpeed(float speed)
        {
            configuredSpeed = Mathf.Max(0.01f, speed);
            ApplyConfiguredSpeed();
        }

        /// <summary>
        /// 设置初速度(通过速度倍率控制快慢)
        /// 保持射程76米和10米处高度不变(使用外部通过SetHeight设置的高度)
        /// </summary>
        /// <param name="speedMultiplier">速度倍率(1.0为正常速度,>1更快,<1更慢)</param>
        public override void SetSpeedMultiplier(float speedMultiplier)
        {
            // 限制倍率在合理范围内
            speedMultiplier = Mathf.Clamp(speedMultiplier, 0.01f, 2.0f);
            
            // 调整重力:速度变为k倍,重力变为k²倍
            customGravity = 9.81f * speedMultiplier * speedMultiplier;
            
            // 使用迭代法找到合适的角度,使得在新速度和新重力下:
            // 1. 射程仍为76米
            // 2. 10米处高度保持为外部设置的targetHeightAt10m
            
            float bestAngle = launchHeight;
            float minError = float.MaxValue;
            
            // 在合理范围内搜索角度,使用更精细的步长
            for (float testAngle = 8f; testAngle <= 20f; testAngle += 0.05f)
            {
                // 计算该角度下满足76米射程的速度
                // 注意:CalculateVelocityForRange已经使用了调整后的customGravity
                // 所以这里不需要再乘speedMultiplier
                float testVelocity = CalculateVelocityForRange(testAngle, targetRange);
                
                // 计算10米处高度
                float heightAt10m = CalculateHeightAt10m(testAngle, testVelocity);
                
                // 计算误差(使用外部设置的目标高度)
                float error = Mathf.Abs(heightAt10m - this.targetHeightAt10m);
                
                if (error < minError)
                {
                    minError = error;
                    bestAngle = testAngle;
                }
            }
            
            // 应用找到的最佳角度
            launchHeight = bestAngle;
            
            // 计算最终速度(不需要再乘speedMultiplier,因为customGravity已经调整过了)
            initialVelocity = CalculateVelocityForRange(launchHeight, targetRange);
            
            // 验证结果
            float finalHeightAt10m = CalculateHeightAt10m(launchHeight, initialVelocity);
            float angleRad = launchHeight * Mathf.Deg2Rad;
            float finalRange = (initialVelocity * initialVelocity * Mathf.Sin(2f * angleRad)) / customGravity;
            
            Debug.Log($"[PhysicsParabola] 速度倍率: {speedMultiplier:F2}x");
            Debug.Log($"[PhysicsParabola] 调整后角度: {launchHeight:F2}°, 初速度: {initialVelocity:F2} m/s, 重力: {customGravity:F2} m/s²");
            Debug.Log($"[PhysicsParabola] 10米处高度: {finalHeightAt10m:F2}m (目标: {this.targetHeightAt10m:F2}m)");
            Debug.Log($"[PhysicsParabola] 射程: {finalRange:F2}m (目标: {targetRange:F2}m)");
        }

        private void ApplyConfiguredSpeed()
        {
            if (configuredSpeed <= 0f)
            {
                initialVelocity = CalculateVelocityForRange(launchHeight, targetRange);
                return;
            }

            initialVelocity = configuredSpeed;
            float angleRad = launchHeight * Mathf.Deg2Rad;
            float sin2Theta = Mathf.Sin(2f * angleRad);

            if (sin2Theta <= 0.001f)
            {
                Debug.LogWarning("[MultipleDirLauncher] 当前角度太小,无法根据速度计算射程重力");
                return;
            }

            customGravity = (initialVelocity * initialVelocity * sin2Theta) / targetRange;
            //Debug.Log($"[MultipleDirLauncher] 使用统一速度: {initialVelocity:F2} m/s, 重力:{customGravity:F2} m/s²");
        }
        /// <summary>
        /// 绘制轨迹预测(编辑模式下)
        /// </summary>
        void OnDrawGizmos()
        {
            if (!showTrajectory || Application.isPlaying) return;

            // 计算初速度
            float velocity = CalculateVelocityForRange(launchHeight, targetRange);
            if (velocity <= 0) return;

            float verticalAngleRad = launchHeight * Mathf.Deg2Rad;
            float horizontalAngleRad = horizontalAngle * Mathf.Deg2Rad;

            // 计算速度分量
            float verticalSpeed = velocity * Mathf.Sin(verticalAngleRad);
            float horizontalSpeed = velocity * Mathf.Cos(verticalAngleRad);

            // 计算水平方向上的速度分量
            float horizontalVelocityX = horizontalSpeed * Mathf.Sin(horizontalAngleRad);
            float horizontalVelocityZ = horizontalSpeed * Mathf.Cos(horizontalAngleRad);

            // 计算总飞行时间(只考虑垂直方向)
            float totalTime = (2f * verticalSpeed) / customGravity;

            Gizmos.color = trajectoryColor;
            Vector3 prevPos = transform.position;

            // 绘制轨迹
            for (int i = 1; i <= trajectoryPoints; i++)
            {
                float t = i * (totalTime / trajectoryPoints);

                // 计算当前点的位置
                float x = horizontalVelocityX * t;
                float z = horizontalVelocityZ * t;
                float y = verticalSpeed * t - 0.5f * customGravity * t * t;

                Vector3 point = transform.position + new Vector3(x, y, z);

                Gizmos.DrawLine(prevPos, point);

                // 标记10米处
                float horizontalDistance = Mathf.Sqrt(x * x + z * z);
                if (Mathf.Abs(horizontalDistance - 10f) < 0.3f)
                {
                    Gizmos.color = Color.green;
                    Gizmos.DrawSphere(point, 0.2f);
                    Gizmos.color = trajectoryColor;
                }

                prevPos = point;

                // 如果低于地面,停止绘制
                if (point.y <= 0) break;
            }

            // 标记76米射程处
            float flightTime = (2f * verticalSpeed) / customGravity;
            float rangeX = horizontalVelocityX * flightTime;
            float rangeZ = horizontalVelocityZ * flightTime;
            Vector3 landingPoint = transform.position + new Vector3(rangeX, 0, rangeZ);

            Gizmos.color = Color.red;
            Gizmos.DrawSphere(landingPoint, 0.5f);

            // 绘制发射方向指示器
            Gizmos.color = Color.blue;
            Vector3 direction = new Vector3(
                Mathf.Sin(horizontalAngleRad),
                0,
                Mathf.Cos(horizontalAngleRad)
            ).normalized;
            Gizmos.DrawRay(transform.position, direction * 5f);
        }

        /// <summary>
        /// 在Inspector中自动计算并显示信息
        /// </summary>
        void OnValidate()
        {
            if (Application.isPlaying) return;

            // 计算速度
            float velocity = CalculateVelocityForRange(launchHeight, targetRange);

            if (velocity > 0)
            {
                // 计算10米处高度
                float heightAt10m = CalculateHeightAt10m(launchHeight, velocity);

                // 计算射程
                float angleRad = launchHeight * Mathf.Deg2Rad;
                float range = (velocity * velocity * Mathf.Sin(2f * angleRad)) / customGravity;

                // 更新显示
                initialVelocity = velocity;

                // 验证约束
                float minAllowedHeight = minHeight - heightTolerance;
                float maxAllowedHeight = maxHeight + heightTolerance;
                float minRange = targetRange - rangeTolerance;
                float maxRange = targetRange + rangeTolerance;

                bool heightValid = (heightAt10m >= minAllowedHeight) && (heightAt10m <= maxAllowedHeight);
                bool rangeValid = (range >= minRange) && (range <= maxRange);

                if (!heightValid || !rangeValid)
                {
                    Debug.LogWarning($"当前参数不满足约束: 高度={heightAt10m:F2}m, 射程={range:F2}m");
                }
            }
        }

        /// <summary>
        /// 在运行时显示轨迹(从固定起点绘制)并检测落地
        /// </summary>
        void Update()
        {
            if (showTrajectory && Application.isPlaying)
            {
                DrawRuntimeTrajectory();
            }
            
            // 检测飞碟是否落地
            // 条件:已发射 && 飞行距离超过75.5米 && 低于地面高度
            if (isLaunched)
            {
                float horizontalDistance = Vector3.Distance(
                    new Vector3(transform.position.x, 0, transform.position.z),
                    new Vector3(launchStartPosition.x, 0, launchStartPosition.z)
                );
                
                if (horizontalDistance >= 75.5f && transform.position.y <= groundHeight)
                {
                    HandleLanding();
                }
            }
        }

        /// <summary>
        /// 处理飞碟落地
        /// </summary>
        private void HandleLanding()
        {
            isLaunched = false;
            FinishTrajectory(TrajectoryRecordResult.Miss);
            
            // 计算飞行距离
            float horizontalDistance = Vector3.Distance(
                new Vector3(transform.position.x, 0, transform.position.z),
                new Vector3(launchStartPosition.x, 0, launchStartPosition.z)
            );
            
            // 计算飞行时间
            float flightTime = Time.time - launchTime;
            
            // 停止物理运动
            if (rb != null)
            {
                rb.velocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
            }
            
            Debug.Log($"[PhysicsParabola] 飞碟落地 - 飞行距离: {horizontalDistance:F2}m, 飞行时间: {flightTime:F2}s");
            
            // 延迟回收
            if (recycleDelay > 0)
            {
                Invoke(nameof(TriggerRecycle), recycleDelay);
            }
            else
            {
                TriggerRecycle();
            }
        }

        /// <summary>
        /// 触发回收回调
        /// </summary>
        private void TriggerRecycle()
        {
            OnComplete?.Invoke();
            Debug.Log($"[FlyingDiscLauncher] 飞碟已回收到对象池");
        }

        public override void ForceRecycle()
        {
            OnRecycleRequested();
            base.ForceRecycle();
        }

        public override void SetSlowMotionScale(float scale)
        {
            if (!hasSlowMotionGravity)
            {
                originalCustomGravity = customGravity;
                hasSlowMotionGravity = true;
            }

            customGravity = originalCustomGravity * scale * scale;
        }

        public override void RestoreSlowMotionScale()
        {
            if (!hasSlowMotionGravity)
                return;

            customGravity = originalCustomGravity;
            hasSlowMotionGravity = false;
        }

        protected override void OnRecycleRequested()
        {
            CancelInvoke(nameof(TriggerRecycle));
            isLaunched = false;

            if (rb != null)
            {
                ObjectSlowMotionController.Instance?.RemoveRigidbodyWithoutRestore(rb);
                rb.velocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
            }

            RestoreSlowMotionScale();
        }

        void DrawRuntimeTrajectory()
        {
            if (initialVelocity <= 0) return;

            float verticalAngleRad = launchHeight * Mathf.Deg2Rad;
            float horizontalAngleRad = horizontalAngle * Mathf.Deg2Rad;

            // 计算速度分量
            float verticalSpeed = initialVelocity * Mathf.Sin(verticalAngleRad);
            float horizontalSpeed = initialVelocity * Mathf.Cos(verticalAngleRad);

            // 计算水平方向上的速度分量
            float horizontalVelocityX = horizontalSpeed * Mathf.Sin(horizontalAngleRad);
            float horizontalVelocityZ = horizontalSpeed * Mathf.Cos(horizontalAngleRad);

            // 计算总飞行时间
            float totalTime = (2f * verticalSpeed) / customGravity;

            // 从记录的发起点开始绘制
            Vector3 prevPos = launchStartPosition;

            // 绘制轨迹
            for (int i = 1; i <= 20; i++)
            {
                float t = i * (totalTime / 20f);

                // 计算当前点的位置
                float x = horizontalVelocityX * t;
                float z = horizontalVelocityZ * t;
                float y = verticalSpeed * t - 0.5f * customGravity * t * t;

                // 从发射点开始计算位置
                Vector3 point = launchStartPosition + new Vector3(x, y, z);

                Debug.DrawLine(prevPos, point, Color.cyan);
                prevPos = point;

                if (point.y <= 0) break;
            }

            // 在落地点画一个标记
            float flightTime = (2f * verticalSpeed) / customGravity;
            float rangeX = horizontalVelocityX * flightTime;
            float rangeZ = horizontalVelocityZ * flightTime;
            Vector3 landingPoint = launchStartPosition + new Vector3(rangeX, 0, rangeZ);

            // 绘制目标点标记
            Debug.DrawLine(landingPoint + Vector3.up * 0.5f, landingPoint - Vector3.up * 0.5f, Color.red);
            Debug.DrawLine(landingPoint + Vector3.right * 0.5f, landingPoint - Vector3.right * 0.5f, Color.red);
            Debug.DrawLine(landingPoint + Vector3.forward * 0.5f, landingPoint - Vector3.forward * 0.5f, Color.red);
        }

    }
}