Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Unity/AIForOceans/Assets/Audio/no/no_1.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_10.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_2.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_3.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_4.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_5.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_6.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_7.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_8.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/no/no_9.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/other/other_1.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/other/other_2.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/other/other_3.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/other/other_4.mp3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_1.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_10.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_2.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_3.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_4.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_5.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_6.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_7.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_8.mp3
Binary file not shown.
Binary file added Unity/AIForOceans/Assets/Audio/yes/yes_9.mp3
Binary file not shown.
16 changes: 16 additions & 0 deletions Unity/AIForOceans/Assets/Scripts/AIForOceans.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "AIForOceans",
"rootNamespace": "AIForOceans",
"references": [
"Unity.TextMeshPro"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
165 changes: 165 additions & 0 deletions Unity/AIForOceans/Assets/Scripts/Animation/FishAnimator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using UnityEngine;

namespace AIForOceans
{
/// <summary>
/// Handles fish animation - bobbing, movement, scanning pause
/// Mirrors the original renderer.js animation logic
/// </summary>
public class FishAnimator : MonoBehaviour
{
[Header("Animation Settings")]
public float bobAmplitude = 10f;
public float bobFrequency = 2f;
public float moveSpeed = 100f;

[Header("Scan Settings")]
public bool isPaused = false;
public float scanPauseDuration = 1.5f;

// Internal state
private float startTime;
private float pauseStartTime;
private float totalPauseTime;
private Vector2 startPosition;
private float bobPhase;

// S-curve animation for scanning
private bool isScanning = false;
private float scanStartTime;
private float scanProgress;

private void Start()
{
startTime = Time.time;
startPosition = transform.position;
}

/// <summary>
/// Initialize with ocean object data
/// </summary>
public void Initialize(OceanObjectData data)
{
bobPhase = data.bobPhase;
moveSpeed = data.speed;
startPosition = data.position;
transform.position = startPosition;
}

private void Update()
{
if (!isPaused)
{
UpdateMovement();
}

UpdateBobbing();

if (isScanning)
{
UpdateScanAnimation();
}
}

/// <summary>
/// Update horizontal movement
/// </summary>
private void UpdateMovement()
{
float elapsed = Time.time - startTime - totalPauseTime;
float xOffset = elapsed * moveSpeed;

Vector2 pos = transform.position;
pos.x = startPosition.x + xOffset;
transform.position = pos;
}

/// <summary>
/// Update bobbing animation (sine wave)
/// </summary>
private void UpdateBobbing()
{
float time = Time.time;
float bobOffset = Mathf.Sin(time * bobFrequency + bobPhase) * bobAmplitude;

Vector2 pos = transform.position;
pos.y = startPosition.y + bobOffset;
transform.position = pos;
}

/// <summary>
/// Start pause for scanning
/// </summary>
public void StartScan()
{
isPaused = true;
pauseStartTime = Time.time;
isScanning = true;
scanStartTime = Time.time;
scanProgress = 0f;
}

/// <summary>
/// End scanning and resume movement
/// </summary>
public void EndScan()
{
isPaused = false;
totalPauseTime += Time.time - pauseStartTime;
isScanning = false;
}

/// <summary>
/// Update scanning S-curve animation
/// </summary>
private void UpdateScanAnimation()
{
float elapsed = Time.time - scanStartTime;
scanProgress = Mathf.Clamp01(elapsed / scanPauseDuration);

// S-curve easing: slow at start and end, fast in middle
float easedProgress = SCurve(scanProgress);

// Can be used to animate scan overlay or other effects
// The original uses this to pause fish in center while AI analyzes
}

/// <summary>
/// S-curve (sigmoid-like) easing function
/// </summary>
public static float SCurve(float t)
{
// Hermite interpolation (smooth step)
return t * t * (3f - 2f * t);
}

/// <summary>
/// More pronounced S-curve
/// </summary>
public static float SCurveSteep(float t)
{
// Quintic smooth step
return t * t * t * (t * (t * 6f - 15f) + 10f);
}

/// <summary>
/// Check if fish has moved off screen
/// </summary>
public bool IsOffScreen(float screenWidth)
{
return transform.position.x > screenWidth + 100f;
}

/// <summary>
/// Reset to start position
/// </summary>
public void Reset()
{
startTime = Time.time;
totalPauseTime = 0f;
transform.position = startPosition;
isPaused = false;
isScanning = false;
}
}
}
160 changes: 160 additions & 0 deletions Unity/AIForOceans/Assets/Scripts/Animation/FishRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using UnityEngine;

namespace AIForOceans
{
/// <summary>
/// Renders a procedurally generated fish from sprite components
/// </summary>
public class FishRenderer : MonoBehaviour
{
[Header("Sprite Renderers")]
public SpriteRenderer bodyRenderer;
public SpriteRenderer eyesRenderer;
public SpriteRenderer mouthRenderer;
public SpriteRenderer dorsalFinRenderer;
public SpriteRenderer pectoralFinFrontRenderer;
public SpriteRenderer pectoralFinBackRenderer;
public SpriteRenderer tailFinRenderer;
public SpriteRenderer scalesRenderer;

[Header("Sprite Arrays (set in inspector or load from Resources)")]
public Sprite[] bodySprites;
public Sprite[] eyesSprites;
public Sprite[] mouthSprites;
public Sprite[] dorsalFinSprites;
public Sprite[] pectoralFinSprites;
public Sprite[] tailFinSprites;
public Sprite[] scalesSprites;

// Current fish data
private OceanObjectData currentData;

/// <summary>
/// Set up the fish visual from data
/// </summary>
public void SetupFish(OceanObjectData data)
{
currentData = data;

if (data.objectType != GameConstants.OceanObjectType.Fish)
{
Debug.LogWarning("FishRenderer.SetupFish called with non-fish object");
return;
}

// Set sprites
SetSpriteIfValid(bodyRenderer, bodySprites, data.bodyIndex);
SetSpriteIfValid(eyesRenderer, eyesSprites, data.eyesIndex);
SetSpriteIfValid(mouthRenderer, mouthSprites, data.mouthIndex);
SetSpriteIfValid(dorsalFinRenderer, dorsalFinSprites, data.dorsalFinIndex);
SetSpriteIfValid(pectoralFinFrontRenderer, pectoralFinSprites, data.pectoralFinIndex);
SetSpriteIfValid(pectoralFinBackRenderer, pectoralFinSprites, data.pectoralFinIndex);
SetSpriteIfValid(tailFinRenderer, tailFinSprites, data.tailFinIndex);
SetSpriteIfValid(scalesRenderer, scalesSprites, data.scalesIndex);

// Apply colors
ApplyColors(data);
}

/// <summary>
/// Set sprite if index is valid
/// </summary>
private void SetSpriteIfValid(SpriteRenderer renderer, Sprite[] sprites, int index)
{
if (renderer == null || sprites == null || sprites.Length == 0)
return;

int safeIndex = Mathf.Clamp(index, 0, sprites.Length - 1);
renderer.sprite = sprites[safeIndex];
}

/// <summary>
/// Apply color tinting to fish parts
/// </summary>
private void ApplyColors(OceanObjectData data)
{
// Body uses primary color
if (bodyRenderer != null)
bodyRenderer.color = data.primaryColor;

// Scales use secondary color
if (scalesRenderer != null)
scalesRenderer.color = data.secondaryColor;

// Fins use fin color
Color finColor = data.finColor;
if (dorsalFinRenderer != null)
dorsalFinRenderer.color = finColor;
if (pectoralFinFrontRenderer != null)
pectoralFinFrontRenderer.color = finColor;
if (pectoralFinBackRenderer != null)
pectoralFinBackRenderer.color = finColor;
if (tailFinRenderer != null)
tailFinRenderer.color = finColor;

// Eyes and mouth stay neutral (white/original)
if (eyesRenderer != null)
eyesRenderer.color = Color.white;
if (mouthRenderer != null)
mouthRenderer.color = Color.white;
}

/// <summary>
/// Set sorting order for all parts
/// </summary>
public void SetSortingOrder(int baseOrder)
{
// Back to front ordering
if (tailFinRenderer != null)
tailFinRenderer.sortingOrder = baseOrder;
if (pectoralFinBackRenderer != null)
pectoralFinBackRenderer.sortingOrder = baseOrder + 1;
if (dorsalFinRenderer != null)
dorsalFinRenderer.sortingOrder = baseOrder + 2;
if (bodyRenderer != null)
bodyRenderer.sortingOrder = baseOrder + 3;
if (scalesRenderer != null)
scalesRenderer.sortingOrder = baseOrder + 4;
if (pectoralFinFrontRenderer != null)
pectoralFinFrontRenderer.sortingOrder = baseOrder + 5;
if (eyesRenderer != null)
eyesRenderer.sortingOrder = baseOrder + 6;
if (mouthRenderer != null)
mouthRenderer.sortingOrder = baseOrder + 7;
}

/// <summary>
/// Flip the fish horizontally
/// </summary>
public void SetFlipped(bool flipped)
{
Vector3 scale = transform.localScale;
scale.x = flipped ? -Mathf.Abs(scale.x) : Mathf.Abs(scale.x);
transform.localScale = scale;
}

/// <summary>
/// Show/hide the fish
/// </summary>
public void SetVisible(bool visible)
{
gameObject.SetActive(visible);
}

/// <summary>
/// Apply a highlight effect (for selection)
/// </summary>
public void SetHighlighted(bool highlighted)
{
float brightness = highlighted ? 1.2f : 1f;

// Brighten all parts slightly
if (bodyRenderer != null)
{
Color c = currentData.primaryColor * brightness;
c.a = 1f;
bodyRenderer.color = c;
}
}
}
}
Loading