添加测试脚本

This commit is contained in:
2026-04-06 20:03:36 +08:00
parent 3e0a33483a
commit 75aa83677f
9 changed files with 793 additions and 67 deletions

View File

@@ -0,0 +1,36 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9d66919bfa33a7445b32a45410e0ccfe, type: 3}
m_Name: FishingRigDefinition
m_EditorClassIdentifier: Assembly-CSharp::FishingRigDefinition
logicalNodes:
- id:
nodeType: 0
distanceFromPrevious: 0
virtualNodeCount: 0
gravityScale: 0
damping: 0
debugColor: {r: 0.17723638, g: 1, b: 0, a: 1}
- id:
nodeType: 2
distanceFromPrevious: 0
virtualNodeCount: 0
gravityScale: 0
damping: 0
debugColor: {r: 0, g: 0.61897755, b: 1, a: 1}
- id:
nodeType: 3
distanceFromPrevious: 0
virtualNodeCount: 0
gravityScale: 0
damping: 0
debugColor: {r: 1, g: 0, b: 0, a: 1}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a48cb68bf14ac8c429abc96a2cdb7821
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -38,12 +38,12 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
serializedVersion: 13
m_BakeOnSceneLoad: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
@@ -206,7 +206,7 @@ Transform:
m_GameObject: {fileID: 330585543}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalPosition: {x: 0, y: -0.03, z: -0.66}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -248,14 +248,14 @@ MonoBehaviour:
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
m_RequiresDepthTexture: 0
m_RequiresColorTexture: 0
m_Version: 2
m_TaaSettings:
quality: 3
frameInfluence: 0.1
jitterScale: 1
mipBias: 0
varianceClampScale: 0.9
contrastAdaptiveSharpening: 0
m_Quality: 3
m_FrameInfluence: 0.1
m_JitterScale: 1
m_MipBias: 0
m_VarianceClampScale: 0.9
m_ContrastAdaptiveSharpening: 0
m_Version: 2
--- !u!1 &410087039
GameObject:
m_ObjectHideFlags: 0
@@ -282,14 +282,14 @@ Light:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
m_Enabled: 1
serializedVersion: 11
serializedVersion: 13
m_Type: 1
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_Intensity: 2
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_CookieSize2D: {x: 10, y: 10}
m_Shadows:
m_Type: 2
m_Resolution: -1
@@ -334,8 +334,11 @@ Light:
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShapeRadius: 0
m_ShadowAngle: 0
m_LightUnit: 1
m_LuxAtDistance: 1
m_EnableSpotReflector: 1
--- !u!4 &410087041
Transform:
m_ObjectHideFlags: 0
@@ -363,17 +366,255 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Version: 3
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_LightLayerMask: 1
m_RenderingLayers: 1
m_CustomShadowLayers: 0
m_ShadowLayerMask: 1
m_ShadowRenderingLayers: 1
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 1
m_RenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_ShadowRenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_Version: 4
m_LightLayerMask: 1
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!1 &445360720
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 445360722}
- component: {fileID: 445360721}
- component: {fileID: 445360723}
- component: {fileID: 445360725}
- component: {fileID: 445360724}
m_Layer: 0
m_Name: FishingLineRoot
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &445360721
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 445360720}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5194be581ec15764eab72311e62182eb, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::FishingGameplayController
solver: {fileID: 445360723}
reelSpeed: 0.5
reelInKey: 101
reelOutKey: 113
--- !u!4 &445360722
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 445360720}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0, y: 0, z: -0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &445360723
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 445360720}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b8bc695f40e430b4588f7fb29f79a3e3, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::FishingLineSolver
rigDefinition: {fileID: 11400000, guid: a48cb68bf14ac8c429abc96a2cdb7821, type: 2}
inlineLogicalNodes:
- id: Start
nodeType: 0
distanceFromPrevious: 0
virtualNodeCount: 0
gravityScale: 0
damping: 0
debugColor: {r: 0.4, g: 1, b: 0.6, a: 1}
- id: Float
nodeType: 1
distanceFromPrevious: 1.2
virtualNodeCount: 10
gravityScale: 0.15
damping: 0.08
debugColor: {r: 1, g: 0.75, b: 0.2, a: 1}
- id: Sinker
nodeType: 2
distanceFromPrevious: 1.4
virtualNodeCount: 10
gravityScale: 1.6
damping: 0.02
debugColor: {r: 0.7, g: 0.85, b: 1, a: 1}
- id: Hook
nodeType: 3
distanceFromPrevious: 0.8
virtualNodeCount: 10
gravityScale: 1.2
damping: 0.03
debugColor: {r: 1, g: 0.35, b: 0.35, a: 1}
startAnchor: {fileID: 1538371803}
initialDirection: {x: 0, y: -1, z: 0}
solverIterations: 8
gravity: 9.81
globalDamping: 0.01
tensionSmoothing: 0.18
simulateInFixedUpdate: 0
currentLineLength: 3.4
minLineLength: 1.2
maxLineLength: 8.5
drawDebug: 1
debugNodeRadius: 0.03
virtualNodeColor: {r: 0.4, g: 0.75, b: 1, a: 1}
segmentColor: {r: 0.85, g: 0.9, b: 1, a: 1}
--- !u!114 &445360724
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 445360720}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0af449a2493cf8c4281c9d5ae01c2a92, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::FishingLineRendererBinder
solver: {fileID: 445360723}
lineRenderer: {fileID: 445360725}
attachmentBindings: []
--- !u!120 &445360725
LineRenderer:
serializedVersion: 3
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 445360720}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 0
m_LightProbeUsage: 0
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_Positions:
- {x: 0, y: 0, z: 0}
- {x: 0, y: -0.01, z: 1}
m_Parameters:
serializedVersion: 3
widthMultiplier: 1
widthCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0.01
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
colorGradient:
serializedVersion: 2
key0: {r: 1, g: 1, b: 1, a: 1}
key1: {r: 1, g: 1, b: 1, a: 1}
key2: {r: 0, g: 0, b: 0, a: 0}
key3: {r: 0, g: 0, b: 0, a: 0}
key4: {r: 0, g: 0, b: 0, a: 0}
key5: {r: 0, g: 0, b: 0, a: 0}
key6: {r: 0, g: 0, b: 0, a: 0}
key7: {r: 0, g: 0, b: 0, a: 0}
ctime0: 0
ctime1: 65535
ctime2: 0
ctime3: 0
ctime4: 0
ctime5: 0
ctime6: 0
ctime7: 0
atime0: 0
atime1: 65535
atime2: 0
atime3: 0
atime4: 0
atime5: 0
atime6: 0
atime7: 0
m_Mode: 0
m_ColorSpace: -1
m_NumColorKeys: 2
m_NumAlphaKeys: 2
numCornerVertices: 0
numCapVertices: 0
alignment: 0
textureMode: 0
textureScale: {x: 1, y: 1}
shadowBias: 0.5
generateLightingData: 0
m_UseWorldSpace: 1
m_Loop: 0
m_ApplyActiveColorSpace: 1
--- !u!1 &832575517
GameObject:
m_ObjectHideFlags: 0
@@ -423,6 +664,118 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1538371799
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1538371803}
- component: {fileID: 1538371802}
- component: {fileID: 1538371801}
- component: {fileID: 1538371800}
m_Layer: 0
m_Name: Tip
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!135 &1538371800
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1538371799}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 0.5
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &1538371801
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1538371799}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &1538371802
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1538371799}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &1538371803
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1538371799}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.02, y: 0.02, z: 0.02}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
@@ -430,3 +783,5 @@ SceneRoots:
- {fileID: 330585546}
- {fileID: 410087041}
- {fileID: 832575519}
- {fileID: 1538371803}
- {fileID: 445360722}

View File

@@ -3,7 +3,7 @@ using UnityEngine;
public class FishingGameplayController : MonoBehaviour
{
[SerializeField] private FishingLineSolver solver;
[SerializeField] [Min(0.01f)] private float reelSpeed = 0.5f;
[SerializeField] [Min(0.01f)] private float reelSpeed = 1.5f;
[SerializeField] private KeyCode reelInKey = KeyCode.E;
[SerializeField] private KeyCode reelOutKey = KeyCode.Q;
@@ -38,7 +38,7 @@ public class FishingGameplayController : MonoBehaviour
if (Mathf.Abs(direction) > Mathf.Epsilon)
{
solver.AdjustLengthScale(direction * reelSpeed * Time.deltaTime);
solver.AdjustLineLength(direction * reelSpeed * Time.deltaTime);
}
}
}

View File

@@ -6,10 +6,8 @@ public enum FishingLineNodeType
{
Start,
Float,
Sinker,
Hook,
Lure,
Weight,
Terminal,
Normal
}

View File

@@ -20,9 +20,9 @@ public class FishingLineSolver : MonoBehaviour
[SerializeField] private bool simulateInFixedUpdate = false;
[Header("Line Length")]
[SerializeField] [Min(0.1f)] private float lengthScale = 1f;
[SerializeField] [Min(0.1f)] private float minLengthScale = 0.35f;
[SerializeField] [Min(0.1f)] private float maxLengthScale = 2.5f;
[SerializeField] [Min(0.01f)] private float currentLineLength = 3.4f;
[SerializeField] [Min(0.01f)] private float minLineLength = 1.2f;
[SerializeField] [Min(0.01f)] private float maxLineLength = 8.5f;
[Header("Debug")]
[SerializeField] private bool drawDebug = true;
@@ -34,14 +34,19 @@ public class FishingLineSolver : MonoBehaviour
private readonly List<RuntimeLogicalNode> logicalNodes = new List<RuntimeLogicalNode>();
private readonly List<float> baseSegmentLengths = new List<float>();
private readonly List<Vector3> linePositions = new List<Vector3>();
private readonly List<FishingLineLogicalNodeDefinition> fallbackLogicalNodes = new List<FishingLineLogicalNodeDefinition>();
private bool runtimeBuilt;
private float currentTensionNormalized;
private float previousLineLength;
private float baseTotalLength;
public IReadOnlyList<Vector3> LinePositions => linePositions;
public int PointCount => points.Count;
public int LogicalNodeCount => logicalNodes.Count;
public float CurrentTensionNormalized => currentTensionNormalized;
public float CurrentLineLength => currentLineLength;
public float BaseTotalLength => baseTotalLength;
public IReadOnlyList<FishingLineLogicalNodeDefinition> LogicalNodeDefinitions => GetActiveDefinitions();
@@ -52,38 +57,15 @@ public class FishingLineSolver : MonoBehaviour
private void Reset()
{
if (inlineLogicalNodes.Count > 0)
{
return;
}
FishingLineLogicalNodeDefinition startNode = new FishingLineLogicalNodeDefinition();
startNode.ConfigurePrototype("Start", FishingLineNodeType.Start, 0f, 0, 0f, 0f, new Color(0.4f, 1f, 0.6f, 1f));
FishingLineLogicalNodeDefinition floatNode = new FishingLineLogicalNodeDefinition();
floatNode.ConfigurePrototype("Float", FishingLineNodeType.Float, 1.2f, 5, 0.15f, 0.08f, new Color(1f, 0.75f, 0.2f, 1f));
FishingLineLogicalNodeDefinition sinkerNode = new FishingLineLogicalNodeDefinition();
sinkerNode.ConfigurePrototype("Sinker", FishingLineNodeType.Sinker, 1.4f, 4, 1.6f, 0.02f, new Color(0.7f, 0.85f, 1f, 1f));
FishingLineLogicalNodeDefinition hookNode = new FishingLineLogicalNodeDefinition();
hookNode.ConfigurePrototype("Hook", FishingLineNodeType.Hook, 0.8f, 2, 1.2f, 0.03f, new Color(1f, 0.35f, 0.35f, 1f));
inlineLogicalNodes = new List<FishingLineLogicalNodeDefinition>
{
startNode,
floatNode,
sinkerNode,
hookNode
};
EnsureInlinePrototypeIfNeeded();
}
private void OnValidate()
{
solverIterations = Mathf.Max(1, solverIterations);
minLengthScale = Mathf.Max(0.1f, minLengthScale);
maxLengthScale = Mathf.Max(minLengthScale, maxLengthScale);
lengthScale = Mathf.Clamp(lengthScale, minLengthScale, maxLengthScale);
minLineLength = Mathf.Max(MinSegmentLength, minLineLength);
maxLineLength = Mathf.Max(minLineLength, maxLineLength);
currentLineLength = Mathf.Clamp(currentLineLength, minLineLength, maxLineLength);
}
private void Update()
@@ -105,19 +87,31 @@ public class FishingLineSolver : MonoBehaviour
[ContextMenu("Rebuild Solver")]
public void Rebuild()
{
EnsureInlinePrototypeIfNeeded();
BuildRuntime();
SnapToAnchors();
RefreshLinePositions();
previousLineLength = currentLineLength;
}
public void SetLengthScale(float newScale)
public void SetLineLength(float newLength)
{
lengthScale = Mathf.Clamp(newScale, minLengthScale, maxLengthScale);
float clampedLength = Mathf.Clamp(newLength, minLineLength, maxLineLength);
bool expanded = clampedLength > currentLineLength + Mathf.Epsilon;
currentLineLength = clampedLength;
if (expanded)
{
ExpandLineToCurrentLength();
RefreshLinePositions();
}
previousLineLength = currentLineLength;
}
public void AdjustLengthScale(float delta)
public void AdjustLineLength(float delta)
{
SetLengthScale(lengthScale + delta);
SetLineLength(currentLineLength + delta);
}
public bool TryGetLogicalNodePosition(int logicalNodeIndex, out Vector3 position)
@@ -160,11 +154,17 @@ public class FishingLineSolver : MonoBehaviour
}
SyncAnchors();
if (currentLineLength > previousLineLength + Mathf.Epsilon)
{
ExpandLineToCurrentLength();
}
Integrate(deltaTime);
SolveConstraints();
SyncAnchors();
RefreshLinePositions();
UpdateTension();
previousLineLength = currentLineLength;
}
private void BuildRuntime()
@@ -173,14 +173,23 @@ public class FishingLineSolver : MonoBehaviour
logicalNodes.Clear();
baseSegmentLengths.Clear();
linePositions.Clear();
baseTotalLength = 0f;
IReadOnlyList<FishingLineLogicalNodeDefinition> definitions = GetActiveDefinitions();
EnsureInlinePrototypeIfNeeded();
IReadOnlyList<FishingLineLogicalNodeDefinition> definitions = GetResolvedDefinitions();
if (definitions.Count == 0)
{
runtimeBuilt = false;
return;
}
if (definitions.Count < 2)
{
Debug.LogWarning("FishingLineSolver needs at least 2 logical nodes to build a valid line.", this);
runtimeBuilt = false;
return;
}
if (definitions[0].NodeType != FishingLineNodeType.Start)
{
Debug.LogWarning("FishingLineSolver expects the first logical node to be Start. The first node is still treated as the anchor.", this);
@@ -213,11 +222,13 @@ public class FishingLineSolver : MonoBehaviour
points.Add(virtualPoint);
baseSegmentLengths.Add(subSegmentLength);
baseTotalLength += subSegmentLength;
linePositions.Add(cursor);
}
cursor += direction * subSegmentLength;
baseSegmentLengths.Add(subSegmentLength);
baseTotalLength += subSegmentLength;
}
RuntimePoint logicalPoint = new RuntimePoint(cursor, anchored, logicalIndex, definition.GravityScale, definition.Damping);
@@ -231,9 +242,119 @@ public class FishingLineSolver : MonoBehaviour
linePositions.Add(cursor);
}
InitializeLineLengthDefaults();
runtimeBuilt = points.Count > 0;
}
private void InitializeLineLengthDefaults()
{
if (baseTotalLength <= MinSegmentLength)
{
minLineLength = Mathf.Max(MinSegmentLength, minLineLength);
maxLineLength = Mathf.Max(minLineLength, maxLineLength);
currentLineLength = Mathf.Clamp(Mathf.Max(currentLineLength, minLineLength), minLineLength, maxLineLength);
return;
}
if (currentLineLength <= MinSegmentLength)
{
currentLineLength = baseTotalLength;
}
if (minLineLength <= MinSegmentLength)
{
minLineLength = Mathf.Max(MinSegmentLength, baseTotalLength * 0.35f);
}
if (maxLineLength <= MinSegmentLength || maxLineLength < currentLineLength)
{
maxLineLength = Mathf.Max(currentLineLength, baseTotalLength * 2.5f);
}
minLineLength = Mathf.Min(minLineLength, maxLineLength);
currentLineLength = Mathf.Clamp(currentLineLength, minLineLength, maxLineLength);
}
private void EnsureInlinePrototypeIfNeeded()
{
if (rigDefinition != null && IsDefinitionListUsable(rigDefinition.LogicalNodes))
{
return;
}
if (IsDefinitionListUsable(inlineLogicalNodes))
{
return;
}
inlineLogicalNodes.Clear();
PopulatePrototypeNodes(inlineLogicalNodes);
}
private IReadOnlyList<FishingLineLogicalNodeDefinition> GetResolvedDefinitions()
{
if (rigDefinition != null && IsDefinitionListUsable(rigDefinition.LogicalNodes))
{
return rigDefinition.LogicalNodes;
}
if (IsDefinitionListUsable(inlineLogicalNodes))
{
return inlineLogicalNodes;
}
fallbackLogicalNodes.Clear();
PopulatePrototypeNodes(fallbackLogicalNodes);
return fallbackLogicalNodes;
}
private static bool IsDefinitionListUsable(IReadOnlyList<FishingLineLogicalNodeDefinition> definitions)
{
if (definitions == null || definitions.Count < 2)
{
return false;
}
if (definitions[0] == null || definitions[0].NodeType != FishingLineNodeType.Start)
{
return false;
}
float totalDistance = 0f;
for (int index = 1; index < definitions.Count; index++)
{
FishingLineLogicalNodeDefinition definition = definitions[index];
if (definition == null)
{
return false;
}
totalDistance += definition.DistanceFromPrevious;
}
return totalDistance > MinSegmentLength;
}
private static void PopulatePrototypeNodes(ICollection<FishingLineLogicalNodeDefinition> target)
{
FishingLineLogicalNodeDefinition startNode = new FishingLineLogicalNodeDefinition();
startNode.ConfigurePrototype("Start", FishingLineNodeType.Start, 0f, 0, 0f, 0f, new Color(0.4f, 1f, 0.6f, 1f));
FishingLineLogicalNodeDefinition floatNode = new FishingLineLogicalNodeDefinition();
floatNode.ConfigurePrototype("Float", FishingLineNodeType.Float, 1.2f, 5, 0.15f, 0.08f, new Color(1f, 0.75f, 0.2f, 1f));
FishingLineLogicalNodeDefinition weightNode = new FishingLineLogicalNodeDefinition();
weightNode.ConfigurePrototype("Weight", FishingLineNodeType.Weight, 1.4f, 4, 1.6f, 0.02f, new Color(0.7f, 0.85f, 1f, 1f));
FishingLineLogicalNodeDefinition terminalNode = new FishingLineLogicalNodeDefinition();
terminalNode.ConfigurePrototype("Terminal", FishingLineNodeType.Terminal, 0.8f, 2, 1.2f, 0.03f, new Color(1f, 0.35f, 0.35f, 1f));
target.Add(startNode);
target.Add(floatNode);
target.Add(weightNode);
target.Add(terminalNode);
}
private void SnapToAnchors()
{
for (int index = 0; index < points.Count; index++)
@@ -298,7 +419,7 @@ public class FishingLineSolver : MonoBehaviour
Vector3 delta = pointB.Position - pointA.Position;
float distance = delta.magnitude;
float restLength = baseSegmentLengths[segmentIndex] * lengthScale;
float restLength = GetTargetSegmentLength(segmentIndex);
if (distance <= restLength || distance <= Mathf.Epsilon)
{
continue;
@@ -339,6 +460,48 @@ public class FishingLineSolver : MonoBehaviour
}
}
private void ExpandLineToCurrentLength()
{
if (points.Count < 2 || baseSegmentLengths.Count == 0)
{
return;
}
for (int segmentIndex = 0; segmentIndex < baseSegmentLengths.Count; segmentIndex++)
{
RuntimePoint pointA = points[segmentIndex];
RuntimePoint pointB = points[segmentIndex + 1];
float targetLength = GetTargetSegmentLength(segmentIndex);
Vector3 delta = pointB.Position - pointA.Position;
Vector3 direction = delta.sqrMagnitude > Mathf.Epsilon
? delta.normalized
: (initialDirection.sqrMagnitude > 0f ? initialDirection.normalized : Vector3.down);
Vector3 targetPosition = pointA.Position + direction * targetLength;
if (pointB.IsAnchored)
{
continue;
}
Vector3 offset = targetPosition - pointB.Position;
pointB.Position += offset;
pointB.PreviousPosition += offset;
}
}
private float GetTargetSegmentLength(int segmentIndex)
{
if (segmentIndex < 0 || segmentIndex >= baseSegmentLengths.Count || baseTotalLength <= MinSegmentLength)
{
return MinSegmentLength;
}
float normalizedLength = baseSegmentLengths[segmentIndex] / baseTotalLength;
return Mathf.Max(MinSegmentLength, currentLineLength * normalizedLength);
}
private void UpdateTension()
{
if (baseSegmentLengths.Count == 0)
@@ -351,7 +514,7 @@ public class FishingLineSolver : MonoBehaviour
for (int segmentIndex = 0; segmentIndex < baseSegmentLengths.Count; segmentIndex++)
{
float currentLength = Vector3.Distance(points[segmentIndex].Position, points[segmentIndex + 1].Position);
float restLength = Mathf.Max(MinSegmentLength, baseSegmentLengths[segmentIndex] * lengthScale);
float restLength = GetTargetSegmentLength(segmentIndex);
maxStretch = Mathf.Max(maxStretch, Mathf.Clamp01((currentLength - restLength) / restLength));
}
@@ -360,12 +523,7 @@ public class FishingLineSolver : MonoBehaviour
private IReadOnlyList<FishingLineLogicalNodeDefinition> GetActiveDefinitions()
{
if (rigDefinition != null && rigDefinition.LogicalNodes.Count > 0)
{
return rigDefinition.LogicalNodes;
}
return inlineLogicalNodes;
return GetResolvedDefinitions();
}
private void OnDrawGizmos()

View File

@@ -920,7 +920,7 @@ PlayerSettings:
qnxGraphicConfPath:
apiCompatibilityLevel: 6
captureStartupLogs: {}
activeInputHandler: 1
activeInputHandler: 2
windowsGamepadBackendHint: 0
enableDirectStorage: 0
cloudProjectId:

View File

@@ -0,0 +1,121 @@
{
"templatePinStates": [],
"dependencyTypeInfos": [
{
"userAdded": false,
"type": "UnityEngine.AnimationClip",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.Animations.AnimatorController",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.AnimatorOverrideController",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.Audio.AudioMixerController",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.ComputeShader",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.Cubemap",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.GameObject",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.LightingDataAsset",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.LightingSettings",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Material",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.MonoScript",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.PhysicsMaterial",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.PhysicsMaterial2D",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Rendering.PostProcessing.PostProcessResources",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Rendering.VolumeProfile",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.SceneAsset",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.Shader",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.ShaderVariantCollection",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.Texture",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Texture2D",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Timeline.TimelineAsset",
"defaultInstantiationMode": 0
}
],
"defaultDependencyTypeInfo": {
"userAdded": false,
"type": "<default_scene_template_dependencies>",
"defaultInstantiationMode": 1
},
"newSceneOverride": 0
}

View File

@@ -11,6 +11,56 @@ showStatusBar = false
scopes = {
}
providers = {
asset = {
active = true
priority = 25
defaultAction = null
}
scene = {
active = true
priority = 50
defaultAction = null
}
adb = {
active = false
priority = 2500
defaultAction = null
}
presets_provider = {
active = false
priority = -10
defaultAction = null
}
find = {
active = true
priority = 25
defaultAction = null
}
packages = {
active = false
priority = 90
defaultAction = null
}
performance = {
active = false
priority = 100
defaultAction = null
}
store = {
active = false
priority = 100
defaultAction = null
}
profilermarkers = {
active = false
priority = 100
defaultAction = null
}
log = {
active = false
priority = 210
defaultAction = null
}
}
objectSelectors = {
}