using Core; using Minigames.TrashMaze.Core; using UnityEngine; namespace Minigames.TrashMaze.Objects { /// /// Component for objects that need reveal memory (obstacles, booster packs, treasures). /// Tracks if object has been revealed and updates material properties accordingly. /// [RequireComponent(typeof(SpriteRenderer))] public class RevealableObject : MonoBehaviour { [Header("Textures")] [SerializeField] private Sprite normalSprite; [SerializeField] private Sprite outlineSprite; [Header("Object Type")] [SerializeField] private bool isBoosterPack = false; [SerializeField] private bool isExit = false; private SpriteRenderer _spriteRenderer; private Material _instanceMaterial; private bool _hasBeenRevealed = false; private bool _isCollected = false; // Material property IDs (cached for performance) private static readonly int IsRevealedID = Shader.PropertyToID("_IsRevealed"); private static readonly int IsInVisionID = Shader.PropertyToID("_IsInVision"); private void Awake() { _spriteRenderer = GetComponent(); // Create instance material so each object has its own properties if (_spriteRenderer.material != null) { _instanceMaterial = new Material(_spriteRenderer.material); _spriteRenderer.material = _instanceMaterial; } else { Logging.Error($"[RevealableObject] No material assigned to {gameObject.name}"); } } private void Start() { // Initialize material properties if (_instanceMaterial != null) { _instanceMaterial.SetFloat(IsRevealedID, 0f); _instanceMaterial.SetFloat(IsInVisionID, 0f); // Set textures if provided if (normalSprite != null) { _instanceMaterial.SetTexture("_MainTex", normalSprite.texture); } if (outlineSprite != null) { _instanceMaterial.SetTexture("_OutlineTex", outlineSprite.texture); } } } private void Update() { if (_isCollected || _instanceMaterial == null) return; // Calculate distance to player float distance = Vector2.Distance(transform.position, PulverController.PlayerPosition); bool isInRadius = distance < PulverController.VisionRadius; // Update real-time vision flag _instanceMaterial.SetFloat(IsInVisionID, isInRadius ? 1f : 0f); // Set revealed flag (once true, stays true) if (isInRadius && !_hasBeenRevealed) { _hasBeenRevealed = true; _instanceMaterial.SetFloat(IsRevealedID, 1f); Logging.Debug($"[RevealableObject] {gameObject.name} revealed!"); } } private void OnTriggerEnter2D(Collider2D other) { // Check if player is interacting if (other.CompareTag("Player") && _hasBeenRevealed && !_isCollected) { HandleInteraction(); } } private void HandleInteraction() { if (isBoosterPack) { CollectBoosterPack(); } else if (isExit) { ActivateExit(); } } private void CollectBoosterPack() { _isCollected = true; Logging.Debug($"[RevealableObject] Booster pack collected: {gameObject.name}"); // Notify controller if (TrashMazeController.Instance != null) { TrashMazeController.Instance.OnBoosterPackCollected(); } // Destroy object Destroy(gameObject); } private void ActivateExit() { Logging.Debug($"[RevealableObject] Exit activated: {gameObject.name}"); // Notify controller if (TrashMazeController.Instance != null) { TrashMazeController.Instance.OnExitReached(); } } private void OnDestroy() { // Clean up instance material if (_instanceMaterial != null) { Destroy(_instanceMaterial); } } /// /// Check if object is currently visible to player /// public bool IsVisible() { float distance = Vector2.Distance(transform.position, PulverController.PlayerPosition); return distance < PulverController.VisionRadius; } /// /// Check if object has been revealed at any point /// public bool HasBeenRevealed() { return _hasBeenRevealed; } /// /// Force reveal the object (for debugging or special cases) /// public void ForceReveal() { _hasBeenRevealed = true; if (_instanceMaterial != null) { _instanceMaterial.SetFloat(IsRevealedID, 1f); } } } }