Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69bb9c93fb | |||
| fbe33f9f3a | |||
| 95700b71c1 | |||
| d451af0c8a |
@@ -18553,6 +18553,21 @@ MonoBehaviour:
|
|||||||
- {fileID: 102900000, guid: 60ac19fbbe20cec48add96b79332c113, type: 3}
|
- {fileID: 102900000, guid: 60ac19fbbe20cec48add96b79332c113, type: 3}
|
||||||
FilterEnum: 0
|
FilterEnum: 0
|
||||||
Filter: '*'
|
Filter: '*'
|
||||||
|
- Path: Assets/ResRaw/Prefabs/Line/fishing line float set 1.prefab
|
||||||
|
Address: Plyaer/fishing line float set 1
|
||||||
|
Type: GameObject
|
||||||
|
Bundle: main/plyaer.bundle
|
||||||
|
Tags:
|
||||||
|
Group:
|
||||||
|
Name: Plyaer
|
||||||
|
Enable: 1
|
||||||
|
BundleMode: 0
|
||||||
|
AddressMode: 2
|
||||||
|
Tags:
|
||||||
|
Collectors:
|
||||||
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
|
FilterEnum: 0
|
||||||
|
Filter: '*'
|
||||||
- Path: Assets/ResRaw/Prefabs/Line/fishing line float set.prefab
|
- Path: Assets/ResRaw/Prefabs/Line/fishing line float set.prefab
|
||||||
Address: Plyaer/fishing line float set
|
Address: Plyaer/fishing line float set
|
||||||
Type: GameObject
|
Type: GameObject
|
||||||
@@ -18583,6 +18598,51 @@ MonoBehaviour:
|
|||||||
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
FilterEnum: 0
|
FilterEnum: 0
|
||||||
Filter: '*'
|
Filter: '*'
|
||||||
|
- Path: Assets/ResRaw/Prefabs/Line/FishingRopeLong.asset
|
||||||
|
Address: Plyaer/FishingRopeLong
|
||||||
|
Type: Missing
|
||||||
|
Bundle: main/plyaer.bundle
|
||||||
|
Tags:
|
||||||
|
Group:
|
||||||
|
Name: Plyaer
|
||||||
|
Enable: 1
|
||||||
|
BundleMode: 0
|
||||||
|
AddressMode: 2
|
||||||
|
Tags:
|
||||||
|
Collectors:
|
||||||
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
|
FilterEnum: 0
|
||||||
|
Filter: '*'
|
||||||
|
- Path: Assets/ResRaw/Prefabs/Line/FishingRopeLong2.asset
|
||||||
|
Address: Plyaer/FishingRopeLong2
|
||||||
|
Type: Missing
|
||||||
|
Bundle: main/plyaer.bundle
|
||||||
|
Tags:
|
||||||
|
Group:
|
||||||
|
Name: Plyaer
|
||||||
|
Enable: 1
|
||||||
|
BundleMode: 0
|
||||||
|
AddressMode: 2
|
||||||
|
Tags:
|
||||||
|
Collectors:
|
||||||
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
|
FilterEnum: 0
|
||||||
|
Filter: '*'
|
||||||
|
- Path: Assets/ResRaw/Prefabs/Line/FishingRopeShort.asset
|
||||||
|
Address: Plyaer/FishingRopeShort
|
||||||
|
Type: Missing
|
||||||
|
Bundle: main/plyaer.bundle
|
||||||
|
Tags:
|
||||||
|
Group:
|
||||||
|
Name: Plyaer
|
||||||
|
Enable: 1
|
||||||
|
BundleMode: 0
|
||||||
|
AddressMode: 2
|
||||||
|
Tags:
|
||||||
|
Collectors:
|
||||||
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
|
FilterEnum: 0
|
||||||
|
Filter: '*'
|
||||||
- Path: Assets/ResRaw/Prefabs/Line/LineHand1.prefab
|
- Path: Assets/ResRaw/Prefabs/Line/LineHand1.prefab
|
||||||
Address: Plyaer/LineHand1
|
Address: Plyaer/LineHand1
|
||||||
Type: GameObject
|
Type: GameObject
|
||||||
@@ -18613,6 +18673,36 @@ MonoBehaviour:
|
|||||||
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
FilterEnum: 0
|
FilterEnum: 0
|
||||||
Filter: '*'
|
Filter: '*'
|
||||||
|
- Path: Assets/ResRaw/Prefabs/Line/RopeSegment_4.asset
|
||||||
|
Address: Plyaer/RopeSegment_4
|
||||||
|
Type: Missing
|
||||||
|
Bundle: main/plyaer.bundle
|
||||||
|
Tags:
|
||||||
|
Group:
|
||||||
|
Name: Plyaer
|
||||||
|
Enable: 1
|
||||||
|
BundleMode: 0
|
||||||
|
AddressMode: 2
|
||||||
|
Tags:
|
||||||
|
Collectors:
|
||||||
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
|
FilterEnum: 0
|
||||||
|
Filter: '*'
|
||||||
|
- Path: Assets/ResRaw/Prefabs/Line/Spool.mat
|
||||||
|
Address: Plyaer/Spool
|
||||||
|
Type: Material
|
||||||
|
Bundle: main/plyaer.bundle
|
||||||
|
Tags:
|
||||||
|
Group:
|
||||||
|
Name: Plyaer
|
||||||
|
Enable: 1
|
||||||
|
BundleMode: 0
|
||||||
|
AddressMode: 2
|
||||||
|
Tags:
|
||||||
|
Collectors:
|
||||||
|
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||||
|
FilterEnum: 0
|
||||||
|
Filter: '*'
|
||||||
- Path: Assets/ResRaw/Prefabs/Player/Anim/AnimationClip/CameraCrouch.anim
|
- Path: Assets/ResRaw/Prefabs/Player/Anim/AnimationClip/CameraCrouch.anim
|
||||||
Address: Plyaer/CameraCrouch
|
Address: Plyaer/CameraCrouch
|
||||||
Type: AnimationClip
|
Type: AnimationClip
|
||||||
|
|||||||
Binary file not shown.
4788
Assets/ResRaw/Prefabs/Line/FishingRopeLong.asset
Normal file
4788
Assets/ResRaw/Prefabs/Line/FishingRopeLong.asset
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/ResRaw/Prefabs/Line/FishingRopeLong.asset.meta
Normal file
8
Assets/ResRaw/Prefabs/Line/FishingRopeLong.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c29a67f2195883840b049b2c2a54a55c
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
6227
Assets/ResRaw/Prefabs/Line/FishingRopeLong2.asset
Normal file
6227
Assets/ResRaw/Prefabs/Line/FishingRopeLong2.asset
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/ResRaw/Prefabs/Line/FishingRopeLong2.asset.meta
Normal file
8
Assets/ResRaw/Prefabs/Line/FishingRopeLong2.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 90165a559e0af984497f40ee19419ea5
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
2282
Assets/ResRaw/Prefabs/Line/FishingRopeShort.asset
Normal file
2282
Assets/ResRaw/Prefabs/Line/FishingRopeShort.asset
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/ResRaw/Prefabs/Line/FishingRopeShort.asset.meta
Normal file
8
Assets/ResRaw/Prefabs/Line/FishingRopeShort.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c70c206ebccc14c4eb6a0cdbe80779f7
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
1715
Assets/ResRaw/Prefabs/Line/RopeSegment_4.asset
Normal file
1715
Assets/ResRaw/Prefabs/Line/RopeSegment_4.asset
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/ResRaw/Prefabs/Line/RopeSegment_4.asset.meta
Normal file
8
Assets/ResRaw/Prefabs/Line/RopeSegment_4.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a41193e381908de44b097f1f57b43028
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
137
Assets/ResRaw/Prefabs/Line/Spool.mat
Normal file
137
Assets/ResRaw/Prefabs/Line/Spool.mat
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 8
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Spool
|
||||||
|
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||||
|
m_Parent: {fileID: 0}
|
||||||
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords: []
|
||||||
|
m_InvalidKeywords: []
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap:
|
||||||
|
RenderType: Opaque
|
||||||
|
disabledShaderPasses:
|
||||||
|
- MOTIONVECTORS
|
||||||
|
m_LockedProperties:
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BaseMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _SpecGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_Lightmaps:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_LightmapsInd:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_ShadowMasks:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
|
m_Floats:
|
||||||
|
- _AddPrecomputedVelocity: 0
|
||||||
|
- _AlphaClip: 0
|
||||||
|
- _AlphaToMask: 0
|
||||||
|
- _Blend: 0
|
||||||
|
- _BlendModePreserveSpecular: 1
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _ClearCoatMask: 0
|
||||||
|
- _ClearCoatSmoothness: 0
|
||||||
|
- _Cull: 2
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailAlbedoMapScale: 1
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _DstBlendAlpha: 0
|
||||||
|
- _EnvironmentReflections: 1
|
||||||
|
- _GlossMapScale: 0
|
||||||
|
- _Glossiness: 0
|
||||||
|
- _GlossyReflections: 0
|
||||||
|
- _Metallic: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.005
|
||||||
|
- _QueueOffset: 0
|
||||||
|
- _ReceiveShadows: 1
|
||||||
|
- _Smoothness: 0.5
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _SrcBlendAlpha: 1
|
||||||
|
- _Surface: 0
|
||||||
|
- _WorkflowMode: 1
|
||||||
|
- _XRMotionVectorsPass: 1
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
|
--- !u!114 &4684454134489156479
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 11
|
||||||
|
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||||
|
version: 10
|
||||||
8
Assets/ResRaw/Prefabs/Line/Spool.mat.meta
Normal file
8
Assets/ResRaw/Prefabs/Line/Spool.mat.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 95a26dca51ebe9c4da5949631fa36027
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
427
Assets/ResRaw/Prefabs/Line/fishing line float set 1.prefab
Normal file
427
Assets/ResRaw/Prefabs/Line/fishing line float set 1.prefab
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &1035052809208993
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4026445325167852}
|
||||||
|
- component: {fileID: 54679398375713381}
|
||||||
|
- component: {fileID: 153611279189314279}
|
||||||
|
- component: {fileID: 135844594273256032}
|
||||||
|
- component: {fileID: 7176287465780574680}
|
||||||
|
m_Layer: 15
|
||||||
|
m_Name: Lure
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4026445325167852
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1035052809208993}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: -1.5, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 4283454774123242}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!54 &54679398375713381
|
||||||
|
Rigidbody:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1035052809208993}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Mass: 0.01
|
||||||
|
m_LinearDamping: 1
|
||||||
|
m_AngularDamping: 0.1
|
||||||
|
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||||
|
m_InertiaTensor: {x: 0.001, y: 0.001, z: 0.001}
|
||||||
|
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ImplicitCom: 1
|
||||||
|
m_ImplicitTensor: 0
|
||||||
|
m_UseGravity: 0
|
||||||
|
m_IsKinematic: 0
|
||||||
|
m_Interpolate: 0
|
||||||
|
m_Constraints: 0
|
||||||
|
m_CollisionDetection: 2
|
||||||
|
--- !u!153 &153611279189314279
|
||||||
|
ConfigurableJoint:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1035052809208993}
|
||||||
|
serializedVersion: 4
|
||||||
|
m_ConnectedBody: {fileID: 54298866000586118}
|
||||||
|
m_ConnectedArticulationBody: {fileID: 0}
|
||||||
|
m_Anchor: {x: 0, y: 0, z: 0}
|
||||||
|
m_Axis: {x: 0, y: 0, z: 0}
|
||||||
|
m_AutoConfigureConnectedAnchor: 0
|
||||||
|
m_ConnectedAnchor: {x: 0, y: 0, z: 0}
|
||||||
|
m_SecondaryAxis: {x: 0, y: 0, z: 0}
|
||||||
|
m_XMotion: 1
|
||||||
|
m_YMotion: 1
|
||||||
|
m_ZMotion: 1
|
||||||
|
m_AngularXMotion: 2
|
||||||
|
m_AngularYMotion: 2
|
||||||
|
m_AngularZMotion: 2
|
||||||
|
m_LinearLimitSpring:
|
||||||
|
spring: 0
|
||||||
|
damper: 0
|
||||||
|
m_LinearLimit:
|
||||||
|
limit: 0.5
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_AngularXLimitSpring:
|
||||||
|
spring: 0
|
||||||
|
damper: 0
|
||||||
|
m_LowAngularXLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_HighAngularXLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_AngularYZLimitSpring:
|
||||||
|
spring: 0
|
||||||
|
damper: 0
|
||||||
|
m_AngularYLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_AngularZLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_TargetPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_TargetVelocity: {x: 0, y: 0, z: 0}
|
||||||
|
m_XDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_YDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_ZDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_TargetRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_TargetAngularVelocity: {x: 0, y: 0, z: 0}
|
||||||
|
m_RotationDriveMode: 0
|
||||||
|
m_AngularXDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_AngularYZDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_SlerpDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_ProjectionMode: 1
|
||||||
|
m_ProjectionDistance: 0
|
||||||
|
m_ProjectionAngle: 0
|
||||||
|
m_ConfiguredInWorldSpace: 0
|
||||||
|
m_SwapBodies: 0
|
||||||
|
m_BreakForce: Infinity
|
||||||
|
m_BreakTorque: Infinity
|
||||||
|
m_EnableCollision: 0
|
||||||
|
m_EnablePreprocessing: 0
|
||||||
|
m_MassScale: 1
|
||||||
|
m_ConnectedMassScale: 1
|
||||||
|
--- !u!135 &135844594273256032
|
||||||
|
SphereCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1035052809208993}
|
||||||
|
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.003
|
||||||
|
m_Center: {x: 0, y: -0.0015, z: 0}
|
||||||
|
--- !u!114 &7176287465780574680
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1035052809208993}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: ee9704c2e1594f4cab270bfd4ca2210b, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||||
|
nodeType: 3
|
||||||
|
body: {fileID: 54679398375713381}
|
||||||
|
--- !u!1 &1387836627839849
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4283454774123242}
|
||||||
|
- component: {fileID: 7859179875146676465}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: fishing line float set 1
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4283454774123242
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1387836627839849}
|
||||||
|
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: 4530253318796540}
|
||||||
|
- {fileID: 4026445325167852}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &7859179875146676465
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1387836627839849}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fd39a2e024a0477c9ad5698d80d9a63a, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineSolver
|
||||||
|
logicalNodes:
|
||||||
|
- {fileID: 8342656697567645068}
|
||||||
|
- {fileID: 7176287465780574680}
|
||||||
|
--- !u!1 &1858052053854210
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4530253318796540}
|
||||||
|
- component: {fileID: 54298866000586118}
|
||||||
|
- component: {fileID: 153691655494134957}
|
||||||
|
- component: {fileID: 8342656697567645068}
|
||||||
|
m_Layer: 15
|
||||||
|
m_Name: Float
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4530253318796540
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1858052053854210}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: -1, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 4283454774123242}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!54 &54298866000586118
|
||||||
|
Rigidbody:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1858052053854210}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Mass: 0.1
|
||||||
|
m_LinearDamping: 1
|
||||||
|
m_AngularDamping: 0.1
|
||||||
|
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||||
|
m_InertiaTensor: {x: 0.001, y: 0.001, z: 0.001}
|
||||||
|
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ImplicitCom: 1
|
||||||
|
m_ImplicitTensor: 0
|
||||||
|
m_UseGravity: 1
|
||||||
|
m_IsKinematic: 0
|
||||||
|
m_Interpolate: 0
|
||||||
|
m_Constraints: 0
|
||||||
|
m_CollisionDetection: 2
|
||||||
|
--- !u!153 &153691655494134957
|
||||||
|
ConfigurableJoint:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1858052053854210}
|
||||||
|
serializedVersion: 4
|
||||||
|
m_ConnectedBody: {fileID: 0}
|
||||||
|
m_ConnectedArticulationBody: {fileID: 0}
|
||||||
|
m_Anchor: {x: 0, y: -0.01, z: 0}
|
||||||
|
m_Axis: {x: 0, y: 0, z: 0}
|
||||||
|
m_AutoConfigureConnectedAnchor: 0
|
||||||
|
m_ConnectedAnchor: {x: 0, y: 0, z: 0}
|
||||||
|
m_SecondaryAxis: {x: 0, y: 0, z: 0}
|
||||||
|
m_XMotion: 1
|
||||||
|
m_YMotion: 1
|
||||||
|
m_ZMotion: 1
|
||||||
|
m_AngularXMotion: 2
|
||||||
|
m_AngularYMotion: 2
|
||||||
|
m_AngularZMotion: 2
|
||||||
|
m_LinearLimitSpring:
|
||||||
|
spring: 0
|
||||||
|
damper: 0
|
||||||
|
m_LinearLimit:
|
||||||
|
limit: 0.5
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_AngularXLimitSpring:
|
||||||
|
spring: 0
|
||||||
|
damper: 0
|
||||||
|
m_LowAngularXLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_HighAngularXLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_AngularYZLimitSpring:
|
||||||
|
spring: 0
|
||||||
|
damper: 0
|
||||||
|
m_AngularYLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_AngularZLimit:
|
||||||
|
limit: 0
|
||||||
|
bounciness: 0
|
||||||
|
contactDistance: 0
|
||||||
|
m_TargetPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_TargetVelocity: {x: 0, y: 0, z: 0}
|
||||||
|
m_XDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_YDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_ZDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_TargetRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_TargetAngularVelocity: {x: 0, y: 0, z: 0}
|
||||||
|
m_RotationDriveMode: 0
|
||||||
|
m_AngularXDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_AngularYZDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_SlerpDrive:
|
||||||
|
serializedVersion: 4
|
||||||
|
positionSpring: 0
|
||||||
|
positionDamper: 0
|
||||||
|
maximumForce: 3.4028233e+38
|
||||||
|
useAcceleration: 0
|
||||||
|
m_ProjectionMode: 1
|
||||||
|
m_ProjectionDistance: 0
|
||||||
|
m_ProjectionAngle: 0
|
||||||
|
m_ConfiguredInWorldSpace: 0
|
||||||
|
m_SwapBodies: 0
|
||||||
|
m_BreakForce: Infinity
|
||||||
|
m_BreakTorque: Infinity
|
||||||
|
m_EnableCollision: 0
|
||||||
|
m_EnablePreprocessing: 0
|
||||||
|
m_MassScale: 1
|
||||||
|
m_ConnectedMassScale: 1
|
||||||
|
--- !u!114 &8342656697567645068
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1858052053854210}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: ee9704c2e1594f4cab270bfd4ca2210b, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||||
|
nodeType: 1
|
||||||
|
body: {fileID: 54298866000586118}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 449040ff936513f4ba4b9715db2f4bf7
|
||||||
|
timeCreated: 1762387921
|
||||||
|
licenseType: Free
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
addedObjectFileIDs:
|
||||||
|
isPrefabVariant: 0
|
||||||
|
variantParentGUID: 00000000000000000000000000000000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -55,6 +55,7 @@ MonoBehaviour:
|
|||||||
velocityDampen: 0.95
|
velocityDampen: 0.95
|
||||||
stiffness: 0.8
|
stiffness: 0.8
|
||||||
iterations: 10
|
iterations: 10
|
||||||
|
hardTightenIterations: 2
|
||||||
initialLength: 0
|
initialLength: 0
|
||||||
lengthSmoothTime: 0.15
|
lengthSmoothTime: 0.15
|
||||||
lengthChangeVelocityKill: 0.4
|
lengthChangeVelocityKill: 0.4
|
||||||
@@ -71,6 +72,7 @@ MonoBehaviour:
|
|||||||
groundSampleStep: 3
|
groundSampleStep: 3
|
||||||
groundInterpolate: 1
|
groundInterpolate: 1
|
||||||
groundUpdateEvery: 1
|
groundUpdateEvery: 1
|
||||||
|
groundPostConstraintIterations: 2
|
||||||
constrainToWaterSurface: 1
|
constrainToWaterSurface: 1
|
||||||
waterLevelY: 0
|
waterLevelY: 0
|
||||||
waterSurfaceOffset: 0.002
|
waterSurfaceOffset: 0.002
|
||||||
@@ -85,11 +87,15 @@ MonoBehaviour:
|
|||||||
movingSpeedThreshold: 2
|
movingSpeedThreshold: 2
|
||||||
smooth: 1
|
smooth: 1
|
||||||
lineWidth: 0.001
|
lineWidth: 0.001
|
||||||
|
cullRemoteRopeWhenInvisible: 1
|
||||||
|
localOwnerAlwaysSimulate: 1
|
||||||
|
visibilityCheckEvery: 10
|
||||||
|
visibilityViewportPadding: 0.08
|
||||||
airDrag: 0.2
|
airDrag: 0.2
|
||||||
airDragXZ: 0.6
|
airDragXZ: 0.6
|
||||||
--- !u!120 &991521994724602848
|
--- !u!120 &991521994724602848
|
||||||
LineRenderer:
|
LineRenderer:
|
||||||
serializedVersion: 2
|
serializedVersion: 3
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
@@ -135,6 +141,7 @@ LineRenderer:
|
|||||||
m_SortingLayerID: 0
|
m_SortingLayerID: 0
|
||||||
m_SortingLayer: 0
|
m_SortingLayer: 0
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
m_Positions:
|
m_Positions:
|
||||||
- {x: 0, y: 0, z: 0}
|
- {x: 0, y: 0, z: 0}
|
||||||
- {x: 0, y: 0, z: 1}
|
- {x: 0, y: 0, z: 1}
|
||||||
@@ -193,7 +200,6 @@ LineRenderer:
|
|||||||
textureScale: {x: 1, y: 1}
|
textureScale: {x: 1, y: 1}
|
||||||
shadowBias: 0.5
|
shadowBias: 0.5
|
||||||
generateLightingData: 0
|
generateLightingData: 0
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_UseWorldSpace: 1
|
m_UseWorldSpace: 1
|
||||||
m_Loop: 0
|
m_Loop: 0
|
||||||
m_ApplyActiveColorSpace: 1
|
m_ApplyActiveColorSpace: 1
|
||||||
@@ -470,6 +476,7 @@ MonoBehaviour:
|
|||||||
Lure: {fileID: 1923684598771359451}
|
Lure: {fileID: 1923684598771359451}
|
||||||
Bobber: {fileID: 2717383850592950062}
|
Bobber: {fileID: 2717383850592950062}
|
||||||
PinchController: {fileID: 2475726686148443307}
|
PinchController: {fileID: 2475726686148443307}
|
||||||
|
LinelenghtDiferent: 0
|
||||||
--- !u!114 &3273975985231415050
|
--- !u!114 &3273975985231415050
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -668,7 +675,7 @@ MonoBehaviour:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 1858052053854210}
|
m_GameObject: {fileID: 1858052053854210}
|
||||||
m_Enabled: 1
|
m_Enabled: 0
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 11500000, guid: 2dedfafdc2d747d98c682cde3e28e513, type: 3}
|
m_Script: {fileID: 11500000, guid: 2dedfafdc2d747d98c682cde3e28e513, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
@@ -776,6 +783,7 @@ MonoBehaviour:
|
|||||||
velocityDampen: 0.95
|
velocityDampen: 0.95
|
||||||
stiffness: 0.8
|
stiffness: 0.8
|
||||||
iterations: 10
|
iterations: 10
|
||||||
|
hardTightenIterations: 2
|
||||||
initialLength: 0
|
initialLength: 0
|
||||||
lengthSmoothTime: 0.15
|
lengthSmoothTime: 0.15
|
||||||
lengthChangeVelocityKill: 0.4
|
lengthChangeVelocityKill: 0.4
|
||||||
@@ -792,6 +800,7 @@ MonoBehaviour:
|
|||||||
groundSampleStep: 3
|
groundSampleStep: 3
|
||||||
groundInterpolate: 1
|
groundInterpolate: 1
|
||||||
groundUpdateEvery: 1
|
groundUpdateEvery: 1
|
||||||
|
groundPostConstraintIterations: 2
|
||||||
constrainToWaterSurface: 0
|
constrainToWaterSurface: 0
|
||||||
waterLevelY: 0
|
waterLevelY: 0
|
||||||
waterSurfaceOffset: 0.002
|
waterSurfaceOffset: 0.002
|
||||||
@@ -806,11 +815,15 @@ MonoBehaviour:
|
|||||||
movingSpeedThreshold: 2
|
movingSpeedThreshold: 2
|
||||||
smooth: 1
|
smooth: 1
|
||||||
lineWidth: 0.001
|
lineWidth: 0.001
|
||||||
|
cullRemoteRopeWhenInvisible: 1
|
||||||
|
localOwnerAlwaysSimulate: 1
|
||||||
|
visibilityCheckEvery: 10
|
||||||
|
visibilityViewportPadding: 0.08
|
||||||
airDrag: 0.9
|
airDrag: 0.9
|
||||||
airDragXZ: 0.6
|
airDragXZ: 0.6
|
||||||
--- !u!120 &484878994603287356
|
--- !u!120 &484878994603287356
|
||||||
LineRenderer:
|
LineRenderer:
|
||||||
serializedVersion: 2
|
serializedVersion: 3
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
@@ -856,6 +869,7 @@ LineRenderer:
|
|||||||
m_SortingLayerID: 0
|
m_SortingLayerID: 0
|
||||||
m_SortingLayer: 0
|
m_SortingLayer: 0
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
m_Positions:
|
m_Positions:
|
||||||
- {x: 0, y: 0, z: 0}
|
- {x: 0, y: 0, z: 0}
|
||||||
- {x: 0, y: 0, z: 1}
|
- {x: 0, y: 0, z: 1}
|
||||||
@@ -914,7 +928,6 @@ LineRenderer:
|
|||||||
textureScale: {x: 1, y: 1}
|
textureScale: {x: 1, y: 1}
|
||||||
shadowBias: 0.5
|
shadowBias: 0.5
|
||||||
generateLightingData: 0
|
generateLightingData: 0
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_UseWorldSpace: 1
|
m_UseWorldSpace: 1
|
||||||
m_Loop: 0
|
m_Loop: 0
|
||||||
m_ApplyActiveColorSpace: 1
|
m_ApplyActiveColorSpace: 1
|
||||||
@@ -953,7 +966,7 @@ Transform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!120 &120710333716555736
|
--- !u!120 &120710333716555736
|
||||||
LineRenderer:
|
LineRenderer:
|
||||||
serializedVersion: 2
|
serializedVersion: 3
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
@@ -999,6 +1012,7 @@ LineRenderer:
|
|||||||
m_SortingLayerID: 0
|
m_SortingLayerID: 0
|
||||||
m_SortingLayer: 0
|
m_SortingLayer: 0
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
m_Positions:
|
m_Positions:
|
||||||
- {x: 0, y: 0, z: 0}
|
- {x: 0, y: 0, z: 0}
|
||||||
- {x: 0, y: 0, z: 1}
|
- {x: 0, y: 0, z: 1}
|
||||||
@@ -1057,7 +1071,6 @@ LineRenderer:
|
|||||||
textureScale: {x: 1, y: 1}
|
textureScale: {x: 1, y: 1}
|
||||||
shadowBias: 0.5
|
shadowBias: 0.5
|
||||||
generateLightingData: 0
|
generateLightingData: 0
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_UseWorldSpace: 1
|
m_UseWorldSpace: 1
|
||||||
m_Loop: 0
|
m_Loop: 0
|
||||||
m_ApplyActiveColorSpace: 1
|
m_ApplyActiveColorSpace: 1
|
||||||
|
|||||||
3
Assets/Scripts/Fishing/New/View/FishingLine.meta
Normal file
3
Assets/Scripts/Fishing/New/View/FishingLine.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 11c32e9f078948c880079b4903f7c8bd
|
||||||
|
timeCreated: 1776008844
|
||||||
8
Assets/Scripts/Fishing/New/View/FishingLine/Feature.meta
Normal file
8
Assets/Scripts/Fishing/New/View/FishingLine/Feature.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2ff164cb3132445289d22c7b3a0f4fab
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,685 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
public enum FishingBobberControlMode
|
||||||
|
{
|
||||||
|
AirPhysics,
|
||||||
|
WaterPresentation,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FishingBobberBiteType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Tap,
|
||||||
|
SlowSink,
|
||||||
|
Lift,
|
||||||
|
BlackDrift,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BobberTiltAxis
|
||||||
|
{
|
||||||
|
LocalX,
|
||||||
|
LocalZ,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
[RequireComponent(typeof(Rigidbody))]
|
||||||
|
public class FishingBobberFeature : FishingLineNodeMotionFeature
|
||||||
|
{
|
||||||
|
protected override int DefaultPriority => 100;
|
||||||
|
|
||||||
|
#region 检测入水
|
||||||
|
|
||||||
|
[Header("入水检测")]
|
||||||
|
[Tooltip("当前测试阶段固定水面高度。")]
|
||||||
|
public float waterLevel = 0f;
|
||||||
|
|
||||||
|
[Tooltip("浮漂底部进入水面达到该深度后,切换为水面表现控制。")]
|
||||||
|
public float enterWaterDepth = 0.002f;
|
||||||
|
|
||||||
|
[Tooltip("浮漂底部高于该深度时退出水面表现控制。通常设为负值用于滞回。")]
|
||||||
|
public float exitWaterDepth = -0.01f;
|
||||||
|
|
||||||
|
[Tooltip("浮漂总高度,单位米。")]
|
||||||
|
public float floatHeight = 0.08f;
|
||||||
|
|
||||||
|
[Tooltip("如果 Pivot 在浮漂底部填 0;如果 Pivot 在模型中部,填底部相对 Pivot 的本地 Y 偏移。")]
|
||||||
|
public float bottomOffsetLocalY;
|
||||||
|
|
||||||
|
[Tooltip("Y 轴控制的平滑时间。")]
|
||||||
|
public float ySmoothTime = 0.08f;
|
||||||
|
|
||||||
|
[Tooltip("Y 轴平滑时允许的最大竖直速度。")]
|
||||||
|
public float maxYSpeed = 2f;
|
||||||
|
|
||||||
|
[Tooltip("Y 轴死区,小范围内直接贴目标值以减少微抖。")]
|
||||||
|
public float yDeadZone = 0.0005f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 吃水控制
|
||||||
|
|
||||||
|
[Header("吃水控制")]
|
||||||
|
[Tooltip("基准底部重量。当前重量等于该值时,使用基础吃水深度。")]
|
||||||
|
public float neutralBottomWeight = 1f;
|
||||||
|
|
||||||
|
[Tooltip("当前底部总重量。运行时可由其他脚本更新。")]
|
||||||
|
public float currentBottomWeight = 1f;
|
||||||
|
|
||||||
|
[Tooltip("基准重量下的基础吃水深度。")]
|
||||||
|
public float baseDraftDepth = 0.02f;
|
||||||
|
|
||||||
|
[Tooltip("每单位重量变化对应增加或减少的吃水深度。")]
|
||||||
|
public float draftDepthPerWeight = 0.01f;
|
||||||
|
|
||||||
|
[Tooltip("吃水深度下限。")]
|
||||||
|
public float minDraftDepth = 0.005f;
|
||||||
|
|
||||||
|
[Tooltip("吃水深度上限。")]
|
||||||
|
public float maxDraftDepth = 0.08f;
|
||||||
|
|
||||||
|
[Tooltip("吃水深度变化的平滑时间。")]
|
||||||
|
public float draftSmoothTime = 0.18f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 漂相动画
|
||||||
|
|
||||||
|
[Header("漂相动画")]
|
||||||
|
[Tooltip("漂相位移动画的平滑时间。")]
|
||||||
|
public float biteSmoothTime = 0.03f;
|
||||||
|
|
||||||
|
[Tooltip("点漂默认振幅。")]
|
||||||
|
public float tapAmplitude = 0.008f;
|
||||||
|
|
||||||
|
[Tooltip("点漂默认时长。")]
|
||||||
|
public float tapDuration = 0.18f;
|
||||||
|
|
||||||
|
[Tooltip("缓沉默认振幅。")]
|
||||||
|
public float slowSinkAmplitude = 0.025f;
|
||||||
|
|
||||||
|
[Tooltip("缓沉默认时长。")]
|
||||||
|
public float slowSinkDuration = 1.2f;
|
||||||
|
|
||||||
|
[Tooltip("顶漂默认振幅。")]
|
||||||
|
public float liftAmplitude = 0.015f;
|
||||||
|
|
||||||
|
[Tooltip("顶漂默认时长。")]
|
||||||
|
public float liftDuration = 1.2f;
|
||||||
|
|
||||||
|
[Tooltip("黑漂默认振幅。")]
|
||||||
|
public float blackDriftAmplitude = 0.06f;
|
||||||
|
|
||||||
|
[Tooltip("黑漂默认时长。")]
|
||||||
|
public float blackDriftDuration = 0.8f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 输入测试
|
||||||
|
|
||||||
|
[Header("输入测试")]
|
||||||
|
[Tooltip("是否启用运行时按键测试漂相。")]
|
||||||
|
public bool enableDebugInput = true;
|
||||||
|
|
||||||
|
[Tooltip("停止当前漂相的按键。")]
|
||||||
|
public KeyCode stopBiteKey = KeyCode.R;
|
||||||
|
|
||||||
|
[Tooltip("触发点漂的按键。")]
|
||||||
|
public KeyCode tapKey = KeyCode.T;
|
||||||
|
|
||||||
|
[Tooltip("触发缓沉的按键。")]
|
||||||
|
public KeyCode slowSinkKey = KeyCode.G;
|
||||||
|
|
||||||
|
[Tooltip("触发顶漂的按键。")]
|
||||||
|
public KeyCode liftKey = KeyCode.H;
|
||||||
|
|
||||||
|
[Tooltip("触发黑漂的按键。")]
|
||||||
|
public KeyCode blackDriftKey = KeyCode.B;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 姿态控制
|
||||||
|
|
||||||
|
[Header("姿态控制")]
|
||||||
|
[Tooltip("重量低于该值时,姿态趋向躺漂。")]
|
||||||
|
public float lyingWeightThreshold = 0.4f;
|
||||||
|
|
||||||
|
[Tooltip("重量达到该值附近时,姿态趋向半躺。")]
|
||||||
|
public float tiltedWeightThreshold = 0.8f;
|
||||||
|
|
||||||
|
[Tooltip("重量达到该值及以上时,姿态趋向立漂。")]
|
||||||
|
public float uprightWeightThreshold = 1.2f;
|
||||||
|
|
||||||
|
[Tooltip("躺漂对应的倾角。")]
|
||||||
|
public float lyingAngle = 88f;
|
||||||
|
|
||||||
|
[Tooltip("半躺对应的倾角。")]
|
||||||
|
public float tiltedAngle = 42f;
|
||||||
|
|
||||||
|
[Tooltip("立漂对应的倾角,通常为 0。")]
|
||||||
|
public float uprightAngle = 0f;
|
||||||
|
|
||||||
|
[Tooltip("绕哪个本地轴做倾倒。")]
|
||||||
|
public BobberTiltAxis tiltAxis = BobberTiltAxis.LocalX;
|
||||||
|
|
||||||
|
[Tooltip("是否反转倾倒方向。")]
|
||||||
|
public bool invertTiltDirection;
|
||||||
|
|
||||||
|
[Tooltip("姿态旋转的平滑速度。")]
|
||||||
|
public float rotationLerpSpeed = 8f;
|
||||||
|
|
||||||
|
[Tooltip("入水后用于压制旋转抖动的角阻尼。")]
|
||||||
|
public float waterAngularDamping = 999f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 运行时状态
|
||||||
|
|
||||||
|
public FishingBobberControlMode CurrentMode => _mode;
|
||||||
|
public FishingBobberBiteType CurrentBiteType => _activeBiteType;
|
||||||
|
public float CurrentDraftDepth => _currentDraftDepth;
|
||||||
|
public float CurrentBottomWeight => currentBottomWeight;
|
||||||
|
|
||||||
|
private Rigidbody _rb;
|
||||||
|
private FishingBobberControlMode _mode = FishingBobberControlMode.AirPhysics;
|
||||||
|
|
||||||
|
private bool _defaultsCached;
|
||||||
|
private bool _waterStateInitialized;
|
||||||
|
private float _defaultAngularDamping;
|
||||||
|
private bool _defaultUseGravity;
|
||||||
|
private RigidbodyConstraints _defaultConstraints;
|
||||||
|
|
||||||
|
private float _draftVelocity;
|
||||||
|
private float _currentDraftDepth;
|
||||||
|
private float _ySmoothVelocity;
|
||||||
|
private float _biteOffsetY;
|
||||||
|
private float _biteOffsetYVelocity;
|
||||||
|
|
||||||
|
private bool _uprightPoseCached;
|
||||||
|
private Quaternion _cachedUprightRotation;
|
||||||
|
private Quaternion _uprightReferenceRotation;
|
||||||
|
private Quaternion _targetRotation;
|
||||||
|
|
||||||
|
private FishingBobberBiteType _activeBiteType = FishingBobberBiteType.None;
|
||||||
|
private float _biteTimer;
|
||||||
|
private float _biteDuration;
|
||||||
|
private float _biteAmplitude;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity 生命周期
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
InitializeRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
HandleDebugInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 运动控制接入
|
||||||
|
|
||||||
|
public override bool IsSupportedNode(FishingLineNode node)
|
||||||
|
{
|
||||||
|
return node != null && node.Type == FishingLineNode.NodeType.Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnBind()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
InitializeRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanControl()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
if (_rb == null || !IsSupportedNode(Node))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var submergeDepth = GetSubmergeDepth();
|
||||||
|
if (_mode == FishingBobberControlMode.WaterPresentation)
|
||||||
|
{
|
||||||
|
return submergeDepth >= exitWaterDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return submergeDepth > enterWaterDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMotionActivated()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
EnterWaterPresentationMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMotionDeactivated()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
ExitWaterPresentationMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TickMotion(float deltaTime)
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var submergeDepth = GetSubmergeDepth();
|
||||||
|
if (submergeDepth < exitWaterDepth)
|
||||||
|
{
|
||||||
|
ExitWaterPresentationMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mode != FishingBobberControlMode.WaterPresentation)
|
||||||
|
{
|
||||||
|
EnterWaterPresentationMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateBiteAnimation(deltaTime);
|
||||||
|
UpdateDraft(deltaTime);
|
||||||
|
var nextRotation = CalculateNextRotation(deltaTime);
|
||||||
|
UpdateVerticalPosition(deltaTime, nextRotation);
|
||||||
|
ApplyRotation(nextRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 漂相接口
|
||||||
|
|
||||||
|
public void SetBottomWeight(float weight)
|
||||||
|
{
|
||||||
|
currentBottomWeight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayTap(float amplitude = -1f, float duration = -1f)
|
||||||
|
{
|
||||||
|
StartBite(
|
||||||
|
FishingBobberBiteType.Tap,
|
||||||
|
amplitude > 0f ? amplitude : tapAmplitude,
|
||||||
|
duration > 0f ? duration : tapDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlaySlowSink(float amplitude = -1f, float duration = -1f)
|
||||||
|
{
|
||||||
|
StartBite(
|
||||||
|
FishingBobberBiteType.SlowSink,
|
||||||
|
amplitude > 0f ? amplitude : slowSinkAmplitude,
|
||||||
|
duration > 0f ? duration : slowSinkDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayLift(float amplitude = -1f, float duration = -1f)
|
||||||
|
{
|
||||||
|
StartBite(
|
||||||
|
FishingBobberBiteType.Lift,
|
||||||
|
amplitude > 0f ? amplitude : liftAmplitude,
|
||||||
|
duration > 0f ? duration : liftDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayBlackDrift(float amplitude = -1f, float duration = -1f)
|
||||||
|
{
|
||||||
|
StartBite(
|
||||||
|
FishingBobberBiteType.BlackDrift,
|
||||||
|
amplitude > 0f ? amplitude : blackDriftAmplitude,
|
||||||
|
duration > 0f ? duration : blackDriftDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopBite()
|
||||||
|
{
|
||||||
|
_activeBiteType = FishingBobberBiteType.None;
|
||||||
|
_biteTimer = 0f;
|
||||||
|
_biteDuration = 0f;
|
||||||
|
_biteAmplitude = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 内部实现
|
||||||
|
|
||||||
|
private void EnsureRuntimeReferences()
|
||||||
|
{
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
_rb = Node != null && Node.Body != null ? Node.Body : GetComponent<Rigidbody>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeRuntimeState()
|
||||||
|
{
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_defaultsCached)
|
||||||
|
{
|
||||||
|
_defaultAngularDamping = _rb.angularDamping;
|
||||||
|
_defaultUseGravity = _rb.useGravity;
|
||||||
|
_defaultConstraints = _rb.constraints;
|
||||||
|
_defaultsCached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentDraftDepth = CalculateRawDraftDepth();
|
||||||
|
_draftVelocity = 0f;
|
||||||
|
_ySmoothVelocity = 0f;
|
||||||
|
_biteOffsetY = 0f;
|
||||||
|
_biteOffsetYVelocity = 0f;
|
||||||
|
_targetRotation = _rb.rotation;
|
||||||
|
|
||||||
|
if (!_uprightPoseCached)
|
||||||
|
{
|
||||||
|
_cachedUprightRotation = _rb.rotation;
|
||||||
|
_uprightPoseCached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_uprightReferenceRotation = _cachedUprightRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterWaterPresentationMode()
|
||||||
|
{
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mode = FishingBobberControlMode.WaterPresentation;
|
||||||
|
_waterStateInitialized = true;
|
||||||
|
_uprightReferenceRotation = _cachedUprightRotation;
|
||||||
|
_targetRotation = _rb.rotation;
|
||||||
|
_draftVelocity = 0f;
|
||||||
|
_ySmoothVelocity = 0f;
|
||||||
|
_biteOffsetYVelocity = 0f;
|
||||||
|
_currentDraftDepth = CalculateRawDraftDepth();
|
||||||
|
|
||||||
|
_rb.useGravity = false;
|
||||||
|
_rb.angularDamping = waterAngularDamping;
|
||||||
|
_rb.constraints = _defaultConstraints | RigidbodyConstraints.FreezeRotation;
|
||||||
|
_rb.angularVelocity = Vector3.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExitWaterPresentationMode()
|
||||||
|
{
|
||||||
|
_mode = FishingBobberControlMode.AirPhysics;
|
||||||
|
RestorePhysicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestorePhysicsState()
|
||||||
|
{
|
||||||
|
if (_rb == null || !_defaultsCached)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rb.useGravity = _defaultUseGravity;
|
||||||
|
_rb.angularDamping = _defaultAngularDamping;
|
||||||
|
_rb.constraints = _defaultConstraints;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetSubmergeDepth()
|
||||||
|
{
|
||||||
|
return waterLevel - GetBottomWorldPosition().y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 GetBottomWorldPosition()
|
||||||
|
{
|
||||||
|
return transform.TransformPoint(new Vector3(0f, bottomOffsetLocalY, 0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private float CalculateRawDraftDepth()
|
||||||
|
{
|
||||||
|
var weightDelta = currentBottomWeight - neutralBottomWeight;
|
||||||
|
var targetDraft = baseDraftDepth + weightDelta * draftDepthPerWeight;
|
||||||
|
return Mathf.Clamp(targetDraft, minDraftDepth, maxDraftDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateDraft(float deltaTime)
|
||||||
|
{
|
||||||
|
var targetDraft = CalculateRawDraftDepth();
|
||||||
|
_currentDraftDepth = Mathf.SmoothDamp(
|
||||||
|
_currentDraftDepth,
|
||||||
|
targetDraft,
|
||||||
|
ref _draftVelocity,
|
||||||
|
Mathf.Max(0.0001f, draftSmoothTime),
|
||||||
|
Mathf.Infinity,
|
||||||
|
deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateVerticalPosition(float deltaTime, Quaternion targetRotation)
|
||||||
|
{
|
||||||
|
var position = _rb.position;
|
||||||
|
var targetY = waterLevel - _currentDraftDepth - GetBottomOffsetWorldY(targetRotation) + _biteOffsetY;
|
||||||
|
|
||||||
|
if (Mathf.Abs(position.y - targetY) < yDeadZone)
|
||||||
|
{
|
||||||
|
position.y = targetY;
|
||||||
|
_ySmoothVelocity = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position.y = Mathf.SmoothDamp(
|
||||||
|
position.y,
|
||||||
|
targetY,
|
||||||
|
ref _ySmoothVelocity,
|
||||||
|
Mathf.Max(0.0001f, ySmoothTime),
|
||||||
|
maxYSpeed,
|
||||||
|
deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
_rb.MovePosition(position);
|
||||||
|
|
||||||
|
var velocity = _rb.linearVelocity;
|
||||||
|
if (Mathf.Abs(velocity.y) > 0f)
|
||||||
|
{
|
||||||
|
velocity.y = 0f;
|
||||||
|
_rb.linearVelocity = velocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Quaternion CalculateNextRotation(float deltaTime)
|
||||||
|
{
|
||||||
|
var targetTiltAngle = EvaluateTargetTiltAngle();
|
||||||
|
var signedAngle = invertTiltDirection ? -targetTiltAngle : targetTiltAngle;
|
||||||
|
var localAxis = tiltAxis == BobberTiltAxis.LocalX ? Vector3.right : Vector3.forward;
|
||||||
|
|
||||||
|
_targetRotation = _uprightReferenceRotation * Quaternion.AngleAxis(signedAngle, localAxis);
|
||||||
|
_rb.angularVelocity = Vector3.zero;
|
||||||
|
return Quaternion.Slerp(
|
||||||
|
_rb.rotation,
|
||||||
|
_targetRotation,
|
||||||
|
1f - Mathf.Exp(-Mathf.Max(0.01f, rotationLerpSpeed) * deltaTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyRotation(Quaternion nextRotation)
|
||||||
|
{
|
||||||
|
_rb.rotation = nextRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetBottomOffsetWorldY(Quaternion rotation)
|
||||||
|
{
|
||||||
|
return (rotation * new Vector3(0f, bottomOffsetLocalY, 0f)).y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float EvaluateTargetTiltAngle()
|
||||||
|
{
|
||||||
|
if (currentBottomWeight <= lyingWeightThreshold)
|
||||||
|
{
|
||||||
|
return lyingAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentBottomWeight <= tiltedWeightThreshold)
|
||||||
|
{
|
||||||
|
var t = Mathf.InverseLerp(lyingWeightThreshold, tiltedWeightThreshold, currentBottomWeight);
|
||||||
|
return Mathf.Lerp(lyingAngle, tiltedAngle, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentBottomWeight <= uprightWeightThreshold)
|
||||||
|
{
|
||||||
|
var t = Mathf.InverseLerp(tiltedWeightThreshold, uprightWeightThreshold, currentBottomWeight);
|
||||||
|
return Mathf.Lerp(tiltedAngle, uprightAngle, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uprightAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartBite(FishingBobberBiteType type, float amplitude, float duration)
|
||||||
|
{
|
||||||
|
if (_mode != FishingBobberControlMode.WaterPresentation)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_activeBiteType = type;
|
||||||
|
_biteTimer = 0f;
|
||||||
|
_biteDuration = Mathf.Max(0.01f, duration);
|
||||||
|
_biteAmplitude = Mathf.Max(0f, amplitude);
|
||||||
|
_biteOffsetYVelocity = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBiteAnimation(float deltaTime)
|
||||||
|
{
|
||||||
|
if (_activeBiteType == FishingBobberBiteType.None)
|
||||||
|
{
|
||||||
|
_biteOffsetY = Mathf.SmoothDamp(
|
||||||
|
_biteOffsetY,
|
||||||
|
0f,
|
||||||
|
ref _biteOffsetYVelocity,
|
||||||
|
Mathf.Max(0.0001f, biteSmoothTime),
|
||||||
|
Mathf.Infinity,
|
||||||
|
deltaTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_biteTimer += deltaTime;
|
||||||
|
var t = Mathf.Clamp01(_biteTimer / _biteDuration);
|
||||||
|
var targetOffset = 0f;
|
||||||
|
|
||||||
|
switch (_activeBiteType)
|
||||||
|
{
|
||||||
|
case FishingBobberBiteType.Tap:
|
||||||
|
if (t < 0.35f)
|
||||||
|
{
|
||||||
|
var downT = t / 0.35f;
|
||||||
|
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, downT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var upT = (t - 0.35f) / 0.65f;
|
||||||
|
targetOffset = -Mathf.Lerp(_biteAmplitude, 0f, upT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FishingBobberBiteType.SlowSink:
|
||||||
|
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FishingBobberBiteType.Lift:
|
||||||
|
targetOffset = Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FishingBobberBiteType.BlackDrift:
|
||||||
|
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_biteOffsetY = Mathf.SmoothDamp(
|
||||||
|
_biteOffsetY,
|
||||||
|
targetOffset,
|
||||||
|
ref _biteOffsetYVelocity,
|
||||||
|
Mathf.Max(0.0001f, biteSmoothTime),
|
||||||
|
Mathf.Infinity,
|
||||||
|
deltaTime);
|
||||||
|
|
||||||
|
if (_biteTimer >= _biteDuration &&
|
||||||
|
_activeBiteType != FishingBobberBiteType.SlowSink &&
|
||||||
|
_activeBiteType != FishingBobberBiteType.BlackDrift)
|
||||||
|
{
|
||||||
|
_activeBiteType = FishingBobberBiteType.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDebugInput()
|
||||||
|
{
|
||||||
|
if (!Application.isPlaying || !enableDebugInput)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.GetKeyDown(stopBiteKey))
|
||||||
|
{
|
||||||
|
StopBite();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.GetKeyDown(tapKey))
|
||||||
|
{
|
||||||
|
PlayTap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.GetKeyDown(slowSinkKey))
|
||||||
|
{
|
||||||
|
PlaySlowSink();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.GetKeyDown(liftKey))
|
||||||
|
{
|
||||||
|
PlayLift();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.GetKeyDown(blackDriftKey))
|
||||||
|
{
|
||||||
|
PlayBlackDrift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 参数校验
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
floatHeight = Mathf.Max(0.001f, floatHeight);
|
||||||
|
ySmoothTime = Mathf.Max(0.001f, ySmoothTime);
|
||||||
|
maxYSpeed = Mathf.Max(0.01f, maxYSpeed);
|
||||||
|
yDeadZone = Mathf.Max(0f, yDeadZone);
|
||||||
|
|
||||||
|
neutralBottomWeight = Mathf.Max(0f, neutralBottomWeight);
|
||||||
|
currentBottomWeight = Mathf.Max(0f, currentBottomWeight);
|
||||||
|
minDraftDepth = Mathf.Max(0f, minDraftDepth);
|
||||||
|
maxDraftDepth = Mathf.Max(minDraftDepth, maxDraftDepth);
|
||||||
|
baseDraftDepth = Mathf.Clamp(baseDraftDepth, minDraftDepth, maxDraftDepth);
|
||||||
|
draftDepthPerWeight = Mathf.Max(0f, draftDepthPerWeight);
|
||||||
|
draftSmoothTime = Mathf.Max(0.001f, draftSmoothTime);
|
||||||
|
|
||||||
|
biteSmoothTime = Mathf.Max(0.001f, biteSmoothTime);
|
||||||
|
tapAmplitude = Mathf.Max(0f, tapAmplitude);
|
||||||
|
tapDuration = Mathf.Max(0.01f, tapDuration);
|
||||||
|
slowSinkAmplitude = Mathf.Max(0f, slowSinkAmplitude);
|
||||||
|
slowSinkDuration = Mathf.Max(0.01f, slowSinkDuration);
|
||||||
|
liftAmplitude = Mathf.Max(0f, liftAmplitude);
|
||||||
|
liftDuration = Mathf.Max(0.01f, liftDuration);
|
||||||
|
blackDriftAmplitude = Mathf.Max(0f, blackDriftAmplitude);
|
||||||
|
blackDriftDuration = Mathf.Max(0.01f, blackDriftDuration);
|
||||||
|
|
||||||
|
lyingWeightThreshold = Mathf.Max(0f, lyingWeightThreshold);
|
||||||
|
tiltedWeightThreshold = Mathf.Max(lyingWeightThreshold, tiltedWeightThreshold);
|
||||||
|
uprightWeightThreshold = Mathf.Max(tiltedWeightThreshold, uprightWeightThreshold);
|
||||||
|
uprightAngle = Mathf.Clamp(uprightAngle, 0f, 89f);
|
||||||
|
tiltedAngle = Mathf.Clamp(tiltedAngle, uprightAngle, 89f);
|
||||||
|
lyingAngle = Mathf.Clamp(lyingAngle, tiltedAngle, 89.9f);
|
||||||
|
rotationLerpSpeed = Mathf.Max(0.01f, rotationLerpSpeed);
|
||||||
|
waterAngularDamping = Mathf.Max(0f, waterAngularDamping);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ca4d5d54d89446b0a10b7ce521fd7d9e
|
||||||
|
timeCreated: 1775958532
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 默认物理组件
|
||||||
|
/// </summary>
|
||||||
|
public class FishingDefaultPhysicsFeature : FishingLineNodeMotionFeature
|
||||||
|
{
|
||||||
|
[Header("Physics")] [SerializeField] private bool useGravity = true;
|
||||||
|
|
||||||
|
protected override int DefaultPriority => 0;
|
||||||
|
|
||||||
|
public override bool IsSupportedNode(FishingLineNode node)
|
||||||
|
{
|
||||||
|
return node != null && node.Type != FishingLineNode.NodeType.Start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanControl()
|
||||||
|
{
|
||||||
|
return Node != null && Node.Body != null && IsSupportedNode(Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMotionActivated()
|
||||||
|
{
|
||||||
|
ApplyPhysicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TickMotion(float deltaTime)
|
||||||
|
{
|
||||||
|
ApplyPhysicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyPhysicsState()
|
||||||
|
{
|
||||||
|
if (Node == null || Node.Body == null || !IsSupportedNode(Node))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node.Body.useGravity = useGravity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2ebfa4366b504ba0a3f398eded17df31
|
||||||
|
timeCreated: 1775957743
|
||||||
@@ -0,0 +1,890 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
public enum BobberControlMode
|
||||||
|
{
|
||||||
|
AirPhysics,
|
||||||
|
WaterPresentation,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BobberBiteType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Tap,
|
||||||
|
SlowSink,
|
||||||
|
Lift,
|
||||||
|
BlackDrift,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BobberPosture
|
||||||
|
{
|
||||||
|
Lying,
|
||||||
|
Tilted,
|
||||||
|
Upright,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
[RequireComponent(typeof(Rigidbody))]
|
||||||
|
public class FishingFloatFeature : FishingLineNodeMotionFeature
|
||||||
|
{
|
||||||
|
protected override int DefaultPriority => 100;
|
||||||
|
|
||||||
|
[Header("Water")] [Tooltip("没有水提供器时使用固定水位")]
|
||||||
|
public float fallbackWaterLevel;
|
||||||
|
|
||||||
|
[Tooltip("可选:挂实现了 IWaterSurfaceProvider 的组件")]
|
||||||
|
public MonoBehaviour waterProviderBehaviour;
|
||||||
|
|
||||||
|
[Header("Enter Water")] [Tooltip("底部进入水面多少米后切换为漂像控制")]
|
||||||
|
public float enterWaterDepth = 0.002f;
|
||||||
|
|
||||||
|
[Tooltip("离开水面多少米后回到空中物理。一般给负值做滞回")] public float exitWaterDepth = -0.01f;
|
||||||
|
|
||||||
|
[Header("Geometry")] [Tooltip("浮漂总高度(米)")]
|
||||||
|
public float floatHeight = 0.08f;
|
||||||
|
|
||||||
|
[Tooltip("如果 Pivot 在浮漂底部,这里填 0;如果 Pivot 在模型中心,就填底部相对 Pivot 的本地 Y")]
|
||||||
|
public float bottomOffsetLocalY;
|
||||||
|
|
||||||
|
[Header("Base Float")] [Tooltip("基础吃铅比例,决定静止时有多少在水下")] [Range(0.05f, 0.95f)]
|
||||||
|
public float baseSubmergeRatio = 0.28f;
|
||||||
|
|
||||||
|
[Tooltip("Y 轴平滑时间,越小响应越快")] public float ySmoothTime = 0.08f;
|
||||||
|
|
||||||
|
[Tooltip("最大竖直速度限制(用于 SmoothDamp)")] public float maxYSpeed = 2f;
|
||||||
|
|
||||||
|
[Tooltip("静止小死区,减少微抖")] public float yDeadZone = 0.0005f;
|
||||||
|
|
||||||
|
[Header("Surface Motion")] [Tooltip("是否启用轻微水面起伏")]
|
||||||
|
public bool enableSurfaceBobbing = true;
|
||||||
|
|
||||||
|
[Tooltip("水面轻微起伏振幅(米)")] public float surfaceBobAmplitude = 0.0015f;
|
||||||
|
|
||||||
|
[Tooltip("水面轻微起伏频率")] public float surfaceBobFrequency = 1.2f;
|
||||||
|
|
||||||
|
[Header("XZ Motion")] [Tooltip("入水后是否锁定 XZ 到入水点附近")]
|
||||||
|
public bool lockXZAroundAnchor = true;
|
||||||
|
|
||||||
|
[Tooltip("XZ 跟随平滑时间")] public float xzSmoothTime = 0.15f;
|
||||||
|
|
||||||
|
[Tooltip("水流/拖拽带来的额外平面偏移最大值")] public float maxPlanarOffset = 0.15f;
|
||||||
|
|
||||||
|
[Header("Sink By Weight / Tension")] [Tooltip("外部向下拉力映射为下沉量的系数。你可以把钩/铅/线组的等效向下拉力喂进来")]
|
||||||
|
public float downForceToSink = 0.0025f;
|
||||||
|
|
||||||
|
[Tooltip("向下拉力下沉的最大附加量")] public float maxExtraSink = 0.08f;
|
||||||
|
|
||||||
|
[Header("Bottom Touch")] [Tooltip("触底时是否启用修正")]
|
||||||
|
public bool enableBottomTouchAdjust = true;
|
||||||
|
|
||||||
|
[Tooltip("触底后减少的下沉量(例如铅坠到底,漂会回升一点)")] public float bottomTouchLift = 0.01f;
|
||||||
|
|
||||||
|
[Header("Posture Source")] [Tooltip("下方 Lure / 钩组 / 铅坠的刚体。姿态主要根据它和浮漂的相对位置判断")]
|
||||||
|
public Rigidbody lureBody;
|
||||||
|
|
||||||
|
[Tooltip("用于归一化的参考长度。一般填:浮漂到 Lure 在“正常拉直”时的大致长度")]
|
||||||
|
public float referenceLength = 0.30f;
|
||||||
|
|
||||||
|
[Header("Posture Threshold")] [Tooltip("最小入水比例。不够时优先躺漂")]
|
||||||
|
public float minSubmergeToStand = 0.16f;
|
||||||
|
|
||||||
|
[Tooltip("垂直分量比低于该值时,优先躺漂")] public float verticalLieThreshold = 0.18f;
|
||||||
|
|
||||||
|
[Tooltip("垂直分量比高于该值,且水平分量较小时,允许立漂")] public float verticalUprightThreshold = 0.75f;
|
||||||
|
|
||||||
|
[Tooltip("水平分量比高于该值时,不允许完全立漂")] public float planarTiltThreshold = 0.30f;
|
||||||
|
|
||||||
|
[Tooltip("水平分量明显大于垂直分量时,优先躺漂")] public float planarDominanceMultiplier = 1.20f;
|
||||||
|
|
||||||
|
[Tooltip("姿态切换滞回")] public float postureHysteresis = 0.04f;
|
||||||
|
|
||||||
|
[Header("Posture Stability")] [Tooltip("候选姿态需持续多久才真正切换")]
|
||||||
|
public float postureConfirmTime = 0.08f;
|
||||||
|
|
||||||
|
[Tooltip("姿态切换后的最短冷却时间,避免来回闪烁")] public float postureSwitchCooldown = 0.10f;
|
||||||
|
|
||||||
|
[Header("Posture Rotation")] [Tooltip("倾斜状态角度")]
|
||||||
|
public float tiltedAngle = 38f;
|
||||||
|
|
||||||
|
[Tooltip("躺漂角度")] public float lyingAngle = 88f;
|
||||||
|
|
||||||
|
[Tooltip("立漂时允许的最大附加倾角")] public float uprightMaxTiltAngle = 8f;
|
||||||
|
|
||||||
|
[Tooltip("平面方向对立漂/斜漂附加倾角的影响强度")] public float planarTiltFactor = 120f;
|
||||||
|
|
||||||
|
[Tooltip("平面方向死区,小于该值时保持上一帧方向")] public float planarDirectionDeadZone = 0.01f;
|
||||||
|
|
||||||
|
[Tooltip("平面方向平滑速度")] public float planarDirectionLerpSpeed = 10f;
|
||||||
|
|
||||||
|
[Tooltip("姿态平滑速度")] public float rotationLerpSpeed = 8f;
|
||||||
|
|
||||||
|
[Header("Debug Input")] public bool debugResetKey = true;
|
||||||
|
public bool debugTapKey = true;
|
||||||
|
public bool debugSlowSinkKey = true;
|
||||||
|
public bool debugLiftKey = true;
|
||||||
|
public bool debugBlackDriftKey = true;
|
||||||
|
|
||||||
|
[Header("Debug")] public bool drawDebug;
|
||||||
|
|
||||||
|
public bool UseTestPosture;
|
||||||
|
public BobberPosture TestPosture;
|
||||||
|
|
||||||
|
public BobberControlMode CurrentMode => _mode;
|
||||||
|
public BobberPosture CurrentPosture => _posture;
|
||||||
|
public float CurrentVerticalRatio => _verticalRatio;
|
||||||
|
public float CurrentPlanarRatio => _planarRatio;
|
||||||
|
|
||||||
|
public float ExternalDownForce { get; set; }
|
||||||
|
public bool IsBottomTouched { get; set; }
|
||||||
|
public Vector2 ExternalPlanarOffset { get; set; }
|
||||||
|
|
||||||
|
private Rigidbody _rb;
|
||||||
|
private BobberControlMode _mode = BobberControlMode.AirPhysics;
|
||||||
|
private BobberPosture _posture = BobberPosture.Lying;
|
||||||
|
|
||||||
|
private float _defaultLinearDamping;
|
||||||
|
private float _defaultAngularDamping;
|
||||||
|
private bool _defaultUseGravity;
|
||||||
|
private bool _defaultsCached;
|
||||||
|
|
||||||
|
private Vector3 _waterAnchorPos;
|
||||||
|
private Vector3 _xzSmoothVelocity;
|
||||||
|
private float _ySmoothVelocity;
|
||||||
|
private float _biteOffsetY;
|
||||||
|
private float _biteOffsetYVelocity;
|
||||||
|
private Quaternion _targetRotation;
|
||||||
|
|
||||||
|
private BobberBiteType _activeBiteType = BobberBiteType.None;
|
||||||
|
private float _biteTimer;
|
||||||
|
private float _biteDuration;
|
||||||
|
private float _biteAmplitude;
|
||||||
|
private Vector3 _blackDriftDirection;
|
||||||
|
|
||||||
|
private float _verticalRatio;
|
||||||
|
private float _planarRatio;
|
||||||
|
private float _verticalDistance;
|
||||||
|
private float _planarDistance;
|
||||||
|
private BobberPosture _pendingPosture;
|
||||||
|
private float _pendingPostureTimer;
|
||||||
|
private float _postureCooldownTimer;
|
||||||
|
private Vector3 _stablePlanarDir = Vector3.forward;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
InitializeRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
HandleDebugKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSupportedNode(FishingLineNode node)
|
||||||
|
{
|
||||||
|
return node != null && node.Type == FishingLineNode.NodeType.Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnBind()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
InitializeRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanControl()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
if (_rb == null || !IsSupportedNode(Node))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var waterY = GetWaterHeight(transform.position);
|
||||||
|
var submergeDepth = waterY - GetBottomWorldPosition().y;
|
||||||
|
if (_mode == BobberControlMode.WaterPresentation)
|
||||||
|
{
|
||||||
|
return submergeDepth >= exitWaterDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return submergeDepth > enterWaterDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMotionActivated()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
EnterWaterPresentationMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMotionDeactivated()
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
ExitWaterPresentationMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TickMotion(float deltaTime)
|
||||||
|
{
|
||||||
|
EnsureRuntimeReferences();
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var waterY = GetWaterHeight(transform.position);
|
||||||
|
var submergeDepth = waterY - GetBottomWorldPosition().y;
|
||||||
|
UpdateWaterPresentation(waterY, submergeDepth, deltaTime);
|
||||||
|
|
||||||
|
if (drawDebug)
|
||||||
|
{
|
||||||
|
DrawDebug(waterY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayTap(float amplitude = 0.008f, float duration = 0.18f)
|
||||||
|
{
|
||||||
|
StartBite(BobberBiteType.Tap, amplitude, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlaySlowSink(float amplitude = 0.025f, float duration = 1.2f)
|
||||||
|
{
|
||||||
|
StartBite(BobberBiteType.SlowSink, amplitude, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayLift(float amplitude = 0.015f, float duration = 1.2f)
|
||||||
|
{
|
||||||
|
StartBite(BobberBiteType.Lift, amplitude, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayBlackDrift(float amplitude = 0.06f, float duration = 0.8f, Vector3? driftDirection = null)
|
||||||
|
{
|
||||||
|
StartBite(BobberBiteType.BlackDrift, amplitude, duration);
|
||||||
|
_blackDriftDirection = (driftDirection ?? transform.forward).normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopBite()
|
||||||
|
{
|
||||||
|
_activeBiteType = BobberBiteType.None;
|
||||||
|
_biteTimer = 0f;
|
||||||
|
_biteDuration = 0f;
|
||||||
|
_biteAmplitude = 0f;
|
||||||
|
_biteOffsetY = 0f;
|
||||||
|
_biteOffsetYVelocity = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureRuntimeReferences()
|
||||||
|
{
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
_rb = Node != null && Node.Body != null ? Node.Body : GetComponent<Rigidbody>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeRuntimeState()
|
||||||
|
{
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_defaultsCached)
|
||||||
|
{
|
||||||
|
_defaultLinearDamping = _rb.linearDamping;
|
||||||
|
_defaultAngularDamping = _rb.angularDamping;
|
||||||
|
_defaultUseGravity = _rb.useGravity;
|
||||||
|
_defaultsCached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pendingPosture = _posture;
|
||||||
|
_pendingPostureTimer = 0f;
|
||||||
|
_postureCooldownTimer = 0f;
|
||||||
|
_stablePlanarDir = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
|
||||||
|
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
_stablePlanarDir = Vector3.forward;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stablePlanarDir.Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
_targetRotation = transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateWaterPresentation(float waterY, float submergeDepth, float deltaTime)
|
||||||
|
{
|
||||||
|
if (submergeDepth < exitWaterDepth)
|
||||||
|
{
|
||||||
|
ExitWaterPresentationMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rb.useGravity = false;
|
||||||
|
_rb.linearVelocity = Vector3.zero;
|
||||||
|
_rb.angularVelocity = Vector3.zero;
|
||||||
|
_rb.linearDamping = 999f;
|
||||||
|
_rb.angularDamping = 999f;
|
||||||
|
|
||||||
|
UpdateBiteAnimation(deltaTime);
|
||||||
|
|
||||||
|
var pos = transform.position;
|
||||||
|
var targetY = CalculateTargetY(waterY);
|
||||||
|
if (Mathf.Abs(pos.y - targetY) < yDeadZone)
|
||||||
|
{
|
||||||
|
pos.y = targetY;
|
||||||
|
_ySmoothVelocity = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos.y = Mathf.SmoothDamp(
|
||||||
|
pos.y,
|
||||||
|
targetY,
|
||||||
|
ref _ySmoothVelocity,
|
||||||
|
Mathf.Max(0.0001f, ySmoothTime),
|
||||||
|
maxYSpeed,
|
||||||
|
deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetXZ = CalculateTargetXZ();
|
||||||
|
var planarPos = new Vector3(pos.x, 0f, pos.z);
|
||||||
|
var planarTarget = new Vector3(targetXZ.x, 0f, targetXZ.z);
|
||||||
|
planarPos = Vector3.SmoothDamp(
|
||||||
|
planarPos,
|
||||||
|
planarTarget,
|
||||||
|
ref _xzSmoothVelocity,
|
||||||
|
Mathf.Max(0.0001f, xzSmoothTime),
|
||||||
|
Mathf.Infinity,
|
||||||
|
deltaTime);
|
||||||
|
|
||||||
|
pos.x = planarPos.x;
|
||||||
|
pos.z = planarPos.z;
|
||||||
|
transform.position = pos;
|
||||||
|
|
||||||
|
EvaluatePostureByComponents(waterY, deltaTime);
|
||||||
|
UpdateTargetRotationByPosture(deltaTime);
|
||||||
|
|
||||||
|
transform.rotation = Quaternion.Slerp(
|
||||||
|
transform.rotation,
|
||||||
|
_targetRotation,
|
||||||
|
1f - Mathf.Exp(-rotationLerpSpeed * deltaTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterWaterPresentationMode()
|
||||||
|
{
|
||||||
|
if (_rb == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mode = BobberControlMode.WaterPresentation;
|
||||||
|
_waterAnchorPos = transform.position;
|
||||||
|
_ySmoothVelocity = 0f;
|
||||||
|
_xzSmoothVelocity = Vector3.zero;
|
||||||
|
_biteOffsetY = 0f;
|
||||||
|
_biteOffsetYVelocity = 0f;
|
||||||
|
_activeBiteType = BobberBiteType.None;
|
||||||
|
_biteTimer = 0f;
|
||||||
|
|
||||||
|
_posture = BobberPosture.Lying;
|
||||||
|
_verticalRatio = 0f;
|
||||||
|
_planarRatio = 0f;
|
||||||
|
_verticalDistance = 0f;
|
||||||
|
_planarDistance = 0f;
|
||||||
|
_pendingPosture = _posture;
|
||||||
|
_pendingPostureTimer = 0f;
|
||||||
|
_postureCooldownTimer = 0f;
|
||||||
|
_stablePlanarDir = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
|
||||||
|
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
_stablePlanarDir = Vector3.forward;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stablePlanarDir.Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
_rb.useGravity = false;
|
||||||
|
_rb.linearVelocity = Vector3.zero;
|
||||||
|
_rb.angularVelocity = Vector3.zero;
|
||||||
|
_rb.linearDamping = 999f;
|
||||||
|
_rb.angularDamping = 999f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExitWaterPresentationMode()
|
||||||
|
{
|
||||||
|
_mode = BobberControlMode.AirPhysics;
|
||||||
|
RestoreAirPhysicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestoreAirPhysicsState()
|
||||||
|
{
|
||||||
|
if (_rb == null || !_defaultsCached)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rb.useGravity = _defaultUseGravity;
|
||||||
|
_rb.linearDamping = _defaultLinearDamping;
|
||||||
|
_rb.angularDamping = _defaultAngularDamping;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float CalculateTargetY(float waterY)
|
||||||
|
{
|
||||||
|
var baseSinkDepth = floatHeight * Mathf.Clamp01(baseSubmergeRatio);
|
||||||
|
var sinkByForce = Mathf.Clamp(ExternalDownForce * downForceToSink, 0f, maxExtraSink);
|
||||||
|
|
||||||
|
var bottomAdjust = 0f;
|
||||||
|
if (enableBottomTouchAdjust && IsBottomTouched)
|
||||||
|
{
|
||||||
|
bottomAdjust -= bottomTouchLift;
|
||||||
|
}
|
||||||
|
|
||||||
|
var surfaceBob = 0f;
|
||||||
|
if (enableSurfaceBobbing)
|
||||||
|
{
|
||||||
|
surfaceBob = Mathf.Sin(Time.time * surfaceBobFrequency * Mathf.PI * 2f) * surfaceBobAmplitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalSink = baseSinkDepth + sinkByForce + bottomAdjust;
|
||||||
|
var targetBottomY = waterY - totalSink;
|
||||||
|
return targetBottomY - bottomOffsetLocalY + surfaceBob + _biteOffsetY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 CalculateTargetXZ()
|
||||||
|
{
|
||||||
|
var planarOffset = Vector2.ClampMagnitude(ExternalPlanarOffset, maxPlanarOffset);
|
||||||
|
var basePos = lockXZAroundAnchor ? _waterAnchorPos : transform.position;
|
||||||
|
|
||||||
|
if (_activeBiteType == BobberBiteType.BlackDrift)
|
||||||
|
{
|
||||||
|
var t = Mathf.Clamp01(_biteDuration > 0f ? _biteTimer / _biteDuration : 1f);
|
||||||
|
var drift = Mathf.SmoothStep(0f, 1f, t) * 0.08f;
|
||||||
|
var blackDrift = _blackDriftDirection * drift;
|
||||||
|
basePos += new Vector3(blackDrift.x, 0f, blackDrift.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector3(
|
||||||
|
basePos.x + planarOffset.x,
|
||||||
|
transform.position.y,
|
||||||
|
basePos.z + planarOffset.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EvaluatePostureByComponents(float waterY, float deltaTime)
|
||||||
|
{
|
||||||
|
var submergeRatio = Mathf.Clamp01(
|
||||||
|
(waterY - GetBottomWorldPosition().y) / Mathf.Max(0.0001f, floatHeight));
|
||||||
|
|
||||||
|
var hasLure = lureBody != null;
|
||||||
|
if (!hasLure)
|
||||||
|
{
|
||||||
|
_verticalDistance = 0f;
|
||||||
|
_planarDistance = 0f;
|
||||||
|
_verticalRatio = 0f;
|
||||||
|
_planarRatio = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var bobberPos = _rb.worldCenterOfMass;
|
||||||
|
var lurePos = lureBody.worldCenterOfMass;
|
||||||
|
var delta = lurePos - bobberPos;
|
||||||
|
|
||||||
|
_verticalDistance = Mathf.Max(0f, Vector3.Dot(delta, Vector3.down));
|
||||||
|
_planarDistance = Vector3.ProjectOnPlane(delta, Vector3.up).magnitude;
|
||||||
|
|
||||||
|
var refLen = Mathf.Max(0.0001f, referenceLength);
|
||||||
|
_verticalRatio = _verticalDistance / refLen;
|
||||||
|
_planarRatio = _planarDistance / refLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
var desiredPosture = DeterminePostureState(submergeRatio, hasLure);
|
||||||
|
ApplyPostureWithStability(desiredPosture, deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BobberPosture DeterminePostureState(float submergeRatio, bool hasLure)
|
||||||
|
{
|
||||||
|
if (UseTestPosture)
|
||||||
|
{
|
||||||
|
return TestPosture;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasLure)
|
||||||
|
{
|
||||||
|
if (submergeRatio < minSubmergeToStand)
|
||||||
|
{
|
||||||
|
return BobberPosture.Lying;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExternalPlanarOffset.magnitude > 0.01f)
|
||||||
|
{
|
||||||
|
return BobberPosture.Tilted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BobberPosture.Upright;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_posture)
|
||||||
|
{
|
||||||
|
case BobberPosture.Lying:
|
||||||
|
{
|
||||||
|
var canStandUpright =
|
||||||
|
submergeRatio >= minSubmergeToStand &&
|
||||||
|
_verticalRatio > verticalUprightThreshold + postureHysteresis &&
|
||||||
|
_planarRatio < planarTiltThreshold - postureHysteresis;
|
||||||
|
|
||||||
|
var canTilt =
|
||||||
|
submergeRatio >= minSubmergeToStand * 0.8f &&
|
||||||
|
_verticalRatio > verticalLieThreshold + postureHysteresis;
|
||||||
|
|
||||||
|
if (canStandUpright)
|
||||||
|
{
|
||||||
|
return BobberPosture.Upright;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canTilt)
|
||||||
|
{
|
||||||
|
return BobberPosture.Tilted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BobberPosture.Lying;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BobberPosture.Tilted:
|
||||||
|
{
|
||||||
|
var shouldLie =
|
||||||
|
submergeRatio < minSubmergeToStand * 0.75f ||
|
||||||
|
_verticalRatio < verticalLieThreshold - postureHysteresis ||
|
||||||
|
_planarDistance > _verticalDistance * planarDominanceMultiplier;
|
||||||
|
|
||||||
|
var shouldStand =
|
||||||
|
submergeRatio >= minSubmergeToStand &&
|
||||||
|
_verticalRatio > verticalUprightThreshold + postureHysteresis &&
|
||||||
|
_planarRatio < planarTiltThreshold - postureHysteresis;
|
||||||
|
|
||||||
|
if (shouldLie)
|
||||||
|
{
|
||||||
|
return BobberPosture.Lying;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldStand)
|
||||||
|
{
|
||||||
|
return BobberPosture.Upright;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BobberPosture.Tilted;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
var shouldLie =
|
||||||
|
submergeRatio < minSubmergeToStand * 0.75f ||
|
||||||
|
_verticalRatio < verticalLieThreshold - postureHysteresis ||
|
||||||
|
_planarDistance > _verticalDistance * (planarDominanceMultiplier + 0.15f);
|
||||||
|
|
||||||
|
var shouldTilt =
|
||||||
|
_verticalRatio < verticalUprightThreshold - postureHysteresis ||
|
||||||
|
_planarRatio > planarTiltThreshold + postureHysteresis;
|
||||||
|
|
||||||
|
if (shouldLie)
|
||||||
|
{
|
||||||
|
return BobberPosture.Lying;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldTilt)
|
||||||
|
{
|
||||||
|
return BobberPosture.Tilted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BobberPosture.Upright;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyPostureWithStability(BobberPosture desiredPosture, float deltaTime)
|
||||||
|
{
|
||||||
|
_postureCooldownTimer = Mathf.Max(0f, _postureCooldownTimer - deltaTime);
|
||||||
|
if (desiredPosture == _posture)
|
||||||
|
{
|
||||||
|
_pendingPosture = _posture;
|
||||||
|
_pendingPostureTimer = 0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_postureCooldownTimer > 0f)
|
||||||
|
{
|
||||||
|
_pendingPosture = desiredPosture;
|
||||||
|
_pendingPostureTimer = 0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pendingPosture != desiredPosture)
|
||||||
|
{
|
||||||
|
_pendingPosture = desiredPosture;
|
||||||
|
_pendingPostureTimer = 0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pendingPostureTimer += deltaTime;
|
||||||
|
if (_pendingPostureTimer >= Mathf.Max(0f, postureConfirmTime))
|
||||||
|
{
|
||||||
|
_posture = desiredPosture;
|
||||||
|
_pendingPosture = _posture;
|
||||||
|
_pendingPostureTimer = 0f;
|
||||||
|
_postureCooldownTimer = Mathf.Max(0f, postureSwitchCooldown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTargetRotationByPosture(float deltaTime)
|
||||||
|
{
|
||||||
|
var candidateDir = Vector3.zero;
|
||||||
|
if (lureBody != null)
|
||||||
|
{
|
||||||
|
var delta = lureBody.worldCenterOfMass - _rb.worldCenterOfMass;
|
||||||
|
candidateDir = Vector3.ProjectOnPlane(delta, Vector3.up);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidateDir.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
candidateDir = new Vector3(_xzSmoothVelocity.x, 0f, _xzSmoothVelocity.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidateDir.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
candidateDir = new Vector3(ExternalPlanarOffset.x, 0f, ExternalPlanarOffset.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
_stablePlanarDir = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
|
||||||
|
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
_stablePlanarDir = Vector3.forward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stablePlanarDir.Normalize();
|
||||||
|
|
||||||
|
var dirDeadZone = Mathf.Max(0.0001f, planarDirectionDeadZone);
|
||||||
|
if (candidateDir.sqrMagnitude > dirDeadZone * dirDeadZone)
|
||||||
|
{
|
||||||
|
candidateDir.Normalize();
|
||||||
|
if (Vector3.Dot(candidateDir, _stablePlanarDir) < 0f)
|
||||||
|
{
|
||||||
|
candidateDir = -candidateDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
var k = 1f - Mathf.Exp(-Mathf.Max(0.01f, planarDirectionLerpSpeed) * deltaTime);
|
||||||
|
_stablePlanarDir = Vector3.Slerp(_stablePlanarDir, candidateDir, k);
|
||||||
|
_stablePlanarDir.Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
var planarDir = _stablePlanarDir;
|
||||||
|
var tiltAxis = Vector3.Cross(Vector3.up, planarDir);
|
||||||
|
if (tiltAxis.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
tiltAxis = transform.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
var angle = _posture switch
|
||||||
|
{
|
||||||
|
BobberPosture.Lying => lyingAngle,
|
||||||
|
BobberPosture.Tilted => tiltedAngle,
|
||||||
|
_ => 0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
_targetRotation = Quaternion.AngleAxis(angle, tiltAxis.normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartBite(BobberBiteType type, float amplitude, float duration)
|
||||||
|
{
|
||||||
|
if (_mode != BobberControlMode.WaterPresentation)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_activeBiteType = type;
|
||||||
|
_biteTimer = 0f;
|
||||||
|
_biteDuration = Mathf.Max(0.01f, duration);
|
||||||
|
_biteAmplitude = amplitude;
|
||||||
|
_biteOffsetYVelocity = 0f;
|
||||||
|
|
||||||
|
if (type == BobberBiteType.BlackDrift && _blackDriftDirection.sqrMagnitude < 1e-6f)
|
||||||
|
{
|
||||||
|
_blackDriftDirection =
|
||||||
|
transform.forward.sqrMagnitude > 1e-6f ? transform.forward.normalized : Vector3.forward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBiteAnimation(float deltaTime)
|
||||||
|
{
|
||||||
|
if (_activeBiteType == BobberBiteType.None)
|
||||||
|
{
|
||||||
|
_biteOffsetY = Mathf.SmoothDamp(
|
||||||
|
_biteOffsetY,
|
||||||
|
0f,
|
||||||
|
ref _biteOffsetYVelocity,
|
||||||
|
0.08f,
|
||||||
|
Mathf.Infinity,
|
||||||
|
deltaTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_biteTimer += deltaTime;
|
||||||
|
var t = Mathf.Clamp01(_biteTimer / _biteDuration);
|
||||||
|
var targetOffset = 0f;
|
||||||
|
|
||||||
|
switch (_activeBiteType)
|
||||||
|
{
|
||||||
|
case BobberBiteType.Tap:
|
||||||
|
if (t < 0.35f)
|
||||||
|
{
|
||||||
|
var k = t / 0.35f;
|
||||||
|
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, k);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var k = (t - 0.35f) / 0.65f;
|
||||||
|
targetOffset = -Mathf.Lerp(_biteAmplitude, 0f, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BobberBiteType.SlowSink:
|
||||||
|
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BobberBiteType.Lift:
|
||||||
|
targetOffset = Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BobberBiteType.BlackDrift:
|
||||||
|
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_biteOffsetY = Mathf.SmoothDamp(
|
||||||
|
_biteOffsetY,
|
||||||
|
targetOffset,
|
||||||
|
ref _biteOffsetYVelocity,
|
||||||
|
0.03f,
|
||||||
|
Mathf.Infinity,
|
||||||
|
deltaTime);
|
||||||
|
|
||||||
|
if (_biteTimer >= _biteDuration &&
|
||||||
|
_activeBiteType != BobberBiteType.SlowSink &&
|
||||||
|
_activeBiteType != BobberBiteType.BlackDrift)
|
||||||
|
{
|
||||||
|
_activeBiteType = BobberBiteType.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetWaterHeight(Vector3 worldPos)
|
||||||
|
{
|
||||||
|
return fallbackWaterLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 GetBottomWorldPosition()
|
||||||
|
{
|
||||||
|
return transform.TransformPoint(new Vector3(0f, bottomOffsetLocalY, 0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDebugKeys()
|
||||||
|
{
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugResetKey && Input.GetKeyDown(KeyCode.R))
|
||||||
|
{
|
||||||
|
StopBite();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugTapKey && Input.GetKeyDown(KeyCode.T))
|
||||||
|
{
|
||||||
|
PlayTap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugSlowSinkKey && Input.GetKeyDown(KeyCode.G))
|
||||||
|
{
|
||||||
|
PlaySlowSink();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugLiftKey && Input.GetKeyDown(KeyCode.H))
|
||||||
|
{
|
||||||
|
PlayLift();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugBlackDriftKey && Input.GetKeyDown(KeyCode.B))
|
||||||
|
{
|
||||||
|
PlayBlackDrift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawDebug(float waterY)
|
||||||
|
{
|
||||||
|
var p = transform.position;
|
||||||
|
var b = GetBottomWorldPosition();
|
||||||
|
|
||||||
|
Debug.DrawLine(
|
||||||
|
new Vector3(p.x - 0.05f, waterY, p.z),
|
||||||
|
new Vector3(p.x + 0.05f, waterY, p.z),
|
||||||
|
Color.cyan);
|
||||||
|
|
||||||
|
Debug.DrawLine(b, b + Vector3.up * floatHeight, Color.yellow);
|
||||||
|
|
||||||
|
if (_mode == BobberControlMode.WaterPresentation)
|
||||||
|
{
|
||||||
|
var a = _waterAnchorPos;
|
||||||
|
Debug.DrawLine(a + Vector3.left * 0.03f, a + Vector3.right * 0.03f, Color.green);
|
||||||
|
Debug.DrawLine(a + Vector3.forward * 0.03f, a + Vector3.back * 0.03f, Color.green);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lureBody != null)
|
||||||
|
{
|
||||||
|
var bobber = _rb.worldCenterOfMass;
|
||||||
|
var lure = lureBody.worldCenterOfMass;
|
||||||
|
Debug.DrawLine(bobber, lure, Color.magenta);
|
||||||
|
|
||||||
|
var verticalEnd = bobber + Vector3.down * _verticalDistance;
|
||||||
|
Debug.DrawLine(bobber, verticalEnd, Color.red);
|
||||||
|
|
||||||
|
var planar = Vector3.ProjectOnPlane(lure - bobber, Vector3.up);
|
||||||
|
Debug.DrawLine(verticalEnd, verticalEnd + planar, Color.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
floatHeight = Mathf.Max(0.001f, floatHeight);
|
||||||
|
ySmoothTime = Mathf.Max(0.001f, ySmoothTime);
|
||||||
|
maxYSpeed = Mathf.Max(0.01f, maxYSpeed);
|
||||||
|
xzSmoothTime = Mathf.Max(0.001f, xzSmoothTime);
|
||||||
|
rotationLerpSpeed = Mathf.Max(0.01f, rotationLerpSpeed);
|
||||||
|
|
||||||
|
maxPlanarOffset = Mathf.Max(0f, maxPlanarOffset);
|
||||||
|
downForceToSink = Mathf.Max(0f, downForceToSink);
|
||||||
|
maxExtraSink = Mathf.Max(0f, maxExtraSink);
|
||||||
|
surfaceBobAmplitude = Mathf.Max(0f, surfaceBobAmplitude);
|
||||||
|
surfaceBobFrequency = Mathf.Max(0f, surfaceBobFrequency);
|
||||||
|
yDeadZone = Mathf.Max(0f, yDeadZone);
|
||||||
|
|
||||||
|
referenceLength = Mathf.Max(0.0001f, referenceLength);
|
||||||
|
minSubmergeToStand = Mathf.Clamp01(minSubmergeToStand);
|
||||||
|
verticalLieThreshold = Mathf.Clamp(verticalLieThreshold, 0f, 2f);
|
||||||
|
verticalUprightThreshold = Mathf.Max(verticalLieThreshold, verticalUprightThreshold);
|
||||||
|
planarTiltThreshold = Mathf.Clamp(planarTiltThreshold, 0f, 2f);
|
||||||
|
planarDominanceMultiplier = Mathf.Max(0.1f, planarDominanceMultiplier);
|
||||||
|
postureHysteresis = Mathf.Clamp(postureHysteresis, 0f, 0.3f);
|
||||||
|
postureConfirmTime = Mathf.Max(0f, postureConfirmTime);
|
||||||
|
postureSwitchCooldown = Mathf.Max(0f, postureSwitchCooldown);
|
||||||
|
|
||||||
|
tiltedAngle = Mathf.Clamp(tiltedAngle, 0f, 89f);
|
||||||
|
lyingAngle = Mathf.Clamp(lyingAngle, tiltedAngle, 89.9f);
|
||||||
|
uprightMaxTiltAngle = Mathf.Clamp(uprightMaxTiltAngle, 0f, tiltedAngle);
|
||||||
|
planarTiltFactor = Mathf.Max(0f, planarTiltFactor);
|
||||||
|
planarDirectionDeadZone = Mathf.Max(0.0001f, planarDirectionDeadZone);
|
||||||
|
planarDirectionLerpSpeed = Mathf.Max(0.01f, planarDirectionLerpSpeed);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 40a38940e81046e2854add979cedbef9
|
||||||
|
timeCreated: 1775958531
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
public abstract class FishingLineNodeFeature : MonoBehaviour
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前功能组件所属的节点。
|
||||||
|
/// </summary>
|
||||||
|
public FishingLineNode Node { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前功能组件所属的鱼线求解器。
|
||||||
|
/// </summary>
|
||||||
|
public FishingLineSolver Solver { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将当前功能组件绑定到指定节点和求解器。
|
||||||
|
/// </summary>
|
||||||
|
public void Bind(FishingLineNode node, FishingLineSolver solver)
|
||||||
|
{
|
||||||
|
Node = node;
|
||||||
|
Solver = solver;
|
||||||
|
|
||||||
|
if (!IsSupportedNode(node))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"{GetType().Name} 不适用于节点 {node.name} 的当前配置。", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnBind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前功能组件是否支持挂在该节点上。
|
||||||
|
/// 子类可按节点类型、尾节点类型或产品标识做限制。
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsSupportedNode(FishingLineNode node)
|
||||||
|
{
|
||||||
|
return node != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点与求解器绑定完成后的回调。
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnBind()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 鱼线链路重建完成后的回调。
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnLineBuilt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 鱼线达到断线条件后的回调。
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnLineBreakRequested()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c7ea70945db841deb0ee8df85f0e15ec
|
||||||
|
timeCreated: 1775957663
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
public abstract class FishingLineNodeMotionFeature : FishingLineNodeFeature
|
||||||
|
{
|
||||||
|
[Header("Motion Control")] [SerializeField]
|
||||||
|
private int priorityOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前运动控制组件的优先级。
|
||||||
|
/// 值越大,越容易取得节点运动控制权。
|
||||||
|
/// 最终优先级 = 默认优先级 + 调整值。
|
||||||
|
/// </summary>
|
||||||
|
public int Priority => DefaultPriority + priorityOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前运动控制组件的默认优先级。
|
||||||
|
/// 子类可通过重写该值,决定自己相对默认物理的抢占能力。
|
||||||
|
/// </summary>
|
||||||
|
protected virtual int DefaultPriority => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前帧该运动控制组件是否希望接管节点运动。
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool CanControl();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前运动控制组件开始接管节点时的回调。
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnMotionActivated()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前运动控制组件失去节点控制权时的回调。
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnMotionDeactivated()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前运动控制组件正在接管节点时,每个 FixedUpdate 执行的逻辑。
|
||||||
|
/// </summary>
|
||||||
|
public abstract void TickMotion(float deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7e75217306a64f8f868f5f9127772de2
|
||||||
|
timeCreated: 1775957711
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
public class FishingLineNode : MonoBehaviour
|
||||||
|
{
|
||||||
|
public enum NodeType
|
||||||
|
{
|
||||||
|
Start,
|
||||||
|
Float,
|
||||||
|
Weight,
|
||||||
|
Tail
|
||||||
|
}
|
||||||
|
|
||||||
|
private FishingLineSolver _solver;
|
||||||
|
[Header("Node")] [SerializeField] private NodeType nodeType = NodeType.Tail;
|
||||||
|
[SerializeField] private Rigidbody body;
|
||||||
|
|
||||||
|
public NodeType Type
|
||||||
|
{
|
||||||
|
get => nodeType;
|
||||||
|
set => nodeType = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rigidbody Body => body;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
_solver = GetComponentInParent<FishingLineSolver>();
|
||||||
|
body = GetComponent<Rigidbody>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ee9704c2e1594f4cab270bfd4ca2210b
|
||||||
|
timeCreated: 1776008915
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
[RequireComponent(typeof(LineRenderer))]
|
||||||
|
public class FishingLineRenderer : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("References")] [SerializeField]
|
||||||
|
private FishingLineSolver solver;
|
||||||
|
|
||||||
|
[SerializeField] private LineRenderer lineRenderer;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
lineRenderer = GetComponent<LineRenderer>();
|
||||||
|
solver = GetComponent<FishingLineSolver>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 14537bf263784fcd8aaf130eb3c51350
|
||||||
|
timeCreated: 1776084149
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NBF
|
||||||
|
{
|
||||||
|
public class FishingLineSolver : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] private FishingLineNode[] logicalNodes = Array.Empty<FishingLineNode>();
|
||||||
|
|
||||||
|
|
||||||
|
#region LineNode
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前配置的逻辑节点只读列表。
|
||||||
|
/// 外部可读取节点顺序,但不应直接修改数组内容。
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<FishingLineNode> LogicalNodes => logicalNodes;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定顺序索引的逻辑节点。
|
||||||
|
/// 索引基于 logicalNodes 配置顺序;超出范围或节点为空时返回 null。
|
||||||
|
/// </summary>
|
||||||
|
public FishingLineNode GetLogicalNode(int logicalIndex)
|
||||||
|
{
|
||||||
|
if (logicalNodes == null || logicalIndex < 0 || logicalIndex >= logicalNodes.Length)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return logicalNodes[logicalIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前起点逻辑节点。
|
||||||
|
/// 会返回配置顺序中第一个非空节点。
|
||||||
|
/// </summary>
|
||||||
|
public FishingLineNode GetStartNode()
|
||||||
|
{
|
||||||
|
return FindFirstValidLogicalNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前终点逻辑节点。
|
||||||
|
/// 会返回配置顺序中最后一个非空节点。
|
||||||
|
/// </summary>
|
||||||
|
public FishingLineNode GetEndNode()
|
||||||
|
{
|
||||||
|
return FindLastValidLogicalNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FishingLineNode FindFirstValidLogicalNode()
|
||||||
|
{
|
||||||
|
if (logicalNodes == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < logicalNodes.Length; i++)
|
||||||
|
{
|
||||||
|
if (logicalNodes[i] != null)
|
||||||
|
{
|
||||||
|
return logicalNodes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FishingLineNode FindLastValidLogicalNode()
|
||||||
|
{
|
||||||
|
if (logicalNodes == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = logicalNodes.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (logicalNodes[i] != null)
|
||||||
|
{
|
||||||
|
return logicalNodes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fd39a2e024a0477c9ad5698d80d9a63a
|
||||||
|
timeCreated: 1776008869
|
||||||
@@ -31,6 +31,12 @@ public class Rope : MonoBehaviour
|
|||||||
[SerializeField, Range(0, 16), Tooltip("主求解后追加的硬长度约束次数。只负责把 poly 拉回到 rest total,不改变可变长度逻辑")]
|
[SerializeField, Range(0, 16), Tooltip("主求解后追加的硬长度约束次数。只负责把 poly 拉回到 rest total,不改变可变长度逻辑")]
|
||||||
private int hardTightenIterations = 2;
|
private int hardTightenIterations = 2;
|
||||||
|
|
||||||
|
[SerializeField, Range(0, 32), Tooltip("当绳子接近拉直时,按误差自动追加的硬长度约束次数上限")]
|
||||||
|
private int adaptiveHardTightenMaxIterations = 8;
|
||||||
|
|
||||||
|
[SerializeField, Min(0f), Tooltip("单段允许的最大超长误差;超过时继续追加硬长度约束")]
|
||||||
|
private float hardConstraintTolerance = 0.0005f;
|
||||||
|
|
||||||
[Header("Length Control (No Min/Max Clamp)")]
|
[Header("Length Control (No Min/Max Clamp)")]
|
||||||
[Tooltip("初始总长度(米)。如果为 0,则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
|
[Tooltip("初始总长度(米)。如果为 0,则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
|
||||||
[SerializeField, Min(0f)]
|
[SerializeField, Min(0f)]
|
||||||
@@ -211,6 +217,8 @@ public class Rope : MonoBehaviour
|
|||||||
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
|
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
|
||||||
iterations = Mathf.Clamp(iterations, 1, 80);
|
iterations = Mathf.Clamp(iterations, 1, 80);
|
||||||
hardTightenIterations = Mathf.Clamp(hardTightenIterations, 0, 16);
|
hardTightenIterations = Mathf.Clamp(hardTightenIterations, 0, 16);
|
||||||
|
adaptiveHardTightenMaxIterations = Mathf.Clamp(adaptiveHardTightenMaxIterations, 0, 32);
|
||||||
|
hardConstraintTolerance = Mathf.Max(0f, hardConstraintTolerance);
|
||||||
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
|
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
|
||||||
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
|
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
|
||||||
lineWidth = Mathf.Max(lineWidth, 0.0001f);
|
lineWidth = Mathf.Max(lineWidth, 0.0001f);
|
||||||
@@ -532,6 +540,7 @@ public class Rope : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
SolveHardDistanceConstraints(hardTightenIterations);
|
SolveHardDistanceConstraints(hardTightenIterations);
|
||||||
|
SolveHardDistanceConstraintsAdaptive();
|
||||||
LockAnchorsHard();
|
LockAnchorsHard();
|
||||||
|
|
||||||
if (constrainToGround)
|
if (constrainToGround)
|
||||||
@@ -572,16 +581,7 @@ public class Rope : MonoBehaviour
|
|||||||
EnsureRenderCaches();
|
EnsureRenderCaches();
|
||||||
|
|
||||||
int last = _physicsNodes - 1;
|
int last = _physicsNodes - 1;
|
||||||
|
DrawHighResLine_Fast(_startTr.position, _endTr.position, last);
|
||||||
Vector3 s = _startTr.position;
|
|
||||||
Vector3 e = _endTr.position;
|
|
||||||
|
|
||||||
_pCurr[0] = s;
|
|
||||||
_pCurr[last] = e;
|
|
||||||
// _pPrev[0] = s;
|
|
||||||
// _pPrev[last] = e;
|
|
||||||
|
|
||||||
DrawHighResLine_Fast();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateLengthSmooth()
|
private void UpdateLengthSmooth()
|
||||||
@@ -734,6 +734,21 @@ public class Rope : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SolveHardDistanceConstraintsAdaptive()
|
||||||
|
{
|
||||||
|
if (adaptiveHardTightenMaxIterations <= 0 || hardConstraintTolerance <= 0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int it = 0; it < adaptiveHardTightenMaxIterations; it++)
|
||||||
|
{
|
||||||
|
if (GetMaxPositiveSegmentDelta() <= hardConstraintTolerance)
|
||||||
|
break;
|
||||||
|
|
||||||
|
LockAnchorsHard();
|
||||||
|
SolveDistanceConstraints_HeadOnly_Hard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SolveDistanceConstraints_HeadOnly_Hard()
|
private void SolveDistanceConstraints_HeadOnly_Hard()
|
||||||
{
|
{
|
||||||
SolveDistanceConstraints_HeadOnly_Bidirectional(1f);
|
SolveDistanceConstraints_HeadOnly_Bidirectional(1f);
|
||||||
@@ -787,6 +802,21 @@ public class Rope : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float GetMaxPositiveSegmentDelta()
|
||||||
|
{
|
||||||
|
float maxDelta = 0f;
|
||||||
|
for (int i = 1; i < _physicsNodes; i++)
|
||||||
|
{
|
||||||
|
float rest = (i == 1) ? _headRestLen : physicsSegmentLen;
|
||||||
|
float segLen = Vector3.Distance(_pCurr[i - 1], _pCurr[i]);
|
||||||
|
float delta = segLen - rest;
|
||||||
|
if (delta > maxDelta)
|
||||||
|
maxDelta = delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxDelta;
|
||||||
|
}
|
||||||
|
|
||||||
private void ConstrainToGround()
|
private void ConstrainToGround()
|
||||||
{
|
{
|
||||||
if (groundMask == 0) return;
|
if (groundMask == 0) return;
|
||||||
@@ -938,7 +968,7 @@ public class Rope : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawHighResLine_Fast()
|
private void DrawHighResLine_Fast(Vector3 renderStart, Vector3 renderEnd, int last)
|
||||||
{
|
{
|
||||||
if (_pCurr == null || _physicsNodes < 2) return;
|
if (_pCurr == null || _physicsNodes < 2) return;
|
||||||
|
|
||||||
@@ -949,7 +979,9 @@ public class Rope : MonoBehaviour
|
|||||||
if (!smooth)
|
if (!smooth)
|
||||||
{
|
{
|
||||||
_lineRenderer.positionCount = _physicsNodes;
|
_lineRenderer.positionCount = _physicsNodes;
|
||||||
_lineRenderer.SetPositions(_pCurr);
|
for (int i = 0; i <= last; i++)
|
||||||
|
_rPoints[i] = GetRenderPoint(i, last, renderStart, renderEnd);
|
||||||
|
_lineRenderer.SetPositions(_rPoints);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +996,6 @@ public class Rope : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
int last = _physicsNodes - 1;
|
|
||||||
|
|
||||||
for (int seg = 0; seg < last; seg++)
|
for (int seg = 0; seg < last; seg++)
|
||||||
{
|
{
|
||||||
@@ -975,10 +1006,10 @@ public class Rope : MonoBehaviour
|
|||||||
int i3 = seg + 2;
|
int i3 = seg + 2;
|
||||||
if (i3 > last) i3 = last;
|
if (i3 > last) i3 = last;
|
||||||
|
|
||||||
Vector3 p0 = _pCurr[i0];
|
Vector3 p0 = GetRenderPoint(i0, last, renderStart, renderEnd);
|
||||||
Vector3 p1 = _pCurr[i1];
|
Vector3 p1 = GetRenderPoint(i1, last, renderStart, renderEnd);
|
||||||
Vector3 p2 = _pCurr[i2];
|
Vector3 p2 = GetRenderPoint(i2, last, renderStart, renderEnd);
|
||||||
Vector3 p3 = _pCurr[i3];
|
Vector3 p3 = GetRenderPoint(i3, last, renderStart, renderEnd);
|
||||||
|
|
||||||
for (int s = 0; s < subdiv; s++)
|
for (int s = 0; s < subdiv; s++)
|
||||||
{
|
{
|
||||||
@@ -1001,12 +1032,21 @@ public class Rope : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_rPoints[idx++] = _pCurr[last];
|
_rPoints[idx++] = renderEnd;
|
||||||
|
|
||||||
_lineRenderer.positionCount = idx;
|
_lineRenderer.positionCount = idx;
|
||||||
_lineRenderer.SetPositions(_rPoints);
|
_lineRenderer.SetPositions(_rPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector3 GetRenderPoint(int index, int last, Vector3 renderStart, Vector3 renderEnd)
|
||||||
|
{
|
||||||
|
if (index <= 0)
|
||||||
|
return renderStart;
|
||||||
|
if (index >= last)
|
||||||
|
return renderEnd;
|
||||||
|
return _pCurr[index];
|
||||||
|
}
|
||||||
|
|
||||||
private static float ClampMonotonic(float value, float p0, float p1, float p2, float p3)
|
private static float ClampMonotonic(float value, float p0, float p1, float p2, float p3)
|
||||||
{
|
{
|
||||||
bool rising = p0 <= p1 && p1 <= p2 && p2 <= p3;
|
bool rising = p0 <= p1 && p1 <= p2 && p2 <= p3;
|
||||||
|
|||||||
Reference in New Issue
Block a user