171 lines
4.8 KiB
C#
171 lines
4.8 KiB
C#
using UnityEngine;
|
|
|
|
public class FloatBobberControllerPro : MonoBehaviour
|
|
{
|
|
[Header("Water")]
|
|
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")]
|
|
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;
|
|
}
|
|
}
|