Files
AppleHillsProduction/Assets/Scripts/Interactions/InteractionOrchestrator.cs

155 lines
5.2 KiB
C#
Raw Normal View History

2025-09-10 16:42:43 +02:00
using System;
using UnityEngine;
/// <summary>
/// Handles the process of moving characters to interactables and orchestrating interactions.
/// </summary>
public class InteractionOrchestrator : MonoBehaviour
{
private static InteractionOrchestrator _instance;
private static bool _isQuitting = false;
// Singleton for easy access (optional, can be replaced with DI or scene reference)
public static InteractionOrchestrator Instance
{
get
{
if (_instance == null && Application.isPlaying && !_isQuitting)
{
_instance = FindAnyObjectByType<InteractionOrchestrator>();
if (_instance == null)
{
var go = new GameObject("InteractionOrchestrator");
_instance = go.AddComponent<InteractionOrchestrator>();
// DontDestroyOnLoad(go);
}
}
return _instance;
}
}
void Awake()
{
_instance = this;
// DontDestroyOnLoad(gameObject);
}
void OnApplicationQuit()
{
_isQuitting = true;
}
// Store pending interaction state
private Interactable _pendingInteractable;
private Input.PlayerTouchController _pendingPlayer;
private FollowerController _pendingFollower;
private bool _interactionInProgress;
/// <summary>
/// Request an interaction between a character and an interactable.
/// </summary>
public void RequestInteraction(Interactable interactable, Character character)
{
// Only support player-initiated interactions for now
if (character is Input.PlayerTouchController player)
{
// Compute closest point on the interaction radius
Vector3 interactablePos = interactable.transform.position;
Vector3 playerPos = player.transform.position;
float stopDistance = GameManager.Instance.PlayerStopDistance;
Vector3 toPlayer = (playerPos - interactablePos).normalized;
Vector3 stopPoint = interactablePos + toPlayer * stopDistance;
// Unsubscribe previous to avoid duplicate calls
player.OnArrivedAtTarget -= OnPlayerArrived;
player.OnArrivedAtTarget += OnPlayerArrived;
_pendingInteractable = interactable;
_pendingPlayer = player;
_pendingFollower = FindFollower();
_interactionInProgress = true;
player.MoveToAndNotify(stopPoint);
}
else
{
// Fallback: immediately interact
OnCharacterArrived(interactable, character);
}
}
// Helper to find the follower in the scene
private FollowerController FindFollower()
{
// Use the recommended Unity API for finding objects
return GameObject.FindFirstObjectByType<FollowerController>();
}
private void OnPlayerArrived()
{
if (!_interactionInProgress || _pendingInteractable == null || _pendingPlayer == null)
return;
// Unsubscribe to avoid memory leaks
_pendingPlayer.OnArrivedAtTarget -= OnPlayerArrived;
// Now dispatch the follower to the interactable
if (_pendingFollower != null)
{
_pendingFollower.OnPickupArrived -= OnFollowerArrived;
_pendingFollower.OnPickupArrived += OnFollowerArrived;
_pendingFollower.GoToPointAndReturn(_pendingInteractable.transform.position, _pendingPlayer.transform);
}
else
{
// No follower found, just interact as player
OnCharacterArrived(_pendingInteractable, _pendingPlayer);
_interactionInProgress = false;
_pendingInteractable = null;
_pendingPlayer = null;
_pendingFollower = null;
}
}
private void OnFollowerArrived()
{
if (!_interactionInProgress || _pendingInteractable == null || _pendingFollower == null)
return;
_pendingFollower.OnPickupArrived -= OnFollowerArrived;
// Now check requirements and interact as follower
OnCharacterArrived(_pendingInteractable, _pendingFollower);
_interactionInProgress = false;
_pendingInteractable = null;
_pendingPlayer = null;
_pendingFollower = null;
}
/// <summary>
/// Called when the character has arrived at the interactable.
/// </summary>
private void OnCharacterArrived(Interactable interactable, Character character)
{
// Check all requirements
var requirements = interactable.GetComponents<InteractionRequirementBase>();
bool allMet = true;
foreach (var req in requirements)
{
// For now, only FollowerController is supported for requirements
// (can be extended to support Player, etc.)
if (character is FollowerController follower)
{
if (!req.TryInteract(follower))
{
allMet = false;
break;
}
}
// Add more character types as needed
}
if (allMet)
{
interactable.OnInteract(character);
}
else
{
interactable.CompleteInteraction(false);
}
}
}