Semi-working Interactables rework
This commit is contained in:
@@ -18,3 +18,4 @@ MonoBehaviour:
|
|||||||
- {fileID: 458265635552197097, guid: a77d1e8b2fa8aa945a6f39b312536e0d, type: 3}
|
- {fileID: 458265635552197097, guid: a77d1e8b2fa8aa945a6f39b312536e0d, type: 3}
|
||||||
- {fileID: 552225285624929822, guid: e39992796d5459442be9967c77e27066, type: 3}
|
- {fileID: 552225285624929822, guid: e39992796d5459442be9967c77e27066, type: 3}
|
||||||
- {fileID: 7644433920135100480, guid: 12d242e44fe80ab44af852254b7cab0f, type: 3}
|
- {fileID: 7644433920135100480, guid: 12d242e44fe80ab44af852254b7cab0f, type: 3}
|
||||||
|
- {fileID: 5970756976527527001, guid: eaab28d7e21337b4baef062e2977e616, type: 3}
|
||||||
|
|||||||
46
Assets/Prefabs/Managers/InteractionManager.prefab
Normal file
46
Assets/Prefabs/Managers/InteractionManager.prefab
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &5970756976527527001
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2154246752606426586}
|
||||||
|
- component: {fileID: 5680731486320555959}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: InteractionManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2154246752606426586
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5970756976527527001}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 20.57967, y: 22.03297, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &5680731486320555959
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5970756976527527001}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 705c4ee7f8204cc68aacd79e2a4a506d, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
7
Assets/Prefabs/Managers/InteractionManager.prefab.meta
Normal file
7
Assets/Prefabs/Managers/InteractionManager.prefab.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eaab28d7e21337b4baef062e2977e616
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -868,7 +868,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: c119ffb87b2a16d4f925ff5d5ffd7092, type: 3}
|
m_Script: {fileID: 11500000, guid: c119ffb87b2a16d4f925ff5d5ffd7092, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
ShouldPlayIntro: 1
|
shouldPlayIntro: 0
|
||||||
--- !u!95 &948124911
|
--- !u!95 &948124911
|
||||||
Animator:
|
Animator:
|
||||||
serializedVersion: 7
|
serializedVersion: 7
|
||||||
@@ -1998,6 +1998,10 @@ PrefabInstance:
|
|||||||
propertyPath: heldIconDisplayHeight
|
propertyPath: heldIconDisplayHeight
|
||||||
value: 2
|
value: 2
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 7852204877518954380, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
|
||||||
|
propertyPath: endReachedDistance
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
m_RemovedComponents: []
|
m_RemovedComponents: []
|
||||||
m_RemovedGameObjects: []
|
m_RemovedGameObjects: []
|
||||||
m_AddedGameObjects: []
|
m_AddedGameObjects: []
|
||||||
|
|||||||
3
Assets/Scripts/Characters.meta
Normal file
3
Assets/Scripts/Characters.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 01ee82c489314d60bf27aa9a405f2633
|
||||||
|
timeCreated: 1757513074
|
||||||
11
Assets/Scripts/Characters/Character.cs
Normal file
11
Assets/Scripts/Characters/Character.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for all characters that can interact in the world (e.g., player, follower).
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Character : MonoBehaviour
|
||||||
|
{
|
||||||
|
// Placeholder for shared character logic or properties.
|
||||||
|
// For now, this is intentionally minimal.
|
||||||
|
}
|
||||||
|
|
||||||
3
Assets/Scripts/Characters/Character.cs.meta
Normal file
3
Assets/Scripts/Characters/Character.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9253c7c4ca6946b1b31196c4bf8d685e
|
||||||
|
timeCreated: 1757513074
|
||||||
@@ -157,11 +157,28 @@ public class InputManager : MonoBehaviour
|
|||||||
Collider2D hit = Physics2D.OverlapPoint(worldPos, mask);
|
Collider2D hit = Physics2D.OverlapPoint(worldPos, mask);
|
||||||
if (hit != null)
|
if (hit != null)
|
||||||
{
|
{
|
||||||
var interactable = hit.GetComponent<ITouchInputConsumer>();
|
var interactable = hit.GetComponent<Interactable>();
|
||||||
if (interactable != null)
|
if (interactable != null)
|
||||||
{
|
{
|
||||||
Debug.unityLogger.Log("Interactable", $"[InputManager] Delegating tap to interactable at {worldPos} (GameObject: {hit.gameObject.name})");
|
Debug.unityLogger.Log("Interactable", $"[InputManager] Delegating tap to interactable at {worldPos} (GameObject: {hit.gameObject.name})");
|
||||||
interactable.OnTap(worldPos);
|
// Find the player Character (by tag)
|
||||||
|
var playerObj = GameObject.FindGameObjectWithTag("Player");
|
||||||
|
var playerCharacter = playerObj != null ? playerObj.GetComponent<Character>() : null;
|
||||||
|
if (playerCharacter != null)
|
||||||
|
{
|
||||||
|
InteractionOrchestrator.Instance.RequestInteraction(interactable, playerCharacter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[InputManager] Player Character not found for interaction delegation.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Fallback: support other ITouchInputConsumer implementations
|
||||||
|
var consumer = hit.GetComponent<ITouchInputConsumer>();
|
||||||
|
if (consumer != null)
|
||||||
|
{
|
||||||
|
consumer.OnTap(worldPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Input
|
|||||||
/// Handles player movement in response to tap and hold input events.
|
/// Handles player movement in response to tap and hold input events.
|
||||||
/// Supports both direct and pathfinding movement modes, and provides event/callbacks for arrival/cancellation.
|
/// Supports both direct and pathfinding movement modes, and provides event/callbacks for arrival/cancellation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer
|
public class PlayerTouchController : Character, ITouchInputConsumer
|
||||||
{
|
{
|
||||||
// --- Movement State ---
|
// --- Movement State ---
|
||||||
private Vector3 targetPosition;
|
private Vector3 targetPosition;
|
||||||
|
|||||||
@@ -9,13 +9,6 @@ public class Interactable : MonoBehaviour, ITouchInputConsumer
|
|||||||
public event Action StartedInteraction;
|
public event Action StartedInteraction;
|
||||||
public event Action<bool> InteractionComplete;
|
public event Action<bool> InteractionComplete;
|
||||||
|
|
||||||
private ObjectiveStepBehaviour stepBehaviour;
|
|
||||||
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
stepBehaviour = GetComponent<ObjectiveStepBehaviour>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles tap input. Triggers interaction logic.
|
/// Handles tap input. Triggers interaction logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -25,48 +18,20 @@ public class Interactable : MonoBehaviour, ITouchInputConsumer
|
|||||||
StartedInteraction?.Invoke();
|
StartedInteraction?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// No hold behavior for interactables.
|
||||||
/// No hold behavior for interactables.
|
|
||||||
/// </summary>
|
|
||||||
public void OnHoldStart(Vector2 worldPosition) { }
|
public void OnHoldStart(Vector2 worldPosition) { }
|
||||||
public void OnHoldMove(Vector2 worldPosition) { }
|
public void OnHoldMove(Vector2 worldPosition) { }
|
||||||
public void OnHoldEnd(Vector2 worldPosition) { }
|
public void OnHoldEnd(Vector2 worldPosition) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the follower arrives at this interactable.
|
/// Called to interact with this object by a character (player, follower, etc).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool OnFollowerArrived(FollowerController follower)
|
public virtual void OnInteract(Character character)
|
||||||
{
|
{
|
||||||
// Check if step is locked here
|
// In the new architecture, requirements and step checks will be handled by orchestrator.
|
||||||
if (stepBehaviour != null && !stepBehaviour.IsStepUnlocked())
|
StartedInteraction?.Invoke();
|
||||||
{
|
// For now, immediately complete interaction as success (can be extended later).
|
||||||
DebugUIMessage.Show("Item is not unlocked yet");
|
InteractionComplete?.Invoke(true);
|
||||||
Debug.Log("[Puzzles] Tried to interact with locked step: " + gameObject.name);
|
|
||||||
InteractionComplete?.Invoke(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var requirements = GetComponents<InteractionRequirementBase>();
|
|
||||||
if (requirements.Length == 0)
|
|
||||||
{
|
|
||||||
InteractionComplete?.Invoke(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool anySuccess = false;
|
|
||||||
foreach (var req in requirements)
|
|
||||||
{
|
|
||||||
if (req.TryInteract(follower))
|
|
||||||
{
|
|
||||||
anySuccess = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InteractionComplete?.Invoke(anySuccess);
|
|
||||||
if (!anySuccess)
|
|
||||||
{
|
|
||||||
Debug.Log($"[Interactable] No interaction requirements succeeded for {gameObject.name}");
|
|
||||||
// Optionally trigger a default failure event or feedback here
|
|
||||||
}
|
|
||||||
return anySuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CompleteInteraction(bool success)
|
public void CompleteInteraction(bool success)
|
||||||
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 705c4ee7f8204cc68aacd79e2a4a506d
|
||||||
|
timeCreated: 1757513080
|
||||||
@@ -13,8 +13,6 @@ public class Pickup : MonoBehaviour
|
|||||||
public SpriteRenderer iconRenderer;
|
public SpriteRenderer iconRenderer;
|
||||||
private Interactable interactable;
|
private Interactable interactable;
|
||||||
|
|
||||||
private bool pickupInProgress = false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -98,76 +96,11 @@ public class Pickup : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the start of an interaction (player approaches, then follower picks up).
|
/// Handles the start of an interaction (for feedback/UI only).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnStartedInteraction()
|
private void OnStartedInteraction()
|
||||||
{
|
{
|
||||||
if (pickupInProgress) return;
|
// Optionally, add pickup-specific feedback here (e.g., highlight, sound).
|
||||||
var playerObj = GameObject.FindGameObjectWithTag("Player");
|
|
||||||
var followerObj = GameObject.FindGameObjectWithTag("Pulver");
|
|
||||||
if (playerObj == null || followerObj == null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("Pickup: Player or Follower not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var playerController = playerObj.GetComponent<PlayerTouchController>();
|
|
||||||
var followerController = followerObj.GetComponent<FollowerController>();
|
|
||||||
if (playerController == null || followerController == null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("Pickup: PlayerTouchController or FollowerController missing.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float playerStopDistance = GameManager.Instance.PlayerStopDistance;
|
|
||||||
float followerPickupDelay = GameManager.Instance.FollowerPickupDelay;
|
|
||||||
// --- Local event/coroutine handlers ---
|
|
||||||
void OnPlayerArrived()
|
|
||||||
{
|
|
||||||
playerController.OnArrivedAtTarget -= OnPlayerArrived;
|
|
||||||
playerController.OnMoveToCancelled -= OnPlayerMoveCancelled;
|
|
||||||
pickupInProgress = true;
|
|
||||||
StartCoroutine(DispatchFollower());
|
|
||||||
}
|
|
||||||
void OnPlayerMoveCancelled()
|
|
||||||
{
|
|
||||||
playerController.OnArrivedAtTarget -= OnPlayerArrived;
|
|
||||||
playerController.OnMoveToCancelled -= OnPlayerMoveCancelled;
|
|
||||||
pickupInProgress = false;
|
|
||||||
}
|
|
||||||
System.Collections.IEnumerator DispatchFollower()
|
|
||||||
{
|
|
||||||
yield return new WaitForSeconds(followerPickupDelay);
|
|
||||||
followerController.OnPickupArrived += OnFollowerArrived;
|
|
||||||
followerController.OnPickupReturned += OnFollowerReturned;
|
|
||||||
followerController.GoToPointAndReturn(transform.position, playerObj.transform);
|
|
||||||
}
|
|
||||||
void OnFollowerArrived()
|
|
||||||
{
|
|
||||||
followerController.OnPickupArrived -= OnFollowerArrived;
|
|
||||||
bool interactionSuccess = true;
|
|
||||||
if (interactable != null)
|
|
||||||
{
|
|
||||||
interactionSuccess = interactable.OnFollowerArrived(followerController);
|
|
||||||
}
|
|
||||||
followerController.SetInteractionResult(interactionSuccess);
|
|
||||||
}
|
|
||||||
void OnFollowerReturned()
|
|
||||||
{
|
|
||||||
followerController.OnPickupReturned -= OnFollowerReturned;
|
|
||||||
pickupInProgress = false;
|
|
||||||
}
|
|
||||||
playerController.OnArrivedAtTarget += OnPlayerArrived;
|
|
||||||
playerController.OnMoveToCancelled += OnPlayerMoveCancelled;
|
|
||||||
Vector3 stopPoint = transform.position + (playerObj.transform.position - transform.position).normalized * playerStopDistance;
|
|
||||||
float distToPickup = Vector2.Distance(new Vector2(playerObj.transform.position.x, playerObj.transform.position.y), new Vector2(transform.position.x, transform.position.y));
|
|
||||||
float dist = Vector2.Distance(new Vector2(playerObj.transform.position.x, playerObj.transform.position.y), new Vector2(stopPoint.x, stopPoint.y));
|
|
||||||
if (distToPickup <= playerStopDistance || dist <= 0.2f)
|
|
||||||
{
|
|
||||||
OnPlayerArrived();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
playerController.MoveToAndNotify(stopPoint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -47,14 +47,13 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
SetSlottedObject(obj);
|
SetSlottedObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreSlottedObject(Vector3 position)
|
private void RestoreSlottedObject()
|
||||||
{
|
{
|
||||||
if (_cachedSlottedObject != null)
|
if (_cachedSlottedObject != null)
|
||||||
{
|
{
|
||||||
_cachedSlottedObject.transform.position = position;
|
|
||||||
_cachedSlottedObject.transform.SetParent(null);
|
_cachedSlottedObject.transform.SetParent(null);
|
||||||
_cachedSlottedObject.SetActive(true);
|
// Do NOT activate or move the object here; it stays hidden until dropped
|
||||||
_cachedSlottedObject = null;
|
// Activation is handled by the drop logic elsewhere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +75,10 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
// CASE 1: No held item, slot has item -> pick up slotted item
|
// CASE 1: No held item, slot has item -> pick up slotted item
|
||||||
if (heldItem == null && _cachedSlottedObject != null)
|
if (heldItem == null && _cachedSlottedObject != null)
|
||||||
{
|
{
|
||||||
|
// Give the hidden slotted object to the follower (do NOT activate or move it)
|
||||||
|
RestoreSlottedObject();
|
||||||
follower.SetHeldItemFromObject(_cachedSlottedObject);
|
follower.SetHeldItemFromObject(_cachedSlottedObject);
|
||||||
RemoveSlottedObject();
|
_cachedSlottedObject = null;
|
||||||
currentlySlottedItem = null;
|
currentlySlottedItem = null;
|
||||||
UpdateSlottedSprite();
|
UpdateSlottedSprite();
|
||||||
return true;
|
return true;
|
||||||
@@ -95,7 +96,8 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
currentlySlottedItem = followerHeldItem;
|
currentlySlottedItem = followerHeldItem;
|
||||||
UpdateSlottedSprite();
|
UpdateSlottedSprite();
|
||||||
|
|
||||||
// 2. Give the slot's object to the follower
|
// 2. Give the slot's object to the follower (do NOT activate or move it)
|
||||||
|
RestoreSlottedObject();
|
||||||
follower.SetHeldItemFromObject(slotObj);
|
follower.SetHeldItemFromObject(slotObj);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using Utils;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls the follower character, including following the player, handling pickups, and managing held items.
|
/// Controls the follower character, including following the player, handling pickups, and managing held items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FollowerController : MonoBehaviour
|
public class FollowerController : Character
|
||||||
{
|
{
|
||||||
[Header("Follower Settings")]
|
[Header("Follower Settings")]
|
||||||
public bool debugDrawTarget = true;
|
public bool debugDrawTarget = true;
|
||||||
@@ -457,5 +457,3 @@ public class FollowerController : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user