Simple interactable rework
This commit is contained in:
@@ -47,7 +47,7 @@ namespace Interactions
|
||||
Gizmos.DrawSphere(targetPos, 0.2f);
|
||||
|
||||
// Draw a line from the parent interactable to this target
|
||||
Interactable parentInteractable = GetComponentInParent<Interactable>();
|
||||
InteractableBase parentInteractable = GetComponentInParent<InteractableBase>();
|
||||
if (parentInteractable != null)
|
||||
{
|
||||
Gizmos.DrawLine(parentInteractable.transform.position, targetPos);
|
||||
|
||||
@@ -17,9 +17,10 @@ namespace Interactions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an interactable object that can respond to tap input events.
|
||||
/// Base class for interactable objects that can respond to tap input events.
|
||||
/// Subclasses should override OnCharacterArrived() to implement interaction-specific logic.
|
||||
/// </summary>
|
||||
public class Interactable : MonoBehaviour, ITouchInputConsumer
|
||||
public abstract class InteractableBase : MonoBehaviour, ITouchInputConsumer
|
||||
{
|
||||
[Header("Interaction Settings")]
|
||||
public bool isOneTime;
|
||||
@@ -34,8 +35,8 @@ namespace Interactions
|
||||
|
||||
// Helpers for managing interaction state
|
||||
private bool _interactionInProgress;
|
||||
private PlayerTouchController _playerRef;
|
||||
private FollowerController _followerController;
|
||||
protected PlayerTouchController _playerRef;
|
||||
protected FollowerController _followerController;
|
||||
private bool _isActive = true;
|
||||
private InteractionEventType _currentEventType;
|
||||
|
||||
@@ -420,7 +421,7 @@ namespace Interactions
|
||||
if (step != null && !step.IsStepUnlocked() && slot == null)
|
||||
{
|
||||
DebugUIMessage.Show("This step is locked!", Color.yellow);
|
||||
BroadcastInteractionComplete(false);
|
||||
CompleteInteraction(false);
|
||||
// Reset variables for next time
|
||||
_interactionInProgress = false;
|
||||
_playerRef = null;
|
||||
@@ -434,6 +435,9 @@ namespace Interactions
|
||||
// Broadcast appropriate event
|
||||
characterArrived?.Invoke();
|
||||
|
||||
// Call the virtual method for subclasses to override
|
||||
OnCharacterArrived();
|
||||
|
||||
// Reset variables for next time
|
||||
_interactionInProgress = false;
|
||||
_playerRef = null;
|
||||
@@ -441,6 +445,17 @@ namespace Interactions
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the character has arrived at the interaction point.
|
||||
/// Subclasses should override this to implement interaction-specific logic
|
||||
/// and call CompleteInteraction(bool success) when done.
|
||||
/// </summary>
|
||||
protected virtual void OnCharacterArrived()
|
||||
{
|
||||
// Default implementation does nothing - subclasses should override
|
||||
// and call CompleteInteraction when their logic is complete
|
||||
}
|
||||
|
||||
private async void OnInteractionComplete(bool success)
|
||||
{
|
||||
// Dispatch InteractionComplete event
|
||||
@@ -481,11 +496,25 @@ namespace Interactions
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BroadcastInteractionComplete(bool success)
|
||||
/// <summary>
|
||||
/// Call this from subclasses to mark the interaction as complete.
|
||||
/// </summary>
|
||||
/// <param name="success">Whether the interaction was successful</param>
|
||||
protected void CompleteInteraction(bool success)
|
||||
{
|
||||
interactionComplete?.Invoke(success);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Legacy method for backward compatibility. Use CompleteInteraction instead.
|
||||
/// </summary>
|
||||
/// TODO: Remove this method in future versions
|
||||
[Obsolete("Use CompleteInteraction instead")]
|
||||
public void BroadcastInteractionComplete(bool success)
|
||||
{
|
||||
CompleteInteraction(success);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Draws gizmos for pickup interaction range in the editor.
|
||||
|
||||
@@ -18,12 +18,12 @@ namespace Interactions
|
||||
[Tooltip("Whether the interaction flow should wait for this action to complete")]
|
||||
public bool pauseInteractionFlow = true;
|
||||
|
||||
protected Interactable parentInteractable;
|
||||
protected InteractableBase parentInteractable;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
// Get the parent interactable component
|
||||
parentInteractable = GetComponentInParent<Interactable>();
|
||||
parentInteractable = GetComponentInParent<InteractableBase>();
|
||||
|
||||
if (parentInteractable == null)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace Interactions
|
||||
/// <summary>
|
||||
/// Interaction requirement that allows slotting, swapping, or picking up items in a slot.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Interactable))]
|
||||
public class ItemSlot : Pickup
|
||||
{
|
||||
// Tracks the current state of the slotted item
|
||||
@@ -53,7 +52,7 @@ namespace Interactions
|
||||
|
||||
private PickupItemData _currentlySlottedItemData;
|
||||
public SpriteRenderer slottedItemRenderer;
|
||||
private GameObject _currentlySlottedItemObject = null;
|
||||
private GameObject _currentlySlottedItemObject;
|
||||
|
||||
public GameObject GetSlottedObject()
|
||||
{
|
||||
@@ -69,7 +68,7 @@ namespace Interactions
|
||||
}
|
||||
}
|
||||
|
||||
public override void Awake()
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
@@ -82,8 +81,8 @@ namespace Interactions
|
||||
{
|
||||
Logging.Debug("[ItemSlot] OnCharacterArrived");
|
||||
|
||||
var heldItemData = FollowerController.CurrentlyHeldItemData;
|
||||
var heldItemObj = FollowerController.GetHeldPickupObject();
|
||||
var heldItemData = _followerController.CurrentlyHeldItemData;
|
||||
var heldItemObj = _followerController.GetHeldPickupObject();
|
||||
var config = _interactionSettings?.GetSlotItemConfig(itemData);
|
||||
var forbidden = config?.forbiddenItems ?? new List<PickupItemData>();
|
||||
|
||||
@@ -97,7 +96,7 @@ namespace Interactions
|
||||
onForbiddenItemSlotted?.Invoke();
|
||||
OnForbiddenItemSlotted?.Invoke(itemData, heldItemData);
|
||||
_currentState = ItemSlotState.Forbidden;
|
||||
Interactable.BroadcastInteractionComplete(false);
|
||||
CompleteInteraction(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,7 +114,7 @@ namespace Interactions
|
||||
var slottedPickup = _currentlySlottedItemObject?.GetComponent<Pickup>();
|
||||
if (slottedPickup != null)
|
||||
{
|
||||
var comboResult = FollowerController.TryCombineItems(slottedPickup, out var combinationResultItem);
|
||||
var comboResult = _followerController.TryCombineItems(slottedPickup, out var combinationResultItem);
|
||||
if (combinationResultItem != null && comboResult == FollowerController.CombinationResult.Successful)
|
||||
{
|
||||
// Combination succeeded: fire slot-removed events and clear internals (don't call SlotItem to avoid duplicate events)
|
||||
@@ -128,14 +127,14 @@ namespace Interactions
|
||||
_currentlySlottedItemData = null;
|
||||
UpdateSlottedSprite();
|
||||
|
||||
Interactable.BroadcastInteractionComplete(false);
|
||||
CompleteInteraction(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No combination (or not applicable) -> perform normal swap/pickup behavior
|
||||
FollowerController.TryPickupItem(_currentlySlottedItemObject, _currentlySlottedItemData, false);
|
||||
_followerController.TryPickupItem(_currentlySlottedItemObject, _currentlySlottedItemData, false);
|
||||
onItemSlotRemoved?.Invoke();
|
||||
OnItemSlotRemoved?.Invoke(_currentlySlottedItemData);
|
||||
_currentState = ItemSlotState.None;
|
||||
@@ -163,7 +162,6 @@ namespace Interactions
|
||||
float desiredHeight = _playerFollowerSettings?.HeldIconDisplayHeight ?? 2.0f;
|
||||
var sprite = _currentlySlottedItemData.mapSprite;
|
||||
float spriteHeight = sprite.bounds.size.y;
|
||||
float spriteWidth = sprite.bounds.size.x;
|
||||
Vector3 parentScale = slottedItemRenderer.transform.parent != null
|
||||
? slottedItemRenderer.transform.parent.localScale
|
||||
: Vector3.one;
|
||||
@@ -209,7 +207,7 @@ namespace Interactions
|
||||
|
||||
if (clearFollowerHeldItem)
|
||||
{
|
||||
FollowerController.ClearHeldItem();
|
||||
_followerController.ClearHeldItem();
|
||||
}
|
||||
UpdateSlottedSprite();
|
||||
|
||||
@@ -227,7 +225,7 @@ namespace Interactions
|
||||
_currentState = ItemSlotState.Correct;
|
||||
}
|
||||
|
||||
Interactable.BroadcastInteractionComplete(true);
|
||||
CompleteInteraction(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -238,18 +236,23 @@ namespace Interactions
|
||||
OnIncorrectItemSlotted?.Invoke(itemData, _currentlySlottedItemData);
|
||||
_currentState = ItemSlotState.Incorrect;
|
||||
}
|
||||
Interactable.BroadcastInteractionComplete(false);
|
||||
CompleteInteraction(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Register with ItemManager when enabled
|
||||
void Start()
|
||||
{
|
||||
// Note: Base Pickup class also calls RegisterPickup in its Start
|
||||
// This additionally registers as ItemSlot
|
||||
ItemManager.Instance?.RegisterPickup(this);
|
||||
ItemManager.Instance?.RegisterItemSlot(this);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Unregister from both pickup and slot managers
|
||||
ItemManager.Instance?.UnregisterPickup(this);
|
||||
ItemManager.Instance?.UnregisterItemSlot(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,21 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using Input;
|
||||
using Interactions;
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour that immediately completes an interaction when started.
|
||||
/// </summary>
|
||||
public class OneClickInteraction : MonoBehaviour
|
||||
namespace Interactions
|
||||
{
|
||||
private Interactable interactable;
|
||||
|
||||
void Awake()
|
||||
/// <summary>
|
||||
/// Interactable that immediately completes when the character arrives at the interaction point.
|
||||
/// Useful for simple trigger interactions that don't require additional logic.
|
||||
/// </summary>
|
||||
public class OneClickInteraction : InteractableBase
|
||||
{
|
||||
interactable = GetComponent<Interactable>();
|
||||
if (interactable != null)
|
||||
/// <summary>
|
||||
/// Override: Immediately completes the interaction with success when character arrives.
|
||||
/// </summary>
|
||||
protected override void OnCharacterArrived()
|
||||
{
|
||||
interactable.interactionStarted.AddListener(OnInteractionStarted);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (interactable != null)
|
||||
{
|
||||
interactable.interactionStarted.RemoveListener(OnInteractionStarted);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteractionStarted(PlayerTouchController playerRef, FollowerController followerRef)
|
||||
{
|
||||
if (interactable != null)
|
||||
{
|
||||
interactable.BroadcastInteractionComplete(true);
|
||||
CompleteInteraction(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,10 @@ using Core; // register with ItemManager
|
||||
|
||||
namespace Interactions
|
||||
{
|
||||
[RequireComponent(typeof(Interactable))]
|
||||
public class Pickup : MonoBehaviour
|
||||
public class Pickup : InteractableBase
|
||||
{
|
||||
public PickupItemData itemData;
|
||||
public SpriteRenderer iconRenderer;
|
||||
protected Interactable Interactable;
|
||||
private PlayerTouchController _playerRef;
|
||||
protected FollowerController FollowerController;
|
||||
|
||||
// Track if the item has been picked up
|
||||
public bool isPickedUp { get; private set; }
|
||||
@@ -24,19 +20,12 @@ namespace Interactions
|
||||
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
||||
|
||||
/// <summary>
|
||||
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
||||
/// Unity Awake callback. Sets up icon and applies item data.
|
||||
/// </summary>
|
||||
public virtual void Awake()
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (iconRenderer == null)
|
||||
iconRenderer = GetComponent<SpriteRenderer>();
|
||||
|
||||
Interactable = GetComponent<Interactable>();
|
||||
if (Interactable != null)
|
||||
{
|
||||
Interactable.interactionStarted.AddListener(OnInteractionStarted);
|
||||
Interactable.characterArrived.AddListener(OnCharacterArrived);
|
||||
}
|
||||
|
||||
ApplyItemData();
|
||||
}
|
||||
@@ -50,16 +39,10 @@ namespace Interactions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unity OnDestroy callback. Cleans up event handlers.
|
||||
/// Unity OnDestroy callback. Unregisters from ItemManager.
|
||||
/// </summary>
|
||||
void OnDestroy()
|
||||
{
|
||||
if (Interactable != null)
|
||||
{
|
||||
Interactable.interactionStarted.RemoveListener(OnInteractionStarted);
|
||||
Interactable.characterArrived.RemoveListener(OnCharacterArrived);
|
||||
}
|
||||
|
||||
// Unregister from ItemManager
|
||||
ItemManager.Instance?.UnregisterPickup(this);
|
||||
}
|
||||
@@ -76,6 +59,7 @@ namespace Interactions
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Applies the item data to the pickup (icon, name, etc).
|
||||
/// </summary>
|
||||
@@ -93,22 +77,17 @@ namespace Interactions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the start of an interaction (for feedback/UI only).
|
||||
/// Override: Called when character arrives at the interaction point.
|
||||
/// Handles item pickup and combination logic.
|
||||
/// </summary>
|
||||
private void OnInteractionStarted(PlayerTouchController playerRef, FollowerController followerRef)
|
||||
{
|
||||
_playerRef = playerRef;
|
||||
FollowerController = followerRef;
|
||||
}
|
||||
|
||||
protected virtual void OnCharacterArrived()
|
||||
protected override void OnCharacterArrived()
|
||||
{
|
||||
Logging.Debug("[Pickup] OnCharacterArrived");
|
||||
|
||||
var combinationResult = FollowerController.TryCombineItems(this, out var combinationResultItem);
|
||||
var combinationResult = _followerController.TryCombineItems(this, out var combinationResultItem);
|
||||
if (combinationResultItem != null)
|
||||
{
|
||||
Interactable.BroadcastInteractionComplete(true);
|
||||
CompleteInteraction(true);
|
||||
|
||||
// Fire the combination event when items are successfully combined
|
||||
if (combinationResult == FollowerController.CombinationResult.Successful)
|
||||
@@ -118,7 +97,7 @@ namespace Interactions
|
||||
{
|
||||
// Get the combined item data
|
||||
var resultItemData = resultPickup.itemData;
|
||||
var heldItem = FollowerController.GetHeldPickupObject();
|
||||
var heldItem = _followerController.GetHeldPickupObject();
|
||||
|
||||
if (heldItem != null)
|
||||
{
|
||||
@@ -135,18 +114,18 @@ namespace Interactions
|
||||
return;
|
||||
}
|
||||
|
||||
FollowerController?.TryPickupItem(gameObject, itemData);
|
||||
_followerController?.TryPickupItem(gameObject, itemData);
|
||||
|
||||
var step = GetComponent<PuzzleS.ObjectiveStepBehaviour>();
|
||||
if (step != null && !step.IsStepUnlocked())
|
||||
{
|
||||
Interactable.BroadcastInteractionComplete(false);
|
||||
CompleteInteraction(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasPickedUp = (combinationResult == FollowerController.CombinationResult.NotApplicable
|
||||
|| combinationResult == FollowerController.CombinationResult.Unsuccessful);
|
||||
Interactable.BroadcastInteractionComplete(wasPickedUp);
|
||||
CompleteInteraction(wasPickedUp);
|
||||
|
||||
// Update pickup state and invoke event when the item was picked up successfully
|
||||
if (wasPickedUp)
|
||||
|
||||
Reference in New Issue
Block a user