using System.Collections.Generic; using UnityEngine; public class BasketController : MonoBehaviour { public ScoreManager scoreManager; [SerializeField] private Transform basketHoldPoint; [SerializeField] private LayerMask trickDetectMask = ~0; [SerializeField] private float basketSpawnInterval = 3f; private readonly Collider2D[] overlapHits = new Collider2D[8]; private BoxCollider2D basketCollider; private TrickController currentTrick; private float nextBasketSpawnTime; private void Awake() { basketCollider = GetComponent(); } private void FixedUpdate() { RefreshTricksInBasket(); TryBasketSpawn(); } private void OnCollisionEnter2D(Collision2D collision) { Debug.Log("2D Solid hit with: " + collision.gameObject.name); if (collision.gameObject.CompareTag("Interactable")) { if (collision.gameObject.GetComponent() != null) { RegisterTrick(collision.gameObject); return; } RefreshTricksInBasket(); if (currentTrick != null) { return; } scoreManager.AddPoints(1); GameObject.Destroy(collision.gameObject); } } private void OnCollisionExit2D(Collision2D collision) { UnregisterTrick(collision.gameObject); } private void OnTriggerEnter2D(Collider2D other) { if (!other.CompareTag("Interactable")) { return; } if (other.GetComponent() != null) { RegisterTrick(other.gameObject); } } private void OnTriggerExit2D(Collider2D other) { UnregisterTrick(other.gameObject); } private void RegisterTrick(GameObject obj) { if (obj.TryGetComponent(out var trick)) { if (currentTrick != null && currentTrick != trick) { return; } currentTrick = trick; trick.SetBasketed(true, GetBasketAnchorPosition(trick)); nextBasketSpawnTime = Time.time + basketSpawnInterval; } } private void UnregisterTrick(GameObject obj) { if (obj == null) { return; } if (obj.TryGetComponent(out var trick)) { if (currentTrick == trick) { currentTrick = null; trick.SetBasketed(false); nextBasketSpawnTime = 0f; } } } private void RefreshTricksInBasket() { if (basketCollider == null) { return; } var filter = new ContactFilter2D(); filter.SetLayerMask(trickDetectMask); filter.useTriggers = true; var hitCount = basketCollider.Overlap(filter, overlapHits); for (var i = 0; i < hitCount; i++) { var hit = overlapHits[i]; if (hit == null || !hit.CompareTag("Interactable")) { continue; } if (hit.TryGetComponent(out var trick)) { if (currentTrick == null) { currentTrick = trick; trick.SetBasketed(true, GetBasketAnchorPosition(trick)); nextBasketSpawnTime = Time.time + basketSpawnInterval; } break; } } if (currentTrick == null) { return; } if (currentTrick.IsCarried) { currentTrick.SetBasketed(false); currentTrick = null; nextBasketSpawnTime = 0f; return; } var stillInside = false; for (var i = 0; i < hitCount; i++) { var hit = overlapHits[i]; if (hit == null || !hit.CompareTag("Interactable")) { continue; } if (hit.TryGetComponent(out var trick) && trick == currentTrick) { stillInside = true; break; } } if (!stillInside) { currentTrick.SetBasketed(false); currentTrick = null; nextBasketSpawnTime = 0f; } } private void TryBasketSpawn() { if (currentTrick == null || basketSpawnInterval <= 0f) { return; } if (Time.time < nextBasketSpawnTime) { return; } TrickController.TrySpawnAt(currentTrick.transform.position); nextBasketSpawnTime = Time.time + basketSpawnInterval; } private Vector2? GetBasketAnchorPosition(TrickController trick) { if (basketHoldPoint != null) { return OffsetForTrickHeight(basketHoldPoint.position, trick); } if (basketCollider != null) { return OffsetForTrickHeight(basketCollider.bounds.center, trick); } return null; } private Vector2 OffsetForTrickHeight(Vector2 anchor, TrickController trick) { if (trick == null) { return anchor; } var renderer = trick.GetComponent(); if (renderer == null) { return anchor; } anchor.y += renderer.bounds.size.y * 0.5f; return anchor; } }