Create a simple dialogue authoring system, tied into our items (#10)

- Editor dialogue graph
- Asset importer for processing the graph into runtime data
- DialogueComponent that steers the dialogue interactions
- DialogueCanbas with a scalable speech bubble to display everything
- Brief README overview of the system

Co-authored-by: AlexanderT <alexander@foolhardyhorizons.com>
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com>
Reviewed-on: #10
This commit is contained in:
2025-09-29 09:34:15 +00:00
parent 2cd791f69d
commit f686f28cb8
73 changed files with 6530 additions and 173 deletions

View File

@@ -1,20 +1,51 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System; // for Action<T>
using Core; // register with ItemManager
namespace Interactions
{
// New enum describing possible states for the slotted item
public enum ItemSlotState
{
None,
Correct,
Incorrect,
Forbidden
}
/// <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
private ItemSlotState _currentState = ItemSlotState.None;
/// <summary>
/// Read-only access to the current slotted item state.
/// </summary>
public ItemSlotState CurrentSlottedState => _currentState;
public UnityEvent onItemSlotted;
public UnityEvent onItemSlotRemoved;
// Native C# event alternative for code-only subscribers
public event Action<PickupItemData> OnItemSlotRemoved;
public UnityEvent onCorrectItemSlotted;
// Native C# event alternative to the UnityEvent for code-only subscribers
public event Action<PickupItemData, PickupItemData> OnCorrectItemSlotted;
public UnityEvent onIncorrectItemSlotted;
// Native C# event alternative for code-only subscribers
public event Action<PickupItemData, PickupItemData> OnIncorrectItemSlotted;
public UnityEvent onForbiddenItemSlotted;
// Native C# event alternative for code-only subscribers
public event Action<PickupItemData, PickupItemData> OnForbiddenItemSlotted;
private PickupItemData _currentlySlottedItemData;
public SpriteRenderer slottedItemRenderer;
private GameObject _currentlySlottedItemObject = null;
@@ -35,6 +66,8 @@ namespace Interactions
protected override void OnCharacterArrived()
{
Debug.Log("[ItemSlot] OnCharacterArrived");
var heldItemData = FollowerController.CurrentlyHeldItemData;
var heldItemObj = FollowerController.GetHeldPickupObject();
var config = GameManager.Instance.GetSlotItemConfig(itemData);
@@ -48,6 +81,8 @@ namespace Interactions
{
DebugUIMessage.Show("Can't place that here.", Color.red);
onForbiddenItemSlotted?.Invoke();
OnForbiddenItemSlotted?.Invoke(itemData, heldItemData);
_currentState = ItemSlotState.Forbidden;
Interactable.BroadcastInteractionComplete(false);
return;
}
@@ -62,6 +97,8 @@ namespace Interactions
{
FollowerController.TryPickupItem(_currentlySlottedItemObject, _currentlySlottedItemData, false);
onItemSlotRemoved?.Invoke();
OnItemSlotRemoved?.Invoke(_currentlySlottedItemData);
_currentState = ItemSlotState.None;
SlotItem(heldItemObj, heldItemData, _currentlySlottedItemObject == null);
return;
}
@@ -105,10 +142,22 @@ namespace Interactions
public void SlotItem(GameObject itemToSlot, PickupItemData itemToSlotData, bool clearFollowerHeldItem = true)
{
// Cache the previous item data before clearing, needed for OnItemSlotRemoved event
var previousItemData = _currentlySlottedItemData;
bool wasSlotCleared = _currentlySlottedItemObject != null && itemToSlot == null;
if (itemToSlot == null)
{
_currentlySlottedItemObject = null;
_currentlySlottedItemData = null;
// Clear state when no item is slotted
_currentState = ItemSlotState.None;
// Fire native event for slot clearing
if (wasSlotCleared)
{
OnItemSlotRemoved?.Invoke(previousItemData);
}
}
else
{
@@ -117,6 +166,7 @@ namespace Interactions
SetSlottedObject(itemToSlot);
_currentlySlottedItemData = itemToSlotData;
}
if (clearFollowerHeldItem)
{
FollowerController.ClearHeldItem();
@@ -133,6 +183,8 @@ namespace Interactions
{
DebugUIMessage.Show("You correctly slotted " + itemToSlotData.itemName + " into: " + itemData.itemName, Color.green);
onCorrectItemSlotted?.Invoke();
OnCorrectItemSlotted?.Invoke(itemData, _currentlySlottedItemData);
_currentState = ItemSlotState.Correct;
}
Interactable.BroadcastInteractionComplete(true);
@@ -143,9 +195,22 @@ namespace Interactions
{
DebugUIMessage.Show("I'm not sure this works.", Color.yellow);
onIncorrectItemSlotted?.Invoke();
OnIncorrectItemSlotted?.Invoke(itemData, _currentlySlottedItemData);
_currentState = ItemSlotState.Incorrect;
}
Interactable.BroadcastInteractionComplete(false);
}
}
// Register with ItemManager when enabled
void Start()
{
ItemManager.Instance?.RegisterItemSlot(this);
}
void OnDestroy()
{
ItemManager.Instance?.UnregisterItemSlot(this);
}
}
}