using UnityEngine; public class NukeBall : BallBase { public AudioClip criticalSound; public AudioClip explosionSound; // Tracks escalating danger/critical phases for audio cues. private int criticalState = 0; private float criticalTime = 1.0f; private float criticalTimer = 0.0f; // Initial resting height the ball bounces back toward after a floor hit. private float height; private Collider2D selfCollider; private bool isBouncingToHeight = false; private float bounceStartY = 0.0f; private float fallTargetY = 0.0f; private float bounceTimer = 0.0f; private float bounceDuration = 1.00f; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { // Cache frequently used components once. audioSource = GetComponent(); animator = GetComponent(); selfCollider = GetComponent(); // Start with a small random horizontal drift. speed = new Vector2(Random.Range(-0.09f, 0.09f), 0.0f); height = GetComponent().position.y; fallTargetY = height; // Find the closest valid floor point under the current position. UpdateFallTargetFromCurrentPosition(); audioSource.PlayOneShot(spawnSound); } // Update is called once per frame void FixedUpdate() { AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); if (stateInfo.IsName("NuclearBallBounce")) { transform.Translate(speed); Vector3 currentPosition = transform.position; if (isBouncingToHeight) { bounceTimer += Time.fixedDeltaTime; float t = Mathf.Clamp01(bounceTimer / bounceDuration); // Ease-out ascent: fast start, gentle finish near target height. float easedT = 1.0f - Mathf.Pow(1.0f - t, 2.0f); currentPosition.y = Mathf.Lerp(bounceStartY, height, easedT); if (t >= 1.0f) { // Reached top of bounce arc; resume falling phase. isBouncingToHeight = false; bounceTimer = 0.0f; currentPosition.y = height; UpdateFallTargetFromCurrentPosition(); } } else { bounceTimer += Time.fixedDeltaTime; float t = Mathf.Clamp01(bounceTimer / bounceDuration); // Ease-in descent: gentle start, faster approach to floor. float easedT = t * t; currentPosition.y = Mathf.Lerp(height, fallTargetY, easedT); } transform.position = currentPosition; } // When in critical state 2, play the critical sound every half a second. if (criticalState == 2) { criticalTimer = 0.5f; } // If in a critical state, increment the critical timer and play the // critical sound if the timer exceeds the critical time. if (criticalState >= 1) { criticalTimer += Time.deltaTime; if (criticalTimer >= criticalTime) { audioSource.PlayOneShot(criticalSound); } // Restart timing window for the next critical beep. criticalTimer = 0.0f; } } void OnCollisionEnter2D(Collision2D collision) { // NukeBall should bounce off walls only. It cannot collide with other balls, not even other NukeBalls. if (collision.gameObject.CompareTag("Wall")) { ContactPoint2D contact = collision.GetContact(0); // Reflect horizontal movement from wall surfaces. speed = Vector2.Reflect(speed, contact.normal); speed.y = 0.0f; audioSource.PlayOneShot(bounceSound); // A floor hit (normal pointing upward) starts an ease-out bounce back to initial height. if (contact.normal.y > 0.5f) { isBouncingToHeight = true; bounceTimer = 0.0f; // Use exact contact point as bounce origin so visual contact feels grounded. bounceStartY = contact.point.y; fallTargetY = bounceStartY; Vector3 currentPosition = transform.position; currentPosition.y = bounceStartY; transform.position = currentPosition; } } } private void UpdateFallTargetFromCurrentPosition() { // Default to current y in case no valid floor is found. fallTargetY = transform.position.y; // Probe straight down and choose nearest upward-facing wall surface. RaycastHit2D[] hits = Physics2D.RaycastAll(transform.position, Vector2.down, 100.0f); float closestDistance = float.MaxValue; foreach (RaycastHit2D hit in hits) { if (hit.collider == null || hit.collider == selfCollider) { continue; } if (!hit.collider.CompareTag("Wall")) { continue; } if (hit.normal.y <= 0.5f) { continue; } if (hit.distance < closestDistance) { closestDistance = hit.distance; fallTargetY = hit.point.y; } } } }