using UnityEngine; using System.Collections.Generic; namespace NBF { [System.Serializable] public struct FishingCastInput { [Range(0, 1)] public float power; [Range(0, 50)] public float windStrength; // 单位 m/s public Vector3 windDirection; [Range(5, 30)] public float lureWeight; // 单位 g [Range(0, 30)] public float spiralAngularSpeed; } public class LureTrajectorySimulator : MonoBehaviour { [Header("基础参数")] public int maxSimulationSteps = 1000; public float simulationDuration = 10f; public float timeStep = 0.02f; [Header("抛投力度")] public float minThrowPower = 15f; public float maxThrowPower = 45f; [Header("空气阻力参数")] [Tooltip("阻力系数,非流线钓饵建议 0.8~1.2")] public float dragCoefficient = 0.1f; [Tooltip("迎风面积,0.005m² ≈ 5cm²")] public float lureArea = 0.001f; [Header("螺旋轨迹参数")] public float spiralRadius = 0.3f; // 初始螺旋半径(单位:米) [Range(0f, 2f)] public float spiralDecay = 1f; // 螺旋逐渐减弱的衰减因子 /// /// 加入了风 /// /// /// /// /// public List CalculateTrajectory(FishingCastInput input, Vector3 startPosition, Vector3 castDirection) { List trajectory = new List(); Vector3 position = startPosition; Vector3 direction = castDirection.normalized; float throwPower = Mathf.Lerp(minThrowPower, maxThrowPower, input.power); Vector3 velocity = direction * throwPower; float lureMass = input.lureWeight / 1000f; // 转 kg Vector3 windDir = input.windDirection.normalized; float windStrength = input.windStrength; float currentTime = 0f; int steps = 0; while (currentTime < simulationDuration && steps < maxSimulationSteps) { if (position.y <= 0f) break; // 模拟风力逐渐生效 float windInfluenceFactor = Mathf.Clamp01(currentTime / 1.5f); // 1.5秒内增长 Vector3 windVelocity = windDir * windStrength * windInfluenceFactor; // 真实空气阻力模型 Vector3 relVelocity = velocity - windVelocity; // 空气阻力 float dragMag = 0.5f * PhysicsHelper.AirDensity * relVelocity.sqrMagnitude * dragCoefficient * lureArea; Vector3 dragForce = -relVelocity.normalized * dragMag; // 合力 = 重力 + 空气阻力 Vector3 acceleration = (Physics.gravity + dragForce / lureMass); velocity += acceleration * timeStep; position += velocity * timeStep; // // 当前角度(代替原来的 spiralAngle 计算) // float spiralAngle = currentTime * input.spiralAngularSpeed; // // float spiralFalloff = Mathf.Exp(-spiralDecay * currentTime); // float radiusNow = spiralRadius * spiralFalloff; // // // 构造绕投掷方向垂直平面上的偏移 // Vector3 right = Vector3.Cross(direction, Vector3.up).normalized; // if (right.sqrMagnitude < 0.001f) // right = Vector3.Cross(direction, Vector3.forward).normalized; // 防止方向与up重合 // Vector3 up = Vector3.Cross(direction, right).normalized; // Vector3 spiralOffset = (right * Mathf.Cos(spiralAngle) + up * Mathf.Sin(spiralAngle)) * radiusNow; // // position += spiralOffset; trajectory.Add(position); currentTime += timeStep; steps++; } return trajectory; } // 示例调用 private List _trajectory; private int _windIndex; public List Test(Transform cameraTransform) { Vector3[] directions = { Vector3.forward, Vector3.back, Vector3.right, Vector3.left, (Vector3.forward + Vector3.right).normalized, (Vector3.forward + Vector3.left).normalized, (Vector3.back + Vector3.right).normalized, (Vector3.back + Vector3.left).normalized }; FishingCastInput baseInput = new FishingCastInput { power = 1f, lureWeight = 2f, windStrength = 6f, // 风力大小 spiralAngularSpeed = 15 }; Vector3 startPos = cameraTransform.position; Vector3 throwDir = cameraTransform.forward.normalized; baseInput.windDirection = directions[_windIndex]; //directions[_windIndex]; (-transform.forward).normalized; _trajectory = CalculateTrajectory(baseInput, startPos, throwDir); _windIndex++; if (_windIndex >= directions.Length) { _windIndex = 0; } var length = CalculateTrajectoryLength(_trajectory); var distance = CalculateHorizontalDistance(_trajectory); Debug.LogError($"轨迹点位数={_trajectory.Count} length={length} distance={distance}"); SceneSettings.Instance.LineRenderer.startWidth = 0.1f; SceneSettings.Instance.LineRenderer.endWidth = 0.1f; SceneSettings.Instance.LineRenderer.positionCount = _trajectory.Count; SceneSettings.Instance.LineRenderer.useWorldSpace = true; SceneSettings.Instance.LineRenderer.SetPositions(_trajectory.ToArray()); return _trajectory; } /// /// 计算轨迹总长度(线的实际长度) /// public float CalculateTrajectoryLength(List trajectory) { if (trajectory == null || trajectory.Count < 2) return 0f; float totalLength = 0f; for (int i = 1; i < trajectory.Count; i++) { totalLength += Vector3.Distance(trajectory[i - 1], trajectory[i]); } return totalLength; } /// /// 计算水平距离(XZ平面上的直线距离) /// public float CalculateHorizontalDistance(List trajectory) { if (trajectory == null || trajectory.Count == 0) return 0f; Vector3 startPoint = trajectory[0]; Vector3 endPoint = trajectory[trajectory.Count - 1]; // 将Y坐标设为相同(地面高度) startPoint.y = 0; endPoint.y = 0; return Vector3.Distance(startPoint, endPoint); } private void OnDrawGizmos() { if (_trajectory == null) return; Gizmos.color = Color.cyan; for (int i = 0; i < _trajectory.Count - 1; i++) { Gizmos.DrawLine(_trajectory[i], _trajectory[i + 1]); } if (_trajectory.Count > 0) { Gizmos.color = Color.green; Gizmos.DrawSphere(_trajectory[0], 0.1f); Gizmos.color = Color.red; Gizmos.DrawSphere(_trajectory[_trajectory.Count - 1], 0.1f); for (int i = 1; i < _trajectory.Count; i += 10) { Gizmos.color = Color.Lerp(Color.green, Color.red, i / (float)_trajectory.Count); Gizmos.DrawSphere(_trajectory[i], 0.05f); } } } } public static class PhysicsHelper { public const float AirDensity = 1.225f; } }