This commit is contained in:
2025-11-26 23:44:01 +08:00
parent 6b5e43d813
commit a60a92e7ba
17 changed files with 1135 additions and 139 deletions

View 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();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d2e2de2e2fef459895d6c89eb7b66a34
timeCreated: 1764169703

View 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();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a90396d330f942dea5b6ac1aff681614
timeCreated: 1764167227

View File

@@ -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;
// }
// }

View File

@@ -1,2 +1,3 @@
fileFormatVersion: 2
guid: 59f0b74408dbbfe44aee75e1ddf784d3
guid: c0e5ba2adc224f279b89a0adf2bd97a9
timeCreated: 1764168783

View 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;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 59f0b74408dbbfe44aee75e1ddf784d3

View 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);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 725d1d7ecc254c8a980d997ac7a9d5d3
timeCreated: 1764166393