using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 5 — Drops a treat somewhere valid, and drops another when it's eaten.
/// Weenie Maze. (Also fine for any "collect the thing that keeps reappearing" game.)
///
/// SETUP
/// 1. Empty GameObject + this script.
/// 2. Treat Prefab: sprite + trigger Collider2D + Tier 1 Collectible (with an ItemType
/// asset like "Treat"). This spawner listens for it being destroyed and makes another.
/// 3. Spawn Area: either
/// - drag in a BoxCollider2D (trigger) covering the play field, or
/// - leave it empty and set Area Size manually (centred on this object).
/// 4. Blocking Layers: walls AND the snake body layer, so treats never appear inside a
/// wall or under the dog. Attempts is how many random cells it tries before giving up.
/// 5. Snap To Grid + Cell Size should match the GridMover so treats land on cell centres.
/// 6. Max Active: 1 for classic snake; more for a maze scattered with treats.
/// </summary>
public class TreatSpawner : MonoBehaviour
{
public GameObject treatPrefab;
public int maxActive = 1;
public float respawnDelay = 0f;
[Header("Area")]
public BoxCollider2D spawnArea;
public Vector2 areaSize = new Vector2(16f, 10f);
[Header("Placement")]
public bool snapToGrid = true;
public float cellSize = 1f;
public LayerMask blockingLayers;
[Tooltip("Keep at least this far from the player when spawning.")]
public float minDistanceFromPlayer = 2f;
public int attempts = 40;
[Header("Events")]
public UnityEvent<Vector3> OnTreatSpawned;
public UnityEvent OnSpawnFailed; // board is full — usually a win!
private readonly List<GameObject> active = new List<GameObject>();
private Transform player;
private float timer;
void Start()
{
var p = GameObject.FindGameObjectWithTag("Player");
if (p != null) player = p.transform;
for (int i = 0; i < maxActive; i++) SpawnOne();
}
void Update()
{
active.RemoveAll(t => t == null);
if (active.Count >= maxActive) return;
timer -= Time.deltaTime;
if (timer <= 0f)
{
SpawnOne();
timer = respawnDelay;
}
}
public void SpawnOne()
{
if (treatPrefab == null) return;
Vector2 centre = spawnArea != null ? (Vector2)spawnArea.bounds.center : (Vector2)transform.position;
Vector2 size = spawnArea != null ? (Vector2)spawnArea.bounds.size : areaSize;
for (int i = 0; i < attempts; i++)
{
Vector2 p = centre + new Vector2(
Random.Range(-size.x * 0.5f, size.x * 0.5f),
Random.Range(-size.y * 0.5f, size.y * 0.5f));
if (snapToGrid)
p = new Vector2(Mathf.Round(p.x / cellSize) * cellSize, Mathf.Round(p.y / cellSize) * cellSize);
if (Physics2D.OverlapBox(p, Vector2.one * cellSize * 0.8f, 0f, blockingLayers) != null) continue;
if (player != null && Vector2.Distance(p, player.position) < minDistanceFromPlayer) continue;
var treat = Instantiate(treatPrefab, p, Quaternion.identity);
active.Add(treat);
OnTreatSpawned?.Invoke(p);
return;
}
OnSpawnFailed?.Invoke();
}
void OnDrawGizmosSelected()
{
Gizmos.color = new Color(1f, 0.9f, 0.3f, 0.4f);
Vector3 c = spawnArea != null ? spawnArea.bounds.center : transform.position;
Vector3 s = spawnArea != null ? spawnArea.bounds.size : (Vector3)areaSize;
Gizmos.DrawWireCube(c, s);
}
}