Files
Fishing2/Assets/Scripts/FloatBobberControllerPro.cs
2025-11-26 23:44:01 +08:00

170 lines
4.8 KiB
C#

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