From 46198d6c4466c0ce563826e0eae115a98a6a6c06 Mon Sep 17 00:00:00 2001 From: Miguel Astor Date: Wed, 5 Aug 2026 05:36:38 -0400 Subject: [PATCH] TO SQUASH: Fucking magnets, how do they work? --- Assets/Scenes/Game.unity | 46 +++++--- Assets/Scripts/Game/BallSpawner.cs | 50 +++++++-- Assets/Scripts/Game/Balls/BallBase.cs | 149 +++++++++++++++++++++++++ Assets/Scripts/Game/Balls/BasicBall.cs | 49 ++++++++ Assets/Scripts/Game/Balls/EyeBall.cs | 46 ++++++++ Assets/Scripts/Game/Balls/FruitBall.cs | 46 ++++++++ Assets/Scripts/Game/Balls/GlassBall.cs | 46 ++++++++ Assets/Scripts/Game/Balls/OozeBall.cs | 46 ++++++++ Assets/Scripts/Game/Player.cs | 5 + ProjectSettings/ProjectSettings.asset | 21 +++- 10 files changed, 472 insertions(+), 32 deletions(-) diff --git a/Assets/Scenes/Game.unity b/Assets/Scenes/Game.unity index 71e7b06..660e36c 100644 --- a/Assets/Scenes/Game.unity +++ b/Assets/Scenes/Game.unity @@ -239,7 +239,7 @@ GameObject: m_IsActive: 1 --- !u!212 &57932792 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -296,6 +296,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &57932793 Transform: m_ObjectHideFlags: 0 @@ -331,7 +332,7 @@ GameObject: m_IsActive: 1 --- !u!212 &118530398 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -388,6 +389,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &118530399 Transform: m_ObjectHideFlags: 0 @@ -473,7 +475,7 @@ Animator: m_WriteDefaultValuesOnDisable: 0 --- !u!212 &171200257 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -530,6 +532,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!114 &171200258 MonoBehaviour: m_ObjectHideFlags: 0 @@ -761,7 +764,7 @@ GameObject: m_IsActive: 1 --- !u!212 &297740151 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -818,6 +821,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &297740152 Transform: m_ObjectHideFlags: 0 @@ -948,7 +952,7 @@ Transform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!212 &739145246 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1005,6 +1009,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!95 &739145247 Animator: serializedVersion: 7 @@ -1046,7 +1051,7 @@ GameObject: m_IsActive: 1 --- !u!212 &797752167 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1103,6 +1108,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &797752168 Transform: m_ObjectHideFlags: 0 @@ -1152,7 +1158,7 @@ Transform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!212 &835753046 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1209,6 +1215,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!1 &933658173 GameObject: m_ObjectHideFlags: 0 @@ -1529,6 +1536,7 @@ MonoBehaviour: magnetRight: {fileID: 1465768807} magnetTop: {fileID: 797752166} magnetBottom: {fileID: 1573512371} + ballSpawner: {fileID: 240489636} --- !u!58 &1002905793 CircleCollider2D: m_ObjectHideFlags: 0 @@ -1634,7 +1642,7 @@ Transform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!212 &1331432503 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1691,6 +1699,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!1 &1357719764 GameObject: m_ObjectHideFlags: 0 @@ -1711,7 +1720,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1357719765 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1768,6 +1777,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &1357719766 Transform: m_ObjectHideFlags: 0 @@ -1848,7 +1858,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1360965132 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1905,6 +1915,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &1360965133 Transform: m_ObjectHideFlags: 0 @@ -1939,7 +1950,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1465768808 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1996,6 +2007,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &1465768809 Transform: m_ObjectHideFlags: 0 @@ -2030,7 +2042,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1573512372 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -2087,6 +2099,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &1573512373 Transform: m_ObjectHideFlags: 0 @@ -2122,7 +2135,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1826182597 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -2179,6 +2192,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &1826182598 Transform: m_ObjectHideFlags: 0 @@ -2260,7 +2274,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1846312115 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -2317,6 +2331,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &1846312116 Transform: m_ObjectHideFlags: 0 @@ -2398,7 +2413,7 @@ GameObject: m_IsActive: 1 --- !u!212 &2050805087 SpriteRenderer: - serializedVersion: 2 + serializedVersion: 3 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -2455,6 +2470,7 @@ SpriteRenderer: m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 m_SpriteSortPoint: 0 + m_BlendShapeWeights: [] --- !u!4 &2050805088 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Game/BallSpawner.cs b/Assets/Scripts/Game/BallSpawner.cs index 0e08cd1..3dfd2df 100644 --- a/Assets/Scripts/Game/BallSpawner.cs +++ b/Assets/Scripts/Game/BallSpawner.cs @@ -31,17 +31,17 @@ public class BallSpawner : MonoBehaviour ballQueue.Enqueue(() => SpawnBall(basicBallPrefab)); ballQueue.Enqueue(() => SpawnBall(basicBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(basicBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(fruitBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(fruitBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(oozeBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(nuclearBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); - // ballQueue.Enqueue(() => SpawnBall(eyeBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(basicBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(fruitBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(fruitBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(oozeBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(nuclearBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(glassBallPrefab)); + ballQueue.Enqueue(() => SpawnBall(eyeBallPrefab)); StartCoroutine(SpawnBalls()); } @@ -172,4 +172,32 @@ public class BallSpawner : MonoBehaviour FixCollisions(); } + + public void MagnetActive(bool flipped) + { + foreach (var ball in balls) + { + if (ball == null) continue; + + var ballScript = ball.GetComponent(); + if (ballScript != null) + { + ballScript.MagnetActive(flipped); + } + } + } + + public void MagnetInactive() + { + foreach (var ball in balls) + { + if (ball == null) continue; + + var ballScript = ball.GetComponent(); + if (ballScript != null) + { + ballScript.MagnetInactive(); + } + } + } } diff --git a/Assets/Scripts/Game/Balls/BallBase.cs b/Assets/Scripts/Game/Balls/BallBase.cs index 8ff7966..a890cda 100644 --- a/Assets/Scripts/Game/Balls/BallBase.cs +++ b/Assets/Scripts/Game/Balls/BallBase.cs @@ -16,6 +16,20 @@ public class BallBase : MonoBehaviour 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")) @@ -42,4 +56,139 @@ public class BallBase : MonoBehaviour } } } + + 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(); + 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(); + if (collider2D != null) + { + bounds = collider2D.bounds; + return true; + } + + Renderer renderer = target.GetComponent(); + if (renderer != null) + { + bounds = renderer.bounds; + return true; + } + + Collider collider3D = target.GetComponent(); + if (collider3D != null) + { + bounds = collider3D.bounds; + return true; + } + + bounds = default; + return false; + } } diff --git a/Assets/Scripts/Game/Balls/BasicBall.cs b/Assets/Scripts/Game/Balls/BasicBall.cs index 79fd916..06c148d 100644 --- a/Assets/Scripts/Game/Balls/BasicBall.cs +++ b/Assets/Scripts/Game/Balls/BasicBall.cs @@ -2,13 +2,32 @@ using UnityEngine; public class BasicBall : BallBase { + private Bounds boardBounds; + + private Collider2D selfCollider; + + private bool hasBoardBounds = false; + + // Faster pull keeps the ball on its current board half while magnet is active. + private float magnetBounceDuration = 0.35f; + + // Prevents magnet bounces from reaching the board center line. + private float magnetCenterLeeway = 0.12f; + + private MagnetBounceAxisState xMagnetBounceState; + + private MagnetBounceAxisState yMagnetBounceState; + // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { audioSource = GetComponent(); animator = GetComponent(); + selfCollider = GetComponent(); speed = new Vector2(Random.Range(-0.05f, 0.05f), Random.Range(-0.05f, 0.05f)); + hasBoardBounds = TryCacheGameBoardBounds(out boardBounds); + audioSource.PlayOneShot(spawnSound); } @@ -19,6 +38,35 @@ public class BasicBall : BallBase if (stateInfo.IsName("BasicBallMove")) { transform.Translate(speed); + + if (affectedByMagnet && hasBoardBounds) + { + Vector3 currentPosition = transform.position; + + currentPosition.x = ApplyMagnetBounceAxis( + currentPosition.x, + boardBounds.min.x, + boardBounds.max.x, + magnetActiveLeftRight, + ref xMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.x : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + currentPosition.y = ApplyMagnetBounceAxis( + currentPosition.y, + boardBounds.min.y, + boardBounds.max.y, + magnetActiveTopBottom, + ref yMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.y : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + transform.position = currentPosition; + } } } @@ -32,4 +80,5 @@ public class BasicBall : BallBase speed = Vector2.Reflect(speed, contact.normal); } } + } diff --git a/Assets/Scripts/Game/Balls/EyeBall.cs b/Assets/Scripts/Game/Balls/EyeBall.cs index 5b03162..d99dda8 100644 --- a/Assets/Scripts/Game/Balls/EyeBall.cs +++ b/Assets/Scripts/Game/Balls/EyeBall.cs @@ -4,13 +4,30 @@ public class EyeBall : BallBase { private static float reorientationAngleDegrees = 3f; + private Bounds boardBounds; + + private Collider2D selfCollider; + + private bool hasBoardBounds = false; + + private float magnetBounceDuration = 0.35f; + + private float magnetCenterLeeway = 0.12f; + + private MagnetBounceAxisState xMagnetBounceState; + + private MagnetBounceAxisState yMagnetBounceState; + // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { audioSource = GetComponent(); animator = GetComponent(); + selfCollider = GetComponent(); speed = new Vector2(Random.Range(-0.05f, 0.05f), Random.Range(-0.05f, 0.05f)); + hasBoardBounds = TryCacheGameBoardBounds(out boardBounds); + audioSource.PlayOneShot(spawnSound); } @@ -40,6 +57,35 @@ public class EyeBall : BallBase if (stateInfo.IsName("EyeBallMove")) { transform.Translate(speed); + + if (affectedByMagnet && hasBoardBounds) + { + Vector3 currentPosition = transform.position; + + currentPosition.x = ApplyMagnetBounceAxis( + currentPosition.x, + boardBounds.min.x, + boardBounds.max.x, + magnetActiveLeftRight, + ref xMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.x : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + currentPosition.y = ApplyMagnetBounceAxis( + currentPosition.y, + boardBounds.min.y, + boardBounds.max.y, + magnetActiveTopBottom, + ref yMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.y : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + transform.position = currentPosition; + } } } diff --git a/Assets/Scripts/Game/Balls/FruitBall.cs b/Assets/Scripts/Game/Balls/FruitBall.cs index 25b9a67..3ead3ec 100644 --- a/Assets/Scripts/Game/Balls/FruitBall.cs +++ b/Assets/Scripts/Game/Balls/FruitBall.cs @@ -6,14 +6,31 @@ public class FruitBall : BallBase private float speedIncreaseTimer = 0.0f; + private Bounds boardBounds; + + private Collider2D selfCollider; + + private bool hasBoardBounds = false; + + private float magnetBounceDuration = 0.35f; + + private float magnetCenterLeeway = 0.12f; + + private MagnetBounceAxisState xMagnetBounceState; + + private MagnetBounceAxisState yMagnetBounceState; + // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { audioSource = GetComponent(); animator = GetComponent(); + selfCollider = GetComponent(); speed = new Vector2(Mathf.Sign(Random.Range(-1f, 1f)) * 0.005f, Mathf.Sign(Random.Range(-1f, 1f)) * 0.005f); + hasBoardBounds = TryCacheGameBoardBounds(out boardBounds); + audioSource.PlayOneShot(spawnSound); } @@ -24,6 +41,35 @@ public class FruitBall : BallBase if (stateInfo.IsName("FruitBallMove")) { transform.Translate(speed * speedMultiplier); + + if (affectedByMagnet && hasBoardBounds) + { + Vector3 currentPosition = transform.position; + + currentPosition.x = ApplyMagnetBounceAxis( + currentPosition.x, + boardBounds.min.x, + boardBounds.max.x, + magnetActiveLeftRight, + ref xMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.x : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + currentPosition.y = ApplyMagnetBounceAxis( + currentPosition.y, + boardBounds.min.y, + boardBounds.max.y, + magnetActiveTopBottom, + ref yMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.y : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + transform.position = currentPosition; + } } if (speedIncreaseTimer > 0.0f) diff --git a/Assets/Scripts/Game/Balls/GlassBall.cs b/Assets/Scripts/Game/Balls/GlassBall.cs index 9fffe20..bb3eb82 100644 --- a/Assets/Scripts/Game/Balls/GlassBall.cs +++ b/Assets/Scripts/Game/Balls/GlassBall.cs @@ -15,14 +15,31 @@ public class GlassBall : BallBase private SpriteRenderer spriteRenderer; + private Bounds boardBounds; + + private Collider2D selfCollider; + + private bool hasBoardBounds = false; + + private float magnetBounceDuration = 0.35f; + + private float magnetCenterLeeway = 0.12f; + + private MagnetBounceAxisState xMagnetBounceState; + + private MagnetBounceAxisState yMagnetBounceState; + // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { audioSource = GetComponent(); animator = GetComponent(); spriteRenderer = GetComponent(); + selfCollider = GetComponent(); speed = new Vector2(Random.Range(-0.05f, 0.05f), Random.Range(-0.05f, 0.05f)); + hasBoardBounds = TryCacheGameBoardBounds(out boardBounds); + audioSource.PlayOneShot(spawnSound); } @@ -41,6 +58,35 @@ public class GlassBall : BallBase stateInfo.IsName("GlassBallMove3")) { transform.Translate(speed); + + if (affectedByMagnet && hasBoardBounds) + { + Vector3 currentPosition = transform.position; + + currentPosition.x = ApplyMagnetBounceAxis( + currentPosition.x, + boardBounds.min.x, + boardBounds.max.x, + magnetActiveLeftRight, + ref xMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.x : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + currentPosition.y = ApplyMagnetBounceAxis( + currentPosition.y, + boardBounds.min.y, + boardBounds.max.y, + magnetActiveTopBottom, + ref yMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.y : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + transform.position = currentPosition; + } } } diff --git a/Assets/Scripts/Game/Balls/OozeBall.cs b/Assets/Scripts/Game/Balls/OozeBall.cs index ad7d77a..1bbc1b9 100644 --- a/Assets/Scripts/Game/Balls/OozeBall.cs +++ b/Assets/Scripts/Game/Balls/OozeBall.cs @@ -13,6 +13,20 @@ public class OozeBall : BallBase private SpriteRenderer spriteRenderer; + private Bounds boardBounds; + + private Collider2D selfCollider; + + private bool hasBoardBounds = false; + + private float magnetBounceDuration = 0.35f; + + private float magnetCenterLeeway = 0.12f; + + private MagnetBounceAxisState xMagnetBounceState; + + private MagnetBounceAxisState yMagnetBounceState; + private float splitTimer = 10.0f; private float tickTimer = 0.5f; @@ -23,8 +37,11 @@ public class OozeBall : BallBase audioSource = GetComponent(); animator = GetComponent(); spriteRenderer = GetComponent(); + selfCollider = GetComponent(); speed = new Vector2(Random.Range(-0.05f, 0.05f), Random.Range(-0.05f, 0.05f)); + hasBoardBounds = TryCacheGameBoardBounds(out boardBounds); + audioSource.PlayOneShot(spawnSound); } @@ -35,6 +52,35 @@ public class OozeBall : BallBase if (stateInfo.IsName("OozeBallMove") || stateInfo.IsName("OozeBallSplit")) { transform.Translate(speed); + + if (affectedByMagnet && hasBoardBounds) + { + Vector3 currentPosition = transform.position; + + currentPosition.x = ApplyMagnetBounceAxis( + currentPosition.x, + boardBounds.min.x, + boardBounds.max.x, + magnetActiveLeftRight, + ref xMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.x : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + currentPosition.y = ApplyMagnetBounceAxis( + currentPosition.y, + boardBounds.min.y, + boardBounds.max.y, + magnetActiveTopBottom, + ref yMagnetBounceState, + selfCollider != null ? selfCollider.bounds.extents.y : 0.0f, + magnetBounceDuration, + magnetCenterLeeway + ); + + transform.position = currentPosition; + } } splitTimer -= Time.deltaTime; diff --git a/Assets/Scripts/Game/Player.cs b/Assets/Scripts/Game/Player.cs index 163b5dd..fe76840 100644 --- a/Assets/Scripts/Game/Player.cs +++ b/Assets/Scripts/Game/Player.cs @@ -64,6 +64,8 @@ public class Player : MonoBehaviour public GameObject magnetBottom; + public BallSpawner ballSpawner; + private bool flipped = false; private bool gameOver = false; @@ -233,6 +235,8 @@ public class Player : MonoBehaviour magnetRight.GetComponent().enabled = false; magnetTop.GetComponent().enabled = false; magnetBottom.GetComponent().enabled = false; + + ballSpawner.MagnetInactive(); } } } @@ -393,6 +397,7 @@ public class Player : MonoBehaviour magnetRight.GetComponent().enabled = true; } + ballSpawner.MagnetActive(flipped); DisableMagnet(); } diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 475f457..7bba23c 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 28 + serializedVersion: 29 productGUID: 1f164c2a78e61e58c8fe4990ed305175 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -65,10 +65,15 @@ PlayerSettings: useOSAutorotation: 1 use32BitDisplayBuffer: 1 preserveFramebufferAlpha: 0 + adjustIOSFPSUsingThermalState: 1 + thermalStateSeriousIOSFPS: 30 + thermalStateCriticalIOSFPS: 15 disableDepthAndStencilBuffers: 0 androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 1 androidUseSwappy: 1 + androidRequestedVisibleInsets: 0 + androidSystemBarsBehavior: 2 androidDisplayOptions: 1 androidBlitType: 0 androidResizeableActivity: 1 @@ -172,7 +177,7 @@ PlayerSettings: tvOS: 0 overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 25 + AndroidMinSdkVersion: 26 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 AndroidPreferredDataLocation: 1 @@ -197,6 +202,7 @@ PlayerSettings: tvOSTargetOSVersionString: 15.0 VisionOSSdkVersion: 0 VisionOSTargetOSVersionString: 1.0 + xcodeProjectType: 0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -264,7 +270,6 @@ PlayerSettings: useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 AndroidTargetArchitectures: 2 - AndroidAllowedArchitectures: -13 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: @@ -301,7 +306,10 @@ PlayerSettings: m_Height: 128 m_Kind: 0 m_BuildTargetPlatformIcons: [] - m_BuildTargetBatching: [] + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 m_BuildTargetShaderSettings: [] m_BuildTargetGraphicsJobs: - m_BuildTarget: MacStandaloneSupport @@ -338,7 +346,6 @@ PlayerSettings: - m_BuildTarget: iOSSupport m_APIs: 10000000 m_Automatic: 1 - m_BuildTargetVRSettings: [] m_DefaultShaderChunkSizeInMB: 16 m_DefaultShaderChunkCount: 0 openGLRequireES31: 0 @@ -515,6 +522,8 @@ PlayerSettings: switchMicroSleepForYieldTime: 25 switchRamDiskSpaceSize: 12 switchUpgradedPlayerSettingsToNMETA: 0 + switchCaStoreSource: 0 + switchCaStoreFilePath: ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -631,6 +640,7 @@ PlayerSettings: Android: 1 il2cppCompilerConfiguration: {} il2cppCodeGeneration: {} + il2cppLTOMode: {} il2cppStacktraceInformation: {} managedStrippingLevel: {} incrementalIl2cppBuild: {} @@ -700,7 +710,6 @@ PlayerSettings: XboxOneXTitleMemory: 8 XboxOneOverrideIdentityName: XboxOneOverrideIdentityPublisher: - vrEditorSettings: {} cloudServicesEnabled: {} luminIcon: m_Name: