Semi-working Interactables rework
This commit is contained in:
154
Assets/Scripts/Interactions/InteractionOrchestrator.cs
Normal file
154
Assets/Scripts/Interactions/InteractionOrchestrator.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user