Files
ggj2026/Assets/Scripts/BasketController.cs
2026-02-01 15:41:21 -06:00

224 lines
5.4 KiB
C#

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<BoxCollider2D>();
}
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<TrickController>() != 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<TrickController>() != null)
{
RegisterTrick(other.gameObject);
}
}
private void OnTriggerExit2D(Collider2D other)
{
UnregisterTrick(other.gameObject);
}
private void RegisterTrick(GameObject obj)
{
if (obj.TryGetComponent<TrickController>(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<TrickController>(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<TrickController>(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<TrickController>(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<SpriteRenderer>();
if (renderer == null)
{
return anchor;
}
anchor.y += renderer.bounds.size.y * 0.5f;
return anchor;
}
}