# Conflicts: # Assets/Scenes/RopeTest.unity # Assets/Scripts/Fishing/New/View/Player/Tackle/FLine.cs # Assets/Scripts/Fishing/Rope/Rope.cs # Assets/Scripts/Fishing/Rope/Rope.cs.meta
349 lines
12 KiB
C#
349 lines
12 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace NBF
|
||
{
|
||
/// <summary>
|
||
/// 硬线系统测试脚本,直接读取 FLine 已配置的节点。
|
||
/// </summary>
|
||
public class FLineTest : MonoBehaviour
|
||
{
|
||
[Header("测试控制")] [SerializeField] private KeyCode fixMiddleKey = KeyCode.M;
|
||
[SerializeField] private KeyCode applyForceKey = KeyCode.F;
|
||
[SerializeField] private Vector3 testForce = new Vector3(0f, 10f, 0f);
|
||
|
||
[Header("动态间距控制")]
|
||
// [SerializeField] private KeyCode extendKey = KeyCode.UpArrow;
|
||
// [SerializeField] private KeyCode contractKey = KeyCode.DownArrow;
|
||
[SerializeField]
|
||
private KeyCode resetKey = KeyCode.Alpha0;
|
||
|
||
[SerializeField] private KeyCode pullFirstKey = KeyCode.UpArrow;
|
||
[SerializeField] private KeyCode relaxFirstKey = KeyCode.DownArrow;
|
||
[SerializeField, Min(0.01f)] private float extendAmount = 0.5f;
|
||
[SerializeField, Min(0.01f)] private float holdAdjustSpeed = 1f;
|
||
[SerializeField, Min(0.01f)] private float transitionSpeed = 2f;
|
||
[SerializeField] private bool smoothTransition = true;
|
||
|
||
[SerializeField] private FLine line;
|
||
private float[] initialLengths;
|
||
|
||
private void OnValidate()
|
||
{
|
||
extendAmount = Mathf.Max(0.01f, extendAmount);
|
||
holdAdjustSpeed = Mathf.Max(0.01f, holdAdjustSpeed);
|
||
transitionSpeed = Mathf.Max(0.01f, transitionSpeed);
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
RefreshInitialLengths(true);
|
||
line.OnLineBreakRequested += OnLineBreakRequested;
|
||
}
|
||
|
||
private void OnLineBreakRequested(FLine lineSolver)
|
||
{
|
||
Debug.LogError($"当前拉力达到极限,切线,极限时间={lineSolver.LimitStateTime}");
|
||
|
||
var nodes = line.GetLineNodes();
|
||
nodes[^1].Rigidbody.isKinematic = false;
|
||
// line.Body.isKinematic = false;
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (!EnsureCable())
|
||
return;
|
||
|
||
RefreshInitialLengths();
|
||
HandleInput();
|
||
|
||
if (line.CurrentBreakStretchPercent > 10f)
|
||
{
|
||
Debug.LogError(
|
||
$"当前极限情况,CurrentBreakStretchPercent={line.CurrentBreakStretchPercent} CurrentStretchLength={line.CurrentStretchLength} TotalLength={line.TotalLength} LimitStateTime={line.LimitStateTime}");
|
||
}
|
||
}
|
||
|
||
private bool EnsureCable()
|
||
{
|
||
if (line)
|
||
return true;
|
||
|
||
line = GetComponent<FLine>();
|
||
return line != null;
|
||
}
|
||
|
||
private List<FLineLogicNode> GetNodes()
|
||
{
|
||
return line != null ? line.GetLineNodes() : null;
|
||
}
|
||
|
||
private void RefreshInitialLengths(bool force = false)
|
||
{
|
||
List<FLineLogicNode> nodes = GetNodes();
|
||
int segmentCount = nodes != null ? Mathf.Max(0, nodes.Count - 1) : 0;
|
||
|
||
if (!force && initialLengths != null && initialLengths.Length == segmentCount)
|
||
return;
|
||
|
||
initialLengths = new float[segmentCount];
|
||
for (int i = 0; i < segmentCount; i++)
|
||
{
|
||
float configuredLength = line.GetSegmentMaxLength(i);
|
||
if (configuredLength <= 0f)
|
||
configuredLength = Mathf.Max(0.01f, line.GetCurrentSegmentLength(i));
|
||
|
||
initialLengths[i] = Mathf.Max(0.01f, configuredLength);
|
||
}
|
||
}
|
||
|
||
private float GetCurrentMaxLength(int segmentIndex)
|
||
{
|
||
float length = line.GetSegmentMaxLength(segmentIndex);
|
||
return Mathf.Max(0.01f, length);
|
||
}
|
||
|
||
private float GetTargetMaxLength(int segmentIndex)
|
||
{
|
||
float length = line.GetTargetMaxLength(segmentIndex);
|
||
if (length <= 0f)
|
||
length = line.GetSegmentMaxLength(segmentIndex);
|
||
|
||
return Mathf.Max(0.01f, length);
|
||
}
|
||
|
||
private int GetSegmentCount()
|
||
{
|
||
return initialLengths != null ? initialLengths.Length : 0;
|
||
}
|
||
|
||
private void HandleInput()
|
||
{
|
||
HandleOriginalControls();
|
||
HandleDynamicDistanceControls();
|
||
}
|
||
|
||
private void HandleOriginalControls()
|
||
{
|
||
List<FLineLogicNode> nodes = GetNodes();
|
||
if (nodes == null)
|
||
return;
|
||
|
||
if (Input.GetKeyDown(fixMiddleKey) && nodes.Count >= 3)
|
||
{
|
||
int middleIndex = nodes.Count / 2;
|
||
FLineLogicNode middleNode = nodes[middleIndex];
|
||
Rigidbody middleRb = middleNode ? middleNode.Rigidbody : null;
|
||
|
||
if (middleNode && middleRb)
|
||
{
|
||
bool newState = !middleRb.isKinematic;
|
||
middleNode.SetFixed(newState);
|
||
Debug.Log($"中间节点({middleIndex}) {(newState ? "固定" : "释放")} - 观察其他节点变化");
|
||
}
|
||
}
|
||
|
||
if (Input.GetKeyDown(applyForceKey) && nodes.Count > 2)
|
||
{
|
||
int randomIndex = Random.Range(1, nodes.Count - 1);
|
||
FLineLogicNode targetNode = nodes[randomIndex];
|
||
Rigidbody targetRb = targetNode ? targetNode.Rigidbody : null;
|
||
|
||
if (targetNode && targetRb && !targetRb.isKinematic)
|
||
{
|
||
targetNode.ApplyForce(testForce, ForceMode.Impulse);
|
||
Debug.Log($"对节点{randomIndex}施加力: {testForce} - 观察传递效果");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void HandleDynamicDistanceControls()
|
||
{
|
||
if (line == null || initialLengths == null || initialLengths.Length == 0)
|
||
return;
|
||
|
||
// HandleLengthAdjustInput();
|
||
|
||
if (Input.GetKeyDown(resetKey))
|
||
ResetAllSegments();
|
||
|
||
if (Input.GetKeyDown(pullFirstKey))
|
||
PullFirstSegment(extendAmount * 0.5f);
|
||
|
||
if (Input.GetKeyDown(relaxFirstKey))
|
||
RelaxFirstSegment(extendAmount * 0.5f);
|
||
|
||
if (Input.mouseScrollDelta.y != 0f && Input.GetKey(KeyCode.LeftShift))
|
||
AdjustNearestSegment(Input.mouseScrollDelta.y * 0.1f);
|
||
}
|
||
|
||
|
||
private void ApplySegmentTargetLength(int segmentIndex, float targetLength)
|
||
{
|
||
line.SetSegmentMaxLength(segmentIndex, targetLength, transitionSpeed);
|
||
}
|
||
|
||
private void ResetAllSegments()
|
||
{
|
||
for (int i = 0; i < GetSegmentCount(); i++)
|
||
{
|
||
ApplySegmentTargetLength(i, initialLengths[i]);
|
||
}
|
||
|
||
Debug.Log("重置绳索到 FLine 初始节点配置");
|
||
}
|
||
|
||
private void PullFirstSegment(float amount)
|
||
{
|
||
if (GetSegmentCount() <= 0)
|
||
return;
|
||
|
||
float targetLength = Mathf.Max(0.1f, GetTargetMaxLength(0) - amount);
|
||
ApplySegmentTargetLength(0, targetLength);
|
||
Debug.Log($"拉紧第一段到 {targetLength:F2}");
|
||
}
|
||
|
||
private void RelaxFirstSegment(float amount)
|
||
{
|
||
if (GetSegmentCount() <= 0)
|
||
return;
|
||
|
||
float targetLength = GetTargetMaxLength(0) + amount;
|
||
ApplySegmentTargetLength(0, targetLength);
|
||
Debug.Log($"放松第一段到 {targetLength:F2}");
|
||
}
|
||
|
||
private void AdjustNearestSegment(float amount)
|
||
{
|
||
int nearestSegment = FindNearestSegmentToCamera();
|
||
if (nearestSegment < 0 || nearestSegment >= GetSegmentCount())
|
||
return;
|
||
|
||
float targetLength = Mathf.Max(0.1f, GetTargetMaxLength(nearestSegment) + amount);
|
||
ApplySegmentTargetLength(nearestSegment, targetLength);
|
||
Debug.Log($"调整段{nearestSegment}到 {targetLength:F2}");
|
||
}
|
||
|
||
private int FindNearestSegmentToCamera()
|
||
{
|
||
Camera cam = Camera.main;
|
||
List<FLineLogicNode> nodes = GetNodes();
|
||
if (cam == null || nodes == null || nodes.Count < 2)
|
||
return -1;
|
||
|
||
int nearestSegment = -1;
|
||
float nearestDistance = float.MaxValue;
|
||
|
||
for (int i = 0; i < nodes.Count - 1; i++)
|
||
{
|
||
Rigidbody bodyA = nodes[i] ? nodes[i].Rigidbody : null;
|
||
Rigidbody bodyB = nodes[i + 1] ? nodes[i + 1].Rigidbody : null;
|
||
if (!bodyA || !bodyB)
|
||
continue;
|
||
|
||
Vector3 midPoint = (bodyA.position + bodyB.position) * 0.5f;
|
||
Vector3 screenPoint = cam.WorldToScreenPoint(midPoint);
|
||
Vector3 mousePos = Input.mousePosition;
|
||
|
||
float distance = Vector2.Distance(
|
||
new Vector2(screenPoint.x, screenPoint.y),
|
||
new Vector2(mousePos.x, mousePos.y)
|
||
);
|
||
|
||
if (distance < nearestDistance)
|
||
{
|
||
nearestDistance = distance;
|
||
nearestSegment = i;
|
||
}
|
||
}
|
||
|
||
return nearestSegment;
|
||
}
|
||
|
||
private void OnGUI()
|
||
{
|
||
if (!EnsureCable())
|
||
return;
|
||
|
||
RefreshInitialLengths();
|
||
|
||
List<FLineLogicNode> nodes = GetNodes();
|
||
int nodeCount = nodes != null ? nodes.Count : 0;
|
||
|
||
GUILayout.BeginArea(new Rect(10f, 10f, 360f, 260f));
|
||
GUILayout.Label("=== 硬线系统测试控制 ===");
|
||
GUILayout.Label("原始控制:");
|
||
GUILayout.Label($" {fixMiddleKey} - 固定/释放中间节点");
|
||
GUILayout.Label($" {applyForceKey} - 随机施加力");
|
||
GUILayout.Space(10f);
|
||
GUILayout.Label("动态间距控制:");
|
||
GUILayout.Label($" {resetKey} - 重置到初始节点配置");
|
||
GUILayout.Label($" {pullFirstKey} - 拉紧第一段");
|
||
GUILayout.Label($" {relaxFirstKey} - 放松第一段");
|
||
GUILayout.Label(" Shift+滚轮 - 调整最近段");
|
||
GUILayout.Space(10f);
|
||
GUILayout.Label("设置:");
|
||
GUILayout.Label($" 节点数: {nodeCount}");
|
||
GUILayout.Label(" 初始长度来源: FLine 节点配置");
|
||
GUILayout.Label($" 过渡模式: {(smoothTransition ? "平滑" : "即时")}");
|
||
if (smoothTransition)
|
||
GUILayout.Label($" 过渡速度: {transitionSpeed:F1}");
|
||
|
||
GUILayout.EndArea();
|
||
|
||
GUILayout.BeginArea(new Rect(10f, 280f, 360f, 220f));
|
||
GUILayout.Label("=== 各段实际长度 ===");
|
||
|
||
for (int i = 0; i < Mathf.Min(GetSegmentCount(), 10); i++)
|
||
{
|
||
Rigidbody bodyA = nodes[i] ? nodes[i].Rigidbody : null;
|
||
Rigidbody bodyB = nodes[i + 1] ? nodes[i + 1].Rigidbody : null;
|
||
if (!bodyA || !bodyB)
|
||
continue;
|
||
|
||
float actualDistance = Vector3.Distance(bodyA.position, bodyB.position);
|
||
float currentLimit = GetCurrentMaxLength(i);
|
||
float targetLimit = GetTargetMaxLength(i);
|
||
|
||
string segmentInfo = $"段{i}: {actualDistance:F2} (限制: {currentLimit:F2}";
|
||
if (line.IsSegmentTransitioning(i))
|
||
segmentInfo += $" -> {targetLimit:F2}";
|
||
|
||
segmentInfo += ")";
|
||
|
||
if (actualDistance > targetLimit * 1.1f)
|
||
{
|
||
GUI.color = Color.red;
|
||
}
|
||
else if (line.IsSegmentTransitioning(i))
|
||
{
|
||
GUI.color = Color.yellow;
|
||
}
|
||
else
|
||
{
|
||
GUI.color = Color.green;
|
||
}
|
||
|
||
GUILayout.Label(segmentInfo);
|
||
}
|
||
|
||
GUI.color = Color.white;
|
||
|
||
bool anyTransitioning = false;
|
||
for (int i = 0; i < GetSegmentCount(); i++)
|
||
{
|
||
if (line.IsSegmentTransitioning(i))
|
||
{
|
||
anyTransitioning = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (anyTransitioning)
|
||
GUILayout.Label("状态: 过渡中...");
|
||
|
||
GUILayout.EndArea();
|
||
}
|
||
}
|
||
} |