using UnityEngine;
///
/// Swim animation for an inflated paper fish: a sideways wave that grows toward
/// the tail and travels backwards, so tail and rear fins swish while the head
/// stays steady. Deforms a per-instance copy of the shared mesh on the CPU.
///
[RequireComponent(typeof(MeshFilter))]
public class FishWiggle : MonoBehaviour
{
[Tooltip("True if the sprite's nose points +X (tail is at the left of the texture).")]
public bool spriteFacesRight = true;
[Tooltip("Sideways swing at the tail tip, as a fraction of fish height.")]
public float amplitude = 0.10f;
[Tooltip("Wave cycles per second when cruising.")]
public float frequency = 1.6f;
[Tooltip("How far along the body the wave is (0 = only the tail moves, 1 = whole body).")]
[Range(0f, 1f)] public float bodyShare = 0.25f;
[Tooltip("Speed multiplier from the controller; 1 = cruising.")]
public float effort = 1f;
Mesh mesh;
Vector3[] baseVerts, verts;
float[] tail; // 0 at the nose .. 1 at the tail tip
float phase;
void Start()
{
var mf = GetComponent();
var src = mf.sharedMesh;
if (src == null) { enabled = false; return; }
mesh = Object.Instantiate(src);
mesh.name = src.name + " (wiggle)";
mesh.MarkDynamic();
mf.sharedMesh = mesh;
baseVerts = mesh.vertices;
verts = new Vector3[baseVerts.Length];
var uv = mesh.uv;
tail = new float[baseVerts.Length];
for (int i = 0; i < tail.Length; i++)
{
float u = uv.Length == baseVerts.Length ? uv[i].x : baseVerts[i].x + 0.5f;
float t = spriteFacesRight ? 1f - u : u;
// ease in: head barely moves, last third of the body carries the swing
tail[i] = Mathf.Pow(Mathf.Clamp01((t - (1f - bodyShare) * 0.6f) / (1f - (1f - bodyShare) * 0.6f)), 2.2f);
}
phase = Random.value * Mathf.PI * 2f;
}
void Update()
{
if (mesh == null) return;
phase += Time.deltaTime * frequency * Mathf.Max(0.2f, effort) * Mathf.PI * 2f;
float amp = amplitude * Mathf.Clamp(effort, 0.5f, 1.5f);
for (int i = 0; i < verts.Length; i++)
{
var v = baseVerts[i];
float k = tail[i];
// wave travels head -> tail: phase lags with tailness
v.z += Mathf.Sin(phase - k * 2.5f) * amp * k;
verts[i] = v;
}
mesh.vertices = verts;
mesh.RecalculateBounds();
}
void OnDestroy() { if (mesh != null) Destroy(mesh); }
}