195 lines
5.2 KiB
C#
195 lines
5.2 KiB
C#
using UnityEngine;
|
|
|
|
public class BallBase : MonoBehaviour
|
|
{
|
|
public AudioClip spawnSound;
|
|
|
|
public AudioClip bounceSound;
|
|
|
|
public AudioClip hitSound;
|
|
|
|
protected Animator animator;
|
|
|
|
protected AudioSource audioSource;
|
|
|
|
protected Vector2 speed;
|
|
|
|
protected bool affectedByMagnet = true;
|
|
|
|
protected bool magnetActiveLeftRight = false;
|
|
|
|
protected bool magnetActiveTopBottom = false;
|
|
|
|
protected struct MagnetBounceAxisState
|
|
{
|
|
public bool magnetWasActive;
|
|
public bool bouncingToAnchor;
|
|
public float anchor;
|
|
public float target;
|
|
public float bounceTimer;
|
|
public int sideDirection;
|
|
}
|
|
|
|
void OnTriggerEnter2D(Collider2D other)
|
|
{
|
|
if(other.gameObject.CompareTag("Bar"))
|
|
{
|
|
if (!audioSource.isPlaying)
|
|
{
|
|
audioSource.PlayOneShot(hitSound);
|
|
}
|
|
|
|
// Destroy all bar segments when the ball hits a bar.
|
|
var barSegments = GameObject.FindGameObjectsWithTag("Bar");
|
|
|
|
foreach (var barSegment in barSegments)
|
|
{
|
|
Destroy(barSegment);
|
|
}
|
|
|
|
// Notify the player that the bar has been hit.
|
|
var player = GameObject.FindGameObjectWithTag("Player");
|
|
|
|
if (player != null)
|
|
{
|
|
player.GetComponent<Player>().OnBarHit();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void MagnetActive(bool flipped)
|
|
{
|
|
if (flipped)
|
|
{
|
|
magnetActiveTopBottom = true;
|
|
}
|
|
else
|
|
{
|
|
magnetActiveLeftRight = true;
|
|
}
|
|
}
|
|
|
|
public void MagnetInactive()
|
|
{
|
|
magnetActiveTopBottom = false;
|
|
magnetActiveLeftRight = false;
|
|
}
|
|
|
|
protected float ApplyMagnetBounceAxis(
|
|
float currentValue,
|
|
float minBound,
|
|
float maxBound,
|
|
bool magnetIsActive,
|
|
ref MagnetBounceAxisState state,
|
|
float colliderExtent,
|
|
float bounceDuration,
|
|
float centerLeeway)
|
|
{
|
|
if (!magnetIsActive)
|
|
{
|
|
state.magnetWasActive = false;
|
|
state.sideDirection = 0;
|
|
state.bounceTimer = 0.0f;
|
|
return currentValue;
|
|
}
|
|
|
|
float center = (minBound + maxBound) * 0.5f;
|
|
float halfSpan = (maxBound - minBound) * 0.5f;
|
|
float maxLeeway = Mathf.Max(0.0f, halfSpan - colliderExtent);
|
|
float safeLeeway = Mathf.Clamp(centerLeeway, 0.0f, maxLeeway);
|
|
float leftAnchorMax = center - safeLeeway;
|
|
float rightAnchorMin = center + safeLeeway;
|
|
|
|
if (!state.magnetWasActive)
|
|
{
|
|
state.magnetWasActive = true;
|
|
state.anchor = currentValue;
|
|
state.sideDirection = state.anchor <= center ? -1 : 1;
|
|
state.target = state.sideDirection < 0 ? minBound + colliderExtent : maxBound - colliderExtent;
|
|
state.bouncingToAnchor = false;
|
|
state.bounceTimer = 0.0f;
|
|
}
|
|
|
|
// Keep the selected side locked while magnet is active.
|
|
if (state.sideDirection < 0)
|
|
{
|
|
state.anchor = Mathf.Min(state.anchor, leftAnchorMax);
|
|
}
|
|
else
|
|
{
|
|
state.anchor = Mathf.Max(state.anchor, rightAnchorMin);
|
|
}
|
|
|
|
state.bounceTimer += Time.fixedDeltaTime;
|
|
float t = Mathf.Clamp01(state.bounceTimer / bounceDuration);
|
|
|
|
if (state.bouncingToAnchor)
|
|
{
|
|
// Mirror NukeBall ascent: ease-out from target back to anchor.
|
|
float easedT = 1.0f - Mathf.Pow(1.0f - t, 2.0f);
|
|
currentValue = Mathf.Lerp(state.target, state.anchor, easedT);
|
|
|
|
if (t >= 1.0f)
|
|
{
|
|
state.bouncingToAnchor = false;
|
|
state.bounceTimer = 0.0f;
|
|
currentValue = state.anchor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Mirror NukeBall descent: ease-in from anchor down to side target.
|
|
float easedT = t * t;
|
|
currentValue = Mathf.Lerp(state.anchor, state.target, easedT);
|
|
|
|
if (t >= 1.0f)
|
|
{
|
|
state.bouncingToAnchor = true;
|
|
state.bounceTimer = 0.0f;
|
|
currentValue = state.target;
|
|
}
|
|
}
|
|
|
|
return currentValue;
|
|
}
|
|
|
|
protected bool TryCacheGameBoardBounds(out Bounds bounds)
|
|
{
|
|
var gameBoard = FindAnyObjectByType<GameBoard>();
|
|
if (gameBoard != null)
|
|
{
|
|
return TryGetWorldBounds(gameBoard.gameObject, out bounds);
|
|
}
|
|
|
|
bounds = default;
|
|
return false;
|
|
}
|
|
|
|
protected static bool TryGetWorldBounds(GameObject target, out Bounds bounds)
|
|
{
|
|
Collider2D collider2D = target.GetComponent<Collider2D>();
|
|
if (collider2D != null)
|
|
{
|
|
bounds = collider2D.bounds;
|
|
return true;
|
|
}
|
|
|
|
Renderer renderer = target.GetComponent<Renderer>();
|
|
if (renderer != null)
|
|
{
|
|
bounds = renderer.bounds;
|
|
return true;
|
|
}
|
|
|
|
Collider collider3D = target.GetComponent<Collider>();
|
|
if (collider3D != null)
|
|
{
|
|
bounds = collider3D.bounds;
|
|
return true;
|
|
}
|
|
|
|
bounds = default;
|
|
return false;
|
|
}
|
|
}
|