Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d7028a5664 | |||
|
|
c55d38b3a6 | ||
|
|
e8b1a3e0f1 | ||
|
|
f2803c9d74 | ||
| 9681d7526f | |||
|
|
a0fa4e6e9c | ||
| d945638997 |
@@ -18583,36 +18583,6 @@ MonoBehaviour:
|
||||
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||
FilterEnum: 0
|
||||
Filter: '*'
|
||||
- Path: Assets/ResRaw/Prefabs/Line/FishingLine1.prefab
|
||||
Address: Plyaer/FishingLine1
|
||||
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/FishingLine11.prefab
|
||||
Address: Plyaer/FishingLine11
|
||||
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/FishingRopeLong.asset
|
||||
Address: Plyaer/FishingRopeLong
|
||||
Type: Missing
|
||||
@@ -18658,6 +18628,21 @@ MonoBehaviour:
|
||||
- {fileID: 102900000, guid: aa3f5467c0c153642ac320466aee0ec1, type: 3}
|
||||
FilterEnum: 0
|
||||
Filter: '*'
|
||||
- Path: Assets/ResRaw/Prefabs/Line/Line1.prefab
|
||||
Address: Plyaer/Line1
|
||||
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/LineHand1.prefab
|
||||
Address: Plyaer/LineHand1
|
||||
Type: GameObject
|
||||
|
||||
BIN
Assets/New Terrain 13.asset
Normal file
BIN
Assets/New Terrain 13.asset
Normal file
Binary file not shown.
8
Assets/New Terrain 13.asset.meta
Normal file
8
Assets/New Terrain 13.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 953400dda9b03df4d967e2e7dd8ef9f8
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 15600000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/New Terrain 14.asset
Normal file
BIN
Assets/New Terrain 14.asset
Normal file
Binary file not shown.
8
Assets/New Terrain 14.asset.meta
Normal file
8
Assets/New Terrain 14.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5b77e954e13d8644859b63f2252924f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 15600000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f94195a9c8f8c747b6ebcfd7fae6ee6
|
||||
timeCreated: 1762387921
|
||||
licenseType: Free
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
addedObjectFileIDs:
|
||||
isPrefabVariant: 0
|
||||
variantParentGUID: 00000000000000000000000000000000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,589 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &2696931885206049402
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6213026895670800501}
|
||||
- component: {fileID: 7362979975150531515}
|
||||
- component: {fileID: 5572865435543895569}
|
||||
m_Layer: 15
|
||||
m_Name: Start
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &6213026895670800501
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2696931885206049402}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 98221710317492190}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &7362979975150531515
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2696931885206049402}
|
||||
serializedVersion: 5
|
||||
m_Mass: 1
|
||||
m_LinearDamping: 1
|
||||
m_AngularDamping: 0.05
|
||||
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||
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: 1
|
||||
m_UseGravity: 1
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!114 &5572865435543895569
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2696931885206049402}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 610df5569209e4b4997cb2dbf3b94cdc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
nodeType: 0
|
||||
body: {fileID: 7362979975150531515}
|
||||
interaction: {fileID: 0}
|
||||
segmentLengthToNext: 0.5
|
||||
fixedVirtualNodesToNext: 2
|
||||
runtimeVirtualNode: 0
|
||||
runtimeChainIndex: -1
|
||||
drawDebugGizmo: 1
|
||||
debugGizmoRadius: 0.03
|
||||
logicalNodeColor: {r: 0.2, g: 0.9, b: 0.2, a: 1}
|
||||
virtualNodeColor: {r: 1, g: 0.6, b: 0.1, a: 1}
|
||||
features: []
|
||||
motionFeatures: []
|
||||
activeMotionFeature: {fileID: 0}
|
||||
--- !u!1 &5077741257619886775
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7385546574667729905}
|
||||
- component: {fileID: 5707703654405666688}
|
||||
- component: {fileID: 3979683508768218053}
|
||||
- component: {fileID: 250386986656750139}
|
||||
- component: {fileID: 6225447558892123241}
|
||||
m_Layer: 15
|
||||
m_Name: End
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &7385546574667729905
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5077741257619886775}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 98221710317492190}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &5707703654405666688
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5077741257619886775}
|
||||
serializedVersion: 5
|
||||
m_Mass: 0.01
|
||||
m_LinearDamping: 1
|
||||
m_AngularDamping: 0.2
|
||||
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||
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: 1
|
||||
m_UseGravity: 1
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!114 &3979683508768218053
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5077741257619886775}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 610df5569209e4b4997cb2dbf3b94cdc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
nodeType: 3
|
||||
body: {fileID: 5707703654405666688}
|
||||
interaction: {fileID: 0}
|
||||
segmentLengthToNext: 0.5
|
||||
fixedVirtualNodesToNext: 2
|
||||
runtimeVirtualNode: 0
|
||||
runtimeChainIndex: -1
|
||||
drawDebugGizmo: 1
|
||||
debugGizmoRadius: 0.03
|
||||
logicalNodeColor: {r: 0.2, g: 0.9, b: 0.2, a: 1}
|
||||
virtualNodeColor: {r: 1, g: 0.6, b: 0.1, a: 1}
|
||||
features: []
|
||||
motionFeatures: []
|
||||
activeMotionFeature: {fileID: 0}
|
||||
--- !u!65 &250386986656750139
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5077741257619886775}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.02, y: 0.02, z: 0.02}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &6225447558892123241
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5077741257619886775}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1de1bec90e454664a860c5248170ff95, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.JointPinchController
|
||||
moveSpeed: 5
|
||||
snapDistance: 0.1
|
||||
--- !u!1 &5252216124238432432
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3116177874895914436}
|
||||
- component: {fileID: 1033618195002336566}
|
||||
- component: {fileID: 4152162740525283091}
|
||||
- component: {fileID: 2513762410452133691}
|
||||
- component: {fileID: 3049258369283796050}
|
||||
m_Layer: 15
|
||||
m_Name: Bobber
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3116177874895914436
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5252216124238432432}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 98221710317492190}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &1033618195002336566
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5252216124238432432}
|
||||
serializedVersion: 5
|
||||
m_Mass: 1
|
||||
m_LinearDamping: 1
|
||||
m_AngularDamping: 0.05
|
||||
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||
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: 0
|
||||
m_ImplicitTensor: 0
|
||||
m_UseGravity: 1
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!114 &4152162740525283091
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5252216124238432432}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 610df5569209e4b4997cb2dbf3b94cdc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
nodeType: 1
|
||||
body: {fileID: 1033618195002336566}
|
||||
interaction: {fileID: 0}
|
||||
segmentLengthToNext: 0.5
|
||||
fixedVirtualNodesToNext: 2
|
||||
runtimeVirtualNode: 0
|
||||
runtimeChainIndex: -1
|
||||
drawDebugGizmo: 1
|
||||
debugGizmoRadius: 0.03
|
||||
logicalNodeColor: {r: 0.2, g: 0.9, b: 0.2, a: 1}
|
||||
virtualNodeColor: {r: 1, g: 0.6, b: 0.1, a: 1}
|
||||
features: []
|
||||
motionFeatures: []
|
||||
activeMotionFeature: {fileID: 0}
|
||||
--- !u!114 &2513762410452133691
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5252216124238432432}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: ca4d5d54d89446b0a10b7ce521fd7d9e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingBobberFeature
|
||||
priorityOffset: 0
|
||||
waterLevel: 0
|
||||
enterWaterDepth: 0.002
|
||||
exitWaterDepth: -0.01
|
||||
floatHeight: 0.08
|
||||
bottomOffsetLocalY: 0
|
||||
ySmoothTime: 0.08
|
||||
maxYSpeed: 2
|
||||
yDeadZone: 0.0005
|
||||
neutralBottomWeight: 1
|
||||
currentBottomWeight: 1
|
||||
baseDraftDepth: 0.02
|
||||
draftDepthPerWeight: 0.01
|
||||
minDraftDepth: 0.005
|
||||
maxDraftDepth: 0.08
|
||||
draftSmoothTime: 0.18
|
||||
biteSmoothTime: 0.03
|
||||
tapAmplitude: 0.008
|
||||
tapDuration: 0.18
|
||||
slowSinkAmplitude: 0.025
|
||||
slowSinkDuration: 1.2
|
||||
liftAmplitude: 0.015
|
||||
liftDuration: 1.2
|
||||
blackDriftAmplitude: 0.06
|
||||
blackDriftDuration: 0.8
|
||||
enableDebugInput: 1
|
||||
stopBiteKey: 114
|
||||
tapKey: 116
|
||||
slowSinkKey: 103
|
||||
liftKey: 104
|
||||
blackDriftKey: 98
|
||||
lyingWeightThreshold: 0.4
|
||||
tiltedWeightThreshold: 0.8
|
||||
uprightWeightThreshold: 1.2
|
||||
lyingAngle: 88
|
||||
tiltedAngle: 42
|
||||
uprightAngle: 0
|
||||
tiltAxis: 0
|
||||
invertTiltDirection: 0
|
||||
rotationLerpSpeed: 8
|
||||
waterAngularDamping: 999
|
||||
--- !u!65 &3049258369283796050
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5252216124238432432}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.02, y: 0.02, z: 0.02}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &5438655829551842420
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 98221710317492190}
|
||||
- component: {fileID: 913314649585263376}
|
||||
- component: {fileID: 6821754774284524478}
|
||||
- component: {fileID: 1999186176030474616}
|
||||
m_Layer: 0
|
||||
m_Name: FishingLine11
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &98221710317492190
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5438655829551842420}
|
||||
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: 6213026895670800501}
|
||||
- {fileID: 3116177874895914436}
|
||||
- {fileID: 7385546574667729905}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &913314649585263376
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5438655829551842420}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dcd0fd8d96f994444b2d8663af6b915d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineSolver
|
||||
ConfigId: 0
|
||||
LineType: 0
|
||||
PinchController: {fileID: 6225447558892123241}
|
||||
anchorTransform: {fileID: 0}
|
||||
logicalNodes:
|
||||
- {fileID: 5572865435543895569}
|
||||
- {fileID: 4152162740525283091}
|
||||
- {fileID: 3979683508768218053}
|
||||
lineRenderer: {fileID: 1999186176030474616}
|
||||
firstSegmentLength: 1.2
|
||||
firstSegmentStep: 0.1
|
||||
jointSolverIterations: 12
|
||||
jointProjectionDistance: 0.02
|
||||
jointProjectionAngle: 1
|
||||
lengthLimitTolerance: 0.01
|
||||
breakStretchThreshold: 0.05
|
||||
breakLimitDuration: 0.15
|
||||
autoBuildOnStart: 1
|
||||
--- !u!120 &6821754774284524478
|
||||
LineRenderer:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5438655829551842420}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 0
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_Positions:
|
||||
- {x: 0, y: 0, z: 0}
|
||||
- {x: 0, y: 1, z: 0}
|
||||
m_Parameters:
|
||||
serializedVersion: 3
|
||||
widthMultiplier: 1
|
||||
widthCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0.001
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
colorGradient:
|
||||
serializedVersion: 2
|
||||
key0: {r: 1, g: 1, b: 1, a: 1}
|
||||
key1: {r: 1, g: 1, b: 1, a: 1}
|
||||
key2: {r: 0, g: 0, b: 0, a: 0}
|
||||
key3: {r: 0, g: 0, b: 0, a: 0}
|
||||
key4: {r: 0, g: 0, b: 0, a: 0}
|
||||
key5: {r: 0, g: 0, b: 0, a: 0}
|
||||
key6: {r: 0, g: 0, b: 0, a: 0}
|
||||
key7: {r: 0, g: 0, b: 0, a: 0}
|
||||
ctime0: 0
|
||||
ctime1: 65535
|
||||
ctime2: 0
|
||||
ctime3: 0
|
||||
ctime4: 0
|
||||
ctime5: 0
|
||||
ctime6: 0
|
||||
ctime7: 0
|
||||
atime0: 0
|
||||
atime1: 65535
|
||||
atime2: 0
|
||||
atime3: 0
|
||||
atime4: 0
|
||||
atime5: 0
|
||||
atime6: 0
|
||||
atime7: 0
|
||||
m_Mode: 0
|
||||
m_ColorSpace: -1
|
||||
m_NumColorKeys: 2
|
||||
m_NumAlphaKeys: 2
|
||||
numCornerVertices: 0
|
||||
numCapVertices: 0
|
||||
alignment: 0
|
||||
textureMode: 0
|
||||
textureScale: {x: 1, y: 1}
|
||||
shadowBias: 0.5
|
||||
generateLightingData: 0
|
||||
m_UseWorldSpace: 1
|
||||
m_Loop: 0
|
||||
m_ApplyActiveColorSpace: 1
|
||||
--- !u!114 &1999186176030474616
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5438655829551842420}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 827786ffede4e7b4781c522e8a4ba9d0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineRenderer
|
||||
solver: {fileID: 913314649585263376}
|
||||
lineRenderer: {fileID: 6821754774284524478}
|
||||
solverIterations: 8
|
||||
damping: 0.98
|
||||
gravityScale: 1
|
||||
simulationStep: 0.0166667
|
||||
maxDeltaTime: 0.0333333
|
||||
constrainToWaterSurface: 1
|
||||
waterSurfaceTransform: {fileID: 0}
|
||||
waterSurfaceHeight: 0
|
||||
ignoreHeadNodeCount: 1
|
||||
ignoreTailNodeCount: 1
|
||||
waterSurfaceFollowSpeed: 12
|
||||
maxSubStepsPerFrame: 2
|
||||
sleepVelocityThreshold: 0.001
|
||||
sleepDistanceThreshold: 0.002
|
||||
stableFramesBeforeSleep: 4
|
||||
wakeDistanceThreshold: 0.001
|
||||
smoothCorners: 1
|
||||
minCornerAngle: 12
|
||||
maxCornerSmoothDistance: 0.03
|
||||
cornerSmoothSubdivisions: 3
|
||||
drawDebugSamples: 0
|
||||
debugLogicalSampleColor: {r: 0, g: 1, b: 1, a: 1}
|
||||
debugVirtualSampleColor: {r: 1, g: 0.55, b: 0.15, a: 1}
|
||||
debugLogicalSampleRadius: 0.018
|
||||
debugVirtualSampleRadius: 0.012
|
||||
@@ -1,6 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1035052809208993
|
||||
--- !u!1 &1386063717907585334
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@@ -8,290 +8,56 @@ GameObject:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4026445325167852}
|
||||
- component: {fileID: 54679398375713381}
|
||||
- component: {fileID: 153611279189314279}
|
||||
- component: {fileID: 135844594273256032}
|
||||
- component: {fileID: 8644988012983742275}
|
||||
- component: {fileID: 2475726686148443307}
|
||||
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 &8644988012983742275
|
||||
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: 610df5569209e4b4997cb2dbf3b94cdc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
nodeType: 3
|
||||
body: {fileID: 54679398375713381}
|
||||
interaction: {fileID: 0}
|
||||
segmentLengthToNext: 0.5
|
||||
runtimeChainIndex: -1
|
||||
features: []
|
||||
motionFeatures: []
|
||||
activeMotionFeature: {fileID: 0}
|
||||
--- !u!114 &2475726686148443307
|
||||
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: 1de1bec90e454664a860c5248170ff95, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.JointPinchController
|
||||
moveSpeed: 5
|
||||
snapDistance: 0.1
|
||||
--- !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: 7305019728002912084}
|
||||
- component: {fileID: 5599783878866626034}
|
||||
- component: {fileID: 4162208118158024875}
|
||||
- component: {fileID: 6741752443570310990}
|
||||
m_Layer: 0
|
||||
m_Name: FishingLine1
|
||||
m_Name: Line1
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4283454774123242
|
||||
--- !u!4 &4162208118158024875
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1387836627839849}
|
||||
m_GameObject: {fileID: 1386063717907585334}
|
||||
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: 9080725476307806222}
|
||||
- {fileID: 4530253318796540}
|
||||
- {fileID: 4026445325167852}
|
||||
- {fileID: 1479551252035771110}
|
||||
- {fileID: 153991853389016720}
|
||||
- {fileID: 6385925521264460254}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &7305019728002912084
|
||||
--- !u!114 &6741752443570310990
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1387836627839849}
|
||||
m_GameObject: {fileID: 1386063717907585334}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dcd0fd8d96f994444b2d8663af6b915d, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: 78dc478e56ff48849761861244c93535, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineSolver
|
||||
ConfigId: 0
|
||||
LineType: 0
|
||||
anchorTransform: {fileID: 0}
|
||||
logicalNodes:
|
||||
- {fileID: 1320258666242339620}
|
||||
- {fileID: 6516239920710810677}
|
||||
- {fileID: 8644988012983742275}
|
||||
- {fileID: 9075018646815510674}
|
||||
- {fileID: 3453378298765533283}
|
||||
- {fileID: 7410869349490881487}
|
||||
PinchController: {fileID: 0}
|
||||
lengthLimitTolerance: 0.01
|
||||
breakStretchThreshold: 0.05
|
||||
--- !u!114 &5599783878866626034
|
||||
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: 827786ffede4e7b4781c522e8a4ba9d0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineRenderer
|
||||
solver: {fileID: 7305019728002912084}
|
||||
--- !u!1 &1858052053854210
|
||||
--- !u!1 &2899898627497558851
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@@ -299,39 +65,39 @@ GameObject:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4530253318796540}
|
||||
- component: {fileID: 54298866000586118}
|
||||
- component: {fileID: 153691655494134957}
|
||||
- component: {fileID: 6516239920710810677}
|
||||
- component: {fileID: 153991853389016720}
|
||||
- component: {fileID: 828578718743757123}
|
||||
- component: {fileID: 9053429622791349644}
|
||||
- component: {fileID: 3453378298765533283}
|
||||
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
|
||||
m_IsActive: 0
|
||||
--- !u!4 &153991853389016720
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858052053854210}
|
||||
m_GameObject: {fileID: 2899898627497558851}
|
||||
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_Father: {fileID: 4162208118158024875}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &54298866000586118
|
||||
--- !u!54 &828578718743757123
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858052053854210}
|
||||
m_GameObject: {fileID: 2899898627497558851}
|
||||
serializedVersion: 5
|
||||
m_Mass: 0.1
|
||||
m_LinearDamping: 1
|
||||
@@ -352,15 +118,15 @@ Rigidbody:
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 2
|
||||
--- !u!153 &153691655494134957
|
||||
--- !u!153 &9053429622791349644
|
||||
ConfigurableJoint:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858052053854210}
|
||||
m_GameObject: {fileID: 2899898627497558851}
|
||||
serializedVersion: 4
|
||||
m_ConnectedBody: {fileID: 9208109815165330647}
|
||||
m_ConnectedBody: {fileID: 2686136634991136867}
|
||||
m_ConnectedArticulationBody: {fileID: 0}
|
||||
m_Anchor: {x: 0, y: -0.01, z: 0}
|
||||
m_Axis: {x: 0, y: 0, z: 0}
|
||||
@@ -454,27 +220,30 @@ ConfigurableJoint:
|
||||
m_EnablePreprocessing: 0
|
||||
m_MassScale: 1
|
||||
m_ConnectedMassScale: 1
|
||||
--- !u!114 &6516239920710810677
|
||||
--- !u!114 &3453378298765533283
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858052053854210}
|
||||
m_GameObject: {fileID: 2899898627497558851}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 610df5569209e4b4997cb2dbf3b94cdc, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: f89affce787d4a1cbcd68bed409183d7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
_solver: {fileID: 0}
|
||||
nodeType: 1
|
||||
body: {fileID: 54298866000586118}
|
||||
body: {fileID: 828578718743757123}
|
||||
Rope: {fileID: 0}
|
||||
interaction: {fileID: 0}
|
||||
_joint: {fileID: 9053429622791349644}
|
||||
segmentLengthToNext: 0.5
|
||||
runtimeChainIndex: -1
|
||||
features: []
|
||||
motionFeatures: []
|
||||
activeMotionFeature: {fileID: 0}
|
||||
--- !u!1 &2542822653532585360
|
||||
--- !u!1 &6377338098506485345
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@@ -482,38 +251,246 @@ GameObject:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 9080725476307806222}
|
||||
- component: {fileID: 9208109815165330647}
|
||||
- component: {fileID: 1320258666242339620}
|
||||
- component: {fileID: 6385925521264460254}
|
||||
- component: {fileID: 3393178238064969316}
|
||||
- component: {fileID: 1271283185862622601}
|
||||
- component: {fileID: 8513982619376093011}
|
||||
- component: {fileID: 7410869349490881487}
|
||||
m_Layer: 15
|
||||
m_Name: Lure
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
--- !u!4 &6385925521264460254
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6377338098506485345}
|
||||
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: 4162208118158024875}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &3393178238064969316
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6377338098506485345}
|
||||
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: 1
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 2
|
||||
--- !u!153 &1271283185862622601
|
||||
ConfigurableJoint:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6377338098506485345}
|
||||
serializedVersion: 4
|
||||
m_ConnectedBody: {fileID: 828578718743757123}
|
||||
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 &8513982619376093011
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6377338098506485345}
|
||||
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 &7410869349490881487
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6377338098506485345}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f89affce787d4a1cbcd68bed409183d7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
_solver: {fileID: 0}
|
||||
nodeType: 3
|
||||
body: {fileID: 3393178238064969316}
|
||||
Rope: {fileID: 0}
|
||||
interaction: {fileID: 0}
|
||||
_joint: {fileID: 1271283185862622601}
|
||||
segmentLengthToNext: 0.5
|
||||
runtimeChainIndex: -1
|
||||
features: []
|
||||
motionFeatures: []
|
||||
activeMotionFeature: {fileID: 0}
|
||||
--- !u!1 &7697635668067303442
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1479551252035771110}
|
||||
- component: {fileID: 2686136634991136867}
|
||||
- component: {fileID: 9075018646815510674}
|
||||
m_Layer: 0
|
||||
m_Name: Start
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &9080725476307806222
|
||||
m_IsActive: 0
|
||||
--- !u!4 &1479551252035771110
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2542822653532585360}
|
||||
m_GameObject: {fileID: 7697635668067303442}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 4283454774123242}
|
||||
m_Father: {fileID: 4162208118158024875}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &9208109815165330647
|
||||
--- !u!54 &2686136634991136867
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2542822653532585360}
|
||||
m_GameObject: {fileID: 7697635668067303442}
|
||||
serializedVersion: 5
|
||||
m_Mass: 1
|
||||
m_LinearDamping: 0
|
||||
@@ -527,28 +504,31 @@ Rigidbody:
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ImplicitCom: 1
|
||||
m_ImplicitTensor: 1
|
||||
m_ImplicitCom: 0
|
||||
m_ImplicitTensor: 0
|
||||
m_UseGravity: 0
|
||||
m_IsKinematic: 1
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!114 &1320258666242339620
|
||||
--- !u!114 &9075018646815510674
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2542822653532585360}
|
||||
m_GameObject: {fileID: 7697635668067303442}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 610df5569209e4b4997cb2dbf3b94cdc, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: f89affce787d4a1cbcd68bed409183d7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineNode
|
||||
_solver: {fileID: 0}
|
||||
nodeType: 0
|
||||
body: {fileID: 9208109815165330647}
|
||||
body: {fileID: 2686136634991136867}
|
||||
Rope: {fileID: 0}
|
||||
interaction: {fileID: 0}
|
||||
_joint: {fileID: 0}
|
||||
segmentLengthToNext: 0.5
|
||||
runtimeChainIndex: -1
|
||||
features: []
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 488209094f0c45a41aa6801dd86e6768
|
||||
guid: ea6901d8aa7c41d41987d8ca92b02f6d
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
@@ -675,7 +675,7 @@ MonoBehaviour:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858052053854210}
|
||||
m_Enabled: 1
|
||||
m_Enabled: 0
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 2dedfafdc2d747d98c682cde3e28e513, type: 3}
|
||||
m_Name:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1630,8 +1630,8 @@ Camera:
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.01
|
||||
far clip plane: 5000
|
||||
near clip plane: 0.1
|
||||
far clip plane: 3000
|
||||
field of view: 60.000004
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
// using UnityEditor;
|
||||
// using UnityEngine;
|
||||
//
|
||||
// [CustomEditor(typeof(Rope))]
|
||||
// public class RopeFishLineEditor : Editor
|
||||
// {
|
||||
// private Rope _target;
|
||||
//
|
||||
// void OnEnable()
|
||||
// {
|
||||
// _target = target as Rope;
|
||||
// // lookAtPoint = serializedObject.FindProperty("lookAtPoint");
|
||||
// }
|
||||
//
|
||||
// public override void OnInspectorGUI()
|
||||
// {
|
||||
// base.OnInspectorGUI();
|
||||
//
|
||||
//
|
||||
// if (GUILayout.Button("打印总长度"))
|
||||
// {
|
||||
// _target.DebugLength();
|
||||
// // Debug.Log($"总长度={_target.GetCurrentLength()} 目标长度={_target.GetTargetLength()} smoot={_target.GetLengthSmoothVel()} relLen={_target.GetLengthByPoints()} PolylineLength={_target.GetPhysicsPolylineLength()}");
|
||||
// }
|
||||
// // serializedObject.Update();
|
||||
// // EditorGUILayout.PropertyField(lookAtPoint);
|
||||
// // serializedObject.ApplyModifiedProperties();
|
||||
// }
|
||||
// }
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(Rope))]
|
||||
public class RopeFishLineEditor : Editor
|
||||
{
|
||||
private Rope _target;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_target = target as Rope;
|
||||
// lookAtPoint = serializedObject.FindProperty("lookAtPoint");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
|
||||
if (GUILayout.Button("打印总长度"))
|
||||
{
|
||||
_target.DebugLength();
|
||||
// Debug.Log($"总长度={_target.GetCurrentLength()} 目标长度={_target.GetTargetLength()} smoot={_target.GetLengthSmoothVel()} relLen={_target.GetLengthByPoints()} PolylineLength={_target.GetPhysicsPolylineLength()}");
|
||||
}
|
||||
// serializedObject.Update();
|
||||
// EditorGUILayout.PropertyField(lookAtPoint);
|
||||
// serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using NBF.Fishing2;
|
||||
using RootMotion.FinalIK;
|
||||
using Log = NBC.Log;
|
||||
|
||||
namespace NBF
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
// using System;
|
||||
// using UnityEngine;
|
||||
//
|
||||
// namespace NBF
|
||||
// {
|
||||
// public class LureController : MonoBehaviour
|
||||
// {
|
||||
// [SerializeField] private Rigidbody rBody;
|
||||
// [SerializeField] private ConfigurableJoint joint;
|
||||
// public Rigidbody RBody => rBody;
|
||||
//
|
||||
// public ConfigurableJoint Joint => joint;
|
||||
//
|
||||
// private void Start()
|
||||
// {
|
||||
// RBody.detectCollisions = true;
|
||||
// RBody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
|
||||
// RBody.interpolation = RigidbodyInterpolation.Interpolate;
|
||||
// }
|
||||
//
|
||||
// public void SetJoint(Rigidbody rb)
|
||||
// {
|
||||
// joint.connectedBody = rb;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public void EnableCollision(bool enable)
|
||||
// {
|
||||
// if (rBody == null)
|
||||
// {
|
||||
// rBody = GetComponent<Rigidbody>();
|
||||
// }
|
||||
//
|
||||
// // rBody.detectCollisions = enable;
|
||||
// }
|
||||
//
|
||||
// public void SetKinematic(bool value)
|
||||
// {
|
||||
// rBody.isKinematic = value;
|
||||
// }
|
||||
//
|
||||
// public void SetJointDistance(float limit)
|
||||
// {
|
||||
// joint.linearLimit = new SoftJointLimit
|
||||
// {
|
||||
// limit = limit
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// private void OnCollisionEnter(Collision other)
|
||||
// {
|
||||
// Debug.Log($"OnCollisionEnter:{other.gameObject.name}");
|
||||
// }
|
||||
// private void OnCollisionExit(Collision other)
|
||||
// {
|
||||
// Debug.Log($"OnCollisionExit:{other.gameObject.name}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public class LureController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Rigidbody rBody;
|
||||
[SerializeField] private ConfigurableJoint joint;
|
||||
public Rigidbody RBody => rBody;
|
||||
|
||||
public ConfigurableJoint Joint => joint;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
RBody.detectCollisions = true;
|
||||
RBody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
|
||||
RBody.interpolation = RigidbodyInterpolation.Interpolate;
|
||||
}
|
||||
|
||||
public void SetJoint(Rigidbody rb)
|
||||
{
|
||||
joint.connectedBody = rb;
|
||||
}
|
||||
|
||||
|
||||
public void EnableCollision(bool enable)
|
||||
{
|
||||
if (rBody == null)
|
||||
{
|
||||
rBody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
// rBody.detectCollisions = enable;
|
||||
}
|
||||
|
||||
public void SetKinematic(bool value)
|
||||
{
|
||||
rBody.isKinematic = value;
|
||||
}
|
||||
|
||||
public void SetJointDistance(float limit)
|
||||
{
|
||||
joint.linearLimit = new SoftJointLimit
|
||||
{
|
||||
limit = limit
|
||||
};
|
||||
}
|
||||
|
||||
private void OnCollisionEnter(Collision other)
|
||||
{
|
||||
Debug.Log($"OnCollisionEnter:{other.gameObject.name}");
|
||||
}
|
||||
private void OnCollisionExit(Collision other)
|
||||
{
|
||||
Debug.Log($"OnCollisionExit:{other.gameObject.name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6901448ac9466974791a863c357f6579
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
guid: 23b031de32454768b4cd922619ef4e8e
|
||||
timeCreated: 1776227094
|
||||
204
Assets/Scripts/Fishing/New/View/FishingLine/FLine.cs
Normal file
204
Assets/Scripts/Fishing/New/View/FishingLine/FLine.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NBC;
|
||||
// using Obi;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
|
||||
public class FLine : FGearBase
|
||||
{
|
||||
public LineType LineType;
|
||||
|
||||
[SerializeField] private bool isLureConnect;
|
||||
|
||||
/// <summary>
|
||||
/// 主线
|
||||
/// </summary>
|
||||
[SerializeField] private Rope fishingRope;
|
||||
|
||||
/// <summary>
|
||||
/// 浮漂和鱼钩线
|
||||
/// </summary>
|
||||
[SerializeField] private Rope bobberRope;
|
||||
|
||||
public LureController Lure;
|
||||
public BobberController Bobber;
|
||||
|
||||
public JointPinchController PinchController;
|
||||
|
||||
|
||||
public float LinelenghtDiferent;
|
||||
|
||||
|
||||
public float Length { get; private set; }
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
var tipRb = Rod.Asset.LineConnectorRigidbody;
|
||||
if (isLureConnect)
|
||||
{
|
||||
Lure.SetJoint(tipRb);
|
||||
Lure.EnableCollision(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
fishingRope.startAnchor = tipRb;
|
||||
Bobber.SetJoint(tipRb);
|
||||
Lure.SetJoint(Bobber.rbody);
|
||||
Lure.gameObject.SetActive(true);
|
||||
Lure.EnableCollision(false);
|
||||
Lure.SetKinematic(false);
|
||||
}
|
||||
|
||||
GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
|
||||
{
|
||||
i.gameObject.SetActive(true);
|
||||
});
|
||||
|
||||
StartCoroutine(LureUseGravity());
|
||||
}
|
||||
|
||||
public void InitTest(Rigidbody tipRb)
|
||||
{
|
||||
if (isLureConnect)
|
||||
{
|
||||
Lure.SetJoint(tipRb);
|
||||
Lure.EnableCollision(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
fishingRope.startAnchor = tipRb;
|
||||
Bobber.SetJoint(tipRb);
|
||||
Lure.SetJoint(Bobber.rbody);
|
||||
Lure.gameObject.SetActive(true);
|
||||
Lure.EnableCollision(false);
|
||||
Lure.SetKinematic(false);
|
||||
}
|
||||
|
||||
GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
|
||||
{
|
||||
i.gameObject.SetActive(true);
|
||||
});
|
||||
|
||||
StartCoroutine(LureUseGravity());
|
||||
}
|
||||
|
||||
private IEnumerator LureUseGravity()
|
||||
{
|
||||
yield return 1;
|
||||
Lure.gameObject.SetActive(false);
|
||||
Lure.gameObject.SetActive(true);
|
||||
yield return 1;
|
||||
Lure.RBody.useGravity = true;
|
||||
}
|
||||
|
||||
public void SetTargetLength(float value)
|
||||
{
|
||||
Log.Error($"SetObiRopeStretch={value}");
|
||||
if (value > 3)
|
||||
{
|
||||
// value -= 0.2f;
|
||||
}
|
||||
|
||||
fishingRope.SetTargetLength(value);
|
||||
}
|
||||
|
||||
public void SetLureLength(float value)
|
||||
{
|
||||
Log.Error($"SetObiRopeStretch={value}");
|
||||
bobberRope.SetTargetLength(value);
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
LinelenghtDiferent = GetLineDistance();
|
||||
|
||||
//非钓鱼状态
|
||||
Rod.PlayerItem.Tension = Mathf.Clamp(LinelenghtDiferent, 0f, 0.05f);
|
||||
}
|
||||
|
||||
#region Tension
|
||||
|
||||
private float GetLineDistance()
|
||||
{
|
||||
if (!Bobber.JointRb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return 0;
|
||||
|
||||
//第一个节点到竿稍的位置-第一段鱼线长度
|
||||
return Vector3.Distance(Bobber.transform.position, Bobber.JointRb.transform.position) -
|
||||
fishingRope.GetCurrentLength();
|
||||
}
|
||||
|
||||
public float GetTension(float weight)
|
||||
{
|
||||
return weight * GetLineDistance();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 极限判定
|
||||
|
||||
[Header("Limit Detection")]
|
||||
[Min(0f)]
|
||||
// 极限判定的长度容差,允许链路在总长或单段长度上存在少量误差。
|
||||
[SerializeField]
|
||||
private float lengthLimitTolerance = 0.01f;
|
||||
|
||||
[Min(0f)]
|
||||
// 达到极限后,只有当前超长值大于该阈值时,才开始进入断线候选计时。
|
||||
[SerializeField]
|
||||
private float breakStretchThreshold = 0.05f;
|
||||
|
||||
/// <summary>
|
||||
/// 当鱼线达到断线条件时发出的一次性消息。
|
||||
/// 外部可订阅该事件,在回调中执行切线、播放表现或状态切换。
|
||||
/// </summary>
|
||||
public event Action<FLine> OnLineBreakRequested;
|
||||
|
||||
/// <summary>
|
||||
/// 当前断线候选状态的累计时间。
|
||||
/// 只有在处于极限状态,且 CurrentStretchLength 大于断线阈值时才会累加;否则重置为 0。
|
||||
/// </summary>
|
||||
public float LimitStateTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前拉力极限百分比。
|
||||
/// 当超长值小于等于 lengthLimitTolerance 时为 0;
|
||||
/// 当超长值大于等于 breakStretchThreshold 时为 100;
|
||||
/// 中间区间按线性比例映射,供 UI 显示使用。
|
||||
/// </summary>
|
||||
public float CurrentBreakStretchPercent => EvaluateBreakStretchPercent(Length);
|
||||
|
||||
|
||||
private float EvaluateBreakStretchPercent(float stretchLength)
|
||||
{
|
||||
if (stretchLength <= lengthLimitTolerance)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
if (stretchLength >= breakStretchThreshold)
|
||||
{
|
||||
return 100f;
|
||||
}
|
||||
|
||||
if (breakStretchThreshold <= lengthLimitTolerance)
|
||||
{
|
||||
return 100f;
|
||||
}
|
||||
|
||||
return Mathf.InverseLerp(lengthLimitTolerance, breakStretchThreshold, stretchLength) * 100f;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ff164cb3132445289d22c7b3a0f4fab
|
||||
timeCreated: 1775957622
|
||||
guid: aecb364a5aa3486d9e9c4f37ba801403
|
||||
timeCreated: 1776227164
|
||||
@@ -1,685 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca4d5d54d89446b0a10b7ce521fd7d9e
|
||||
timeCreated: 1775958532
|
||||
@@ -1,44 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ebfa4366b504ba0a3f398eded17df31
|
||||
timeCreated: 1775957743
|
||||
@@ -1,944 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public interface IWaterSurfaceProvider
|
||||
{
|
||||
float GetWaterHeight(Vector3 worldPos);
|
||||
Vector3 GetWaterNormal(Vector3 worldPos);
|
||||
}
|
||||
|
||||
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 IWaterSurfaceProvider _waterProvider;
|
||||
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>();
|
||||
}
|
||||
|
||||
if (_waterProvider == null && waterProviderBehaviour != null)
|
||||
{
|
||||
_waterProvider = waterProviderBehaviour as IWaterSurfaceProvider;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (_waterProvider != null)
|
||||
{
|
||||
return _waterProvider.GetWaterHeight(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
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40a38940e81046e2854add979cedbef9
|
||||
timeCreated: 1775958531
|
||||
@@ -12,12 +12,12 @@ namespace NBF
|
||||
/// <summary>
|
||||
/// 当前功能组件所属的鱼线求解器。
|
||||
/// </summary>
|
||||
public FishingLineSolver Solver { get; private set; }
|
||||
public FLine Solver { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 将当前功能组件绑定到指定节点和求解器。
|
||||
/// </summary>
|
||||
public void Bind(FishingLineNode node, FishingLineSolver solver)
|
||||
public void Bind(FishingLineNode node, FLine solver)
|
||||
{
|
||||
Node = node;
|
||||
Solver = solver;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7ea70945db841deb0ee8df85f0e15ec
|
||||
timeCreated: 1775957663
|
||||
guid: ad2d8ec3c7054440819bc7a15991f724
|
||||
timeCreated: 1776227197
|
||||
@@ -1,3 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e75217306a64f8f868f5f9127772de2
|
||||
timeCreated: 1775957711
|
||||
guid: aabd7c367ac74642942c4a4499e35281
|
||||
timeCreated: 1776227237
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -14,12 +14,13 @@ namespace NBF
|
||||
Tail
|
||||
}
|
||||
|
||||
private FishingLineSolver _solver;
|
||||
[SerializeField] private FLine _solver;
|
||||
|
||||
[Header("Node")] [SerializeField] private NodeType nodeType = NodeType.Tail;
|
||||
[SerializeField] public Rigidbody body;
|
||||
public Rope Rope;
|
||||
[SerializeField] private MonoBehaviour interaction;
|
||||
private ConfigurableJoint _joint;
|
||||
[SerializeField] private ConfigurableJoint _joint;
|
||||
|
||||
[Header("Segment To Next Logical Node")] [Min(0f)] [SerializeField]
|
||||
private float segmentLengthToNext = 0.5f;
|
||||
@@ -43,6 +44,18 @@ namespace NBF
|
||||
set => nodeType = value;
|
||||
}
|
||||
|
||||
public float Lenght { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 真实实际长度
|
||||
/// </summary>
|
||||
public float RealLength { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。
|
||||
/// </summary>
|
||||
public float StretchLength { get; private set; }
|
||||
|
||||
public Rigidbody Body => body;
|
||||
|
||||
public MonoBehaviour Interaction => interaction;
|
||||
@@ -60,8 +73,8 @@ namespace NBF
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_solver = GetComponentInParent<FishingLineSolver>();
|
||||
_joint = GetComponent<ConfigurableJoint>();
|
||||
if (!_solver) _solver = GetComponentInParent<FLine>();
|
||||
if (!_joint) _joint = GetComponent<ConfigurableJoint>();
|
||||
EnsureFeatureCache();
|
||||
}
|
||||
|
||||
@@ -74,6 +87,7 @@ namespace NBF
|
||||
{
|
||||
EnsureFeatureCache();
|
||||
UpdateMotionControl(Time.fixedDeltaTime);
|
||||
UpdateLenght();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
@@ -84,8 +98,43 @@ namespace NBF
|
||||
}
|
||||
|
||||
segmentLengthToNext = Mathf.Max(0f, segmentLengthToNext);
|
||||
|
||||
}
|
||||
|
||||
private void UpdateLenght()
|
||||
{
|
||||
//更新长度
|
||||
Lenght = 0;
|
||||
RealLength = 0;
|
||||
StretchLength = 0;
|
||||
if (_joint)
|
||||
{
|
||||
Lenght = _joint.linearLimit.limit;
|
||||
if (_joint && _joint.connectedBody)
|
||||
{
|
||||
RealLength = Vector3.Distance(transform.position, _joint.connectedBody.transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
if (RealLength > Lenght)
|
||||
{
|
||||
StretchLength = RealLength - Lenght;
|
||||
}
|
||||
}
|
||||
|
||||
#region Line
|
||||
|
||||
public void SetLenght(float lenght)
|
||||
{
|
||||
if (!_joint) return;
|
||||
if (!Mathf.Approximately(lenght, _joint.linearLimit.limit))
|
||||
{
|
||||
_joint.linearLimit = new SoftJointLimit() { limit = lenght };
|
||||
Rope.SetTargetLength(lenght - 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Feature
|
||||
|
||||
@@ -118,7 +167,7 @@ namespace NBF
|
||||
/// <summary>
|
||||
/// 刷新并重新绑定当前节点上的功能组件。
|
||||
/// </summary>
|
||||
public void BindFeatures(FishingLineSolver solver)
|
||||
public void BindFeatures(FLine solver)
|
||||
{
|
||||
EnsureFeatureCache();
|
||||
foreach (var t in features)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 610df5569209e4b4997cb2dbf3b94cdc
|
||||
guid: f89affce787d4a1cbcd68bed409183d7
|
||||
timeCreated: 1776227097
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -25,10 +26,34 @@ namespace NBF
|
||||
|
||||
public JointPinchController PinchController;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
// var tipRb = Rod.Asset.LineConnectorRigidbody;
|
||||
// anchorTransform = tipRb.transform;
|
||||
//
|
||||
// GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
|
||||
// {
|
||||
// i.gameObject.SetActive(true);
|
||||
// });
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitRenderer();
|
||||
GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
|
||||
{
|
||||
i.gameObject.SetActive(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
UpdateAnchorNode();
|
||||
CalculateLineRealLength(Time.fixedDeltaTime);
|
||||
UpdateBreakCountdown(Time.fixedDeltaTime);
|
||||
}
|
||||
|
||||
#region Start Node
|
||||
@@ -77,23 +102,18 @@ namespace NBF
|
||||
|
||||
#region Line
|
||||
|
||||
/// <summary>
|
||||
/// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。
|
||||
/// </summary>
|
||||
public float CurrentStretchLength { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定逻辑段的配置长度。
|
||||
/// segmentIndex 为 0 时表示第一段;大于 0 时表示对应逻辑节点到下一个逻辑节点的线长。
|
||||
/// </summary>
|
||||
public void SetLenght(float length, int segmentIndex = 0)
|
||||
public void SetLenght(float length, int index = 0)
|
||||
{
|
||||
ConfigureStartNode();
|
||||
CalculateLineRealLength(0f);
|
||||
}
|
||||
|
||||
private void CalculateLineRealLength(float deltaTime)
|
||||
{
|
||||
var node = logicalNodes[index + 1];
|
||||
if (node != null)
|
||||
{
|
||||
node.SetLenght(length);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -196,7 +216,12 @@ namespace NBF
|
||||
|
||||
#region 极限判定
|
||||
|
||||
/// <summary>
|
||||
/// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。
|
||||
/// </summary>
|
||||
[Header("Limit Detection")]
|
||||
public float CurrentStretchLength { get; private set; }
|
||||
|
||||
[Min(0f)]
|
||||
// 极限判定的长度容差,允许链路在总长或单段长度上存在少量误差。
|
||||
[SerializeField]
|
||||
@@ -205,7 +230,12 @@ namespace NBF
|
||||
[Min(0f)]
|
||||
// 达到极限后,只有当前超长值大于该阈值时,才开始进入断线候选计时。
|
||||
[SerializeField]
|
||||
private float breakStretchThreshold = 0.05f;
|
||||
private float breakStretchThreshold = 0.08f;
|
||||
|
||||
[Min(0f)]
|
||||
// 断线候选状态允许持续的最大时间;超过后会发出一次断线消息。
|
||||
[SerializeField]
|
||||
private float breakLimitDuration = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// 当鱼线达到断线条件时发出的一次性消息。
|
||||
@@ -213,12 +243,24 @@ namespace NBF
|
||||
/// </summary>
|
||||
public event Action<FishingLineSolver> OnLineBreakRequested;
|
||||
|
||||
/// <summary>
|
||||
/// 当前是否处于极限状态。
|
||||
/// 只要整链超出总长度容差,或任一逻辑段超出单段容差,即认为到达极限。
|
||||
/// </summary>
|
||||
public bool IsAtLimit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前断线候选状态的累计时间。
|
||||
/// 只有在处于极限状态,且 CurrentStretchLength 大于断线阈值时才会累加;否则重置为 0。
|
||||
/// </summary>
|
||||
public float LimitStateTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前极限断线消息是否已经发出过。
|
||||
/// 在退出断线候选状态前只会发一次,避免重复通知。
|
||||
/// </summary>
|
||||
public bool HasBreakNotificationSent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前拉力极限百分比。
|
||||
/// 当超长值小于等于 lengthLimitTolerance 时为 0;
|
||||
@@ -227,6 +269,10 @@ namespace NBF
|
||||
/// </summary>
|
||||
public float CurrentBreakStretchPercent => EvaluateBreakStretchPercent(CurrentStretchLength);
|
||||
|
||||
/// <summary>
|
||||
/// 当前是否正在进行断线候选计时。
|
||||
/// </summary>
|
||||
public bool IsBreakCountdownActive => IsAtLimit && CurrentStretchLength > breakStretchThreshold;
|
||||
|
||||
private float EvaluateBreakStretchPercent(float stretchLength)
|
||||
{
|
||||
@@ -248,12 +294,92 @@ namespace NBF
|
||||
return Mathf.InverseLerp(lengthLimitTolerance, breakStretchThreshold, stretchLength) * 100f;
|
||||
}
|
||||
|
||||
private void SetLimitState(bool isAtLimit)
|
||||
{
|
||||
IsAtLimit = isAtLimit;
|
||||
}
|
||||
|
||||
private void UpdateBreakCountdown(float deltaTime)
|
||||
{
|
||||
if (logicalNodes == null || logicalNodes.Length == 0)
|
||||
{
|
||||
SetLimitState(false);
|
||||
ResetLimitState();
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentStretchLength = 0;
|
||||
//计算长度
|
||||
foreach (var node in logicalNodes)
|
||||
{
|
||||
CurrentStretchLength += node.StretchLength;
|
||||
}
|
||||
|
||||
SetLimitState(CurrentStretchLength > lengthLimitTolerance);
|
||||
|
||||
if (!IsBreakCountdownActive)
|
||||
{
|
||||
LimitStateTime = 0f;
|
||||
HasBreakNotificationSent = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LimitStateTime += Mathf.Max(0f, deltaTime);
|
||||
if (HasBreakNotificationSent || LimitStateTime < breakLimitDuration)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HasBreakNotificationSent = true;
|
||||
NotifyLineBreakRequested();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发出鱼线达到断线条件的消息。
|
||||
/// 这里预留给外部订阅,当前不在求解器内部直接执行断线逻辑。
|
||||
/// </summary>
|
||||
private void NotifyLineBreakRequested()
|
||||
{
|
||||
OnLineBreakRequested?.Invoke(this);
|
||||
}
|
||||
|
||||
private void ResetLimitState()
|
||||
{
|
||||
CurrentStretchLength = 0f;
|
||||
IsAtLimit = false;
|
||||
LimitStateTime = 0f;
|
||||
HasBreakNotificationSent = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnInit()
|
||||
#region Renderer
|
||||
|
||||
private Transform _ropeRoot;
|
||||
|
||||
private void InitRenderer()
|
||||
{
|
||||
var tipRb = Rod.Asset.LineConnectorRigidbody;
|
||||
anchorTransform = tipRb.transform;
|
||||
var root = new GameObject("RopeRoot");
|
||||
_ropeRoot = root.transform;
|
||||
_ropeRoot.SetParent(transform);
|
||||
CreateRopes();
|
||||
}
|
||||
|
||||
private void CreateRopes()
|
||||
{
|
||||
foreach (var node in LogicalNodes)
|
||||
{
|
||||
if (node.Type == FishingLineNode.NodeType.Start) continue;
|
||||
var ropeObject = new GameObject($"rope_{node.Type}");
|
||||
ropeObject.transform.SetParent(_ropeRoot);
|
||||
var rope = ropeObject.AddComponent<Rope>();
|
||||
node.Rope = rope;
|
||||
// rope.groundMask = LayerMask.GetMask("Terrain");
|
||||
rope.startAnchor = node.Joint.connectedBody;
|
||||
rope.endAnchor = node.body;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcd0fd8d96f994444b2d8663af6b915d
|
||||
guid: 78dc478e56ff48849761861244c93535
|
||||
timeCreated: 1776227360
|
||||
@@ -1,4 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
@@ -37,6 +37,7 @@ namespace NBF
|
||||
targetFirstSegmentLength =
|
||||
Mathf.Clamp(initialFirstSegmentLength, minFirstSegmentLength, maxFirstSegmentLength);
|
||||
solver.SetLenght(targetFirstSegmentLength);
|
||||
solver.SetLenght(0.5f, 1);
|
||||
// solver.BuildLine();
|
||||
|
||||
solver.OnLineBreakRequested += OnLineBreakRequested;
|
||||
@@ -78,9 +79,9 @@ namespace NBF
|
||||
solver.SetLenght(targetFirstSegmentLength);
|
||||
}
|
||||
|
||||
if (solver.CurrentBreakStretchPercent > 0)
|
||||
if (solver.CurrentBreakStretchPercent > 10)
|
||||
{
|
||||
// Debug.LogError(solver.CurrentBreakStretchPercent);
|
||||
Debug.LogError($"当前极限情况,CurrentBreakStretchPercent={solver.CurrentBreakStretchPercent} CurrentStretchLength={solver.CurrentStretchLength} LimitStateTime={solver.LimitStateTime}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77af114bb80f3904a83cdeaacd5af508
|
||||
guid: 5382d66f55f6463cb469c5094b0e7a6b
|
||||
timeCreated: 1776234046
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38f37be41b0a4792b866b9ad9b4d9268
|
||||
timeCreated: 1776093454
|
||||
@@ -1,39 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public class FishingLineRenderer : MonoBehaviour
|
||||
{
|
||||
[Header("References")] [SerializeField]
|
||||
private FishingLineSolver solver;
|
||||
|
||||
private List<FishingNodeRope> _ropes = new List<FishingNodeRope>();
|
||||
|
||||
private Transform _ropeRoot;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
solver = GetComponent<FishingLineSolver>();
|
||||
var ropeRoot = new GameObject("RopeRenderer");
|
||||
ropeRoot.transform.SetParent(transform);
|
||||
_ropeRoot = ropeRoot.transform;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
foreach (var node in solver.LogicalNodes)
|
||||
{
|
||||
if (node.Type == FishingLineNode.NodeType.Start) continue;
|
||||
var ropeObj = new GameObject($"Rope_{node.Type}");
|
||||
ropeObj.transform.SetParent(_ropeRoot);
|
||||
var rope = ropeObj.AddComponent<FishingNodeRope>();
|
||||
rope.startAnchor = node.Joint.connectedBody;
|
||||
rope.endAnchor = node.body;
|
||||
rope.SetLength(0.5f);
|
||||
_ropes.Add(rope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 827786ffede4e7b4781c522e8a4ba9d0
|
||||
@@ -1,402 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
/// <summary>
|
||||
/// 单段鱼线节点模拟(startAnchor -> endAnchor)
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class FishingNodeRope : MonoBehaviour
|
||||
{
|
||||
[Header("Anchors")]
|
||||
public Rigidbody startAnchor;
|
||||
|
||||
public Rigidbody endAnchor;
|
||||
|
||||
[Header("Length")]
|
||||
[SerializeField, Min(0.001f)] private float segmentLength = 0.1f;
|
||||
[SerializeField, Min(0.001f)] private float minLength = 0.02f;
|
||||
[SerializeField] private bool initializeFromAnchorDistance = true;
|
||||
|
||||
[Header("Simulation")]
|
||||
[SerializeField, Range(1, 60)] private int solverIterations = 14;
|
||||
[SerializeField, Range(0f, 1f)] private float stiffness = 0.85f;
|
||||
[SerializeField, Min(0f)] private float gravityScale = 1f;
|
||||
[SerializeField, Range(0f, 1f)] private float velocityDamping = 0.98f;
|
||||
|
||||
[Header("Ground Check")]
|
||||
[SerializeField] private bool constrainToGround = true;
|
||||
[SerializeField, Range(1, 16), Tooltip("每 N 个模拟点做一次地面检测")]
|
||||
private int groundSampleStep = 3;
|
||||
|
||||
[SerializeField] private LayerMask groundMask = ~0;
|
||||
[SerializeField, Min(0f)] private float groundCastHeight = 0.5f;
|
||||
[SerializeField, Min(0.01f)] private float groundCastDistance = 2f;
|
||||
[SerializeField, Min(0f)] private float groundOffset = 0.002f;
|
||||
|
||||
[Header("Bend Balance")]
|
||||
[SerializeField, Range(0, 8)] private int bendIterations = 2;
|
||||
[SerializeField, Range(0f, 1f)] private float bendBalance = 0.35f;
|
||||
|
||||
[Header("Render")]
|
||||
[SerializeField, Min(0.0001f)] private float lineWidth = 0.001f;
|
||||
|
||||
private LineRenderer _lineRenderer;
|
||||
private Vector3[] _pCurr;
|
||||
private Vector3[] _pPrev;
|
||||
private float[] _segmentRestLengths;
|
||||
private int _nodeCount;
|
||||
private bool _initialized;
|
||||
|
||||
public float Length { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_lineRenderer = GetComponent<LineRenderer>();
|
||||
_lineRenderer.startWidth = lineWidth;
|
||||
_lineRenderer.endWidth = lineWidth;
|
||||
_lineRenderer.positionCount = 0;
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
segmentLength = Mathf.Max(0.001f, segmentLength);
|
||||
minLength = Mathf.Max(0.001f, minLength);
|
||||
solverIterations = Mathf.Clamp(solverIterations, 1, 60);
|
||||
stiffness = Mathf.Clamp01(stiffness);
|
||||
velocityDamping = Mathf.Clamp01(velocityDamping);
|
||||
gravityScale = Mathf.Max(0f, gravityScale);
|
||||
groundSampleStep = Mathf.Max(1, groundSampleStep);
|
||||
groundCastHeight = Mathf.Max(0f, groundCastHeight);
|
||||
groundCastDistance = Mathf.Max(0.01f, groundCastDistance);
|
||||
groundOffset = Mathf.Max(0f, groundOffset);
|
||||
bendIterations = Mathf.Clamp(bendIterations, 0, 8);
|
||||
bendBalance = Mathf.Clamp01(bendBalance);
|
||||
lineWidth = Mathf.Max(0.0001f, lineWidth);
|
||||
|
||||
if (_lineRenderer != null)
|
||||
{
|
||||
_lineRenderer.startWidth = lineWidth;
|
||||
_lineRenderer.endWidth = lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!EnsureInitialized() || _nodeCount < 2)
|
||||
return;
|
||||
|
||||
SimulateVerlet();
|
||||
|
||||
for (int it = 0; it < solverIterations; it++)
|
||||
{
|
||||
LockAnchorsHard(Time.fixedDeltaTime);
|
||||
SolveDistanceConstraints(stiffness);
|
||||
SolveBendBalance();
|
||||
}
|
||||
|
||||
// 最后再硬约束一遍,保证每段长度更贴近 rest length。
|
||||
LockAnchorsHard(Time.fixedDeltaTime);
|
||||
SolveDistanceConstraints(1f);
|
||||
|
||||
if (constrainToGround)
|
||||
{
|
||||
ConstrainToGround();
|
||||
LockAnchorsHard(Time.fixedDeltaTime);
|
||||
SolveDistanceConstraints(1f);
|
||||
}
|
||||
|
||||
LockAnchorsHard(Time.fixedDeltaTime);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (_pCurr == null || _nodeCount < 2 || _lineRenderer == null)
|
||||
return;
|
||||
|
||||
_lineRenderer.startWidth = lineWidth;
|
||||
_lineRenderer.endWidth = lineWidth;
|
||||
_lineRenderer.positionCount = _nodeCount;
|
||||
_lineRenderer.SetPositions(_pCurr);
|
||||
}
|
||||
|
||||
public void SetLength(float length)
|
||||
{
|
||||
float target = Mathf.Max(length, minLength);
|
||||
bool firstInit = !_initialized;
|
||||
Length = target;
|
||||
RebuildFromLength(target, keepShapeFromStart: !firstInit);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public void AddLength(float delta)
|
||||
{
|
||||
if (delta <= 0f) return;
|
||||
SetLength(Length + delta);
|
||||
}
|
||||
|
||||
public void ReduceLength(float delta)
|
||||
{
|
||||
if (delta <= 0f) return;
|
||||
SetLength(Length - delta);
|
||||
}
|
||||
|
||||
private bool EnsureInitialized()
|
||||
{
|
||||
if (_initialized)
|
||||
return true;
|
||||
|
||||
if (!startAnchor || !endAnchor)
|
||||
return false;
|
||||
|
||||
float initialLength = initializeFromAnchorDistance
|
||||
? Vector3.Distance(GetStartPos(), GetEndPos())
|
||||
: Mathf.Max(segmentLength, minLength);
|
||||
|
||||
SetLength(initialLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Vector3 GetStartPos() => startAnchor ? startAnchor.position : transform.position;
|
||||
private Vector3 GetEndPos() => endAnchor ? endAnchor.position : transform.position;
|
||||
|
||||
private void RebuildFromLength(float totalLength, bool keepShapeFromStart)
|
||||
{
|
||||
float clampedLength = Mathf.Max(totalLength, minLength);
|
||||
Length = clampedLength;
|
||||
|
||||
int fullSeg = Mathf.FloorToInt(clampedLength / segmentLength);
|
||||
float rem = clampedLength - fullSeg * segmentLength;
|
||||
bool hasRem = rem > 1e-4f;
|
||||
int segmentCount = Mathf.Max(1, fullSeg + (hasRem ? 1 : 0));
|
||||
int desiredNodes = segmentCount + 1;
|
||||
|
||||
float[] newRest = new float[segmentCount];
|
||||
for (int i = 0; i < segmentCount; i++)
|
||||
newRest[i] = segmentLength;
|
||||
if (hasRem)
|
||||
newRest[segmentCount - 1] = rem;
|
||||
|
||||
if (_pCurr == null || _pPrev == null || _nodeCount < 2 || !keepShapeFromStart)
|
||||
{
|
||||
BuildLinearNodes(desiredNodes, newRest);
|
||||
return;
|
||||
}
|
||||
|
||||
int oldNodes = _nodeCount;
|
||||
int oldSegments = oldNodes - 1;
|
||||
int add = Mathf.Max(0, segmentCount - oldSegments);
|
||||
int remove = Mathf.Max(0, oldSegments - segmentCount);
|
||||
|
||||
Vector3[] newCurr = new Vector3[desiredNodes];
|
||||
Vector3[] newPrev = new Vector3[desiredNodes];
|
||||
|
||||
if (add > 0)
|
||||
{
|
||||
Array.Copy(_pCurr, 1, newCurr, 1 + add, oldNodes - 1);
|
||||
Array.Copy(_pPrev, 1, newPrev, 1 + add, oldNodes - 1);
|
||||
|
||||
Vector3 s = GetStartPos();
|
||||
int firstOldIdx = 1 + add;
|
||||
Vector3 dir = GetInitialFillDir(s, firstOldIdx < newCurr.Length ? newCurr[firstOldIdx] : GetEndPos());
|
||||
Vector3 inheritDisp = Vector3.zero;
|
||||
if (firstOldIdx < newCurr.Length)
|
||||
inheritDisp = newCurr[firstOldIdx] - newPrev[firstOldIdx];
|
||||
|
||||
for (int i = 1; i <= add; i++)
|
||||
{
|
||||
Vector3 pos = s + dir * (segmentLength * i);
|
||||
newCurr[i] = pos;
|
||||
newPrev[i] = pos - inheritDisp;
|
||||
}
|
||||
}
|
||||
else if (remove > 0)
|
||||
{
|
||||
int srcStart = 1 + remove;
|
||||
int copyCount = desiredNodes - 1;
|
||||
Array.Copy(_pCurr, srcStart, newCurr, 1, copyCount);
|
||||
Array.Copy(_pPrev, srcStart, newPrev, 1, copyCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(_pCurr, newCurr, desiredNodes);
|
||||
Array.Copy(_pPrev, newPrev, desiredNodes);
|
||||
}
|
||||
|
||||
_pCurr = newCurr;
|
||||
_pPrev = newPrev;
|
||||
_segmentRestLengths = newRest;
|
||||
_nodeCount = desiredNodes;
|
||||
|
||||
LockAnchorsHard(Time.fixedDeltaTime > 0f ? Time.fixedDeltaTime : 0.02f);
|
||||
}
|
||||
|
||||
private void BuildLinearNodes(int desiredNodes, float[] restLengths)
|
||||
{
|
||||
_nodeCount = Mathf.Max(2, desiredNodes);
|
||||
_pCurr = new Vector3[_nodeCount];
|
||||
_pPrev = new Vector3[_nodeCount];
|
||||
_segmentRestLengths = restLengths;
|
||||
|
||||
Vector3 s = GetStartPos();
|
||||
Vector3 e = GetEndPos();
|
||||
Vector3 dir = GetInitialFillDir(s, e);
|
||||
|
||||
_pCurr[0] = s;
|
||||
_pPrev[0] = s;
|
||||
|
||||
float traveled = 0f;
|
||||
for (int i = 1; i < _nodeCount - 1; i++)
|
||||
{
|
||||
traveled += _segmentRestLengths[i - 1];
|
||||
Vector3 pos = s + dir * traveled;
|
||||
_pCurr[i] = pos;
|
||||
_pPrev[i] = pos;
|
||||
}
|
||||
|
||||
_pCurr[_nodeCount - 1] = e;
|
||||
_pPrev[_nodeCount - 1] = e;
|
||||
}
|
||||
|
||||
private Vector3 GetInitialFillDir(Vector3 start, Vector3 toward)
|
||||
{
|
||||
Vector3 d = toward - start;
|
||||
if (d.sqrMagnitude < 1e-8f)
|
||||
return Vector3.down;
|
||||
return d.normalized;
|
||||
}
|
||||
|
||||
private void SimulateVerlet()
|
||||
{
|
||||
float dt = Mathf.Max(Time.fixedDeltaTime, 1e-6f);
|
||||
float dt2 = dt * dt;
|
||||
Vector3 gravity = Physics.gravity * gravityScale;
|
||||
|
||||
int last = _nodeCount - 1;
|
||||
for (int i = 1; i < last; i++)
|
||||
{
|
||||
Vector3 disp = (_pCurr[i] - _pPrev[i]) * velocityDamping;
|
||||
Vector3 next = _pCurr[i] + disp + gravity * dt2;
|
||||
_pPrev[i] = _pCurr[i];
|
||||
_pCurr[i] = next;
|
||||
}
|
||||
}
|
||||
|
||||
private void LockAnchorsHard(float dt)
|
||||
{
|
||||
if (_nodeCount < 2)
|
||||
return;
|
||||
|
||||
Vector3 s = GetStartPos();
|
||||
Vector3 e = GetEndPos();
|
||||
|
||||
_pCurr[0] = s;
|
||||
_pPrev[0] = startAnchor ? s - startAnchor.linearVelocity * dt : s;
|
||||
|
||||
int last = _nodeCount - 1;
|
||||
_pCurr[last] = e;
|
||||
_pPrev[last] = endAnchor ? e - endAnchor.linearVelocity * dt : e;
|
||||
}
|
||||
|
||||
private void SolveDistanceConstraints(float solveStiffness)
|
||||
{
|
||||
int last = _nodeCount - 1;
|
||||
if (last <= 0)
|
||||
return;
|
||||
|
||||
float k = Mathf.Clamp01(solveStiffness);
|
||||
|
||||
SolveDistanceSweep(0, last, 1, last, k);
|
||||
SolveDistanceSweep(last - 1, -1, -1, last, k);
|
||||
}
|
||||
|
||||
private void SolveDistanceSweep(int start, int endExclusive, int step, int last, float k)
|
||||
{
|
||||
for (int i = start; i != endExclusive; i += step)
|
||||
{
|
||||
float rest = _segmentRestLengths[i];
|
||||
Vector3 a = _pCurr[i];
|
||||
Vector3 b = _pCurr[i + 1];
|
||||
|
||||
Vector3 delta = b - a;
|
||||
float sq = delta.sqrMagnitude;
|
||||
if (sq < 1e-12f)
|
||||
continue;
|
||||
|
||||
float dist = Mathf.Sqrt(sq);
|
||||
float diff = (dist - rest) / dist;
|
||||
Vector3 corr = delta * (diff * k);
|
||||
|
||||
bool aLocked = i == 0;
|
||||
bool bLocked = i + 1 == last;
|
||||
|
||||
if (!aLocked && !bLocked)
|
||||
{
|
||||
_pCurr[i] = a + corr * 0.5f;
|
||||
_pCurr[i + 1] = b - corr * 0.5f;
|
||||
}
|
||||
else if (aLocked && !bLocked)
|
||||
{
|
||||
_pCurr[i + 1] = b - corr;
|
||||
}
|
||||
else if (!aLocked)
|
||||
{
|
||||
_pCurr[i] = a + corr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SolveBendBalance()
|
||||
{
|
||||
if (bendIterations <= 0 || bendBalance <= 0f || _nodeCount < 3)
|
||||
return;
|
||||
|
||||
int last = _nodeCount - 1;
|
||||
for (int it = 0; it < bendIterations; it++)
|
||||
{
|
||||
for (int i = 1; i < last; i++)
|
||||
{
|
||||
Vector3 target = (_pCurr[i - 1] + _pCurr[i + 1]) * 0.5f;
|
||||
_pCurr[i] = Vector3.Lerp(_pCurr[i], target, bendBalance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConstrainToGround()
|
||||
{
|
||||
if (groundMask == 0 || _nodeCount < 3)
|
||||
return;
|
||||
|
||||
int last = _nodeCount - 1;
|
||||
int step = Mathf.Max(1, groundSampleStep);
|
||||
|
||||
for (int i = 1; i < last; i += step)
|
||||
{
|
||||
Vector3 p = _pCurr[i];
|
||||
Vector3 origin = p + Vector3.up * groundCastHeight;
|
||||
if (!Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask,
|
||||
QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float minY = hit.point.y + groundOffset;
|
||||
if (p.y < minY)
|
||||
{
|
||||
p.y = minY;
|
||||
_pCurr[i] = p;
|
||||
|
||||
Vector3 prev = _pPrev[i];
|
||||
if (prev.y < minY) prev.y = minY;
|
||||
_pPrev[i] = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53f61ff2ae804a41a3ac35ea7bd00b20
|
||||
timeCreated: 1776157309
|
||||
@@ -14,23 +14,29 @@ public class Rope : MonoBehaviour
|
||||
[Header("Physics (Dynamic Nodes, Fixed Segment Len)")] [SerializeField, Min(0.01f), Tooltip("物理每段固定长度(越小越细致越耗)")]
|
||||
private float physicsSegmentLen = 0.15f;
|
||||
|
||||
[SerializeField, Range(2, 200)] private int minPhysicsNodes = 12;
|
||||
[SerializeField, Range(2, 200)] private int minPhysicsNodes = 2;
|
||||
|
||||
[SerializeField, Range(2, 400), Tooltip("物理节点上限(仅用于性能保护;与“最大长度不限制”不是一回事)")]
|
||||
private int maxPhysicsNodes = 120;
|
||||
private int maxPhysicsNodes = 200;
|
||||
|
||||
[SerializeField] private float gravityStrength = 2.0f;
|
||||
[SerializeField] private float gravityStrength = 6.0f;
|
||||
[SerializeField, Range(0f, 1f)] private float velocityDampen = 0.95f;
|
||||
|
||||
[SerializeField, Range(0.0f, 1.0f), Tooltip("约束修正强度,越大越硬。0.6~0.9 常用")]
|
||||
private float stiffness = 0.8f;
|
||||
|
||||
[SerializeField, Range(1, 80), Tooltip("迭代次数。鱼线 10~30 通常够用")]
|
||||
private int iterations = 20;
|
||||
[SerializeField, Range(1, 80), Tooltip("迭代次数")]
|
||||
private int iterations = 10;
|
||||
|
||||
[SerializeField, Range(0, 16), Tooltip("主求解后追加的硬长度约束次数。只负责把 poly 拉回到 rest total,不改变可变长度逻辑")]
|
||||
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)")]
|
||||
[Tooltip("初始总长度(米)。如果为 0,则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
|
||||
[SerializeField, Min(0f)]
|
||||
@@ -40,7 +46,10 @@ public class Rope : MonoBehaviour
|
||||
private float lengthSmoothTime = 0.15f;
|
||||
|
||||
[Tooltip("当长度在变化时,额外把速度压掉一些(防抖)。0=不额外处理,1=变化时几乎清速度(建议只在收线生效)")] [SerializeField, Range(0f, 1f)]
|
||||
private float lengthChangeVelocityKill = 0.6f;
|
||||
private float lengthChangeVelocityKill = 0.4f;
|
||||
|
||||
[Tooltip("允许的最小松弛余量(避免目标长度刚好等于锚点距离时抖动)")] [SerializeField, Min(0f)]
|
||||
private float minSlack = 0.002f;
|
||||
|
||||
[Header("Head Segment Clamp")] [Tooltip("第一段(起点->第1节点)允许的最小长度,避免收线时第一段被压到0导致数值炸")] [SerializeField, Min(0.0001f)]
|
||||
private float headMinLen = 0.01f;
|
||||
@@ -49,9 +58,9 @@ public class Rope : MonoBehaviour
|
||||
private float nodeHysteresis = 0.05f;
|
||||
|
||||
[Header("Simple Ground/Water Constraint (Cheap)")] [SerializeField]
|
||||
private bool constrainToGround = true;
|
||||
private bool constrainToGround = false;
|
||||
|
||||
[SerializeField] private LayerMask groundMask = ~0;
|
||||
[SerializeField] private LayerMask groundMask = 0;
|
||||
[SerializeField, Min(0f)] private float groundRadius = 0.01f;
|
||||
[SerializeField, Min(0f)] private float groundCastHeight = 1.0f;
|
||||
[SerializeField, Min(0.01f)] private float groundCastDistance = 2.5f;
|
||||
@@ -63,7 +72,7 @@ public class Rope : MonoBehaviour
|
||||
private bool groundInterpolate = true;
|
||||
|
||||
[SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")]
|
||||
private int groundUpdateEvery = 2;
|
||||
private int groundUpdateEvery = 1;
|
||||
|
||||
[SerializeField, Range(0, 8), Tooltip("地面约束后,再做几次长度约束,减少 poly 被地面抬长")]
|
||||
private int groundPostConstraintIterations = 2;
|
||||
@@ -71,7 +80,7 @@ public class Rope : MonoBehaviour
|
||||
private int _groundFrameCounter;
|
||||
|
||||
[Header("Simple Water Float (Cheap)")] [SerializeField, Tooltip("绳子落到水面以下时,是否把节点约束回水面")]
|
||||
private bool constrainToWaterSurface = true;
|
||||
private bool constrainToWaterSurface = false;
|
||||
|
||||
[SerializeField, Tooltip("静态水面高度;如果你后面接波浪水面,可改成采样函数")]
|
||||
private float waterLevelY = 0f;
|
||||
@@ -126,7 +135,7 @@ public class Rope : MonoBehaviour
|
||||
private float visibilityViewportPadding = 0.08f;
|
||||
|
||||
[Header("Air Drag (Stable)")] [SerializeField, Range(0f, 5f), Tooltip("空气阻力(Y向),指数衰减,越大越不飘")]
|
||||
private float airDrag = 0.9f;
|
||||
private float airDrag = 0.2f;
|
||||
|
||||
[SerializeField, Range(0f, 2f), Tooltip("横向额外阻力(XZ),指数衰减,越大越不左右飘")]
|
||||
private float airDragXZ = 0.6f;
|
||||
@@ -155,25 +164,21 @@ public class Rope : MonoBehaviour
|
||||
// node stability
|
||||
private int _lastDesiredNodes = 0;
|
||||
|
||||
// caches
|
||||
private Transform _startTr;
|
||||
private Transform _endTr;
|
||||
|
||||
// precomputed
|
||||
private float _dt;
|
||||
private float _dt2;
|
||||
private float _kY;
|
||||
private float _kXZ;
|
||||
private Camera _cachedCamera;
|
||||
private Transform _cameraTr;
|
||||
private int _visibilityCheckCounter;
|
||||
private bool _isCulledByVisibility;
|
||||
private int _tIdleSubdiv = -1;
|
||||
private int _tMovingSubdiv = -1;
|
||||
|
||||
private FRod _rod;
|
||||
|
||||
public void Init(FRod rod)
|
||||
{
|
||||
_rod = rod;
|
||||
if (Application.isPlaying)
|
||||
RefreshVisibilityState(true);
|
||||
}
|
||||
|
||||
// Catmull t caches(只缓存 idle/moving 两档,减少每帧重复乘法)
|
||||
private struct TCaches
|
||||
@@ -185,30 +190,29 @@ public class Rope : MonoBehaviour
|
||||
|
||||
private TCaches _tIdle;
|
||||
private TCaches _tMoving;
|
||||
private enum SampleConstraintMode
|
||||
{
|
||||
GroundMinY,
|
||||
WaterSurfaceY
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_lineRenderer = GetComponent<LineRenderer>();
|
||||
_gravity = new Vector3(0f, -gravityStrength, 0f);
|
||||
_dt = Mathf.Max(Time.fixedDeltaTime, 1e-6f);
|
||||
_dt2 = _dt * _dt;
|
||||
|
||||
RefreshAnchorTransforms();
|
||||
|
||||
InitLengthSystem();
|
||||
AllocateAndInitNodes();
|
||||
EnsureRenderCaches();
|
||||
RefreshVisibilityState(true);
|
||||
}
|
||||
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
renderSubdivisionsIdle = Mathf.Max(renderSubdivisionsIdle, 1);
|
||||
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
|
||||
iterations = Mathf.Clamp(iterations, 1, 80);
|
||||
hardTightenIterations = Mathf.Clamp(hardTightenIterations, 0, 16);
|
||||
adaptiveHardTightenMaxIterations = Mathf.Clamp(adaptiveHardTightenMaxIterations, 0, 32);
|
||||
hardConstraintTolerance = Mathf.Max(0f, hardConstraintTolerance);
|
||||
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
|
||||
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
|
||||
lineWidth = Mathf.Max(lineWidth, 0.0001f);
|
||||
@@ -235,37 +239,30 @@ public class Rope : MonoBehaviour
|
||||
visibilityViewportPadding = Mathf.Clamp(visibilityViewportPadding, 0f, 0.5f);
|
||||
}
|
||||
|
||||
private bool ShouldAlwaysSimulate()
|
||||
private void RefreshAnchorTransforms()
|
||||
{
|
||||
if (!localOwnerAlwaysSimulate)
|
||||
return false;
|
||||
|
||||
var owner = _rod?.PlayerItem?.Owner;
|
||||
return owner == null || owner.IsSelf;
|
||||
_startTr = startAnchor ? startAnchor.transform : null;
|
||||
_endTr = endAnchor ? endAnchor.transform : null;
|
||||
}
|
||||
|
||||
private Vector3 GetStartPosition()
|
||||
{
|
||||
return startAnchor ? startAnchor.position : transform.position;
|
||||
}
|
||||
|
||||
private Vector3 GetEndPosition()
|
||||
private Transform GetActiveCameraTransform()
|
||||
{
|
||||
return endAnchor ? endAnchor.position : transform.position;
|
||||
}
|
||||
|
||||
private Camera GetActiveCamera()
|
||||
{
|
||||
if (BaseCamera.Main)
|
||||
Camera main = BaseCamera.Main;
|
||||
if (main)
|
||||
{
|
||||
_cachedCamera = BaseCamera.Main;
|
||||
return _cachedCamera;
|
||||
_cameraTr = main.transform;
|
||||
return _cameraTr;
|
||||
}
|
||||
|
||||
if (!_cachedCamera)
|
||||
_cachedCamera = Camera.main;
|
||||
if (!_cameraTr)
|
||||
{
|
||||
Camera fallback = Camera.main;
|
||||
if (fallback)
|
||||
_cameraTr = fallback.transform;
|
||||
}
|
||||
|
||||
return _cachedCamera;
|
||||
return _cameraTr;
|
||||
}
|
||||
|
||||
private static bool IsViewportPointVisible(Vector3 viewportPoint, float padding)
|
||||
@@ -279,12 +276,18 @@ public class Rope : MonoBehaviour
|
||||
|
||||
private bool IsVisibleToMainCamera()
|
||||
{
|
||||
Camera cam = GetActiveCamera();
|
||||
Transform camTr = GetActiveCameraTransform();
|
||||
if (!camTr)
|
||||
return true;
|
||||
|
||||
Camera cam = camTr.GetComponent<Camera>();
|
||||
if (!cam)
|
||||
cam = BaseCamera.Main ? BaseCamera.Main : Camera.main;
|
||||
if (!cam)
|
||||
return true;
|
||||
|
||||
Vector3 start = GetStartPosition();
|
||||
Vector3 end = GetEndPosition();
|
||||
Vector3 start = _startTr ? _startTr.position : (startAnchor ? startAnchor.position : transform.position);
|
||||
Vector3 end = _endTr ? _endTr.position : (endAnchor ? endAnchor.position : transform.position);
|
||||
Vector3 middle = (start + end) * 0.5f;
|
||||
float padding = visibilityViewportPadding;
|
||||
|
||||
@@ -295,7 +298,7 @@ public class Rope : MonoBehaviour
|
||||
|
||||
private void RefreshVisibilityState(bool force = false)
|
||||
{
|
||||
if (!cullRemoteRopeWhenInvisible || ShouldAlwaysSimulate())
|
||||
if (!cullRemoteRopeWhenInvisible)
|
||||
{
|
||||
_isCulledByVisibility = false;
|
||||
if (_lineRenderer)
|
||||
@@ -335,8 +338,8 @@ public class Rope : MonoBehaviour
|
||||
if (_physicsNodes < 2)
|
||||
return;
|
||||
|
||||
Vector3 start = GetStartPosition();
|
||||
Vector3 end = GetEndPosition();
|
||||
Vector3 start = _startTr ? _startTr.position : (startAnchor ? startAnchor.position : transform.position);
|
||||
Vector3 end = _endTr ? _endTr.position : (endAnchor ? endAnchor.position : transform.position);
|
||||
int last = _physicsNodes - 1;
|
||||
|
||||
for (int i = 0; i <= last; i++)
|
||||
@@ -387,7 +390,7 @@ public class Rope : MonoBehaviour
|
||||
_pCurr = new Vector3[maxPhysicsNodes];
|
||||
_pPrev = new Vector3[maxPhysicsNodes];
|
||||
|
||||
Vector3 start = GetStartPosition();
|
||||
Vector3 start = startAnchor ? startAnchor.position : transform.position;
|
||||
Vector3 dir = Vector3.down;
|
||||
|
||||
for (int i = 0; i < _physicsNodes; i++)
|
||||
@@ -495,6 +498,7 @@ public class Rope : MonoBehaviour
|
||||
{
|
||||
if (!startAnchor || !endAnchor) return;
|
||||
|
||||
RefreshAnchorTransforms();
|
||||
RefreshVisibilityState();
|
||||
if (_isCulledByVisibility)
|
||||
return;
|
||||
@@ -514,13 +518,15 @@ public class Rope : MonoBehaviour
|
||||
|
||||
Simulate_VerletFast();
|
||||
|
||||
|
||||
for (int it = 0; it < iterations; it++)
|
||||
{
|
||||
LockAnchorsHard();
|
||||
SolveDistanceConstraintsBidirectional(stiffness);
|
||||
SolveDistanceConstraints_HeadOnly_Fast();
|
||||
}
|
||||
|
||||
SolveHardDistanceConstraints(hardTightenIterations);
|
||||
SolveHardDistanceConstraintsAdaptive();
|
||||
LockAnchorsHard();
|
||||
|
||||
if (constrainToGround)
|
||||
@@ -554,20 +560,14 @@ public class Rope : MonoBehaviour
|
||||
{
|
||||
if (!startAnchor || !endAnchor || _pCurr == null || _physicsNodes < 2) return;
|
||||
|
||||
RefreshAnchorTransforms();
|
||||
if (_isCulledByVisibility)
|
||||
return;
|
||||
|
||||
EnsureRenderCaches();
|
||||
|
||||
int last = _physicsNodes - 1;
|
||||
|
||||
Vector3 s = GetStartPosition();
|
||||
Vector3 e = GetEndPosition();
|
||||
|
||||
_pCurr[0] = s;
|
||||
_pCurr[last] = e;
|
||||
|
||||
DrawHighResLine_Fast();
|
||||
DrawHighResLine_Fast(_startTr.position, _endTr.position, last);
|
||||
}
|
||||
|
||||
private void UpdateLengthSmooth()
|
||||
@@ -584,9 +584,10 @@ public class Rope : MonoBehaviour
|
||||
Time.fixedDeltaTime
|
||||
);
|
||||
|
||||
// 长度变化时额外压一点速度,减少收放线时抖动
|
||||
float delta = Mathf.Abs(_targetLength - _currentLength);
|
||||
if (delta > 0.0001f && lengthChangeVelocityKill > 0f)
|
||||
// 仅在收线(目标长度小于当前长度)时额外压速度;
|
||||
// 放线时不要压速度,否则新增节点下落会出现“顿一下再突然加速”。
|
||||
float reelInDelta = _currentLength - _targetLength;
|
||||
if (reelInDelta > 0.0001f && lengthChangeVelocityKill > 0f)
|
||||
{
|
||||
float keep = 1f - Mathf.Clamp01(lengthChangeVelocityKill);
|
||||
for (int i = 1; i < _physicsNodes - 1; i++)
|
||||
@@ -623,7 +624,7 @@ public class Rope : MonoBehaviour
|
||||
Array.Copy(_pCurr, 1, _pCurr, 1 + addCount, oldCount - 1);
|
||||
Array.Copy(_pPrev, 1, _pPrev, 1 + addCount, oldCount - 1);
|
||||
|
||||
Vector3 s = GetStartPosition();
|
||||
Vector3 s = _startTr ? _startTr.position : startAnchor.position;
|
||||
|
||||
Vector3 dir = Vector3.down;
|
||||
int firstOld = 1 + addCount;
|
||||
@@ -695,8 +696,8 @@ public class Rope : MonoBehaviour
|
||||
{
|
||||
if (!startAnchor || !endAnchor || _pCurr == null || _pPrev == null || _physicsNodes < 2) return;
|
||||
|
||||
Vector3 s = GetStartPosition();
|
||||
Vector3 e = GetEndPosition();
|
||||
Vector3 s = _startTr ? _startTr.position : startAnchor.position;
|
||||
Vector3 e = _endTr ? _endTr.position : endAnchor.position;
|
||||
|
||||
_pCurr[0] = s;
|
||||
_pPrev[0] = s - startAnchor.linearVelocity * _dt;
|
||||
@@ -706,16 +707,41 @@ public class Rope : MonoBehaviour
|
||||
_pPrev[last] = e - endAnchor.linearVelocity * _dt;
|
||||
}
|
||||
|
||||
private void SolveDistanceConstraints_HeadOnly_Fast()
|
||||
{
|
||||
SolveDistanceConstraints_HeadOnly_Bidirectional(stiffness);
|
||||
}
|
||||
|
||||
private void SolveHardDistanceConstraints(int extraIterations)
|
||||
{
|
||||
for (int it = 0; it < extraIterations; it++)
|
||||
{
|
||||
LockAnchorsHard();
|
||||
SolveDistanceConstraintsBidirectional(1f);
|
||||
SolveDistanceConstraints_HeadOnly_Hard();
|
||||
}
|
||||
}
|
||||
|
||||
private void SolveDistanceConstraintsBidirectional(float combinedStiffness)
|
||||
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()
|
||||
{
|
||||
SolveDistanceConstraints_HeadOnly_Bidirectional(1f);
|
||||
}
|
||||
|
||||
private void SolveDistanceConstraints_HeadOnly_Bidirectional(float combinedStiffness)
|
||||
{
|
||||
int last = _physicsNodes - 1;
|
||||
if (last <= 0) return;
|
||||
@@ -764,14 +790,66 @@ 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()
|
||||
{
|
||||
if (groundMask == 0) return;
|
||||
|
||||
ApplySampledConstraint(SampleConstraintMode.GroundMinY, groundSampleStep, groundInterpolate);
|
||||
int last = _physicsNodes - 1;
|
||||
int step = Mathf.Max(1, groundSampleStep);
|
||||
|
||||
int prevSampleIdx = 1;
|
||||
float prevMinY = SampleMinY(_pCurr[prevSampleIdx]);
|
||||
|
||||
ApplyMinY(prevSampleIdx, prevMinY);
|
||||
|
||||
for (int i = 1 + step; i < last; i += step)
|
||||
{
|
||||
float nextMinY = SampleMinY(_pCurr[i]);
|
||||
ApplyMinY(i, nextMinY);
|
||||
|
||||
if (groundInterpolate)
|
||||
{
|
||||
int a = prevSampleIdx;
|
||||
int b = i;
|
||||
int span = b - a;
|
||||
for (int j = 1; j < span; j++)
|
||||
{
|
||||
int idx = a + j;
|
||||
float t = j / (float)span;
|
||||
float minY = Mathf.Lerp(prevMinY, nextMinY, t);
|
||||
ApplyMinY(idx, minY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = prevSampleIdx + 1; idx < i; idx++)
|
||||
ApplyMinY(idx, prevMinY);
|
||||
}
|
||||
|
||||
prevSampleIdx = i;
|
||||
prevMinY = nextMinY;
|
||||
}
|
||||
|
||||
for (int i = prevSampleIdx + 1; i < last; i++)
|
||||
ApplyMinY(i, prevMinY);
|
||||
}
|
||||
|
||||
private float SampleGroundMinY(Vector3 p)
|
||||
private float SampleMinY(Vector3 p)
|
||||
{
|
||||
Vector3 origin = p + Vector3.up * groundCastHeight;
|
||||
if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask,
|
||||
@@ -803,87 +881,46 @@ public class Rope : MonoBehaviour
|
||||
int last = _physicsNodes - 1;
|
||||
if (last <= 1) return;
|
||||
|
||||
int step = Mathf.Max(1, waterSampleStep);
|
||||
float surfaceY = waterLevelY + waterSurfaceOffset;
|
||||
bool startUnderWater = _pCurr[0].y < surfaceY;
|
||||
int startAdjacentIdx = GetStartAdjacentNodeIndex(last);
|
||||
|
||||
ApplySampledConstraint(
|
||||
SampleConstraintMode.WaterSurfaceY,
|
||||
waterSampleStep,
|
||||
waterInterpolate,
|
||||
surfaceY,
|
||||
startUnderWater,
|
||||
startAdjacentIdx
|
||||
);
|
||||
}
|
||||
|
||||
private void ApplySampledConstraint(SampleConstraintMode mode, int sampleStep, bool interpolate,
|
||||
float constantValue = 0f, bool startUnderWater = false, int startAdjacentIdx = -1)
|
||||
{
|
||||
int last = _physicsNodes - 1;
|
||||
if (last <= 1) return;
|
||||
|
||||
int step = Mathf.Max(1, sampleStep);
|
||||
int prevSampleIdx = 1;
|
||||
float prevValue = GetConstraintSampleValue(mode, prevSampleIdx, constantValue);
|
||||
float prevSurfaceY = surfaceY;
|
||||
|
||||
ApplyConstraintValue(mode, prevSampleIdx, prevValue, startUnderWater, startAdjacentIdx);
|
||||
ApplyWaterSurface(prevSampleIdx, prevSurfaceY, startUnderWater, startAdjacentIdx);
|
||||
|
||||
for (int i = 1 + step; i < last; i += step)
|
||||
{
|
||||
float nextValue = GetConstraintSampleValue(mode, i, constantValue);
|
||||
ApplyConstraintValue(mode, i, nextValue, startUnderWater, startAdjacentIdx);
|
||||
float nextSurfaceY = surfaceY;
|
||||
ApplyWaterSurface(i, nextSurfaceY, startUnderWater, startAdjacentIdx);
|
||||
|
||||
if (interpolate)
|
||||
if (waterInterpolate)
|
||||
{
|
||||
int span = i - prevSampleIdx;
|
||||
int a = prevSampleIdx;
|
||||
int b = i;
|
||||
int span = b - a;
|
||||
for (int j = 1; j < span; j++)
|
||||
{
|
||||
int idx = prevSampleIdx + j;
|
||||
int idx = a + j;
|
||||
float t = j / (float)span;
|
||||
float value = Mathf.Lerp(prevValue, nextValue, t);
|
||||
ApplyConstraintValue(mode, idx, value, startUnderWater, startAdjacentIdx);
|
||||
float y = Mathf.Lerp(prevSurfaceY, nextSurfaceY, t);
|
||||
ApplyWaterSurface(idx, y, startUnderWater, startAdjacentIdx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = prevSampleIdx + 1; idx < i; idx++)
|
||||
ApplyConstraintValue(mode, idx, prevValue, startUnderWater, startAdjacentIdx);
|
||||
ApplyWaterSurface(idx, prevSurfaceY, startUnderWater, startAdjacentIdx);
|
||||
}
|
||||
|
||||
prevSampleIdx = i;
|
||||
prevValue = nextValue;
|
||||
prevSurfaceY = nextSurfaceY;
|
||||
}
|
||||
|
||||
for (int i = prevSampleIdx + 1; i < last; i++)
|
||||
ApplyConstraintValue(mode, i, prevValue, startUnderWater, startAdjacentIdx);
|
||||
}
|
||||
|
||||
private float GetConstraintSampleValue(SampleConstraintMode mode, int index, float constantValue)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case SampleConstraintMode.GroundMinY:
|
||||
return SampleGroundMinY(_pCurr[index]);
|
||||
case SampleConstraintMode.WaterSurfaceY:
|
||||
return constantValue;
|
||||
default:
|
||||
return constantValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyConstraintValue(SampleConstraintMode mode, int index, float value, bool startUnderWater,
|
||||
int startAdjacentIdx)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case SampleConstraintMode.GroundMinY:
|
||||
ApplyMinY(index, value);
|
||||
break;
|
||||
case SampleConstraintMode.WaterSurfaceY:
|
||||
ApplyWaterSurface(index, value, startUnderWater, startAdjacentIdx);
|
||||
break;
|
||||
}
|
||||
ApplyWaterSurface(i, prevSurfaceY, startUnderWater, startAdjacentIdx);
|
||||
}
|
||||
|
||||
private int GetStartAdjacentNodeIndex(int last)
|
||||
@@ -919,7 +956,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;
|
||||
|
||||
@@ -930,15 +967,23 @@ public class Rope : MonoBehaviour
|
||||
if (!smooth)
|
||||
{
|
||||
_lineRenderer.positionCount = _physicsNodes;
|
||||
_lineRenderer.SetPositions(_pCurr);
|
||||
for (int i = 0; i <= last; i++)
|
||||
_rPoints[i] = GetRenderPoint(i, last, renderStart, renderEnd);
|
||||
_lineRenderer.SetPositions(_rPoints);
|
||||
return;
|
||||
}
|
||||
|
||||
int subdiv = PickRenderSubdivisions_Fast();
|
||||
TCaches tc = (subdiv == renderSubdivisionsMoving) ? _tMoving : _tIdle;
|
||||
|
||||
int needed = (_physicsNodes - 1) * subdiv + 1;
|
||||
if (needed > _rCapacity)
|
||||
{
|
||||
_rCapacity = needed;
|
||||
_rPoints = new Vector3[_rCapacity];
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
int last = _physicsNodes - 1;
|
||||
|
||||
for (int seg = 0; seg < last; seg++)
|
||||
{
|
||||
@@ -949,10 +994,10 @@ public class Rope : MonoBehaviour
|
||||
int i3 = seg + 2;
|
||||
if (i3 > last) i3 = last;
|
||||
|
||||
Vector3 p0 = _pCurr[i0];
|
||||
Vector3 p1 = _pCurr[i1];
|
||||
Vector3 p2 = _pCurr[i2];
|
||||
Vector3 p3 = _pCurr[i3];
|
||||
Vector3 p0 = GetRenderPoint(i0, last, renderStart, renderEnd);
|
||||
Vector3 p1 = GetRenderPoint(i1, last, renderStart, renderEnd);
|
||||
Vector3 p2 = GetRenderPoint(i2, last, renderStart, renderEnd);
|
||||
Vector3 p3 = GetRenderPoint(i3, last, renderStart, renderEnd);
|
||||
|
||||
for (int s = 0; s < subdiv; s++)
|
||||
{
|
||||
@@ -975,12 +1020,21 @@ public class Rope : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
_rPoints[idx++] = _pCurr[last];
|
||||
_rPoints[idx++] = renderEnd;
|
||||
|
||||
_lineRenderer.positionCount = idx;
|
||||
_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)
|
||||
{
|
||||
bool rising = p0 <= p1 && p1 <= p2 && p2 <= p3;
|
||||
@@ -13,8 +13,7 @@ namespace NBF
|
||||
|
||||
public struct ThrowAnimationRequest
|
||||
{
|
||||
// public LureController Lure;
|
||||
public FishingLineNode EndNode;
|
||||
public LureController Lure;
|
||||
public Vector3 ThrowOriginPosition;
|
||||
public Vector3 StartPosition;
|
||||
public Vector3 Forward;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace NBF
|
||||
private float _castElapsedTime;
|
||||
private Vector3 _castStartPos;
|
||||
private Vector3 _castTargetPos;
|
||||
private FishingLineNode _castingLure;
|
||||
private LureController _castingLure;
|
||||
|
||||
public bool IsPlaying => _castingLure != null;
|
||||
|
||||
@@ -40,18 +40,18 @@ namespace NBF
|
||||
|
||||
public void Play(ThrowAnimationRequest request)
|
||||
{
|
||||
if (request.EndNode == null)
|
||||
if (request.Lure == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Stop(snapToTarget: false);
|
||||
|
||||
_castingLure = request.EndNode;
|
||||
_castingLure = request.Lure;
|
||||
_chargedProgress = Mathf.Clamp01(request.ChargedProgress);
|
||||
_castElapsedTime = 0f;
|
||||
|
||||
var lureBody = request.EndNode.body;
|
||||
var lureBody = request.Lure.RBody;
|
||||
_castStartPos = request.StartPosition;
|
||||
|
||||
Vector3 forward = GetHorizontalForward(request.Forward);
|
||||
@@ -81,7 +81,7 @@ namespace NBF
|
||||
return;
|
||||
}
|
||||
|
||||
var lureBody = _castingLure.body;
|
||||
var lureBody = _castingLure.RBody;
|
||||
if (snapToTarget)
|
||||
{
|
||||
_castingLure.transform.position = _castTargetPos;
|
||||
|
||||
@@ -61,12 +61,7 @@ namespace NBF
|
||||
PlayerView.Unity.ModelAsset.PlayerAnimator.StartThrow = false;
|
||||
|
||||
var rod = GetRod();
|
||||
if (rod == null || rod.Line == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
var endNode = rod.Line.GetEndNode();
|
||||
if (endNode == null)
|
||||
if (rod == null || rod.Line == null || rod.Line.Lure == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -75,9 +70,9 @@ namespace NBF
|
||||
_throwAnimation.Player = Player;
|
||||
_throwAnimation?.Play(new ThrowAnimationRequest
|
||||
{
|
||||
EndNode = endNode,
|
||||
Lure = rod.Line.Lure,
|
||||
ThrowOriginPosition = PlayerView.Unity.transform.position,
|
||||
StartPosition = endNode.body.position,
|
||||
StartPosition = rod.Line.Lure.RBody.position,
|
||||
Forward = PlayerView.Unity.transform.forward,
|
||||
ChargedProgress = ChargedProgress
|
||||
});
|
||||
|
||||
@@ -7,9 +7,7 @@ namespace NBF
|
||||
protected override void OnInit()
|
||||
{
|
||||
// transform.position = Rod.lineHandler.LineConnector_1.transform.position;
|
||||
|
||||
var node = Rod.Line.GetLogicalNode(FishingLineNode.NodeType.Float);
|
||||
SetParent(node.transform);
|
||||
SetParent(Rod.Line.Bobber.transform);
|
||||
transform.localPosition = Vector3.zero;
|
||||
// var buoyancy = GetComponentInParent<CapsuleBuoyancyStable>();
|
||||
// buoyancy.InitBobber();
|
||||
|
||||
@@ -18,10 +18,8 @@ namespace NBF
|
||||
// transform.rotation = Rod.lineHandler.LineConnector_2.transform.rotation; // 确保旋转也同步
|
||||
// SetParent(Rod.lineHandler.LineConnector_2.transform);
|
||||
|
||||
var node = Rod.Line.GetLogicalNode(FishingLineNode.NodeType.Tail);
|
||||
SetParent(node.transform);
|
||||
|
||||
// SetParent(Rod.Line.Lure.transform);
|
||||
SetParent(Rod.Line.Lure.transform);
|
||||
transform.localPosition = Vector3.zero;
|
||||
|
||||
// var target = lineHandler.LineConnector_2.GetComponent<Rigidbody>();
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
// using System;
|
||||
// using System.Collections;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Linq;
|
||||
// using NBC;
|
||||
// // using Obi;
|
||||
// using UnityEngine;
|
||||
//
|
||||
// namespace NBF
|
||||
// {
|
||||
// public enum LineType
|
||||
// {
|
||||
// Hand,
|
||||
// HandDouble,
|
||||
// Spinning,
|
||||
// SpinningFloat,
|
||||
// }
|
||||
//
|
||||
// public class FLine : FGearBase
|
||||
// {
|
||||
// public LineType LineType;
|
||||
//
|
||||
// [SerializeField] private bool isLureConnect;
|
||||
// [SerializeField] private RodLine rodLine;
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 主线
|
||||
// /// </summary>
|
||||
// [SerializeField] private Rope fishingRope;
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 浮漂和鱼钩线
|
||||
// /// </summary>
|
||||
// [SerializeField] private Rope bobberRope;
|
||||
//
|
||||
// public LureController Lure;
|
||||
// public BobberController Bobber;
|
||||
//
|
||||
// public JointPinchController PinchController;
|
||||
//
|
||||
//
|
||||
// public float LinelenghtDiferent;
|
||||
//
|
||||
// protected override void OnInit()
|
||||
// {
|
||||
// var tipRb = Rod.Asset.LineConnectorRigidbody;
|
||||
// if (isLureConnect)
|
||||
// {
|
||||
// Lure.SetJoint(tipRb);
|
||||
// Lure.EnableCollision(false);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// fishingRope.startAnchor = tipRb;
|
||||
// Bobber.SetJoint(tipRb);
|
||||
// Lure.SetJoint(Bobber.rbody);
|
||||
// Lure.gameObject.SetActive(true);
|
||||
// Lure.EnableCollision(false);
|
||||
// Lure.SetKinematic(false);
|
||||
// }
|
||||
//
|
||||
// GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
|
||||
// {
|
||||
// i.gameObject.SetActive(true);
|
||||
// });
|
||||
//
|
||||
// StartCoroutine(LureUseGravity());
|
||||
// if (isLureConnect)
|
||||
// {
|
||||
// fishingRope.Init(Rod);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// fishingRope.Init(Rod);
|
||||
// bobberRope.Init(Rod);
|
||||
// }
|
||||
//
|
||||
// // rodLine.GenerateLineRendererRope(guides.ToArray(), _LineThickness);
|
||||
// }
|
||||
//
|
||||
// public void InitTest(Rigidbody tipRb)
|
||||
// {
|
||||
// if (isLureConnect)
|
||||
// {
|
||||
// Lure.SetJoint(tipRb);
|
||||
// Lure.EnableCollision(false);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// fishingRope.startAnchor = tipRb;
|
||||
// Bobber.SetJoint(tipRb);
|
||||
// Lure.SetJoint(Bobber.rbody);
|
||||
// Lure.gameObject.SetActive(true);
|
||||
// Lure.EnableCollision(false);
|
||||
// Lure.SetKinematic(false);
|
||||
// }
|
||||
//
|
||||
// GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
|
||||
// {
|
||||
// i.gameObject.SetActive(true);
|
||||
// });
|
||||
//
|
||||
// StartCoroutine(LureUseGravity());
|
||||
// if (isLureConnect)
|
||||
// {
|
||||
// fishingRope.Init(Rod);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// fishingRope.Init(Rod);
|
||||
// bobberRope.Init(Rod);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private IEnumerator LureUseGravity()
|
||||
// {
|
||||
// yield return 1;
|
||||
// Lure.gameObject.SetActive(false);
|
||||
// Lure.gameObject.SetActive(true);
|
||||
// yield return 1;
|
||||
// Lure.RBody.useGravity = true;
|
||||
// }
|
||||
//
|
||||
// public void SetTargetLength(float value)
|
||||
// {
|
||||
// Log.Error($"SetObiRopeStretch={value}");
|
||||
// if (value > 3)
|
||||
// {
|
||||
// // value -= 0.2f;
|
||||
// }
|
||||
//
|
||||
// fishingRope.SetTargetLength(value);
|
||||
// }
|
||||
//
|
||||
// public void SetLureLength(float value)
|
||||
// {
|
||||
// Log.Error($"SetObiRopeStretch={value}");
|
||||
// bobberRope.SetTargetLength(value);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private void Update()
|
||||
// {
|
||||
// LinelenghtDiferent = GetLineDistance();
|
||||
//
|
||||
// //非钓鱼状态
|
||||
// Rod.PlayerItem.Tension = Mathf.Clamp(LinelenghtDiferent, 0f, 0.05f);
|
||||
// }
|
||||
//
|
||||
// #region Tension
|
||||
//
|
||||
// private float GetLineDistance()
|
||||
// {
|
||||
// if (!Bobber.JointRb)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// // return 0;
|
||||
//
|
||||
// //第一个节点到竿稍的位置-第一段鱼线长度
|
||||
// return Vector3.Distance(Bobber.transform.position, Bobber.JointRb.transform.position) -
|
||||
// fishingRope.GetCurrentLength();
|
||||
// }
|
||||
//
|
||||
// public float GetTension(float weight)
|
||||
// {
|
||||
// return weight * GetLineDistance();
|
||||
// }
|
||||
//
|
||||
// #endregion
|
||||
// }
|
||||
// }
|
||||
@@ -14,10 +14,7 @@ namespace NBF
|
||||
|
||||
// SetParent(Rod.lineHandler.LineConnector_1.transform);
|
||||
|
||||
var node = Rod.Line.GetLogicalNode(FishingLineNode.NodeType.Float);
|
||||
SetParent(node.transform);
|
||||
|
||||
// SetParent(Rod.Line.Lure.transform);
|
||||
SetParent(Rod.Line.Lure.transform);
|
||||
transform.localPosition = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace NBF
|
||||
public FBait Bait;
|
||||
public FLure Lure;
|
||||
public FWeight Weight;
|
||||
public FishingLineSolver Line;
|
||||
public FLine Line;
|
||||
|
||||
|
||||
public Transform GearRoot;
|
||||
@@ -72,29 +72,24 @@ namespace NBF
|
||||
if (Line.LineType == LineType.Spinning)
|
||||
{
|
||||
//没有浮漂类型
|
||||
// Line.Lure.SetJointDistance(PlayerItem.LineLength);
|
||||
// if (PlayerItem.StretchRope)
|
||||
// {
|
||||
// // Line.SetTargetLength(PlayerItem.Tension > 0f ? 0f : PlayerItem.LineLength);
|
||||
// Line.SetTargetLength(PlayerItem.LineLength);
|
||||
// }
|
||||
|
||||
Line.SetLenght(PlayerItem.LineLength);
|
||||
Line.Lure.SetJointDistance(PlayerItem.LineLength);
|
||||
if (PlayerItem.StretchRope)
|
||||
{
|
||||
// Line.SetTargetLength(PlayerItem.Tension > 0f ? 0f : PlayerItem.LineLength);
|
||||
Line.SetTargetLength(PlayerItem.LineLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//有浮漂
|
||||
// Line.Lure.SetJointDistance(PlayerItem.FloatLength);
|
||||
// Line.Bobber.SetJointDistance(PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
// if (PlayerItem.StretchRope)
|
||||
// {
|
||||
// // Line.SetTargetLength(PlayerItem.Tension > 0f ? 0f : PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
// Line.SetTargetLength(PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
// Line.SetLureLength(PlayerItem.FloatLength);
|
||||
// }
|
||||
|
||||
Line.SetLenght(PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
Line.SetLenght(PlayerItem.FloatLength, 1);
|
||||
Line.Lure.SetJointDistance(PlayerItem.FloatLength);
|
||||
Line.Bobber.SetJointDistance(PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
if (PlayerItem.StretchRope)
|
||||
{
|
||||
// Line.SetTargetLength(PlayerItem.Tension > 0f ? 0f : PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
Line.SetTargetLength(PlayerItem.LineLength - PlayerItem.FloatLength);
|
||||
Line.SetLureLength(PlayerItem.FloatLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +251,7 @@ namespace NBF
|
||||
var solver = Instantiate(lineSolverPrefab, GearRoot);
|
||||
solver.transform.position = Asset.lineConnector.position;
|
||||
solver.transform.rotation = Asset.lineConnector.rotation;
|
||||
var indexNames = new[] { "FishingLine1", "FishingLine1" };
|
||||
var indexNames = new[] { "fishing line float set", "fishing line spinning" };
|
||||
var path =
|
||||
$"Assets/ResRaw/Prefabs/Line/{indexNames[currentLineTypeIndex]}.prefab";
|
||||
var prefab = Assets.Load<GameObject>(path);
|
||||
@@ -266,7 +261,7 @@ namespace NBF
|
||||
obj.transform.localScale = Vector3.one;
|
||||
obj.transform.rotation = Quaternion.identity;
|
||||
|
||||
Line = obj.GetComponent<FishingLineSolver>();
|
||||
Line = obj.GetComponent<FLine>();
|
||||
Line.transform.position = Asset.lineConnector.position;
|
||||
Line.Init(this);
|
||||
}
|
||||
@@ -344,13 +339,11 @@ namespace NBF
|
||||
var state = PlayerItem.Owner.State;
|
||||
|
||||
|
||||
var endNode = Line.GetEndNode();
|
||||
|
||||
Vector3 vector = endNode.transform.position;
|
||||
Vector3 vector = Line.Lure.transform.position;
|
||||
|
||||
// 当前物体的朝向与指向 Lure 的方向之间的夹角,在 0(完全对齐)到 1(完全相反)之间的一个比例值
|
||||
float headingAlignment = Vector3.Angle(base.transform.forward,
|
||||
(endNode.transform.position - transform.position).normalized) / 180f;
|
||||
(Line.Lure.transform.position - transform.position).normalized) / 180f;
|
||||
// 经过朝向调制后的有效张力
|
||||
var effectiveTension = Mathf.Clamp(CurrentTension01 * headingAlignment, 0f, 1f);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameObjectInspector_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1acad9deef3549c4b9617dfa169c66599f7e00_003Fef_003F654c7b7e_003FGameObjectInspector_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameObjectInspector_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc955c8752c5a4d23acdf053ed11d8af39fca00_003F28_003F2934024a_003FGameObjectInspector_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameObject_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F021f30a9a92b48ce98ae6b39956dd76a1df600_003F28_003F384825fa_003FGameObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameObject_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5ea200363ab142a582463089d51cabd3214200_003F71_003F9c369583_003FGameObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIconAttribute_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F021f30a9a92b48ce98ae6b39956dd76a1df600_003F6a_003F44c4467c_003FIconAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMGUIContainer_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb4f75f0eb2d14004826911645c6175d61fbe00_003F49_003F22dd7281_003FIMGUIContainer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMGUIContainer_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F348ed09ed1634d388253e20b5aab3fcf223400_003Ff5_003F8f871742_003FIMGUIContainer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
@@ -36,10 +36,10 @@ EditorUserSettings:
|
||||
value: 06090c5f54015f5a0f085b7b11765d444e4e1e287429773178704561b3b23561
|
||||
flags: 0
|
||||
RecentlyUsedSceneGuid-7:
|
||||
value: 5505015f5c515a085f5b092149760f441716407a787d7564287b1b36e7e1366e
|
||||
value: 0257035f51050d090f0f5d734521094414164e797e7a20667d7a4536e0e36461
|
||||
flags: 0
|
||||
RecentlyUsedSceneGuid-8:
|
||||
value: 0257035f51050d090f0f5d734521094414164e797e7a20667d7a4536e0e36461
|
||||
value: 5505015f5c515a085f5b092149760f441716407a787d7564287b1b36e7e1366e
|
||||
flags: 0
|
||||
RecentlyUsedSceneGuid-9:
|
||||
value: 07060c5454040c0a545b547240700a441216417e7f2e7268752c4966b4b0663d
|
||||
|
||||
Reference in New Issue
Block a user