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;
}
}