From 1389a9ec7f69b17c1b2b99e370e46c4f1c8ac966 Mon Sep 17 00:00:00 2001 From: "Bob.Song" <605277374@qq.com> Date: Mon, 6 Apr 2026 21:12:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/FishingRigDefinition.asset | 36 - Assets/New Terrain.asset | Bin 0 -> 557360 bytes ...tion.asset.meta => New Terrain.asset.meta} | 4 +- Assets/Scenes/SampleScene.unity | 711 +++++++++++++++-- Assets/Scripts/FishingFloatNodeBehaviour.cs | 32 + .../Scripts/FishingFloatNodeBehaviour.cs.meta | 2 + .../Scripts/FishingGameplayController.cs.meta | 2 - .../FishingGroundProbeNodeBehaviour.cs | 152 ++++ .../FishingGroundProbeNodeBehaviour.cs.meta | 2 + Assets/Scripts/FishingLineNode.cs | 104 ++- Assets/Scripts/FishingLineNodeBehaviour.cs | 30 + .../Scripts/FishingLineNodeBehaviour.cs.meta | 2 + Assets/Scripts/FishingLineRendererBinder.cs | 55 +- Assets/Scripts/FishingLineSolver.cs | 726 +++++++++--------- ...roller.cs => FishingLineTestController.cs} | 4 +- .../Scripts/FishingLineTestController.cs.meta | 2 + Assets/Scripts/FishingLureNodeBehaviour.cs | 34 + .../Scripts/FishingLureNodeBehaviour.cs.meta | 2 + Assets/Scripts/FishingRigDefinition.cs | 10 - Assets/Scripts/FishingRigDefinition.cs.meta | 2 - ProjectSettings/TagManager.asset | 29 +- 21 files changed, 1329 insertions(+), 612 deletions(-) delete mode 100644 Assets/FishingRigDefinition.asset create mode 100644 Assets/New Terrain.asset rename Assets/{FishingRigDefinition.asset.meta => New Terrain.asset.meta} (64%) create mode 100644 Assets/Scripts/FishingFloatNodeBehaviour.cs create mode 100644 Assets/Scripts/FishingFloatNodeBehaviour.cs.meta delete mode 100644 Assets/Scripts/FishingGameplayController.cs.meta create mode 100644 Assets/Scripts/FishingGroundProbeNodeBehaviour.cs create mode 100644 Assets/Scripts/FishingGroundProbeNodeBehaviour.cs.meta create mode 100644 Assets/Scripts/FishingLineNodeBehaviour.cs create mode 100644 Assets/Scripts/FishingLineNodeBehaviour.cs.meta rename Assets/Scripts/{FishingGameplayController.cs => FishingLineTestController.cs} (86%) create mode 100644 Assets/Scripts/FishingLineTestController.cs.meta create mode 100644 Assets/Scripts/FishingLureNodeBehaviour.cs create mode 100644 Assets/Scripts/FishingLureNodeBehaviour.cs.meta delete mode 100644 Assets/Scripts/FishingRigDefinition.cs delete mode 100644 Assets/Scripts/FishingRigDefinition.cs.meta diff --git a/Assets/FishingRigDefinition.asset b/Assets/FishingRigDefinition.asset deleted file mode 100644 index 5f11459..0000000 --- a/Assets/FishingRigDefinition.asset +++ /dev/null @@ -1,36 +0,0 @@ -%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} diff --git a/Assets/New Terrain.asset b/Assets/New Terrain.asset new file mode 100644 index 0000000000000000000000000000000000000000..4e665bc7983c9810acc2a19356cb786782efa3ef GIT binary patch literal 557360 zcmeI)UyL2sT?g>F>vhsLKm&!6(h^Kb3I7@rl9mD?acVoUgWbBZL&{(GdUxVovj4by z?brd@+Y(A!{*{&j4MEgMAOr#-9x8Z2l~9EWf+s+N2MR)!cmef=2N0_H{btUr@9gYu zBzQxgBi*wz=R0%Gna}*YH%d}fJLT0oOVu6sHOnu1@4ao?9a~-Y=6mnG_nrstx$o)w zsxREQabq-!;KdAY-1vugJoU$S-~G(Lee!pn|LYh3;>5>(JzDQutg753%ePn6EOxok ztjwCasYbEIZy%~=e>AFQv3aw7w@+@6`4`3C6N}X>|1LCbQI#@^mVb=CUmxqa|DpIq zS5dbm^LwKIZ;sWM#it!()`n4M{}069aq0hX)3y^w+VB6CCZFwWu)F_T2l=Ra|3WpJ zl>T!L{p0KR|MJ29{rSIQkdLa9aeTiQ2c5pRWj@PM+7j~{#rd4&C-XEM9i7h)HGZ#+ zKGNokGjF82{SQ^|h<$$~J~{6%8RVntPviJbMSJ%B$|j#h-Im>cw@33q=jTgze%Gf6JuOH;M^scYFGwlzo|1pp z9(mrMA1wKUd*s(6|7gj-d!PI_O8(G3`5%=0;XU&2js8Cwc|QA(Hu;gL+mh$!dgOmr z_J1UrN7a#%=5m{Vy5w)&C;#)3AKNGYOv#TA^21fm?=K_I`JEW#{rNq*Pu|V%v3>Gx zekb?IyZPmNw152V^Z9Se{2y=fs7lG}BhT+=Oa4949*aAr%RgW8)BEIKDEXN^^6Sz6 z?F;So`?h`ZJ4^odeeyS!{OllazyCZ~^7yW?YyNG1s^m}Xk>~k)XXJVQ&NcawsM`|H zr{48-KAQW!ZQh-~C-=#_^A}_7xqo;5o*Lu}&G;*2{_kw^s7lHATl&7c-@iwm=l{1#{sVjD`TgQgBG32N4`x1_e?Ru$pFfm&@BP((fBtaO|NQ=o)n}sb ze17Mmz#Wk{%!vGlGpp>|6TH@cjXIle0lvHKGfbHmv-fOeEIw4wvw;x%DeqCF<0gMo^quEF zzguq(^7j3GEVjw>zctAF@7Et~@>$ev$>X2@{Wgi_-S6+be;$wi^ZmNr!e-=9BR@*mH(1MdI)9d*$C|L&&G`TJ+F zI#RyB#w}94XOOqPFO>0TnIACzdow@a`SZR(|BJov&p$cH+wp(1jQ{*gjQ>+FG5-4p z{rAWJ=|R3wosM(=`!RlA7awT)kE)dJ{QOm!-v^`pAfFFqet^%QSjsNqRA29we4EkSe-f!LbA0FiG`~5#+{G8t}HhEN~q)$HI79!02 zBk}3qUklCq<+cd({`zQ>ABnmx-TS|Lzx+}(@Adxg-Y*~9C-2@bzdXoC&F{lk#rXOB z_?66OQI!(&@BKdf)o33b?b4h}|DV5nJoB4zliwA6ch8R(26_AZd405}&#yK4Eb6x8 z^J)J1@nSU3KR?dblgW5>SoVYrzH?~(dHy*0iFFd-sR-ZZ^ z3unjEl~`!DJ3FbL9$!4Qu{|AcEY%NH%dvWSZF+2_UV5gUoUgA=FHh>~+}7H7nw?)9 zZ`aYo?)5VK>G8FCvfXw(-;|?2vbMD{F8ytH>+9pKC+h9Zwae3(V>G@sx+>YvJ?M_)2v5*kruDeSWox=UUE9C-ugq6uB_h`pA0eXs+$tR*H1~ zG0B`qb7bom&QI#@SYp8WwVip#>-JjpT=i`7=MmN+m+tLyz>J&gXQ_3(ba7n8;jc{N z>S}3M1M+GNpPlbGwqxzA#;MOcp}H9AkB*n(=BYNuR}%a5W==hBl(o(Aa=98FnXZku zo4c(&?=e(tGhEIq{bZc{oxi8wo_FAhjq$~`x(P~$$2Qkv0^517wu3E2!{uqcd}1<* zsjOc(v$}C+e6=|_?J(J8@8&sOU#Zu!wPo3v^0}39Tu0@$Y*!v?o+|l(n!Wtr+b2w^ zKecl6rPB-k7b~~LK5wg^JyIS8d-ssvHu8y=AB6w`0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBoLe<5%rjv_zz-+%wZFMRwp`QIVrCrh{7t+%aFj~4yQ13MTN2oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs zfjtFA(fZ`!JtK_-2oNAZfB*pk1PBlyK!5-N0t5&UAh3_X@4jN6Kr;aX1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5;&|D(WYp{m;d4ZwdrTve|= KURC+Gs{RK(pPBan literal 0 HcmV?d00001 diff --git a/Assets/FishingRigDefinition.asset.meta b/Assets/New Terrain.asset.meta similarity index 64% rename from Assets/FishingRigDefinition.asset.meta rename to Assets/New Terrain.asset.meta index 1da9eeb..d3cfd52 100644 --- a/Assets/FishingRigDefinition.asset.meta +++ b/Assets/New Terrain.asset.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: a48cb68bf14ac8c429abc96a2cdb7821 +guid: 353d79ea0bc081b4c8f234204cbdcf46 NativeFormatImporter: externalObjects: {} - mainObjectFileID: 11400000 + mainObjectFileID: 15600000 userData: assetBundleName: assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 43d365f..e0ab830 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -392,33 +392,17 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 445360722} - - component: {fileID: 445360721} - - component: {fileID: 445360723} + - component: {fileID: 445360726} - component: {fileID: 445360725} - component: {fileID: 445360724} + - component: {fileID: 445360723} m_Layer: 0 - m_Name: FishingLineRoot + m_Name: LineRoot 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 @@ -428,69 +412,17 @@ Transform: 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_LocalPosition: {x: -0, y: 1, z: -0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 1930940348} + - {fileID: 1230107384} + - {fileID: 1508371650} + - {fileID: 663592153} 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} @@ -502,10 +434,9 @@ MonoBehaviour: 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 + solver: {fileID: 445360725} + lineRenderer: {fileID: 445360724} +--- !u!120 &445360724 LineRenderer: serializedVersion: 3 m_ObjectHideFlags: 0 @@ -556,7 +487,7 @@ LineRenderer: m_MaskInteraction: 0 m_Positions: - {x: 0, y: 0, z: 0} - - {x: 0, y: -0.01, z: 1} + - {x: 0, y: 0, z: 1} m_Parameters: serializedVersion: 3 widthMultiplier: 1 @@ -615,6 +546,334 @@ LineRenderer: m_UseWorldSpace: 1 m_Loop: 0 m_ApplyActiveColorSpace: 1 +--- !u!114 &445360725 +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 + lineRoot: {fileID: 445360722} + startAnchor: {fileID: 1538371803} + solverIterations: 8 + gravity: 9.81 + globalDamping: 0.01 + initialDirection: {x: 0, y: -1, z: 0} + autoUseNodeDistances: 1 + manualTotalLength: 3 + minManualLength: 0.5 + maxManualLength: 15 + drawDebug: 1 + debugPointRadius: 0.03 + virtualPointColor: {r: 0.45, g: 0.75, b: 1, a: 1} + segmentColor: {r: 0.9, g: 0.95, b: 1, a: 1} +--- !u!114 &445360726 +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: 465a2f7c62ee04948b577ee52382c43e, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingLineTestController + solver: {fileID: 445360725} + reelSpeed: 1.5 + reelInKey: 101 + reelOutKey: 113 +--- !u!1 &528985859 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 528985860} + - component: {fileID: 528985863} + - component: {fileID: 528985862} + - component: {fileID: 528985861} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &528985860 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 528985859} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1230107384} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &528985861 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 528985859} + 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_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &528985862 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 528985859} + 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 &528985863 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 528985859} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &663592152 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 663592153} + - component: {fileID: 663592154} + - component: {fileID: 663592155} + m_Layer: 0 + m_Name: TerminalNode + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &663592153 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 663592152} + 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: + - {fileID: 733128128} + m_Father: {fileID: 445360722} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &663592154 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 663592152} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6e0f6939c01292c4bb2adc26e7d6f24f, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingLineNode + nodeId: Terminal + nodeType: 3 + distanceFromPrevious: 0 + virtualNodeCount: 3 + gravityScale: 1 + damping: 0.04 + alignToLine: 1 + localForwardAxis: {x: 0, y: 0, z: 1} + upAxis: {x: 0, y: 1, z: 0} + debugColor: {r: 1, g: 1, b: 1, a: 1} +--- !u!114 &663592155 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 663592152} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 953e78672cb7e2a4ebacb573fa9a7627, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingGroundProbeNodeBehaviour + behaviourEnabled: 1 + probeShape: 2 + collisionLayers: + serializedVersion: 2 + m_Bits: 64 + probeRadius: 0.08 + capsuleHeight: 0.3 + boxHalfExtents: {x: 0.08, y: 0.08, z: 0.08} + castDistance: 0.5 + collisionPadding: 0.01 + contactDamping: 0.2 + contactFriction: 0.85 + contactSnapDistance: 0.03 + drawDebug: 1 + castColor: {r: 1, g: 0.85, b: 0.2, a: 0.9} + hitColor: {r: 0.25, g: 1, b: 0.4, a: 1} +--- !u!1 &733128127 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 733128128} + - component: {fileID: 733128131} + - component: {fileID: 733128130} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &733128128 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733128127} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 663592153} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &733128130 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733128127} + 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 &733128131 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733128127} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &832575517 GameObject: m_ObjectHideFlags: 0 @@ -664,6 +923,144 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1230107383 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1230107384} + - component: {fileID: 1230107385} + - component: {fileID: 1230107386} + m_Layer: 0 + m_Name: FloatNode + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1230107384 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1230107383} + 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: + - {fileID: 528985860} + m_Father: {fileID: 445360722} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1230107385 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1230107383} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6e0f6939c01292c4bb2adc26e7d6f24f, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingLineNode + nodeId: Float + nodeType: 1 + distanceFromPrevious: 0 + virtualNodeCount: 3 + gravityScale: 1 + damping: 0.04 + alignToLine: 1 + localForwardAxis: {x: 0, y: 0, z: 1} + upAxis: {x: 0, y: 1, z: 0} + debugColor: {r: 1, g: 1, b: 1, a: 1} +--- !u!114 &1230107386 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1230107383} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 953e78672cb7e2a4ebacb573fa9a7627, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingGroundProbeNodeBehaviour + behaviourEnabled: 1 + probeShape: 1 + collisionLayers: + serializedVersion: 2 + m_Bits: 64 + probeRadius: 0.08 + capsuleHeight: 0.3 + boxHalfExtents: {x: 0.08, y: 0.08, z: 0.08} + castDistance: 0.5 + collisionPadding: 0.01 + contactDamping: 0.2 + contactFriction: 0.85 + contactSnapDistance: 0.03 + drawDebug: 1 + castColor: {r: 1, g: 0.85, b: 0.2, a: 0.9} + hitColor: {r: 0.25, g: 1, b: 0.4, a: 1} +--- !u!1 &1508371649 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1508371650} + - component: {fileID: 1508371651} + m_Layer: 0 + m_Name: WeightNode + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1508371650 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1508371649} + 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: 445360722} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1508371651 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1508371649} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6e0f6939c01292c4bb2adc26e7d6f24f, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingLineNode + nodeId: Weight + nodeType: 2 + distanceFromPrevious: 0 + virtualNodeCount: 3 + gravityScale: 1 + damping: 0.04 + alignToLine: 1 + localForwardAxis: {x: 0, y: 0, z: 1} + upAxis: {x: 0, y: 1, z: 0} + debugColor: {r: 1, g: 1, b: 1, a: 1} --- !u!1 &1538371799 GameObject: m_ObjectHideFlags: 0 @@ -770,12 +1167,159 @@ Transform: 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_LocalPosition: {x: 0, y: 1, 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!1 &1603549249 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1603549252} + - component: {fileID: 1603549251} + - component: {fileID: 1603549250} + m_Layer: 6 + m_Name: Terrain + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!154 &1603549250 +TerrainCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1603549249} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_TerrainData: {fileID: 15600000, guid: 353d79ea0bc081b4c8f234204cbdcf46, type: 2} + m_EnableTreeColliders: 1 +--- !u!218 &1603549251 +Terrain: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1603549249} + m_Enabled: 1 + serializedVersion: 6 + m_TerrainData: {fileID: 15600000, guid: 353d79ea0bc081b4c8f234204cbdcf46, type: 2} + m_TreeDistance: 5000 + m_TreeBillboardDistance: 50 + m_TreeCrossFadeLength: 5 + m_TreeMaximumFullLODCount: 50 + m_DetailObjectDistance: 80 + m_DetailObjectDensity: 1 + m_HeightmapPixelError: 5 + m_SplatMapDistance: 1000 + m_HeightmapMinimumLODSimplification: 0 + m_HeightmapMaximumLOD: 0 + m_ShadowCastingMode: 2 + m_DrawHeightmap: 1 + m_DrawInstanced: 0 + m_DrawTreesAndFoliage: 1 + m_StaticShadowCaster: 0 + m_IgnoreQualitySettings: 0 + m_ReflectionProbeUsage: 1 + m_MaterialTemplate: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2} + m_BakeLightProbesForTrees: 1 + m_PreserveTreePrototypeLayers: 0 + m_DeringLightProbesForTrees: 1 + m_ReceiveGI: 1 + m_ScaleInLightmap: 0.0256 + m_LightmapParameters: {fileID: 15203, guid: 0000000000000000f000000000000000, type: 0} + m_GroupingID: 0 + m_RenderingLayerMask: 1 + m_AllowAutoConnect: 1 + m_EnableHeightmapRayTracing: 1 + m_EnableTreesAndDetailsRayTracing: 0 + m_TreeMotionVectorModeOverride: 3 +--- !u!4 &1603549252 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1603549249} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.46, y: 0, z: -4.86} + 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!1 &1930940347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1930940348} + - component: {fileID: 1930940349} + m_Layer: 0 + m_Name: StartNode + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1930940348 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1930940347} + 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: 445360722} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1930940349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1930940347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6e0f6939c01292c4bb2adc26e7d6f24f, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FishingLineNode + nodeId: Start + nodeType: 0 + distanceFromPrevious: 0 + virtualNodeCount: 3 + gravityScale: 1 + damping: 0.04 + alignToLine: 1 + localForwardAxis: {x: 0, y: 0, z: 1} + upAxis: {x: 0, y: 1, z: 0} + debugColor: {r: 1, g: 1, b: 1, a: 1} --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 @@ -785,3 +1329,4 @@ SceneRoots: - {fileID: 832575519} - {fileID: 1538371803} - {fileID: 445360722} + - {fileID: 1603549252} diff --git a/Assets/Scripts/FishingFloatNodeBehaviour.cs b/Assets/Scripts/FishingFloatNodeBehaviour.cs new file mode 100644 index 0000000..11e5e16 --- /dev/null +++ b/Assets/Scripts/FishingFloatNodeBehaviour.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +public class FishingFloatNodeBehaviour : FishingLineNodeBehaviour +{ + [SerializeField] private Transform waterSurface; + [SerializeField] private float fallbackWaterHeight = 0f; + [SerializeField] private float surfaceOffset = 0f; + [SerializeField] [Min(0f)] private float buoyancy = 16f; + [SerializeField] [Range(0f, 1f)] private float waterDrag = 0.22f; + [SerializeField] [Min(0.01f)] private float fullBuoyancyDepth = 0.35f; + + public override void Evaluate(ref FishingLineNodeInfluence influence, in FishingLineNodeContext context) + { + if (!BehaviourEnabled) + { + return; + } + + float surfaceY = waterSurface != null ? waterSurface.position.y : fallbackWaterHeight; + surfaceY += surfaceOffset; + + float depth = surfaceY - context.Position.y; + if (depth <= 0f) + { + return; + } + + float normalizedDepth = Mathf.Clamp01(depth / fullBuoyancyDepth); + influence.AdditionalAcceleration += Vector3.up * (buoyancy * normalizedDepth); + influence.ExtraDamping = Mathf.Max(influence.ExtraDamping, waterDrag); + } +} diff --git a/Assets/Scripts/FishingFloatNodeBehaviour.cs.meta b/Assets/Scripts/FishingFloatNodeBehaviour.cs.meta new file mode 100644 index 0000000..be60118 --- /dev/null +++ b/Assets/Scripts/FishingFloatNodeBehaviour.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d619081562aa3d546b20322841df5e50 \ No newline at end of file diff --git a/Assets/Scripts/FishingGameplayController.cs.meta b/Assets/Scripts/FishingGameplayController.cs.meta deleted file mode 100644 index 92516ee..0000000 --- a/Assets/Scripts/FishingGameplayController.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 5194be581ec15764eab72311e62182eb \ No newline at end of file diff --git a/Assets/Scripts/FishingGroundProbeNodeBehaviour.cs b/Assets/Scripts/FishingGroundProbeNodeBehaviour.cs new file mode 100644 index 0000000..9b2f8c8 --- /dev/null +++ b/Assets/Scripts/FishingGroundProbeNodeBehaviour.cs @@ -0,0 +1,152 @@ +using UnityEngine; + +public enum FishingGroundProbeShape +{ + Sphere, + Capsule, + Box +} + +public class FishingGroundProbeNodeBehaviour : FishingLineNodeBehaviour +{ + [Header("Probe")] + [SerializeField] private FishingGroundProbeShape probeShape = FishingGroundProbeShape.Sphere; + [SerializeField] private LayerMask collisionLayers = ~0; + [SerializeField] [Min(0.01f)] private float probeRadius = 0.08f; + [SerializeField] [Min(0.01f)] private float capsuleHeight = 0.3f; + [SerializeField] private Vector3 boxHalfExtents = new Vector3(0.08f, 0.08f, 0.08f); + [SerializeField] [Min(0.05f)] private float castDistance = 0.5f; + [SerializeField] [Min(0f)] private float collisionPadding = 0.01f; + [SerializeField] [Range(0f, 1f)] private float contactDamping = 0.2f; + [SerializeField] [Range(0f, 1f)] private float contactFriction = 0.85f; + [SerializeField] [Min(0f)] private float contactSnapDistance = 0.03f; + + [Header("Debug")] + [SerializeField] private bool drawDebug = true; + [SerializeField] private Color castColor = new Color(1f, 0.85f, 0.2f, 0.9f); + [SerializeField] private Color hitColor = new Color(0.25f, 1f, 0.4f, 1f); + + private bool hadHitLastFrame; + private RaycastHit lastHit; + + public override void Evaluate(ref FishingLineNodeInfluence influence, in FishingLineNodeContext context) + { + if (!BehaviourEnabled) + { + return; + } + + if (!TryProbe(context.Position, out RaycastHit hit, out float supportOffset)) + { + hadHitLastFrame = false; + return; + } + + hadHitLastFrame = true; + lastHit = hit; + + float minimumY = hit.point.y + supportOffset + collisionPadding; + bool needsSnap = context.Position.y < minimumY || minimumY - context.Position.y <= contactSnapDistance; + if (needsSnap) + { + influence.PositionOffset += Vector3.up * (minimumY - context.Position.y); + Vector3 groundVelocity = Vector3.ProjectOnPlane(context.Velocity, hit.normal) * (1f - contactFriction); + influence.VelocityOffset += groundVelocity - context.Velocity; + influence.ExtraDamping = Mathf.Max(influence.ExtraDamping, contactDamping); + } + } + + private bool TryProbe(Vector3 position, out RaycastHit hit, out float supportOffset) + { + Vector3 direction = Vector3.down; + float distance = castDistance * 2f; + + switch (probeShape) + { + case FishingGroundProbeShape.Capsule: + { + float halfSegment = Mathf.Max(0f, capsuleHeight * 0.5f - probeRadius); + Vector3 center = position + Vector3.up * castDistance; + Vector3 top = center + Vector3.up * halfSegment; + Vector3 bottom = center - Vector3.up * halfSegment; + supportOffset = probeRadius; + return Physics.CapsuleCast(top, bottom, probeRadius, direction, out hit, distance, collisionLayers, QueryTriggerInteraction.Ignore); + } + case FishingGroundProbeShape.Box: + { + Vector3 center = position + Vector3.up * castDistance; + supportOffset = boxHalfExtents.y; + return Physics.BoxCast(center, boxHalfExtents, direction, out hit, transform.rotation, distance, collisionLayers, QueryTriggerInteraction.Ignore); + } + default: + { + Vector3 origin = position + Vector3.up * castDistance; + supportOffset = probeRadius; + return Physics.SphereCast(origin, probeRadius, direction, out hit, distance, collisionLayers, QueryTriggerInteraction.Ignore); + } + } + } + + private void OnDrawGizmos() + { + if (!drawDebug) + { + return; + } + + Vector3 start = transform.position + Vector3.up * castDistance; + Vector3 end = start + Vector3.down * (castDistance * 2f); + + Gizmos.color = castColor; + switch (probeShape) + { + case FishingGroundProbeShape.Capsule: + DrawCapsuleCastGizmo(start, end); + break; + case FishingGroundProbeShape.Box: + DrawBoxCastGizmo(start, end); + break; + default: + Gizmos.DrawWireSphere(start, probeRadius); + Gizmos.DrawWireSphere(end, probeRadius); + Gizmos.DrawLine(start, end); + break; + } + + if (!hadHitLastFrame) + { + return; + } + + Gizmos.color = hitColor; + Gizmos.DrawSphere(lastHit.point, 0.03f); + Gizmos.DrawLine(lastHit.point, lastHit.point + lastHit.normal * 0.2f); + } + + private void DrawCapsuleCastGizmo(Vector3 start, Vector3 end) + { + float halfSegment = Mathf.Max(0f, capsuleHeight * 0.5f - probeRadius); + Vector3 startTop = start + Vector3.up * halfSegment; + Vector3 startBottom = start - Vector3.up * halfSegment; + Vector3 endTop = end + Vector3.up * halfSegment; + Vector3 endBottom = end - Vector3.up * halfSegment; + + Gizmos.DrawWireSphere(startTop, probeRadius); + Gizmos.DrawWireSphere(startBottom, probeRadius); + Gizmos.DrawWireSphere(endTop, probeRadius); + Gizmos.DrawWireSphere(endBottom, probeRadius); + Gizmos.DrawLine(startTop, endTop); + Gizmos.DrawLine(startBottom, endBottom); + } + + private void DrawBoxCastGizmo(Vector3 start, Vector3 end) + { + Matrix4x4 previous = Gizmos.matrix; + Gizmos.matrix = Matrix4x4.TRS(start, transform.rotation, Vector3.one); + Gizmos.DrawWireCube(Vector3.zero, boxHalfExtents * 2f); + Gizmos.matrix = Matrix4x4.TRS(end, transform.rotation, Vector3.one); + Gizmos.DrawWireCube(Vector3.zero, boxHalfExtents * 2f); + Gizmos.matrix = previous; + Gizmos.DrawLine(start, end); + } +} diff --git a/Assets/Scripts/FishingGroundProbeNodeBehaviour.cs.meta b/Assets/Scripts/FishingGroundProbeNodeBehaviour.cs.meta new file mode 100644 index 0000000..88db2b2 --- /dev/null +++ b/Assets/Scripts/FishingGroundProbeNodeBehaviour.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 953e78672cb7e2a4ebacb573fa9a7627 \ No newline at end of file diff --git a/Assets/Scripts/FishingLineNode.cs b/Assets/Scripts/FishingLineNode.cs index c8b479d..da4fe24 100644 --- a/Assets/Scripts/FishingLineNode.cs +++ b/Assets/Scripts/FishingLineNode.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using UnityEngine; @@ -11,56 +10,79 @@ public enum FishingLineNodeType Normal } -[Serializable] -public class FishingLineLogicalNodeDefinition +public class FishingLineNode : MonoBehaviour { - [SerializeField] private string id = "Node"; + [SerializeField] private string nodeId = "Node"; [SerializeField] private FishingLineNodeType nodeType = FishingLineNodeType.Normal; - [SerializeField] [Min(0f)] private float distanceFromPrevious = 1f; + [SerializeField] [Min(0f)] private float distanceFromPrevious = 0f; [SerializeField] [Min(0)] private int virtualNodeCount = 3; [SerializeField] [Min(0f)] private float gravityScale = 1f; [SerializeField] [Range(0f, 1f)] private float damping = 0.04f; - [SerializeField] private Color debugColor = Color.white; - - public string Id => id; - public FishingLineNodeType NodeType => nodeType; - public float DistanceFromPrevious => distanceFromPrevious; - public int VirtualNodeCount => virtualNodeCount; - public float GravityScale => gravityScale; - public float Damping => damping; - public Color DebugColor => debugColor; - - public void ConfigurePrototype( - string newId, - FishingLineNodeType newNodeType, - float newDistanceFromPrevious, - int newVirtualNodeCount, - float newGravityScale, - float newDamping, - Color newDebugColor) - { - id = newId; - nodeType = newNodeType; - distanceFromPrevious = Mathf.Max(0f, newDistanceFromPrevious); - virtualNodeCount = Mathf.Max(0, newVirtualNodeCount); - gravityScale = Mathf.Max(0f, newGravityScale); - damping = Mathf.Clamp01(newDamping); - debugColor = newDebugColor; - } -} - -[Serializable] -public class FishingLineAttachmentBinding -{ - [SerializeField] [Min(0)] private int logicalNodeIndex; - [SerializeField] private List targets = new List(); [SerializeField] private bool alignToLine = true; [SerializeField] private Vector3 localForwardAxis = Vector3.forward; [SerializeField] private Vector3 upAxis = Vector3.up; + [SerializeField] private Color debugColor = Color.white; - public int LogicalNodeIndex => logicalNodeIndex; - public IReadOnlyList Targets => targets; + private readonly List behaviours = new List(); + + public string NodeId => nodeId; + public FishingLineNodeType NodeType => nodeType; + public int VirtualNodeCount => virtualNodeCount; + public float GravityScale => gravityScale; + public float Damping => damping; public bool AlignToLine => alignToLine; public Vector3 LocalForwardAxis => localForwardAxis; public Vector3 UpAxis => upAxis; + public Color DebugColor => debugColor; + public IReadOnlyList Behaviours => behaviours; + + private void Reset() + { + if (string.IsNullOrWhiteSpace(nodeId)) + { + nodeId = gameObject.name; + } + + RefreshBehaviours(); + } + + private void OnValidate() + { + if (string.IsNullOrWhiteSpace(nodeId)) + { + nodeId = gameObject.name; + } + } + + [ContextMenu("Refresh Node Behaviours")] + public void RefreshBehaviours() + { + behaviours.Clear(); + FishingLineNodeBehaviour[] found = GetComponents(); + for (int index = 0; index < found.Length; index++) + { + FishingLineNodeBehaviour behaviour = found[index]; + if (behaviour == null) + { + continue; + } + + behaviours.Add(behaviour); + } + } + + public float ResolveDistanceFromPrevious(FishingLineNode previousNode) + { + if (distanceFromPrevious > 0f) + { + return distanceFromPrevious; + } + + if (previousNode == null) + { + return 0f; + } + + return Vector3.Distance(previousNode.transform.position, transform.position); + } } diff --git a/Assets/Scripts/FishingLineNodeBehaviour.cs b/Assets/Scripts/FishingLineNodeBehaviour.cs new file mode 100644 index 0000000..e87f012 --- /dev/null +++ b/Assets/Scripts/FishingLineNodeBehaviour.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +public struct FishingLineNodeContext +{ + public FishingLineSolver Solver; + public FishingLineNode Node; + public Vector3 Position; + public Vector3 PreviousPosition; + public Vector3 Velocity; + public Vector3 Tangent; + public float DeltaTime; + public float Time; +} + +public struct FishingLineNodeInfluence +{ + public Vector3 PositionOffset; + public Vector3 VelocityOffset; + public Vector3 AdditionalAcceleration; + public float ExtraDamping; +} + +public abstract class FishingLineNodeBehaviour : MonoBehaviour +{ + [SerializeField] private bool behaviourEnabled = true; + + public bool BehaviourEnabled => behaviourEnabled; + + public abstract void Evaluate(ref FishingLineNodeInfluence influence, in FishingLineNodeContext context); +} diff --git a/Assets/Scripts/FishingLineNodeBehaviour.cs.meta b/Assets/Scripts/FishingLineNodeBehaviour.cs.meta new file mode 100644 index 0000000..241006b --- /dev/null +++ b/Assets/Scripts/FishingLineNodeBehaviour.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 17d8d651410bae146843019f74bc987b \ No newline at end of file diff --git a/Assets/Scripts/FishingLineRendererBinder.cs b/Assets/Scripts/FishingLineRendererBinder.cs index a896400..3ed581d 100644 --- a/Assets/Scripts/FishingLineRendererBinder.cs +++ b/Assets/Scripts/FishingLineRendererBinder.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(LineRenderer))] @@ -6,74 +5,26 @@ public class FishingLineRendererBinder : MonoBehaviour { [SerializeField] private FishingLineSolver solver; [SerializeField] private LineRenderer lineRenderer; - [SerializeField] private List attachmentBindings = new List(); private void Reset() { - lineRenderer = GetComponent(); solver = GetComponent(); + lineRenderer = GetComponent(); } private void LateUpdate() { - if (solver == null) + if (solver == null || lineRenderer == null) { return; } - UpdateLineRenderer(); - UpdateAttachments(); - } - - private void UpdateLineRenderer() - { - if (lineRenderer == null) - { - return; - } - - IReadOnlyList positions = solver.LinePositions; + var positions = solver.LinePositions; lineRenderer.useWorldSpace = true; lineRenderer.positionCount = positions.Count; - for (int index = 0; index < positions.Count; index++) { lineRenderer.SetPosition(index, positions[index]); } } - - private void UpdateAttachments() - { - for (int bindingIndex = 0; bindingIndex < attachmentBindings.Count; bindingIndex++) - { - FishingLineAttachmentBinding binding = attachmentBindings[bindingIndex]; - if (!solver.TryGetLogicalNodePosition(binding.LogicalNodeIndex, out Vector3 position)) - { - continue; - } - - Quaternion rotation = Quaternion.identity; - if (binding.AlignToLine && solver.TryGetLogicalNodeTangent(binding.LogicalNodeIndex, out Vector3 tangent)) - { - rotation = Quaternion.LookRotation(tangent, binding.UpAxis.sqrMagnitude > 0f ? binding.UpAxis.normalized : Vector3.up); - } - - IReadOnlyList targets = binding.Targets; - for (int targetIndex = 0; targetIndex < targets.Count; targetIndex++) - { - Transform target = targets[targetIndex]; - if (target == null) - { - continue; - } - - target.position = position; - if (binding.AlignToLine) - { - Quaternion axisOffset = Quaternion.FromToRotation(binding.LocalForwardAxis.normalized, Vector3.forward); - target.rotation = rotation * Quaternion.Inverse(axisOffset); - } - } - } - } } diff --git a/Assets/Scripts/FishingLineSolver.cs b/Assets/Scripts/FishingLineSolver.cs index 4118582..095d659 100644 --- a/Assets/Scripts/FishingLineSolver.cs +++ b/Assets/Scripts/FishingLineSolver.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using UnityEngine; @@ -6,139 +5,106 @@ public class FishingLineSolver : MonoBehaviour { private const float MinSegmentLength = 0.01f; - [Header("Rig")] - [SerializeField] private FishingRigDefinition rigDefinition; - [SerializeField] private List inlineLogicalNodes = new List(); + [Header("Scene Nodes")] + [SerializeField] private Transform lineRoot; [SerializeField] private Transform startAnchor; - [SerializeField] private Vector3 initialDirection = Vector3.down; [Header("Simulation")] [SerializeField] [Min(1)] private int solverIterations = 8; [SerializeField] [Min(0f)] private float gravity = 9.81f; [SerializeField] [Range(0f, 1f)] private float globalDamping = 0.01f; - [SerializeField] [Range(0f, 1f)] private float tensionSmoothing = 0.18f; - [SerializeField] private bool simulateInFixedUpdate = false; + [SerializeField] private Vector3 initialDirection = Vector3.down; + [SerializeField] [Min(0.05f)] private float maxSolverSegmentLength = 0.25f; - [Header("Line Length")] - [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("Start Segment")] + [SerializeField] private bool useSceneDistanceForStartSegment = true; + [SerializeField] [Min(0.1f)] private float startSegmentLength = 3f; + [SerializeField] [Min(0.1f)] private float minStartSegmentLength = 0.5f; + [SerializeField] [Min(0.1f)] private float maxStartSegmentLength = 15f; [Header("Debug")] [SerializeField] private bool drawDebug = true; - [SerializeField] [Min(0.005f)] private float debugNodeRadius = 0.03f; - [SerializeField] private Color virtualNodeColor = new Color(0.4f, 0.75f, 1f, 1f); - [SerializeField] private Color segmentColor = new Color(0.85f, 0.9f, 1f, 1f); + [SerializeField] [Min(0.005f)] private float debugPointRadius = 0.03f; + [SerializeField] private Color virtualPointColor = new Color(0.45f, 0.75f, 1f, 1f); + [SerializeField] private Color segmentColor = new Color(0.9f, 0.95f, 1f, 1f); + private readonly List logicalNodes = new List(); private readonly List points = new List(); - private readonly List logicalNodes = new List(); private readonly List baseSegmentLengths = new List(); private readonly List linePositions = new List(); - private readonly List fallbackLogicalNodes = new List(); + private readonly List logicalPointIndices = new List(); private bool runtimeBuilt; - private float currentTensionNormalized; - private float previousLineLength; - private float baseTotalLength; + private float fixedRigLength; + private int startSegmentSubsegments; public IReadOnlyList 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 LogicalNodes => logicalNodes; + public float FixedRigLength => fixedRigLength; + public float StartSegmentLength => startSegmentLength; + public float TotalLineLength => fixedRigLength + startSegmentLength; - public IReadOnlyList LogicalNodeDefinitions => GetActiveDefinitions(); + private void Reset() + { + lineRoot = transform; + startAnchor = transform; + } private void OnEnable() { Rebuild(); } - private void Reset() - { - EnsureInlinePrototypeIfNeeded(); - } - private void OnValidate() { solverIterations = Mathf.Max(1, solverIterations); - minLineLength = Mathf.Max(MinSegmentLength, minLineLength); - maxLineLength = Mathf.Max(minLineLength, maxLineLength); - currentLineLength = Mathf.Clamp(currentLineLength, minLineLength, maxLineLength); + minStartSegmentLength = Mathf.Max(0.1f, minStartSegmentLength); + maxStartSegmentLength = Mathf.Max(minStartSegmentLength, maxStartSegmentLength); + startSegmentLength = Mathf.Clamp(startSegmentLength, minStartSegmentLength, maxStartSegmentLength); } private void Update() { - if (!simulateInFixedUpdate) - { - Simulate(Time.deltaTime); - } - } - - private void FixedUpdate() - { - if (simulateInFixedUpdate) - { - Simulate(Time.fixedDeltaTime); - } + Simulate(Time.deltaTime); } [ContextMenu("Rebuild Solver")] public void Rebuild() { - EnsureInlinePrototypeIfNeeded(); + CollectLogicalNodes(); BuildRuntime(); - SnapToAnchors(); + SnapAnchors(); RefreshLinePositions(); - previousLineLength = currentLineLength; + SyncLogicalNodeTransforms(); } - public void SetLineLength(float newLength) + public void SetStartSegmentLength(float newLength) { - float clampedLength = Mathf.Clamp(newLength, minLineLength, maxLineLength); - bool expanded = clampedLength > currentLineLength + Mathf.Epsilon; - currentLineLength = clampedLength; + useSceneDistanceForStartSegment = false; + startSegmentLength = Mathf.Clamp(newLength, minStartSegmentLength, maxStartSegmentLength); + } - if (expanded) + public void AdjustStartSegmentLength(float delta) + { + SetStartSegmentLength(startSegmentLength + delta); + } + + public bool TryGetLogicalNodePosition(string nodeId, out Vector3 position) + { + for (int index = 0; index < logicalNodes.Count; index++) { - ExpandLineToCurrentLength(); - RefreshLinePositions(); + FishingLineNode node = logicalNodes[index]; + if (node == null || !string.Equals(node.NodeId, nodeId, System.StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + position = points[GetLogicalPointIndex(index)].Position; + return true; } - previousLineLength = currentLineLength; - } - - public void AdjustLineLength(float delta) - { - SetLineLength(currentLineLength + delta); - } - - public bool TryGetLogicalNodePosition(int logicalNodeIndex, out Vector3 position) - { - if (logicalNodeIndex < 0 || logicalNodeIndex >= logicalNodes.Count) - { - position = default; - return false; - } - - position = logicalNodes[logicalNodeIndex].Point.Position; - return true; - } - - public bool TryGetLogicalNodeTangent(int logicalNodeIndex, out Vector3 tangent) - { - if (logicalNodeIndex < 0 || logicalNodeIndex >= logicalNodes.Count) - { - tangent = Vector3.forward; - return false; - } - - int pointIndex = logicalNodes[logicalNodeIndex].PointIndex; - Vector3 previous = pointIndex > 0 ? points[pointIndex - 1].Position : points[pointIndex].Position; - Vector3 next = pointIndex < points.Count - 1 ? points[pointIndex + 1].Position : points[pointIndex].Position; - tangent = (next - previous).normalized; - return tangent.sqrMagnitude > 0f; + position = default; + return false; } private void Simulate(float deltaTime) @@ -148,247 +114,166 @@ public class FishingLineSolver : MonoBehaviour Rebuild(); } - if (points.Count == 0 || deltaTime <= 0f) + if (!runtimeBuilt || deltaTime <= 0f) { return; } - SyncAnchors(); - if (currentLineLength > previousLineLength + Mathf.Epsilon) - { - ExpandLineToCurrentLength(); - } - + EnsureRuntimeTopologyMatchesLength(); + SyncStartAnchor(); Integrate(deltaTime); + ApplyNodeBehaviours(deltaTime); SolveConstraints(); - SyncAnchors(); + ApplyNodeBehaviours(0f); + SolveConstraints(); + SyncStartAnchor(); RefreshLinePositions(); - UpdateTension(); - previousLineLength = currentLineLength; + SyncLogicalNodeTransforms(); + } + + private void CollectLogicalNodes() + { + logicalNodes.Clear(); + + Transform root = lineRoot != null ? lineRoot : transform; + for (int childIndex = 0; childIndex < root.childCount; childIndex++) + { + Transform child = root.GetChild(childIndex); + if (child == null) + { + continue; + } + + FishingLineNode node = child.GetComponent(); + if (node == null) + { + continue; + } + + node.RefreshBehaviours(); + logicalNodes.Add(node); + } } private void BuildRuntime() { + List previousPolyline = linePositions.Count > 1 ? new List(linePositions) : null; + points.Clear(); - logicalNodes.Clear(); baseSegmentLengths.Clear(); linePositions.Clear(); - baseTotalLength = 0f; + logicalPointIndices.Clear(); + fixedRigLength = 0f; + startSegmentSubsegments = 0; + runtimeBuilt = false; - EnsureInlinePrototypeIfNeeded(); - IReadOnlyList definitions = GetResolvedDefinitions(); - if (definitions.Count == 0) + if (logicalNodes.Count < 1) { - runtimeBuilt = false; return; } - if (definitions.Count < 2) + Vector3 anchor = GetStartAnchorPosition(); + if (useSceneDistanceForStartSegment) { - Debug.LogWarning("FishingLineSolver needs at least 2 logical nodes to build a valid line.", this); - runtimeBuilt = false; - return; + startSegmentLength = Mathf.Clamp( + Mathf.Max(MinSegmentLength, Vector3.Distance(anchor, logicalNodes[0].transform.position)), + minStartSegmentLength, + maxStartSegmentLength); + } + else + { + startSegmentLength = Mathf.Clamp(startSegmentLength, minStartSegmentLength, maxStartSegmentLength); } - if (definitions[0].NodeType != FishingLineNodeType.Start) + RuntimePoint anchorPoint = new RuntimePoint(anchor, true, -1, logicalNodes[0].GravityScale, logicalNodes[0].Damping); + points.Add(anchorPoint); + + int currentPointIndex = 1; + FishingLineNode firstNode = logicalNodes[0]; + startSegmentSubsegments = Mathf.Max(1, Mathf.Max(firstNode.VirtualNodeCount + 1, Mathf.CeilToInt(startSegmentLength / maxSolverSegmentLength))); + float startSubsegmentLength = startSegmentLength / startSegmentSubsegments; + for (int virtualIndex = 1; virtualIndex < startSegmentSubsegments; virtualIndex++) { - Debug.LogWarning("FishingLineSolver expects the first logical node to be Start. The first node is still treated as the anchor.", this); + RuntimePoint virtualPoint = new RuntimePoint( + anchor, + false, + -1, + Mathf.Lerp(0f, firstNode.GravityScale, virtualIndex / (float)startSegmentSubsegments), + Mathf.Lerp(0f, firstNode.Damping, virtualIndex / (float)startSegmentSubsegments)); + + points.Add(virtualPoint); + baseSegmentLengths.Add(startSubsegmentLength); + currentPointIndex++; } - Vector3 cursor = startAnchor != null ? startAnchor.position : transform.position; - Vector3 direction = initialDirection.sqrMagnitude > 0f ? initialDirection.normalized : Vector3.down; + RuntimePoint firstLogicalPoint = new RuntimePoint(anchor, false, 0, firstNode.GravityScale, firstNode.Damping); + points.Add(firstLogicalPoint); + baseSegmentLengths.Add(startSubsegmentLength); + logicalPointIndices.Add(currentPointIndex); + currentPointIndex++; - for (int logicalIndex = 0; logicalIndex < definitions.Count; logicalIndex++) + for (int logicalIndex = 1; logicalIndex < logicalNodes.Count; logicalIndex++) { - FishingLineLogicalNodeDefinition definition = definitions[logicalIndex]; - bool anchored = logicalIndex == 0; + FishingLineNode node = logicalNodes[logicalIndex]; + FishingLineNode previousNode = logicalNodes[logicalIndex - 1]; + float baseDistance = Mathf.Max(MinSegmentLength, node.ResolveDistanceFromPrevious(previousNode)); + fixedRigLength += baseDistance; - if (logicalIndex > 0) + int requiredSubsegments = Mathf.Max(1, node.VirtualNodeCount + 1); + float baseSubsegmentLength = baseDistance / requiredSubsegments; + for (int virtualIndex = 1; virtualIndex < requiredSubsegments; virtualIndex++) { - FishingLineLogicalNodeDefinition previousDefinition = definitions[logicalIndex - 1]; - float logicalDistance = Mathf.Max(MinSegmentLength, definition.DistanceFromPrevious); - int virtualNodeCount = Mathf.Max(0, definition.VirtualNodeCount); - float subSegmentLength = logicalDistance / (virtualNodeCount + 1); + RuntimePoint virtualPoint = new RuntimePoint( + anchor, + false, + -1, + Mathf.Lerp(previousNode.GravityScale, node.GravityScale, virtualIndex / (float)requiredSubsegments), + Mathf.Lerp(previousNode.Damping, node.Damping, virtualIndex / (float)requiredSubsegments)); - for (int virtualIndex = 0; virtualIndex < virtualNodeCount; virtualIndex++) - { - cursor += direction * subSegmentLength; - RuntimePoint virtualPoint = new RuntimePoint( - cursor, - false, - -1, - Mathf.Lerp(previousDefinition.GravityScale, definition.GravityScale, (virtualIndex + 1f) / (virtualNodeCount + 1f)), - Mathf.Lerp(previousDefinition.Damping, definition.Damping, (virtualIndex + 1f) / (virtualNodeCount + 1f))); - - 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); - if (anchored) - { - logicalPoint.Anchor = startAnchor; + points.Add(virtualPoint); + baseSegmentLengths.Add(baseSubsegmentLength); + currentPointIndex++; } + RuntimePoint logicalPoint = new RuntimePoint(anchor, false, logicalIndex, node.GravityScale, node.Damping); points.Add(logicalPoint); - logicalNodes.Add(new RuntimeLogicalNode(logicalIndex, points.Count - 1, logicalPoint)); - linePositions.Add(cursor); + baseSegmentLengths.Add(baseSubsegmentLength); + logicalPointIndices.Add(currentPointIndex); + currentPointIndex++; } - InitializeLineLengthDefaults(); - runtimeBuilt = points.Count > 0; + InitializeRuntimePointPositions(previousPolyline); + runtimeBuilt = true; } - private void InitializeLineLengthDefaults() + private void SnapAnchors() { - 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)) + if (points.Count == 0) { return; } - if (IsDefinitionListUsable(inlineLogicalNodes)) + RuntimePoint startPoint = points[0]; + Vector3 anchorPosition = GetStartAnchorPosition(); + startPoint.Position = anchorPosition; + startPoint.PreviousPosition = anchorPosition; + } + + private void SyncStartAnchor() + { + if (points.Count == 0) { return; } - inlineLogicalNodes.Clear(); - PopulatePrototypeNodes(inlineLogicalNodes); - } - - private IReadOnlyList 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 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 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++) - { - RuntimePoint point = points[index]; - if (!point.IsAnchored) - { - continue; - } - - Vector3 anchorPosition = point.Anchor != null ? point.Anchor.position : transform.position; - point.Position = anchorPosition; - point.PreviousPosition = anchorPosition; - } - } - - private void SyncAnchors() - { - for (int index = 0; index < points.Count; index++) - { - RuntimePoint point = points[index]; - if (!point.IsAnchored) - { - continue; - } - - Vector3 anchorPosition = point.Anchor != null ? point.Anchor.position : transform.position; - point.Position = anchorPosition; - } + Vector3 anchorPosition = GetStartAnchorPosition(); + points[0].Position = anchorPosition; + points[0].PreviousPosition = anchorPosition; } private void Integrate(float deltaTime) { - float deltaTimeSqr = deltaTime * deltaTime; + float deltaTimeSquared = deltaTime * deltaTime; for (int index = 0; index < points.Count; index++) { @@ -401,13 +286,65 @@ public class FishingLineSolver : MonoBehaviour Vector3 velocity = point.Position - point.PreviousPosition; float dampingFactor = Mathf.Clamp01(1f - globalDamping - point.Damping); - Vector3 nextPosition = point.Position + velocity * dampingFactor + Vector3.down * (gravity * point.GravityScale * deltaTimeSqr); + Vector3 nextPosition = point.Position + velocity * dampingFactor + Vector3.down * (gravity * point.GravityScale * deltaTimeSquared); point.PreviousPosition = point.Position; point.Position = nextPosition; } } + private void ApplyNodeBehaviours(float deltaTime) + { + for (int logicalIndex = 0; logicalIndex < logicalNodes.Count; logicalIndex++) + { + FishingLineNode node = logicalNodes[logicalIndex]; + RuntimePoint point = points[GetLogicalPointIndex(logicalIndex)]; + if (point.IsAnchored) + { + continue; + } + + Vector3 tangent = GetLogicalNodeTangent(logicalIndex); + Vector3 velocity = point.Position - point.PreviousPosition; + + FishingLineNodeContext context = new FishingLineNodeContext + { + Solver = this, + Node = node, + Position = point.Position, + PreviousPosition = point.PreviousPosition, + Velocity = velocity, + Tangent = tangent, + DeltaTime = deltaTime, + Time = Time.time + }; + + FishingLineNodeInfluence influence = default; + IReadOnlyList behaviours = node.Behaviours; + for (int behaviourIndex = 0; behaviourIndex < behaviours.Count; behaviourIndex++) + { + FishingLineNodeBehaviour behaviour = behaviours[behaviourIndex]; + if (behaviour == null || !behaviour.BehaviourEnabled) + { + continue; + } + + behaviour.Evaluate(ref influence, context); + } + + ApplyInfluence(point, influence, deltaTime); + } + } + + private static void ApplyInfluence(RuntimePoint point, FishingLineNodeInfluence influence, float deltaTime) + { + Vector3 velocity = point.Position - point.PreviousPosition + influence.VelocityOffset; + velocity *= Mathf.Clamp01(1f - influence.ExtraDamping); + + point.PreviousPosition = point.Position - velocity; + point.Position += influence.PositionOffset + influence.AdditionalAcceleration * (deltaTime * deltaTime); + } + private void SolveConstraints() { for (int iteration = 0; iteration < solverIterations; iteration++) @@ -419,19 +356,13 @@ public class FishingLineSolver : MonoBehaviour Vector3 delta = pointB.Position - pointA.Position; float distance = delta.magnitude; - float restLength = GetTargetSegmentLength(segmentIndex); + float restLength = GetSegmentTargetLength(segmentIndex); if (distance <= restLength || distance <= Mathf.Epsilon) { continue; } Vector3 correction = delta * ((distance - restLength) / distance); - - if (pointA.IsAnchored && pointB.IsAnchored) - { - continue; - } - if (pointA.IsAnchored) { pointB.Position -= correction; @@ -444,13 +375,28 @@ public class FishingLineSolver : MonoBehaviour continue; } - Vector3 halfCorrection = correction * 0.5f; - pointA.Position += halfCorrection; - pointB.Position -= halfCorrection; + Vector3 half = correction * 0.5f; + pointA.Position += half; + pointB.Position -= half; } } } + private float GetSegmentTargetLength(int segmentIndex) + { + if (segmentIndex < 0 || segmentIndex >= baseSegmentLengths.Count) + { + return MinSegmentLength; + } + + if (segmentIndex < startSegmentSubsegments) + { + return Mathf.Max(MinSegmentLength, startSegmentLength / Mathf.Max(1, startSegmentSubsegments)); + } + + return Mathf.Max(MinSegmentLength, baseSegmentLengths[segmentIndex]); + } + private void RefreshLinePositions() { linePositions.Clear(); @@ -460,70 +406,62 @@ public class FishingLineSolver : MonoBehaviour } } - private void ExpandLineToCurrentLength() + private void SyncLogicalNodeTransforms() { - if (points.Count < 2 || baseSegmentLengths.Count == 0) + for (int logicalIndex = 0; logicalIndex < logicalNodes.Count; logicalIndex++) { - return; - } + FishingLineNode node = logicalNodes[logicalIndex]; + RuntimePoint point = points[GetLogicalPointIndex(logicalIndex)]; + node.transform.position = point.Position; - 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) + if (!node.AlignToLine) { continue; } - Vector3 offset = targetPosition - pointB.Position; - pointB.Position += offset; - pointB.PreviousPosition += offset; + Vector3 tangent = GetLogicalNodeTangent(logicalIndex); + if (tangent.sqrMagnitude <= Mathf.Epsilon) + { + continue; + } + + Quaternion lineRotation = Quaternion.LookRotation(tangent.normalized, node.UpAxis.sqrMagnitude > 0f ? node.UpAxis.normalized : Vector3.up); + Quaternion axisOffset = Quaternion.FromToRotation(node.LocalForwardAxis.normalized, Vector3.forward); + node.transform.rotation = lineRotation * Quaternion.Inverse(axisOffset); } } - private float GetTargetSegmentLength(int segmentIndex) + private Vector3 GetStartAnchorPosition() { - if (segmentIndex < 0 || segmentIndex >= baseSegmentLengths.Count || baseTotalLength <= MinSegmentLength) + if (startAnchor != null) { - return MinSegmentLength; + return startAnchor.position; } - float normalizedLength = baseSegmentLengths[segmentIndex] / baseTotalLength; - return Mathf.Max(MinSegmentLength, currentLineLength * normalizedLength); + if (logicalNodes.Count > 0 && logicalNodes[0] != null) + { + return logicalNodes[0].transform.position; + } + + return transform.position; } - private void UpdateTension() + private int GetLogicalPointIndex(int logicalNodeIndex) { - if (baseSegmentLengths.Count == 0) + if (logicalNodeIndex < 0 || logicalNodeIndex >= logicalPointIndices.Count) { - currentTensionNormalized = 0f; - return; + return Mathf.Clamp(startSegmentSubsegments, 0, points.Count - 1); } - float maxStretch = 0f; - for (int segmentIndex = 0; segmentIndex < baseSegmentLengths.Count; segmentIndex++) - { - float currentLength = Vector3.Distance(points[segmentIndex].Position, points[segmentIndex + 1].Position); - float restLength = GetTargetSegmentLength(segmentIndex); - maxStretch = Mathf.Max(maxStretch, Mathf.Clamp01((currentLength - restLength) / restLength)); - } - - currentTensionNormalized = Mathf.Lerp(currentTensionNormalized, maxStretch, tensionSmoothing); + return logicalPointIndices[logicalNodeIndex]; } - private IReadOnlyList GetActiveDefinitions() + private Vector3 GetLogicalNodeTangent(int logicalNodeIndex) { - return GetResolvedDefinitions(); + int pointIndex = GetLogicalPointIndex(logicalNodeIndex); + Vector3 previous = pointIndex > 0 ? points[pointIndex - 1].Position : points[pointIndex].Position; + Vector3 next = pointIndex < points.Count - 1 ? points[pointIndex + 1].Position : points[pointIndex].Position; + return next - previous; } private void OnDrawGizmos() @@ -533,54 +471,133 @@ public class FishingLineSolver : MonoBehaviour return; } - IReadOnlyList definitions = GetActiveDefinitions(); - Gizmos.color = segmentColor; - for (int segmentIndex = 0; segmentIndex < points.Count - 1; segmentIndex++) + for (int index = 0; index < points.Count - 1; index++) { - Gizmos.DrawLine(points[segmentIndex].Position, points[segmentIndex + 1].Position); + Gizmos.DrawLine(points[index].Position, points[index + 1].Position); } for (int pointIndex = 0; pointIndex < points.Count; pointIndex++) { RuntimePoint point = points[pointIndex]; - if (point.IsLogicalNode) + if (point.LogicalNodeIndex >= 0 && point.LogicalNodeIndex < logicalNodes.Count) { - FishingLineLogicalNodeDefinition definition = definitions[point.LogicalNodeIndex]; - Gizmos.color = definition.DebugColor; - Gizmos.DrawSphere(point.Position, debugNodeRadius * 1.35f); + Gizmos.color = logicalNodes[point.LogicalNodeIndex].DebugColor; + Gizmos.DrawSphere(point.Position, debugPointRadius * 1.35f); } else { - Gizmos.color = virtualNodeColor; - Gizmos.DrawSphere(point.Position, debugNodeRadius); + Gizmos.color = virtualPointColor; + Gizmos.DrawSphere(point.Position, debugPointRadius); } } } - [Serializable] - private class RuntimeLogicalNode + private void EnsureRuntimeTopologyMatchesLength() { - public RuntimeLogicalNode(int logicalIndex, int pointIndex, RuntimePoint point) + if (logicalNodes.Count < 1) { - LogicalIndex = logicalIndex; - PointIndex = pointIndex; - Point = point; + return; } - public int LogicalIndex { get; } - public int PointIndex { get; } - public RuntimePoint Point { get; } + int minSubsegments = Mathf.Max(1, logicalNodes[0].VirtualNodeCount + 1); + int requiredSubsegments = Mathf.Max(minSubsegments, Mathf.CeilToInt(startSegmentLength / maxSolverSegmentLength)); + if (requiredSubsegments != startSegmentSubsegments) + { + BuildRuntime(); + SnapAnchors(); + RefreshLinePositions(); + } + } + + private void InitializeRuntimePointPositions(IReadOnlyList previousPolyline) + { + if (points.Count == 0) + { + return; + } + + Vector3 anchor = GetStartAnchorPosition(); + points[0].Position = anchor; + points[0].PreviousPosition = anchor; + + float targetTotalLength = TotalLineLength; + if (previousPolyline != null && previousPolyline.Count > 1) + { + Vector3 oldAnchor = previousPolyline[0]; + Vector3 offset = anchor - oldAnchor; + float cumulativeDistance = 0f; + for (int pointIndex = 1; pointIndex < points.Count; pointIndex++) + { + cumulativeDistance += GetSegmentTargetLength(pointIndex - 1); + float normalized = targetTotalLength > MinSegmentLength ? cumulativeDistance / targetTotalLength : 0f; + Vector3 sampled = SamplePolylineNormalized(previousPolyline, normalized) + offset; + points[pointIndex].Position = sampled; + points[pointIndex].PreviousPosition = sampled; + } + + return; + } + + Vector3 direction = initialDirection.sqrMagnitude > 0f ? initialDirection.normalized : Vector3.down; + Vector3 cursor = anchor; + for (int pointIndex = 1; pointIndex < points.Count; pointIndex++) + { + cursor += direction * GetSegmentTargetLength(pointIndex - 1); + points[pointIndex].Position = cursor; + points[pointIndex].PreviousPosition = cursor; + } + } + + private static Vector3 SamplePolylineNormalized(IReadOnlyList polyline, float normalized) + { + if (polyline == null || polyline.Count == 0) + { + return Vector3.zero; + } + + if (polyline.Count == 1) + { + return polyline[0]; + } + + float totalLength = 0f; + for (int index = 0; index < polyline.Count - 1; index++) + { + totalLength += Vector3.Distance(polyline[index], polyline[index + 1]); + } + + if (totalLength <= Mathf.Epsilon) + { + return polyline[0]; + } + + float targetDistance = Mathf.Clamp01(normalized) * totalLength; + float traversed = 0f; + for (int index = 0; index < polyline.Count - 1; index++) + { + Vector3 from = polyline[index]; + Vector3 to = polyline[index + 1]; + float segmentLength = Vector3.Distance(from, to); + if (traversed + segmentLength >= targetDistance) + { + float t = segmentLength <= Mathf.Epsilon ? 0f : (targetDistance - traversed) / segmentLength; + return Vector3.Lerp(from, to, t); + } + + traversed += segmentLength; + } + + return polyline[polyline.Count - 1]; } - [Serializable] private class RuntimePoint { - public RuntimePoint(Vector3 position, bool isAnchored, int logicalNodeIndex, float gravityScale, float damping) + public RuntimePoint(Vector3 position, bool anchored, int logicalNodeIndex, float gravityScale, float damping) { Position = position; PreviousPosition = position; - IsAnchored = isAnchored; + IsAnchored = anchored; LogicalNodeIndex = logicalNodeIndex; GravityScale = gravityScale; Damping = damping; @@ -589,11 +606,8 @@ public class FishingLineSolver : MonoBehaviour public Vector3 Position; public Vector3 PreviousPosition; public bool IsAnchored; - public Transform Anchor; public int LogicalNodeIndex; public float GravityScale; public float Damping; - - public bool IsLogicalNode => LogicalNodeIndex >= 0; } } diff --git a/Assets/Scripts/FishingGameplayController.cs b/Assets/Scripts/FishingLineTestController.cs similarity index 86% rename from Assets/Scripts/FishingGameplayController.cs rename to Assets/Scripts/FishingLineTestController.cs index 256105e..5ab5326 100644 --- a/Assets/Scripts/FishingGameplayController.cs +++ b/Assets/Scripts/FishingLineTestController.cs @@ -1,6 +1,6 @@ using UnityEngine; -public class FishingGameplayController : MonoBehaviour +public class FishingLineTestController : MonoBehaviour { [SerializeField] private FishingLineSolver solver; [SerializeField] [Min(0.01f)] private float reelSpeed = 1.5f; @@ -38,7 +38,7 @@ public class FishingGameplayController : MonoBehaviour if (Mathf.Abs(direction) > Mathf.Epsilon) { - solver.AdjustLineLength(direction * reelSpeed * Time.deltaTime); + solver.AdjustStartSegmentLength(direction * reelSpeed * Time.deltaTime); } } } diff --git a/Assets/Scripts/FishingLineTestController.cs.meta b/Assets/Scripts/FishingLineTestController.cs.meta new file mode 100644 index 0000000..bcab124 --- /dev/null +++ b/Assets/Scripts/FishingLineTestController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 465a2f7c62ee04948b577ee52382c43e \ No newline at end of file diff --git a/Assets/Scripts/FishingLureNodeBehaviour.cs b/Assets/Scripts/FishingLureNodeBehaviour.cs new file mode 100644 index 0000000..47cb328 --- /dev/null +++ b/Assets/Scripts/FishingLureNodeBehaviour.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +public class FishingLureNodeBehaviour : FishingLineNodeBehaviour +{ + [SerializeField] [Min(0f)] private float swimStrength = 2f; + [SerializeField] [Min(0f)] private float swimFrequency = 6f; + [SerializeField] [Range(0f, 1f)] private float waterDrag = 0.12f; + [SerializeField] private Transform waterSurface; + [SerializeField] private float fallbackWaterHeight = 0f; + + public override void Evaluate(ref FishingLineNodeInfluence influence, in FishingLineNodeContext context) + { + if (!BehaviourEnabled) + { + return; + } + + float surfaceY = waterSurface != null ? waterSurface.position.y : fallbackWaterHeight; + if (context.Position.y > surfaceY) + { + return; + } + + Vector3 side = Vector3.Cross(context.Tangent.sqrMagnitude > 0f ? context.Tangent.normalized : Vector3.forward, Vector3.up); + if (side.sqrMagnitude <= Mathf.Epsilon) + { + side = Vector3.right; + } + + float swim = Mathf.Sin(context.Time * swimFrequency) * swimStrength; + influence.AdditionalAcceleration += side.normalized * swim; + influence.ExtraDamping = Mathf.Max(influence.ExtraDamping, waterDrag); + } +} diff --git a/Assets/Scripts/FishingLureNodeBehaviour.cs.meta b/Assets/Scripts/FishingLureNodeBehaviour.cs.meta new file mode 100644 index 0000000..85e9393 --- /dev/null +++ b/Assets/Scripts/FishingLureNodeBehaviour.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3c801f9083845c14088f6db1fdbc6020 \ No newline at end of file diff --git a/Assets/Scripts/FishingRigDefinition.cs b/Assets/Scripts/FishingRigDefinition.cs deleted file mode 100644 index 855159a..0000000 --- a/Assets/Scripts/FishingRigDefinition.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -[CreateAssetMenu(fileName = "FishingRigDefinition", menuName = "Fishing/Fishing Rig Definition")] -public class FishingRigDefinition : ScriptableObject -{ - [SerializeField] private List logicalNodes = new List(); - - public IReadOnlyList LogicalNodes => logicalNodes; -} diff --git a/Assets/Scripts/FishingRigDefinition.cs.meta b/Assets/Scripts/FishingRigDefinition.cs.meta deleted file mode 100644 index f7759fa..0000000 --- a/Assets/Scripts/FishingRigDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9d66919bfa33a7445b32a45410e0ccfe \ No newline at end of file diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 6413d11..5ef3972 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -2,7 +2,7 @@ %TAG !u! tag:unity3d.com,2011: --- !u!78 &1 TagManager: - serializedVersion: 2 + serializedVersion: 3 tags: [] layers: - Default @@ -11,7 +11,7 @@ TagManager: - - Water - UI - - + - Terrain - - - @@ -50,27 +50,4 @@ TagManager: - Light Layer 5 - Light Layer 6 - Light Layer 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_MigratedRenderPipelines: []