浮力
This commit is contained in:
8
Assets/Resources/gfx/test.meta
Normal file
8
Assets/Resources/gfx/test.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b082403ccfaf6a4e97e2f5ef9ec10e0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
140
Assets/Resources/gfx/test/bob_25002-bob_25002_emissive.mat
Normal file
140
Assets/Resources/gfx/test/bob_25002-bob_25002_emissive.mat
Normal file
@@ -0,0 +1,140 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-3102228912620000641
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 10
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: bob_25002-bob_25002_emissive
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 2800000, guid: ba7837965ad0fcc448dbdf2a1ada9942, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AddPrecomputedVelocity: 0
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _UVSec: 0
|
||||
- _WorkflowMode: 0
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _EmissionColor: {r: 0.6985294, g: 0.48542836, b: 0.21572232, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f221df6c6ebdb0499361f1418f55f7a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
144
Assets/Resources/gfx/test/bob_25002-bob_25002_mat.mat
Normal file
144
Assets/Resources/gfx/test/bob_25002-bob_25002_mat.mat
Normal file
@@ -0,0 +1,144 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: bob_25002-bob_25002_mat
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _SPECGLOSSMAP
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AddPrecomputedVelocity: 0
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpMapScale: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _Fresnel: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.7
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0.15
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Shininess: 6
|
||||
- _Smoothness: 0.271
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecInt: 1
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _UVSec: 0
|
||||
- _WorkflowMode: 1
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &7261695233209220307
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 10
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be41c511450533646b6a0485f18d26db
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -514,7 +514,7 @@ BoxCollider:
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.005, y: 0.005, z: 0.005}
|
||||
m_Center: {x: 0, y: -0.01, z: 0}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3062767698477047043
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -627,6 +627,7 @@ GameObject:
|
||||
- component: {fileID: 3372919389234347908}
|
||||
- component: {fileID: 2709071706889968141}
|
||||
- component: {fileID: 3372919389234347909}
|
||||
- component: {fileID: 3372919389234347910}
|
||||
m_Layer: 0
|
||||
m_Name: bob_25002
|
||||
m_TagString: Untagged
|
||||
@@ -770,8 +771,8 @@ MeshRenderer:
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 7881e4598f2626c4a8ffb3e956070a4b, type: 2}
|
||||
- {fileID: 2100000, guid: 940b6068f71807340a836245c4bbcb7e, type: 2}
|
||||
- {fileID: 2100000, guid: be41c511450533646b6a0485f18d26db, type: 2}
|
||||
- {fileID: 2100000, guid: 6f221df6c6ebdb0499361f1418f55f7a, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
@@ -872,21 +873,48 @@ MonoBehaviour:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3063281911495263383}
|
||||
m_Enabled: 1
|
||||
m_Enabled: 0
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f0b74408dbbfe44aee75e1ddf784d3, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::FloatBobberController
|
||||
useKWS: 0
|
||||
waterLayer:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
waterRaycastHeight: 10
|
||||
stiffness: 0.35
|
||||
damping: 0.82
|
||||
noiseStrength: 0.02
|
||||
lineAttachPoint: {fileID: 2113762193}
|
||||
tiltStrength: 0
|
||||
waterLevel: 0
|
||||
bobberVolume: 30
|
||||
bobberMass: 1
|
||||
bobberHeight: 0.25
|
||||
sinkerWeight: 2
|
||||
baitWeight: 0.5
|
||||
hookWeight: 0.2
|
||||
fallSpeed: 8
|
||||
riseSpeed: 3
|
||||
angleLaySpeed: 2
|
||||
uprightSpeed: 2
|
||||
bottomDrag: 1.2
|
||||
maxLayAngle: 85
|
||||
noiseAmp: 0.001
|
||||
noiseFreq: 1.5
|
||||
--- !u!114 &3372919389234347910
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3063281911495263383}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c0e5ba2adc224f279b89a0adf2bd97a9, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::FloatBobberController
|
||||
waterLevel: 0
|
||||
bobberVolume: 4
|
||||
bobberMass: 1
|
||||
bobberHeight: 0.25
|
||||
sinkerWeight: 2
|
||||
baitWeight: 0.5
|
||||
hookWeight: 0.2
|
||||
fallSpeed: 8
|
||||
riseSpeed: 3
|
||||
smoothDamping: 8
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
40
Assets/Scripts/Editor/FloatBobberControllerEditor.cs
Normal file
40
Assets/Scripts/Editor/FloatBobberControllerEditor.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
[CustomEditor(typeof(FloatBobberController))]
|
||||
public class FloatBobberControllerEditor : Editor
|
||||
{
|
||||
private FloatBobberController _target;
|
||||
void OnEnable()
|
||||
{
|
||||
_target = target as FloatBobberController;
|
||||
// lookAtPoint = serializedObject.FindProperty("lookAtPoint");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
if (GUILayout.Button("TriggerDownPulse"))
|
||||
{
|
||||
_target.TriggerDownPulse();
|
||||
}
|
||||
if (GUILayout.Button("TriggerUpPulse"))
|
||||
{
|
||||
_target.TriggerUpPulse();
|
||||
}
|
||||
if (GUILayout.Button("AddFishPull"))
|
||||
{
|
||||
_target.AddFishPull(0.5f);
|
||||
}
|
||||
if (GUILayout.Button("AddFishPull"))
|
||||
{
|
||||
_target.ReleaseFishPull(0.5f);
|
||||
}
|
||||
// serializedObject.Update();
|
||||
// EditorGUILayout.PropertyField(lookAtPoint);
|
||||
// serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2e2de2e2fef459895d6c89eb7b66a34
|
||||
timeCreated: 1764169703
|
||||
40
Assets/Scripts/Editor/FloatBobberControllerProEditor.cs
Normal file
40
Assets/Scripts/Editor/FloatBobberControllerProEditor.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
[CustomEditor(typeof(FloatBobberControllerPro))]
|
||||
public class FloatBobberControllerProEditor : Editor
|
||||
{
|
||||
private FloatBobberControllerPro _target;
|
||||
void OnEnable()
|
||||
{
|
||||
_target = target as FloatBobberControllerPro;
|
||||
// lookAtPoint = serializedObject.FindProperty("lookAtPoint");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
if (GUILayout.Button("TriggerDownPulse"))
|
||||
{
|
||||
_target.TriggerDownPulse();
|
||||
}
|
||||
if (GUILayout.Button("TriggerUpPulse"))
|
||||
{
|
||||
_target.TriggerUpPulse();
|
||||
}
|
||||
if (GUILayout.Button("AddFishPull"))
|
||||
{
|
||||
_target.AddFishPull(0.5f);
|
||||
}
|
||||
if (GUILayout.Button("AddFishPull"))
|
||||
{
|
||||
_target.ReleaseFishPull(0.5f);
|
||||
}
|
||||
// serializedObject.Update();
|
||||
// EditorGUILayout.PropertyField(lookAtPoint);
|
||||
// serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a90396d330f942dea5b6ac1aff681614
|
||||
timeCreated: 1764167227
|
||||
@@ -1,170 +1,361 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
|
||||
public class FloatBobberControllerPro : MonoBehaviour
|
||||
public class FloatBobberController : MonoBehaviour
|
||||
{
|
||||
[Header("Water")]
|
||||
[Header("水属性")]
|
||||
public float waterLevel = 0f;
|
||||
public float waterDensity = 1f;
|
||||
|
||||
[Header("Bobber Physical")]
|
||||
public float bobberVolume = 30f; // 浮漂最大浮力 (cm³)
|
||||
public float bobberMass = 1f; // 浮漂自重 (g)
|
||||
public float bobberHeight = 0.25f; // 浮漂长度,用来决定躺漂角度
|
||||
|
||||
[Header("Tackle Weight")]
|
||||
|
||||
[Header("浮漂属性")]
|
||||
public float bobberVolume = 30f; // 浮漂最大排水体积 (cm³)
|
||||
public float bobberMass = 1f; // 浮漂自重 (g)
|
||||
public float bobberHeight = 0.25f; // 浮漂总高度
|
||||
[Range(0, 1)] public float bobberFloatPartRatio = 0.7f; // 浮漂浮体部分占总高度的比例
|
||||
|
||||
[Header("配件重量")]
|
||||
public float sinkerWeight = 2f;
|
||||
public float baitWeight = 0.5f;
|
||||
public float hookWeight = 0.2f;
|
||||
|
||||
[Header("Behaviour")]
|
||||
[Header("行为参数")]
|
||||
public float fallSpeed = 8f;
|
||||
public float riseSpeed = 3f;
|
||||
public float angleLaySpeed = 2f; // 躺漂速度
|
||||
public float uprightSpeed = 2f; // 立漂速度
|
||||
public float bottomDrag = 1.2f; // 铅坠触底阻力(越大越难被浮漂拉起)
|
||||
public float smoothDamping = 8f;
|
||||
|
||||
// 私有变量
|
||||
private float totalDownwardWeight;
|
||||
private float maxBuoyancyForce;
|
||||
private float currentSubmergedLength; // 当前浸没长度
|
||||
private float bobberFloatPartHeight; // 浮体部分高度
|
||||
|
||||
// 浮漂状态
|
||||
private float currentBuoyancy; // 当前实际浮力
|
||||
private Vector3 targetPosition;
|
||||
|
||||
// 冲击力相关
|
||||
private float impulseForce = 0f;
|
||||
private float impulseDecay = 4f;
|
||||
|
||||
[Header("Angles")]
|
||||
public float maxLayAngle = 75f; // 最大躺漂角度
|
||||
float currentAngle = 0f;
|
||||
void Start()
|
||||
{
|
||||
InitializeBobber();
|
||||
}
|
||||
|
||||
[Header("Noise")]
|
||||
public float noiseAmp = 0.015f;
|
||||
public float noiseFreq = 1.5f;
|
||||
void InitializeBobber()
|
||||
{
|
||||
// 计算浮体部分高度(能够产生浮力的部分)
|
||||
bobberFloatPartHeight = bobberHeight * bobberFloatPartRatio;
|
||||
|
||||
// 最大浮力 = 浮体部分完全浸没时的排水量
|
||||
maxBuoyancyForce = bobberFloatPartHeight * 100f; // 简化计算,可根据需要调整系数
|
||||
|
||||
// 初始位置调整:让浮漂底部刚好在水面
|
||||
Vector3 pos = transform.position;
|
||||
pos.y = waterLevel - (bobberHeight * 0.5f); // 假设原点在中心,调整到浮漂底部在水面
|
||||
transform.position = pos;
|
||||
|
||||
RecalculateWeights();
|
||||
}
|
||||
|
||||
float impulseForce = 0f;
|
||||
float impulseDecay = 4f;
|
||||
|
||||
void Update()
|
||||
void FixedUpdate()
|
||||
{
|
||||
SimulateBobber();
|
||||
}
|
||||
|
||||
void RecalculateWeights()
|
||||
{
|
||||
totalDownwardWeight = bobberMass + sinkerWeight + baitWeight + hookWeight;
|
||||
}
|
||||
|
||||
void SimulateBobber()
|
||||
{
|
||||
float totalWeight = bobberMass + sinkerWeight + baitWeight + hookWeight;
|
||||
float netBuoyancy = bobberVolume - totalWeight; // 正 → 上浮;负 → 下拉
|
||||
|
||||
// -----------------------------
|
||||
// ① 计算浮漂底部 Y 的高度
|
||||
// -----------------------------
|
||||
float bobberBottomY = transform.position.y - bobberHeight * 0.5f;
|
||||
float bottomY = waterLevel - 0.02f; // 水底高度(可替换真实地形)
|
||||
|
||||
bool sinkerOnBottom = (bobberBottomY <= bottomY);
|
||||
|
||||
// -----------------------------
|
||||
// ② 计算 targetY
|
||||
// -----------------------------
|
||||
float targetY;
|
||||
|
||||
if (!sinkerOnBottom)
|
||||
RecalculateWeights();
|
||||
|
||||
// -------------------------
|
||||
// 1. 计算当前浸没长度和浮力
|
||||
// -------------------------
|
||||
// 浮漂的基准位置(底部位置)
|
||||
float bobberBottomY = transform.position.y;
|
||||
float bobberTopY = bobberBottomY + bobberHeight;
|
||||
|
||||
// 计算浸没长度:浮漂底部到水面的距离,限制在0到浮体高度之间
|
||||
float submergedLength = Mathf.Clamp(waterLevel - bobberBottomY, 0f, bobberFloatPartHeight);
|
||||
currentSubmergedLength = submergedLength;
|
||||
|
||||
// 当前浮力 = (浸没长度 / 浮体高度) * 最大浮力
|
||||
float submergedRatio = submergedLength / bobberFloatPartHeight;
|
||||
currentBuoyancy = submergedRatio * maxBuoyancyForce;
|
||||
|
||||
// -------------------------
|
||||
// 2. 计算净力并决定运动
|
||||
// -------------------------
|
||||
float netForce = currentBuoyancy - totalDownwardWeight;
|
||||
|
||||
// 目标Y位置基于净力计算
|
||||
float targetY = transform.position.y;
|
||||
|
||||
if (Mathf.Abs(netForce) < 0.01f) // 基本平衡
|
||||
{
|
||||
// 铅坠悬浮 → 浮漂直立
|
||||
if (netBuoyancy > 0)
|
||||
// 保持当前位置,微小波动可以在这里添加
|
||||
targetY = transform.position.y;
|
||||
}
|
||||
else if (netForce > 0) // 浮力大于重力,上浮
|
||||
{
|
||||
float riseAmount = netForce * 0.001f * riseSpeed;
|
||||
targetY += riseAmount * Time.deltaTime;
|
||||
|
||||
// 限制不能浮出太多(露出部分不能超过非浮体部分)
|
||||
float maxBobberTopY = waterLevel + (bobberHeight - bobberFloatPartHeight);
|
||||
if (bobberTopY + riseAmount > maxBobberTopY)
|
||||
{
|
||||
float rise = Mathf.Clamp01(netBuoyancy / bobberVolume) * 0.1f;
|
||||
targetY = waterLevel + rise;
|
||||
}
|
||||
else
|
||||
{
|
||||
float sink = Mathf.Abs(netBuoyancy) * 0.02f;
|
||||
targetY = waterLevel - sink;
|
||||
targetY = maxBobberTopY - bobberHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
else // 重力大于浮力,下沉
|
||||
{
|
||||
// 铅坠触底 → 浮漂无法再被向下拉
|
||||
if (netBuoyancy > bottomDrag)
|
||||
float sinkAmount = Mathf.Abs(netForce) * 0.001f * fallSpeed;
|
||||
targetY -= sinkAmount * Time.deltaTime;
|
||||
|
||||
// 限制不能沉没太多(浮体部分完全浸没后浮力达到最大)
|
||||
float minBobberBottomY = waterLevel - bobberFloatPartHeight;
|
||||
if (bobberBottomY - sinkAmount < minBobberBottomY)
|
||||
{
|
||||
// 浮漂浮力足够将其立起来
|
||||
float rise = Mathf.Clamp01((netBuoyancy - bottomDrag) / bobberVolume) * 0.1f;
|
||||
targetY = waterLevel + rise; // 轻轻立起
|
||||
}
|
||||
else
|
||||
{
|
||||
// 浮漂浮力不足 → 躺漂
|
||||
targetY = waterLevel + 0.01f; // 漂身贴水
|
||||
targetY = minBobberBottomY;
|
||||
}
|
||||
}
|
||||
|
||||
// 水波噪声
|
||||
targetY += Mathf.Sin(Time.time * noiseFreq) * noiseAmp;
|
||||
|
||||
// 顿口/顶漂力
|
||||
if (impulseForce != 0f)
|
||||
|
||||
// -------------------------
|
||||
// 3. 应用冲击力
|
||||
// -------------------------
|
||||
if (Mathf.Abs(impulseForce) > 0.01f)
|
||||
{
|
||||
targetY += impulseForce * Time.deltaTime;
|
||||
impulseForce = Mathf.Lerp(impulseForce, 0, Time.deltaTime * impulseDecay);
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// ③ 上浮 / 下沉差速
|
||||
// -----------------------------
|
||||
float y = transform.position.y;
|
||||
float diff = targetY - y;
|
||||
|
||||
if (diff > 0) // 上浮
|
||||
y += diff * Time.deltaTime * riseSpeed;
|
||||
else
|
||||
y += diff * Time.deltaTime * fallSpeed;
|
||||
|
||||
transform.position = new Vector3(transform.position.x, y, transform.position.z);
|
||||
|
||||
// -----------------------------
|
||||
// ④ 浮漂角度控制
|
||||
// -----------------------------
|
||||
float targetAngle = 0f;
|
||||
|
||||
if (sinkerOnBottom)
|
||||
{
|
||||
// 触底 → 判断是否能立漂
|
||||
if (netBuoyancy > bottomDrag)
|
||||
{
|
||||
targetAngle = 0f; // 立漂
|
||||
}
|
||||
else
|
||||
{
|
||||
// 躺漂
|
||||
targetAngle = maxLayAngle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 铅坠在水中 → 漂直立
|
||||
targetAngle = 0f;
|
||||
}
|
||||
|
||||
// 平滑角度
|
||||
currentAngle = Mathf.Lerp(
|
||||
currentAngle,
|
||||
targetAngle,
|
||||
Time.deltaTime * (targetAngle == 0 ? uprightSpeed : angleLaySpeed)
|
||||
);
|
||||
|
||||
transform.rotation = Quaternion.Euler(currentAngle, 0, 0);
|
||||
|
||||
// -------------------------
|
||||
// 4. 平滑移动
|
||||
// -------------------------
|
||||
targetPosition = new Vector3(transform.position.x, targetY, transform.position.z);
|
||||
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * smoothDamping);
|
||||
|
||||
// 调试信息
|
||||
DebugDisplay();
|
||||
}
|
||||
|
||||
void DebugDisplay()
|
||||
{
|
||||
Debug.Log($"浸没比例: {(currentSubmergedLength / bobberFloatPartHeight):P1} " +
|
||||
$"当前浮力: {currentBuoyancy:F2} " +
|
||||
$"总重力: {totalDownwardWeight:F2} " +
|
||||
$"净力: {currentBuoyancy - totalDownwardWeight:F2}");
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// 公共方法 - 用于调漂和鱼咬钩
|
||||
// ----------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 调整配重(用于调漂)
|
||||
/// </summary>
|
||||
public void AdjustSinkerWeight(float newWeight)
|
||||
{
|
||||
sinkerWeight = newWeight;
|
||||
RecalculateWeights();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前调目(浮漂露出水面的格数)
|
||||
/// </summary>
|
||||
public float GetCurrentVisibleMarks()
|
||||
{
|
||||
float bobberBottomY = transform.position.y;
|
||||
float visibleHeight = (bobberBottomY + bobberHeight) - waterLevel;
|
||||
float markHeight = bobberHeight / 10f; // 假设浮漂有10格
|
||||
return Mathf.Max(0, visibleHeight / markHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置目标调目(自动计算需要的配重)
|
||||
/// </summary>
|
||||
public void SetTargetMarks(float targetMarks)
|
||||
{
|
||||
float markHeight = bobberHeight / 10f;
|
||||
float targetVisibleHeight = targetMarks * markHeight;
|
||||
float targetSubmergedLength = bobberFloatPartHeight - targetVisibleHeight;
|
||||
|
||||
// 需要的浮力 = (浸没长度 / 浮体高度) * 最大浮力
|
||||
float requiredBuoyancy = (targetSubmergedLength / bobberFloatPartHeight) * maxBuoyancyForce;
|
||||
|
||||
// 配重 = 浮漂自重 + 钩饵重 - 需要的浮力
|
||||
float requiredSinkerWeight = bobberMass + hookWeight + baitWeight - requiredBuoyancy;
|
||||
|
||||
sinkerWeight = Mathf.Max(0, requiredSinkerWeight);
|
||||
RecalculateWeights();
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// 外部控制接口
|
||||
// 鱼咬钩相关方法
|
||||
// ----------------------------------------
|
||||
|
||||
public void TriggerDownPulse(float s = 0.8f)
|
||||
|
||||
public void TriggerDownPulse(float strength = 0.8f)
|
||||
{
|
||||
impulseForce -= Mathf.Abs(s);
|
||||
impulseForce -= Mathf.Abs(strength);
|
||||
}
|
||||
|
||||
public void TriggerUpPulse(float s = 0.8f)
|
||||
public void TriggerUpPulse(float strength = 0.8f)
|
||||
{
|
||||
impulseForce += Mathf.Abs(s);
|
||||
impulseForce += Mathf.Abs(strength);
|
||||
}
|
||||
|
||||
public void AddFishPull(float v)
|
||||
public void AddFishPull(float pullForce)
|
||||
{
|
||||
sinkerWeight += v;
|
||||
// 鱼的拉力相当于增加向下的力
|
||||
sinkerWeight += pullForce;
|
||||
}
|
||||
|
||||
public void ReleaseFishPull(float v)
|
||||
public void ReleaseFishPull(float pullForce)
|
||||
{
|
||||
sinkerWeight -= v;
|
||||
sinkerWeight -= pullForce;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// 可视化调试
|
||||
// ----------------------------------------
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
// 绘制水面
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawLine(new Vector3(-1, waterLevel, 0), new Vector3(1, waterLevel, 0));
|
||||
|
||||
// 绘制浮漂
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
// 浸没部分用蓝色
|
||||
Gizmos.color = Color.cyan;
|
||||
float submergedBottom = transform.position.y;
|
||||
float submergedTop = submergedBottom + currentSubmergedLength;
|
||||
Gizmos.DrawWireCube(
|
||||
new Vector3(transform.position.x, (submergedBottom + submergedTop) * 0.5f, transform.position.z),
|
||||
new Vector3(0.1f, currentSubmergedLength, 0.1f)
|
||||
);
|
||||
|
||||
// 露出部分用红色
|
||||
Gizmos.color = Color.red;
|
||||
float visibleBottom = submergedTop;
|
||||
float visibleTop = transform.position.y + bobberHeight;
|
||||
float visibleHeight = visibleTop - visibleBottom;
|
||||
if (visibleHeight > 0)
|
||||
{
|
||||
Gizmos.DrawWireCube(
|
||||
new Vector3(transform.position.x, (visibleBottom + visibleTop) * 0.5f, transform.position.z),
|
||||
new Vector3(0.1f, visibleHeight, 0.1f)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// using UnityEngine;
|
||||
//
|
||||
// public class FloatBobberController : MonoBehaviour
|
||||
// {
|
||||
// [Header("水属性")] public float waterLevel = 0f;
|
||||
// [Header("浮漂最大浮力")] public float bobberVolume = 30f; // 浮漂最大浮力 (cm³)
|
||||
// [Header("浮漂自重")] public float bobberMass = 1f; // 浮漂自重 (g)
|
||||
// public float bobberHeight = 0.25f; // 浮漂长度,用来决定躺漂角度
|
||||
//
|
||||
// [Header("配件重量")] public float sinkerWeight = 2f;
|
||||
// public float baitWeight = 0.5f;
|
||||
// public float hookWeight = 0.2f;
|
||||
//
|
||||
// [Header("Behaviour")] public float fallSpeed = 8f;
|
||||
// public float riseSpeed = 3f;
|
||||
// public float smoothDamping = 8f; // 插值平滑
|
||||
//
|
||||
// // [Header("Noise")] public float noiseAmp = 0.015f;
|
||||
// // public float noiseFreq = 1.5f;
|
||||
//
|
||||
// float impulseForce = 0f;
|
||||
// float impulseDecay = 4f;
|
||||
//
|
||||
// void FixedUpdate()
|
||||
// {
|
||||
// SimulateBobber();
|
||||
// }
|
||||
//
|
||||
// void SimulateBobber()
|
||||
// {
|
||||
// float totalDownwardWeight = bobberMass + sinkerWeight + baitWeight + hookWeight;
|
||||
//
|
||||
// float maxBuoyancy = bobberVolume; // 最大浮力 = 体积
|
||||
// float netBuoyancy = maxBuoyancy - totalDownwardWeight;
|
||||
//
|
||||
// float targetY;
|
||||
//
|
||||
// // -------------------------
|
||||
// // 1. 判断浮漂应该沉多少(吃水深度)
|
||||
// // -------------------------
|
||||
// if (netBuoyancy > 0)
|
||||
// {
|
||||
// float buoyPercent = Mathf.Clamp01(netBuoyancy / maxBuoyancy);
|
||||
// float rise = buoyPercent * 0.1f; // 浮漂露出水面的高度
|
||||
//
|
||||
// targetY = waterLevel + rise;
|
||||
//
|
||||
// // targetY += Mathf.Sin(Time.time * noiseFreq) * noiseAmp; // 微扰模拟波浪
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // 净浮力为负 → 说明浮漂整体被拉下,沉入水中
|
||||
// float sinkDistance = Mathf.Abs(netBuoyancy) * 0.03f;
|
||||
// targetY = waterLevel - sinkDistance;
|
||||
// }
|
||||
//
|
||||
// // 顿口/顶漂力
|
||||
// if (impulseForce != 0f)
|
||||
// {
|
||||
// targetY += impulseForce * Time.deltaTime;
|
||||
// impulseForce = Mathf.Lerp(impulseForce, 0, Time.deltaTime * impulseDecay);
|
||||
// }
|
||||
//
|
||||
// // -----------------------------
|
||||
// // ③ 上浮 / 下沉差速
|
||||
// // -----------------------------
|
||||
// float y = transform.position.y;
|
||||
// float diff = targetY - y;
|
||||
//
|
||||
// if (diff > 0) // 上浮
|
||||
// y += diff * Time.deltaTime * riseSpeed;
|
||||
// else
|
||||
// y += diff * Time.deltaTime * fallSpeed;
|
||||
//
|
||||
// transform.position = new Vector3(transform.position.x, y, transform.position.z);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // ----------------------------------------
|
||||
// // 外部控制接口
|
||||
// // ----------------------------------------
|
||||
//
|
||||
// public void TriggerDownPulse(float s = 0.8f)
|
||||
// {
|
||||
// impulseForce -= Mathf.Abs(s);
|
||||
// }
|
||||
//
|
||||
// public void TriggerUpPulse(float s = 0.8f)
|
||||
// {
|
||||
// impulseForce += Mathf.Abs(s);
|
||||
// }
|
||||
//
|
||||
// public void AddFishPull(float v)
|
||||
// {
|
||||
// sinkerWeight += v;
|
||||
// }
|
||||
//
|
||||
// public void ReleaseFishPull(float v)
|
||||
// {
|
||||
// sinkerWeight -= v;
|
||||
// }
|
||||
// }
|
||||
@@ -1,2 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59f0b74408dbbfe44aee75e1ddf784d3
|
||||
guid: c0e5ba2adc224f279b89a0adf2bd97a9
|
||||
timeCreated: 1764168783
|
||||
169
Assets/Scripts/FloatBobberControllerPro.cs
Normal file
169
Assets/Scripts/FloatBobberControllerPro.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class FloatBobberControllerPro : MonoBehaviour
|
||||
{
|
||||
[Header("Water")]
|
||||
public float waterLevel = 0f;
|
||||
|
||||
[Header("Bobber Physical")]
|
||||
public float bobberVolume = 30f; // 浮漂最大浮力 (cm³)
|
||||
public float bobberMass = 1f; // 浮漂自重 (g)
|
||||
public float bobberHeight = 0.25f; // 浮漂长度,用来决定躺漂角度
|
||||
|
||||
[Header("Tackle Weight")]
|
||||
public float sinkerWeight = 2f;
|
||||
public float baitWeight = 0.5f;
|
||||
public float hookWeight = 0.2f;
|
||||
|
||||
[Header("Behaviour")]
|
||||
public float fallSpeed = 8f;
|
||||
public float riseSpeed = 3f;
|
||||
public float angleLaySpeed = 2f; // 躺漂速度
|
||||
public float uprightSpeed = 2f; // 立漂速度
|
||||
public float bottomDrag = 1.2f; // 铅坠触底阻力(越大越难被浮漂拉起)
|
||||
|
||||
[Header("Angles")]
|
||||
public float maxLayAngle = 75f; // 最大躺漂角度
|
||||
float currentAngle = 0f;
|
||||
|
||||
[Header("Noise")]
|
||||
public float noiseAmp = 0.015f;
|
||||
public float noiseFreq = 1.5f;
|
||||
|
||||
float impulseForce = 0f;
|
||||
float impulseDecay = 4f;
|
||||
|
||||
void Update()
|
||||
{
|
||||
SimulateBobber();
|
||||
}
|
||||
|
||||
void SimulateBobber()
|
||||
{
|
||||
float totalWeight = bobberMass + sinkerWeight + baitWeight + hookWeight;
|
||||
float netBuoyancy = bobberVolume - totalWeight; // 正 → 上浮;负 → 下拉
|
||||
|
||||
// -----------------------------
|
||||
// ① 计算浮漂底部 Y 的高度
|
||||
// -----------------------------
|
||||
float bobberBottomY = transform.position.y - bobberHeight * 0.5f;
|
||||
float bottomY = waterLevel - 0.02f; // 水底高度(可替换真实地形)
|
||||
|
||||
bool sinkerOnBottom = (bobberBottomY <= bottomY);
|
||||
|
||||
// -----------------------------
|
||||
// ② 计算 targetY
|
||||
// -----------------------------
|
||||
float targetY;
|
||||
|
||||
if (!sinkerOnBottom)
|
||||
{
|
||||
// 铅坠悬浮 → 浮漂直立
|
||||
if (netBuoyancy > 0)
|
||||
{
|
||||
float rise = Mathf.Clamp01(netBuoyancy / bobberVolume) * 0.1f;
|
||||
targetY = waterLevel + rise;
|
||||
}
|
||||
else
|
||||
{
|
||||
float sink = Mathf.Abs(netBuoyancy) * 0.02f;
|
||||
targetY = waterLevel - sink;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 铅坠触底 → 浮漂无法再被向下拉
|
||||
if (netBuoyancy > bottomDrag)
|
||||
{
|
||||
// 浮漂浮力足够将其立起来
|
||||
float rise = Mathf.Clamp01((netBuoyancy - bottomDrag) / bobberVolume) * 0.1f;
|
||||
targetY = waterLevel + rise; // 轻轻立起
|
||||
}
|
||||
else
|
||||
{
|
||||
// 浮漂浮力不足 → 躺漂
|
||||
targetY = waterLevel + 0.01f; // 漂身贴水
|
||||
}
|
||||
}
|
||||
|
||||
// 水波噪声
|
||||
targetY += Mathf.Sin(Time.time * noiseFreq) * noiseAmp;
|
||||
|
||||
// 顿口/顶漂力
|
||||
if (impulseForce != 0f)
|
||||
{
|
||||
targetY += impulseForce * Time.deltaTime;
|
||||
impulseForce = Mathf.Lerp(impulseForce, 0, Time.deltaTime * impulseDecay);
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// ③ 上浮 / 下沉差速
|
||||
// -----------------------------
|
||||
float y = transform.position.y;
|
||||
float diff = targetY - y;
|
||||
|
||||
if (diff > 0) // 上浮
|
||||
y += diff * Time.deltaTime * riseSpeed;
|
||||
else
|
||||
y += diff * Time.deltaTime * fallSpeed;
|
||||
|
||||
transform.position = new Vector3(transform.position.x, y, transform.position.z);
|
||||
|
||||
// -----------------------------
|
||||
// ④ 浮漂角度控制
|
||||
// -----------------------------
|
||||
float targetAngle = 0f;
|
||||
|
||||
if (sinkerOnBottom)
|
||||
{
|
||||
// 触底 → 判断是否能立漂
|
||||
if (netBuoyancy > bottomDrag)
|
||||
{
|
||||
targetAngle = 0f; // 立漂
|
||||
}
|
||||
else
|
||||
{
|
||||
// 躺漂
|
||||
targetAngle = maxLayAngle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 铅坠在水中 → 漂直立
|
||||
targetAngle = 0f;
|
||||
}
|
||||
|
||||
// 平滑角度
|
||||
currentAngle = Mathf.Lerp(
|
||||
currentAngle,
|
||||
targetAngle,
|
||||
Time.deltaTime * (targetAngle == 0 ? uprightSpeed : angleLaySpeed)
|
||||
);
|
||||
|
||||
transform.rotation = Quaternion.Euler(currentAngle, 0, 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// 外部控制接口
|
||||
// ----------------------------------------
|
||||
|
||||
public void TriggerDownPulse(float s = 0.8f)
|
||||
{
|
||||
impulseForce -= Mathf.Abs(s);
|
||||
}
|
||||
|
||||
public void TriggerUpPulse(float s = 0.8f)
|
||||
{
|
||||
impulseForce += Mathf.Abs(s);
|
||||
}
|
||||
|
||||
public void AddFishPull(float v)
|
||||
{
|
||||
sinkerWeight += v;
|
||||
}
|
||||
|
||||
public void ReleaseFishPull(float v)
|
||||
{
|
||||
sinkerWeight -= v;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/FloatBobberControllerPro.cs.meta
Normal file
2
Assets/Scripts/FloatBobberControllerPro.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59f0b74408dbbfe44aee75e1ddf784d3
|
||||
206
Assets/Scripts/FloatBobberControllerProV4.cs
Normal file
206
Assets/Scripts/FloatBobberControllerProV4.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using UnityEngine;
|
||||
|
||||
public enum BobberState
|
||||
{
|
||||
LyingDown, // 躺漂
|
||||
RisingUp, // 起漂
|
||||
Standing, // 正常站立
|
||||
Bottom, // 挂底
|
||||
TopLift, // 顶漂
|
||||
DownPull, // 黑漂
|
||||
Nibble // 小顿口
|
||||
}
|
||||
|
||||
public class FloatBobberControllerProV4 : MonoBehaviour
|
||||
{
|
||||
[Header("Environment")]
|
||||
public float waterLevel = 0f;
|
||||
|
||||
[Header("Float Settings")]
|
||||
public float floatLength = 0.20f; // 漂总长度
|
||||
public float buoyancyForce = 0.35f; // 浮力强度
|
||||
public float mass = 0.015f; // 重量
|
||||
public float tiltRecoverySpeed = 3f; // 漂恢复垂直速度
|
||||
public float maxTiltAngle = 60f; // 躺漂最大角度
|
||||
|
||||
[Header("Line Settings")]
|
||||
public float lineTension = 0f; // 动态线张力(由鱼影响)
|
||||
public float bottomDrag = 1.5f; // 铅坠触底时的阻力
|
||||
|
||||
[Header("State Machine")]
|
||||
public BobberState state = BobberState.LyingDown;
|
||||
|
||||
// internal vars
|
||||
private float verticalSpeed = 0f;
|
||||
private float angle = 60f; // 初始躺漂角度
|
||||
private float lastHeight;
|
||||
private float deltaY;
|
||||
|
||||
void Start()
|
||||
{
|
||||
lastHeight = transform.position.y;
|
||||
state = BobberState.LyingDown;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
deltaY = transform.position.y - lastHeight;
|
||||
lastHeight = transform.position.y;
|
||||
|
||||
ApplyPhysics();
|
||||
ProcessStateMachine();
|
||||
ApplyRotation();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 一切物理都由状态机控制
|
||||
// ---------------------------------------------------------------------
|
||||
void ProcessStateMachine()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case BobberState.LyingDown:
|
||||
LyingDownBehaviour();
|
||||
break;
|
||||
|
||||
case BobberState.RisingUp:
|
||||
RisingUpBehaviour();
|
||||
break;
|
||||
|
||||
case BobberState.Standing:
|
||||
StandingBehaviour();
|
||||
break;
|
||||
|
||||
case BobberState.Bottom:
|
||||
BottomBehaviour();
|
||||
break;
|
||||
|
||||
case BobberState.TopLift:
|
||||
TopLiftBehaviour();
|
||||
break;
|
||||
|
||||
case BobberState.DownPull:
|
||||
DownPullBehaviour();
|
||||
break;
|
||||
|
||||
case BobberState.Nibble:
|
||||
NibbleBehaviour();
|
||||
break;
|
||||
}
|
||||
|
||||
AutoTransition();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 【状态 → 行为】
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void LyingDownBehaviour()
|
||||
{
|
||||
// 浮漂处于平躺,几乎无浮力
|
||||
angle = Mathf.Lerp(angle, maxTiltAngle, Time.deltaTime * 1.5f);
|
||||
|
||||
// 水面浮力很小
|
||||
verticalSpeed += (buoyancyForce * 0.1f - mass * 9.8f) * Time.deltaTime;
|
||||
}
|
||||
|
||||
void RisingUpBehaviour()
|
||||
{
|
||||
// 浮漂正在被浮力慢慢扶正
|
||||
angle = Mathf.Lerp(angle, 0, Time.deltaTime * (tiltRecoverySpeed * 0.7f));
|
||||
|
||||
// 浮力略加强
|
||||
verticalSpeed += (buoyancyForce * 0.5f) * Time.deltaTime;
|
||||
}
|
||||
|
||||
void StandingBehaviour()
|
||||
{
|
||||
// 完全立稳
|
||||
angle = Mathf.Lerp(angle, 0, Time.deltaTime * tiltRecoverySpeed);
|
||||
|
||||
// 浮力与重力平衡,小幅波动
|
||||
verticalSpeed += Mathf.Sin(Time.time * 4f) * 0.001f;
|
||||
}
|
||||
|
||||
void BottomBehaviour()
|
||||
{
|
||||
// 铅坠或饵触底 → 浮漂立不起来
|
||||
angle = Mathf.Lerp(angle, 20f, Time.deltaTime * 2f);
|
||||
|
||||
// 上浮被底部拖住
|
||||
verticalSpeed *= 0.6f;
|
||||
}
|
||||
|
||||
void TopLiftBehaviour()
|
||||
{
|
||||
// 顶漂 → 漂被往上托一点
|
||||
verticalSpeed += 0.02f;
|
||||
}
|
||||
|
||||
void DownPullBehaviour()
|
||||
{
|
||||
// 黑漂 → 往下猛拉
|
||||
verticalSpeed -= 0.05f;
|
||||
}
|
||||
|
||||
void NibbleBehaviour()
|
||||
{
|
||||
// 小顿口 → 轻微波动
|
||||
verticalSpeed += Mathf.Sin(Time.time * 20f) * 0.0015f;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 状态自动切换
|
||||
// ---------------------------------------------------------------------
|
||||
void AutoTransition()
|
||||
{
|
||||
// 1. 浮漂露出 40% 以上 → 起漂或站漂
|
||||
float headHeight = transform.position.y + floatLength;
|
||||
|
||||
if (state == BobberState.LyingDown && headHeight > waterLevel - 0.02f)
|
||||
state = BobberState.RisingUp;
|
||||
|
||||
if (state == BobberState.RisingUp && angle < 12f)
|
||||
state = BobberState.Standing;
|
||||
|
||||
// 2. 挂底判定
|
||||
float tailHeight = transform.position.y - floatLength;
|
||||
if (tailHeight < waterLevel - 0.03f)
|
||||
state = BobberState.Bottom;
|
||||
|
||||
// 3. 顶漂
|
||||
if (deltaY > 0.015f)
|
||||
state = BobberState.TopLift;
|
||||
|
||||
// 4. 黑漂
|
||||
if (deltaY < -0.02f)
|
||||
state = BobberState.DownPull;
|
||||
|
||||
// 5. 小顿口
|
||||
if (Mathf.Abs(deltaY) > 0.003f && Mathf.Abs(deltaY) < 0.015f)
|
||||
state = BobberState.Nibble;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 垂直物理
|
||||
// ---------------------------------------------------------------------
|
||||
void ApplyPhysics()
|
||||
{
|
||||
float submerged = Mathf.Clamp01((waterLevel - transform.position.y) * 8f);
|
||||
float upForce = buoyancyForce * submerged - mass * 9.8f;
|
||||
|
||||
verticalSpeed += upForce * Time.deltaTime;
|
||||
verticalSpeed = Mathf.Clamp(verticalSpeed, -0.2f, 0.2f);
|
||||
|
||||
transform.position += new Vector3(0, verticalSpeed, 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 倾斜角控制
|
||||
// ---------------------------------------------------------------------
|
||||
void ApplyRotation()
|
||||
{
|
||||
Quaternion q = Quaternion.Euler(angle, 0, 0);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * 8f);
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/FloatBobberControllerProV4.cs.meta
Normal file
3
Assets/Scripts/FloatBobberControllerProV4.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 725d1d7ecc254c8a980d997ac7a9d5d3
|
||||
timeCreated: 1764166393
|
||||
@@ -15,6 +15,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACursor_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F021f30a9a92b48ce98ae6b39956dd76a1df600_003Fd0_003F709b15ec_003FCursor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3789ee403a53437cbb6b5d9ab6311f51573620_003Fe4_003F91da590a_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEditorWindow_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1acad9deef3549c4b9617dfa169c66599f7e00_003F51_003F0bcae924_003FEditorWindow_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEditor_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1acad9deef3549c4b9617dfa169c66599f7e00_003Fc8_003F346a24ac_003FEditor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F314938d17f3848e8ac683e11b27f62ee46ae00_003F70_003F17d560d4_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F59bd7c40c082431db25e1e728ab6278946ae00_003Fb4_003F05ce572a_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F59bd7c40c082431db25e1e728ab6278946ae00_003Fb4_003F05ce572a_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
@@ -23,6 +24,7 @@
|
||||
<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>
|
||||
<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_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F348ed09ed1634d388253e20b5aab3fcf223400_003Ff5_003F8f871742_003FIMGUIContainer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonSerializerInternalWriter_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe2e3d26278e439d44964729238a685ad58d3189abf8fb84cdfe34b893a290a2_003FJsonSerializerInternalWriter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKeyCode_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F021f30a9a92b48ce98ae6b39956dd76a1df600_003Fd1_003F01a95d3a_003FKeyCode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKeyCode_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb4c8c45fec274213bfac03ee0e9a3d621f5a00_003Fab_003Fc81c90e9_003FKeyCode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
Reference in New Issue
Block a user