Interactables documentaiton
This commit is contained in:
573
docs/interactables/code_reference.md
Normal file
573
docs/interactables/code_reference.md
Normal file
@@ -0,0 +1,573 @@
|
||||
# Interactables System - Code Reference
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
2. [Class Hierarchy](#class-hierarchy)
|
||||
3. [InteractableBase - The Template Method](#interactablebase---the-template-method)
|
||||
- [Interaction Flow](#interaction-flow)
|
||||
- [Virtual Methods to Override](#virtual-methods-to-override)
|
||||
4. [Creating Custom Interactables](#creating-custom-interactables)
|
||||
- [Example 1: Simple Button (OneClickInteraction)](#example-1-simple-button-oneclickinteraction)
|
||||
- [Example 2: Item Pickup](#example-2-item-pickup)
|
||||
- [Example 3: Item Slot with Validation](#example-3-item-slot-with-validation)
|
||||
5. [Character Movement](#character-movement)
|
||||
6. [Action Component System](#action-component-system)
|
||||
7. [Events System](#events-system)
|
||||
8. [Save/Load System Integration](#saveload-system-integration)
|
||||
9. [Integration with Puzzle System](#integration-with-puzzle-system)
|
||||
10. [Advanced Patterns](#advanced-patterns)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Simple, centrally orchestrated interaction system for player and follower characters.
|
||||
|
||||
### Core Concepts
|
||||
|
||||
- **Template Method Pattern**: `InteractableBase` defines the interaction flow; subclasses override specific steps
|
||||
- **Action Component System**: Modular actions respond to interaction events independently
|
||||
- **Async/Await Flow**: Character movement and timeline playback use async patterns
|
||||
- **Save/Load Integration**: `SaveableInteractable` provides persistence for interaction state
|
||||
|
||||
---
|
||||
|
||||
## Class Hierarchy
|
||||
|
||||
```
|
||||
ManagedBehaviour
|
||||
└── InteractableBase
|
||||
├── OneClickInteraction
|
||||
└── SaveableInteractable
|
||||
├── Pickup
|
||||
└── ItemSlot
|
||||
```
|
||||
|
||||
### Class Descriptions
|
||||
|
||||
- **InteractableBase** - Abstract base class that orchestrates the complete interaction flow using the Template Method pattern. Handles tap input, character movement, validation, and event dispatching for all interactables.
|
||||
|
||||
- **SaveableInteractable** - Extends InteractableBase with save/load capabilities, integrating with the ManagedBehaviour save system. Provides abstract methods for JSON serialization and deserialization of state.
|
||||
|
||||
- **OneClickInteraction** - Simplest concrete interactable that completes immediately when character arrives with no additional logic. All functionality comes from UnityEvents configured in the Inspector.
|
||||
|
||||
- **Pickup** - Represents items that can be picked up by the follower, handling item combination and state tracking. Integrates with ItemManager and supports bilateral restoration with ItemSlots.
|
||||
|
||||
- **ItemSlot** - Container that accepts specific items with validation for correct/incorrect/forbidden items. Manages item placement, swapping, and supports combination with special puzzle integration that allows swapping when locked.
|
||||
|
||||
---
|
||||
|
||||
## InteractableBase - The Template Method
|
||||
|
||||
### Interaction Flow
|
||||
|
||||
When a player taps an interactable, the following flow executes:
|
||||
|
||||
```csharp
|
||||
OnTap() → CanBeClicked() → StartInteractionFlowAsync()
|
||||
↓
|
||||
1. Find Characters (player, follower)
|
||||
2. OnInteractionStarted() [Virtual Hook]
|
||||
3. Fire interactionStarted events
|
||||
4. MoveCharactersAsync()
|
||||
5. OnInteractingCharacterArrived() [Virtual Hook]
|
||||
6. Fire characterArrived events
|
||||
7. ValidateInteraction()
|
||||
8. DoInteraction() [Virtual Hook - OVERRIDE THIS]
|
||||
9. OnInteractionFinished() [Virtual Hook]
|
||||
10. Fire interactionComplete events
|
||||
```
|
||||
|
||||
### Virtual Methods to Override
|
||||
|
||||
#### 1. `CanBeClicked()` - Pre-Interaction Validation
|
||||
```csharp
|
||||
protected virtual bool CanBeClicked()
|
||||
{
|
||||
if (!isActive) return false;
|
||||
// Add custom checks here
|
||||
return true;
|
||||
}
|
||||
```
|
||||
**When to override:** Add high-level validation before interaction starts (cooldowns, prerequisites, etc.)
|
||||
|
||||
#### 2. `OnInteractionStarted()` - Setup Logic
|
||||
```csharp
|
||||
protected virtual void OnInteractionStarted()
|
||||
{
|
||||
// Called after characters found, before movement
|
||||
// Setup animations, sound effects, etc.
|
||||
}
|
||||
```
|
||||
**When to override:** Perform setup that needs to happen before character movement
|
||||
|
||||
#### 3. `DoInteraction()` - Main Logic ⭐ **OVERRIDE THIS**
|
||||
```csharp
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
// Your interaction logic here
|
||||
return true; // Return true for success, false for failure
|
||||
}
|
||||
```
|
||||
**When to override:** **Always override this** - this is your main interaction logic
|
||||
|
||||
#### 4. `OnInteractingCharacterArrived()` - Arrival Reaction
|
||||
```csharp
|
||||
protected virtual void OnInteractingCharacterArrived()
|
||||
{
|
||||
// Called when character reaches interaction point
|
||||
// Trigger arrival animations, sounds, etc.
|
||||
}
|
||||
```
|
||||
**When to override:** React to character arrival with visuals/audio
|
||||
|
||||
#### 5. `OnInteractionFinished()` - Cleanup Logic
|
||||
```csharp
|
||||
protected virtual void OnInteractionFinished(bool success)
|
||||
{
|
||||
// Called after interaction completes
|
||||
// Cleanup, reset state, etc.
|
||||
}
|
||||
```
|
||||
**When to override:** Perform cleanup after interaction completes
|
||||
|
||||
#### 6. `CanProceedWithInteraction()` - Validation
|
||||
```csharp
|
||||
protected virtual (bool canProceed, string errorMessage) CanProceedWithInteraction()
|
||||
{
|
||||
// Validate if interaction can proceed
|
||||
// Return error message to show to player
|
||||
return (true, null);
|
||||
}
|
||||
```
|
||||
**When to override:** Add validation that shows error messages to player
|
||||
|
||||
---
|
||||
|
||||
## Creating Custom Interactables
|
||||
|
||||
### Example 1: Simple Button (OneClickInteraction)
|
||||
|
||||
The simplest interactable just completes when the character arrives:
|
||||
|
||||
```csharp
|
||||
using Interactions;
|
||||
|
||||
public class OneClickInteraction : InteractableBase
|
||||
{
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
// Simply return success - no additional logic needed
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Use Case:** Triggers, pressure plates, simple activators
|
||||
|
||||
**Configuration:**
|
||||
- Set `characterToInteract` to define which character activates it
|
||||
- Use UnityEvents in inspector to trigger game logic
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Item Pickup
|
||||
|
||||
From `Pickup.cs` - demonstrates validation and follower interaction:
|
||||
|
||||
```csharp
|
||||
public class Pickup : SaveableInteractable
|
||||
{
|
||||
public PickupItemData itemData;
|
||||
public bool IsPickedUp { get; internal set; }
|
||||
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
// Try combination first if follower is holding something
|
||||
var heldItemObject = FollowerController?.GetHeldPickupObject();
|
||||
var heldItemData = heldItemObject?.GetComponent<Pickup>()?.itemData;
|
||||
|
||||
var combinationResult = FollowerController.TryCombineItems(
|
||||
this, out var resultItem
|
||||
);
|
||||
|
||||
if (combinationResult == FollowerController.CombinationResult.Successful)
|
||||
{
|
||||
IsPickedUp = true;
|
||||
FireCombinationEvent(resultItem, heldItemData);
|
||||
return true;
|
||||
}
|
||||
|
||||
// No combination - do regular pickup
|
||||
FollowerController?.TryPickupItem(gameObject, itemData);
|
||||
IsPickedUp = true;
|
||||
OnItemPickedUp?.Invoke(itemData);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Patterns:**
|
||||
- Access `FollowerController` directly (set by base class)
|
||||
- Return `true` for successful pickup
|
||||
- Use custom events (`OnItemPickedUp`) for specific notifications
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Item Slot with Validation
|
||||
|
||||
From `ItemSlot.cs` - demonstrates complex validation and state management:
|
||||
|
||||
```csharp
|
||||
public class ItemSlot : SaveableInteractable
|
||||
{
|
||||
public PickupItemData itemData; // What item should go here
|
||||
private ItemSlotState currentState = ItemSlotState.None;
|
||||
|
||||
protected override (bool canProceed, string errorMessage) CanProceedWithInteraction()
|
||||
{
|
||||
var heldItem = FollowerController?.CurrentlyHeldItemData;
|
||||
|
||||
// Can't interact with empty slot and no item
|
||||
if (heldItem == null && currentlySlottedItemObject == null)
|
||||
return (false, "This requires an item.");
|
||||
|
||||
// Check forbidden items
|
||||
if (heldItem != null && currentlySlottedItemObject == null)
|
||||
{
|
||||
var config = interactionSettings?.GetSlotItemConfig(itemData);
|
||||
var forbidden = config?.forbiddenItems ?? new List<PickupItemData>();
|
||||
|
||||
if (PickupItemData.ListContainsEquivalent(forbidden, heldItem))
|
||||
return (false, "Can't place that here.");
|
||||
}
|
||||
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
var heldItemData = FollowerController.CurrentlyHeldItemData;
|
||||
var heldItemObj = FollowerController.GetHeldPickupObject();
|
||||
|
||||
// Scenario 1: Slot empty + holding item = Slot it
|
||||
if (heldItemData != null && currentlySlottedItemObject == null)
|
||||
{
|
||||
SlotItem(heldItemObj, heldItemData);
|
||||
FollowerController.ClearHeldItem();
|
||||
return IsSlottedItemCorrect(); // Returns true only if correct item
|
||||
}
|
||||
|
||||
// Scenario 2: Slot full + holding item = Try combine or swap
|
||||
if (currentlySlottedItemObject != null)
|
||||
{
|
||||
// Try combination...
|
||||
// Or swap items...
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Patterns:**
|
||||
- `CanProceedWithInteraction()` shows error messages to player
|
||||
- `DoInteraction()` returns true only for correct item (affects puzzle completion)
|
||||
- Access settings via `GameManager.GetSettingsObject<T>()`
|
||||
|
||||
---
|
||||
|
||||
## Character Movement
|
||||
|
||||
### Character Types
|
||||
|
||||
```csharp
|
||||
public enum CharacterToInteract
|
||||
{
|
||||
None, // No character movement
|
||||
Trafalgar, // Player only
|
||||
Pulver, // Follower only (player moves to range first)
|
||||
Both // Both characters move
|
||||
}
|
||||
```
|
||||
|
||||
Set in Inspector on `InteractableBase`.
|
||||
|
||||
### Custom Movement Targets
|
||||
|
||||
Add `CharacterMoveToTarget` component as child of your interactable:
|
||||
|
||||
```csharp
|
||||
// Automatically used if present
|
||||
var moveTarget = GetComponentInChildren<CharacterMoveToTarget>();
|
||||
Vector3 targetPos = moveTarget.GetTargetPosition();
|
||||
```
|
||||
|
||||
See [Editor Reference](editor_reference.md#character-movement-targets) for details.
|
||||
|
||||
---
|
||||
|
||||
## Action Component System
|
||||
|
||||
Add modular behaviors to interactables via `InteractionActionBase` components.
|
||||
|
||||
### Creating an Action Component
|
||||
|
||||
```csharp
|
||||
using Interactions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class MyCustomAction : InteractionActionBase
|
||||
{
|
||||
protected override async Task<bool> ExecuteAsync(
|
||||
InteractionEventType eventType,
|
||||
PlayerTouchController player,
|
||||
FollowerController follower)
|
||||
{
|
||||
// Your action logic here
|
||||
|
||||
if (eventType == InteractionEventType.InteractionStarted)
|
||||
{
|
||||
// Play sound, spawn VFX, etc.
|
||||
await Task.Delay(1000); // Simulate async work
|
||||
}
|
||||
|
||||
return true; // Return success
|
||||
}
|
||||
|
||||
protected override bool ShouldExecute(
|
||||
InteractionEventType eventType,
|
||||
PlayerTouchController player,
|
||||
FollowerController follower)
|
||||
{
|
||||
// Add conditions for when this action should run
|
||||
return base.ShouldExecute(eventType, player, follower);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuring in Inspector
|
||||
|
||||

|
||||
|
||||
- **Respond To Events**: Select which events trigger this action
|
||||
- **Pause Interaction Flow**: If true, interaction waits for this action to complete
|
||||
|
||||
### Built-in Action: Timeline Playback
|
||||
|
||||
`InteractionTimelineAction` plays Unity Timeline sequences in response to events:
|
||||
|
||||
```csharp
|
||||
// Automatically configured via Inspector
|
||||
// See Editor Reference for details
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Character binding to timeline tracks
|
||||
- Sequential timeline playback
|
||||
- Loop options (loop all, loop last)
|
||||
- Timeout protection
|
||||
|
||||
---
|
||||
|
||||
## Events System
|
||||
|
||||
### UnityEvents (Inspector-Configurable)
|
||||
|
||||
Available on all `InteractableBase`:
|
||||
|
||||
```csharp
|
||||
[Header("Interaction Events")]
|
||||
public UnityEvent<PlayerTouchController, FollowerController> interactionStarted;
|
||||
public UnityEvent interactionInterrupted;
|
||||
public UnityEvent characterArrived;
|
||||
public UnityEvent<bool> interactionComplete; // bool = success
|
||||
```
|
||||
|
||||
### C# Events (Code Subscribers)
|
||||
|
||||
Pickup example:
|
||||
```csharp
|
||||
public event Action<PickupItemData> OnItemPickedUp;
|
||||
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
||||
```
|
||||
|
||||
ItemSlot example:
|
||||
```csharp
|
||||
public event Action<PickupItemData> OnItemSlotRemoved;
|
||||
public event Action<PickupItemData, PickupItemData> OnCorrectItemSlotted;
|
||||
public event Action<PickupItemData, PickupItemData> OnIncorrectItemSlotted;
|
||||
```
|
||||
|
||||
### Subscribing to Events
|
||||
|
||||
```csharp
|
||||
void Start()
|
||||
{
|
||||
var pickup = GetComponent<Pickup>();
|
||||
pickup.OnItemPickedUp += HandleItemPickedUp;
|
||||
}
|
||||
|
||||
void HandleItemPickedUp(PickupItemData itemData)
|
||||
{
|
||||
Debug.Log($"Picked up: {itemData.itemName}");
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
var pickup = GetComponent<Pickup>();
|
||||
if (pickup != null)
|
||||
pickup.OnItemPickedUp -= HandleItemPickedUp;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Save/Load System Integration
|
||||
|
||||
### Making an Interactable Saveable
|
||||
|
||||
1. Inherit from `SaveableInteractable` instead of `InteractableBase`
|
||||
2. Define a serializable data structure
|
||||
3. Override `GetSerializableState()` and `ApplySerializableState()`
|
||||
|
||||
### Example Implementation
|
||||
|
||||
```csharp
|
||||
using Interactions;
|
||||
using UnityEngine;
|
||||
|
||||
// 1. Define save data structure
|
||||
[System.Serializable]
|
||||
public class MyInteractableSaveData
|
||||
{
|
||||
public bool hasBeenActivated;
|
||||
public int activationCount;
|
||||
}
|
||||
|
||||
// 2. Inherit from SaveableInteractable
|
||||
public class MyInteractable : SaveableInteractable
|
||||
{
|
||||
private bool hasBeenActivated = false;
|
||||
private int activationCount = 0;
|
||||
|
||||
// 3. Serialize state
|
||||
protected override object GetSerializableState()
|
||||
{
|
||||
return new MyInteractableSaveData
|
||||
{
|
||||
hasBeenActivated = this.hasBeenActivated,
|
||||
activationCount = this.activationCount
|
||||
};
|
||||
}
|
||||
|
||||
// 4. Deserialize state
|
||||
protected override void ApplySerializableState(string serializedData)
|
||||
{
|
||||
var data = JsonUtility.FromJson<MyInteractableSaveData>(serializedData);
|
||||
if (data == null) return;
|
||||
|
||||
this.hasBeenActivated = data.hasBeenActivated;
|
||||
this.activationCount = data.activationCount;
|
||||
|
||||
// IMPORTANT: Don't fire events during restoration
|
||||
// Don't re-run initialization logic
|
||||
}
|
||||
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
hasBeenActivated = true;
|
||||
activationCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
## Integration with Puzzle System
|
||||
|
||||
Interactables can be puzzle steps by adding `ObjectiveStepBehaviour`:
|
||||
|
||||
```csharp
|
||||
// On GameObject with Interactable component
|
||||
var stepBehaviour = gameObject.AddComponent<ObjectiveStepBehaviour>();
|
||||
stepBehaviour.stepData = myPuzzleStepSO;
|
||||
```
|
||||
|
||||
### Automatic Puzzle Integration
|
||||
|
||||
`InteractableBase` automatically checks for puzzle locks:
|
||||
|
||||
```csharp
|
||||
private (bool, string) ValidateInteractionBase()
|
||||
{
|
||||
var step = GetComponent<PuzzleS.ObjectiveStepBehaviour>();
|
||||
if (step != null && !step.IsStepUnlocked())
|
||||
{
|
||||
// Special case: ItemSlots can swap even when locked
|
||||
if (!(this is ItemSlot))
|
||||
{
|
||||
return (false, "This step is locked!");
|
||||
}
|
||||
}
|
||||
return (true, null);
|
||||
}
|
||||
```
|
||||
|
||||
**Result:** Locked puzzle steps can't be interacted with (except ItemSlots for item swapping).
|
||||
|
||||
---
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Async Validation
|
||||
|
||||
For complex validation that requires async operations:
|
||||
|
||||
```csharp
|
||||
protected override (bool canProceed, string errorMessage) CanProceedWithInteraction()
|
||||
{
|
||||
// Synchronous validation only
|
||||
// Async validation should be done in OnInteractionStarted
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
protected override void OnInteractionStarted()
|
||||
{
|
||||
// Can perform async checks here if needed
|
||||
// But interaction flow continues automatically
|
||||
}
|
||||
```
|
||||
|
||||
### Interrupting Interactions
|
||||
|
||||
Interactions auto-interrupt if player cancels movement:
|
||||
|
||||
```csharp
|
||||
// Automatically handled in MoveCharactersAsync()
|
||||
playerRef.OnMoveToCancelled += () => {
|
||||
interactionInterrupted?.Invoke();
|
||||
// Flow stops here
|
||||
};
|
||||
```
|
||||
|
||||
### One-Time Interactions
|
||||
|
||||
```csharp
|
||||
[Header("Interaction Settings")]
|
||||
public bool isOneTime = true;
|
||||
|
||||
// Automatically disabled after first successful interaction
|
||||
// No override needed
|
||||
```
|
||||
|
||||
### Cooldown Systems
|
||||
|
||||
```csharp
|
||||
[Header("Interaction Settings")]
|
||||
public float cooldown = 5f; // Seconds
|
||||
|
||||
// Automatically handled by base class
|
||||
// Interaction disabled for 5 seconds after completion
|
||||
```
|
||||
305
docs/interactables/editor_reference.md
Normal file
305
docs/interactables/editor_reference.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# Interactables System - Editor Reference
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
2. [Adding Interactables to Scene](#adding-interactables-to-scene)
|
||||
3. [InteractableBase Inspector](#interactablebase-inspector)
|
||||
- [Interaction Settings](#interaction-settings)
|
||||
- [Interaction Events](#interaction-events-unityevents)
|
||||
4. [Character Movement Targets](#character-movement-targets)
|
||||
5. [Pickup Inspector](#pickup-inspector)
|
||||
6. [ItemSlot Inspector](#itemslot-inspector)
|
||||
7. [OneClickInteraction Inspector](#oneclickinteraction-inspector)
|
||||
8. [Interaction Action Components](#interaction-action-components)
|
||||
9. [Custom Action Components](#custom-action-components)
|
||||
10. [Puzzle Integration](#puzzle-integration)
|
||||
11. [Save System Configuration](#save-system-configuration)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This guide covers configuring interactables using the Unity Inspector and scene tools. It might be helpful, although
|
||||
not necessary to be familiar with the code architecture covered in the [Code Reference](code_reference.md).
|
||||
|
||||
---
|
||||
|
||||
## Adding Interactables to Scene
|
||||
|
||||
### Method 1: Add Component Manually
|
||||
Select GameObject → Add Component → Search "Interactable" → Choose type
|
||||
|
||||
### Method 2: Use Interactable Editor
|
||||
`AppleHills > Interactable Editor` → Scene tab → Select GameObject → Click button for desired type
|
||||
|
||||
See [Editor Tools Reference](editor_tools_reference.md#interactable-editor) for details.
|
||||
|
||||
---
|
||||
|
||||
## InteractableBase Inspector
|
||||
|
||||

|
||||
|
||||
### Interaction Settings
|
||||
|
||||
**Is One Time** - Disable after first successful interaction (switches, consumables)
|
||||
|
||||
**Cooldown** - Temporarily disable after use, in seconds. `-1` = no cooldown (levers, buttons)
|
||||
|
||||
**Character To Interact** - Which character(s) move to activate:
|
||||
- **None** - No movement, instant interaction
|
||||
- **Trafalgar** - Player moves to point
|
||||
- **Pulver** - Follower moves (player moves to range first)
|
||||
- **Both** - Both characters move
|
||||
|
||||
### Interaction Events (UnityEvents)
|
||||
|
||||

|
||||
|
||||
**Interaction Started** `<PlayerTouchController, FollowerController>` - Fires after tap, before movement
|
||||
|
||||
**Interaction Interrupted** - Player cancels or validation fails
|
||||
|
||||
**Character Arrived** - Character reaches destination
|
||||
|
||||
**Interaction Complete** `<bool>` - After DoInteraction(), bool = success
|
||||
|
||||
### Example Event Configuration
|
||||
|
||||

|
||||
|
||||
**Door that opens when player arrives:**
|
||||
- Character To Interact: `Trafalgar`
|
||||
- Character Arrived: `DoorAnimator.SetTrigger("Open")`, `AudioSource.Play()`
|
||||
- Interaction Complete: `PuzzleStep.CompleteStep()` (if success)
|
||||
|
||||
---
|
||||
|
||||
## Character Movement Targets
|
||||
|
||||
### Default Movement
|
||||
|
||||
Without `CharacterMoveToTarget`, characters move to default distances configured in `GameManager`:
|
||||
- `PlayerStopDistance` - Follower interactions (~1.5 units)
|
||||
- `PlayerStopDistanceDirectInteraction` - Player interactions (~0.5 units)
|
||||
|
||||
### Custom Movement Targets
|
||||
|
||||
Add `CharacterMoveToTarget` component to child GameObject:
|
||||
|
||||

|
||||
|
||||
**Fields:**
|
||||
- **Character Type** - Which character (Trafalgar/Pulver/Both/None)
|
||||
- **Position Offset** - Offset from transform position
|
||||
|
||||
### Scene Gizmos
|
||||
|
||||

|
||||
|
||||
**Colors:** 🔵 Blue (Trafalgar), 🟠 Orange (Pulver), 🟣 Purple (Both), ⚪ Gray (None)
|
||||
|
||||
---
|
||||
|
||||
## Pickup Inspector
|
||||
|
||||

|
||||
|
||||
**Required Fields:**
|
||||
|
||||
**Item Data** - `PickupItemData` ScriptableObject defining the item. Create via `Assets > Create > AppleHills > Items + Puzzles > Pickup Item Data`
|
||||
|
||||
**Icon Renderer** - `SpriteRenderer` displaying item icon (auto-assigned if not set)
|
||||
|
||||
### PickupItemData ScriptableObject
|
||||
|
||||

|
||||
|
||||
**Fields:** Item Name, Description, Map Sprite, Pick Up Sound, Drop Sound
|
||||
|
||||
**Item ID** (Read-Only) - Auto-generated unique identifier for save/load
|
||||
|
||||
---
|
||||
|
||||
## ItemSlot Inspector
|
||||
|
||||

|
||||
|
||||
**Required Fields:**
|
||||
|
||||
**Item Data** - `PickupItemData` defining the **correct** item for this slot
|
||||
|
||||
**Icon Renderer** - `SpriteRenderer` showing slot icon (background/outline)
|
||||
|
||||
**Slotted Item Renderer** - `SpriteRenderer` showing currently slotted item (usually child GameObject)
|
||||
|
||||
### Slot Events
|
||||
|
||||

|
||||
|
||||
**On Item Slotted** - Any item placed
|
||||
**On Item Slot Removed** - Item removed
|
||||
**On Correct Item Slotted** - Correct item placed (also fires `interactionComplete(true)`)
|
||||
**On Incorrect Item Slotted** - Wrong item placed
|
||||
**On Forbidden Item Slotted** - Forbidden item attempted
|
||||
|
||||
|
||||
### Slot Item Configuration (Settings)
|
||||
|
||||

|
||||
|
||||
Configured in `InteractionSettings` at `Assets/Settings/InteractionSettings`:
|
||||
- **Correct Items** - List of accepted items
|
||||
- **Forbidden Items** - Items that can't be placed
|
||||
- **Incorrect Items** - Items that slot but aren't correct
|
||||
|
||||
|
||||
---
|
||||
|
||||
## OneClickInteraction Inspector
|
||||
|
||||

|
||||
|
||||
**No additional fields** - only inherits `InteractableBase` settings.
|
||||
|
||||
### Typical Configuration
|
||||
|
||||
- **Character To Interact:** `Trafalgar` or `Pulver`
|
||||
- **Is One Time:** Depends on use case
|
||||
- **Interaction Complete Event:** Configure to trigger game logic
|
||||
|
||||
### Example Use Cases
|
||||
|
||||
**Pressure Plate:**
|
||||
- Character To Interact: `Pulver`
|
||||
- Is One Time: `false`
|
||||
- Interaction Complete: Call `Door.Open()`
|
||||
|
||||
**Tutorial Trigger:**
|
||||
- Character To Interact: `None`
|
||||
- Is One Time: `true`
|
||||
- Interaction Started: Call `TutorialManager.ShowTip()`
|
||||
|
||||
**Dialogue Starter:**
|
||||
- Character To Interact: `Both`
|
||||
- Is One Time: `false`
|
||||
- Character Arrived: Call `DialogueManager.StartDialogue()`
|
||||
|
||||
---
|
||||
|
||||
## Interaction Action Components
|
||||
|
||||
### InteractionTimelineAction
|
||||
|
||||

|
||||
|
||||
Plays Unity Timeline sequences in response to interaction events.
|
||||
|
||||
#### Required Fields
|
||||
|
||||
**Playable Director**
|
||||
- **Type:** `PlayableDirector` component
|
||||
- **Purpose:** Timeline player
|
||||
- **Setup:** Auto-assigned from same GameObject if present
|
||||
|
||||
**Timeline Mappings** (Array)
|
||||
Each element maps an interaction event to timeline(s):
|
||||
|
||||

|
||||
|
||||
##### Event Type
|
||||
- **Type:** `InteractionEventType` enum
|
||||
- **Options:**
|
||||
- `InteractionStarted`
|
||||
- `PlayerArrived`
|
||||
- `InteractingCharacterArrived`
|
||||
- `InteractionComplete`
|
||||
- `InteractionInterrupted`
|
||||
- **Purpose:** When to play this timeline
|
||||
|
||||
##### Timelines (Array)
|
||||
- **Type:** `PlayableAsset[]`
|
||||
- **Purpose:** Timeline(s) to play for this event
|
||||
- **Note:** Plays sequentially if multiple
|
||||
|
||||
##### Bind Player Character
|
||||
- **Type:** `bool`
|
||||
- **Purpose:** Automatically bind player to timeline track
|
||||
- **Track Name:** `Player` (customizable via Player Track Name field)
|
||||
|
||||
##### Bind Pulver Character
|
||||
- **Type:** `bool`
|
||||
- **Purpose:** Automatically bind follower to timeline track
|
||||
- **Track Name:** `Pulver` (customizable via Pulver Track Name field)
|
||||
|
||||
##### Player Track Name / Pulver Track Name
|
||||
- **Type:** `string`
|
||||
- **Default:** `"Player"` / `"Pulver"`
|
||||
- **Purpose:** Name of timeline track to bind character to
|
||||
- **Note:** Must match track name in Timeline asset exactly
|
||||
|
||||
##### Timeout Seconds
|
||||
- **Type:** `float`
|
||||
- **Default:** `30`
|
||||
- **Purpose:** Safety timeout - auto-complete if timeline doesn't finish
|
||||
- **Use Case:** Prevent stuck interactions if timeline errors
|
||||
|
||||
##### Loop Last / Loop All
|
||||
- **Type:** `bool`
|
||||
- **Purpose:** Loop behavior for timeline sequence
|
||||
- **Loop Last:** Replays final timeline on next interaction
|
||||
- **Loop All:** Cycles through all timelines repeatedly
|
||||
|
||||
---
|
||||
|
||||
## Custom Action Components
|
||||
|
||||
See [Code Reference - Action Component System](code_reference.md#action-component-system).
|
||||
|
||||
**Base Fields:**
|
||||
- **Respond To Events** - Which events trigger this action
|
||||
- **Pause Interaction Flow** - Wait for completion (`true`) or run in background (`false`)
|
||||
|
||||
---
|
||||
|
||||
## Puzzle Integration
|
||||
|
||||
### Adding Puzzle Step to Interactable
|
||||
|
||||
1. Select interactable GameObject
|
||||
2. Add Component → `ObjectiveStepBehaviour`
|
||||
3. Assign `Step Data` (PuzzleStepSO asset)
|
||||
|
||||

|
||||
|
||||
**GameObject has two components:**
|
||||
- **ItemSlot** (or other Interactable type)
|
||||
- **ObjectiveStepBehaviour**
|
||||
|
||||
**Behavior:**
|
||||
- Interactable locked until puzzle step unlocked
|
||||
- Successful interaction (return `true` from `DoInteraction()`) completes puzzle step
|
||||
- ItemSlots can still swap items when locked (special case)
|
||||
|
||||
### Automatic Step Completion
|
||||
|
||||
**For Pickup:**
|
||||
```csharp
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
// ...pickup logic...
|
||||
return true; // Automatically completes puzzle step if present
|
||||
}
|
||||
```
|
||||
|
||||
**For ItemSlot:**
|
||||
```csharp
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
// ...slot logic...
|
||||
return IsSlottedItemCorrect(); // Only completes if correct item
|
||||
}
|
||||
```
|
||||
|
||||
No additional code needed - `InteractableBase` handles step completion automatically.
|
||||
251
docs/interactables/editor_tools_reference.md
Normal file
251
docs/interactables/editor_tools_reference.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Editor Tools Reference
|
||||
|
||||
## Overview
|
||||
|
||||
AppleHills provides two specialized editor tools for managing puzzles and interactables:
|
||||
- **Interactable Editor** - Manage scene interactables and debug interactions
|
||||
- **Puzzle Editor** - Manage puzzle steps and debug puzzle flow
|
||||
|
||||
Both tools are accessible via the `AppleHills` menu and follow a consistent two-tab design pattern for editing and debugging.
|
||||
|
||||
---
|
||||
|
||||
## Interactable Editor
|
||||
|
||||
**Menu:** `AppleHills > Interactable Editor`
|
||||
|
||||
The Interactable Editor provides scene-based management and runtime debugging for interactable objects in your scenes.
|
||||
|
||||
### Edit Tab
|
||||
|
||||

|
||||
|
||||
The Edit tab lets you browse, select, and modify all interactables in the current scene with a real-time inspector.
|
||||
|
||||
#### Left Panel - Scene Interactable List
|
||||
|
||||
**Refresh Button** - Manual refresh (auto-refreshes on scene changes, hierarchy changes, and play mode toggle)
|
||||
|
||||
**Found Count** - Displays total number of interactables found in the active scene
|
||||
|
||||
**Search Field** - Filter interactables by GameObject name for quick access
|
||||
|
||||
**Interactable Cards** - Each card shows:
|
||||
- GameObject name
|
||||
- Interactable component type
|
||||
- Item/Slot data reference (for Pickup and ItemSlot types)
|
||||
- Ping button to highlight in scene hierarchy
|
||||
|
||||
**Auto-Discovery:** Automatically scans for all `InteractableBase` components when:
|
||||
- Scene loads or unloads
|
||||
- GameObjects or components are added/removed
|
||||
- Play mode is toggled
|
||||
|
||||
#### Right Panel - Dynamic Inspector
|
||||
|
||||
The right panel adapts based on what's selected:
|
||||
|
||||
**Nothing Selected State:**
|
||||
- Shows a help message prompting you to select an interactable from the list
|
||||
|
||||
**GameObject Without Interactable State:**
|
||||
- Displays "Add Interactable Component" buttons for:
|
||||
- OneClickInteraction
|
||||
- Pickup
|
||||
- ItemSlot
|
||||
- SaveableInteractable
|
||||
- InteractableBase
|
||||
- Clicking any button adds the component with full undo support and auto-refreshes the list
|
||||
|
||||
**Interactable Selected State:**
|
||||
- Shows full Unity inspector for the selected component
|
||||
- All changes auto-save with undo/redo support (Ctrl+Z / Ctrl+Y)
|
||||
- Additional Information section displays:
|
||||
- Component type
|
||||
- Attached action components with Ping buttons
|
||||
- Type-specific data (Item Data for Pickup, Slot Data for ItemSlot)
|
||||
- In Play Mode: shows slotted object for ItemSlot types
|
||||
|
||||
**Selection Synchronization:**
|
||||
- Bidirectional sync between editor list and scene hierarchy
|
||||
- Selecting in the list highlights in hierarchy and vice versa
|
||||
- Selecting a GameObject without an interactable shows the "Add Component" interface
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
### Debug Tab
|
||||
|
||||
**Availability:** Play Mode only
|
||||
|
||||
The Debug tab provides runtime testing tools for triggering interactions and events on interactables.
|
||||
|
||||
#### Interactable Debug Cards
|
||||
|
||||
Each debug card represents one interactable in the scene and includes:
|
||||
|
||||
**Header Section:**
|
||||
- GameObject name (bold text)
|
||||
- Interactable component type (gray text)
|
||||
- Ping button (locates object in hierarchy)
|
||||
|
||||
**Full Interaction Button:**
|
||||
- Simulates complete `OnTap()` flow
|
||||
- Triggers character movement and full event chain
|
||||
- Tests end-to-end interaction behavior
|
||||
|
||||
**Individual Event Triggers:**
|
||||
- **Started** - Calls `OnInteractionStarted()` and fires `interactionStarted` event
|
||||
- **Arrived** - Calls `OnInteractingCharacterArrived()` and fires `characterArrived` event
|
||||
- **Do Interaction** - Calls `DoInteraction()` directly to test core interaction logic
|
||||
- **Complete (Success)** - Calls `OnInteractionFinished(true)` and triggers puzzle completion
|
||||
- **Complete (Fail)** - Calls `OnInteractionFinished(false)` to test failure handling
|
||||
- **Interrupted** - Invokes `interactionInterrupted` event
|
||||
|
||||
**Registered Actions Display:**
|
||||
- Lists all action components registered to this interactable
|
||||
- Shows which events each action responds to
|
||||
|
||||
#### Common Testing Workflows
|
||||
|
||||
**Test Full Interaction:**
|
||||
1. Enter Play Mode
|
||||
2. Find target interactable in debug list
|
||||
3. Click **Full Interaction** button
|
||||
4. Verify complete behavior chain
|
||||
|
||||
**Test Specific Event:**
|
||||
1. Enter Play Mode
|
||||
2. Locate interactable
|
||||
3. Click individual event button (e.g., **Started** or **Arrived**)
|
||||
4. Verify specific event behavior
|
||||
|
||||
**Test Event Sequence:**
|
||||
1. Click **Started**
|
||||
2. Click **Arrived**
|
||||
3. Click **Do Interaction**
|
||||
4. Click **Complete (Success)**
|
||||
5. Verify full event chain executes correctly
|
||||
|
||||
**Test Action Integration:**
|
||||
1. Find interactable with timeline or dialogue action
|
||||
2. Check Registered Actions to confirm action is attached
|
||||
3. Click **Started** or appropriate event trigger
|
||||
4. Verify action executes (timeline plays, dialogue shows, etc.)
|
||||
|
||||
**Test Puzzle Integration:**
|
||||
1. Open both Interactable Editor and Puzzle Editor
|
||||
2. Verify required puzzle step is unlocked in Puzzle Editor
|
||||
3. Click **Full Interaction** in Interactable Editor
|
||||
4. Switch to Puzzle Editor and verify step marked as completed
|
||||
|
||||
---
|
||||
|
||||
## Puzzle Editor
|
||||
|
||||
**Menu:** `AppleHills > Puzzle Editor`
|
||||
|
||||

|
||||
|
||||
The Puzzle Editor manages puzzle step assets and provides runtime debugging for the puzzle progression system.
|
||||
|
||||
### Edit Tab
|
||||
|
||||
The Edit tab displays all `PuzzleStepSO` assets in your project with full editing capabilities.
|
||||
|
||||
#### Left Panel - Puzzle Step List
|
||||
|
||||
**Search Field** - Filter puzzle steps by name
|
||||
|
||||
**Folder Organization:**
|
||||
- Steps are grouped by their asset folder location
|
||||
- Click folder headers to expand/collapse groups
|
||||
- Helps organize large numbers of puzzle steps
|
||||
|
||||
**Step Cards** - Each card displays:
|
||||
- Display name (user-friendly identifier)
|
||||
- Step ID (unique technical identifier)
|
||||
- Dependency information (unlocked by / unlocks)
|
||||
|
||||
**Toolbar Actions:**
|
||||
- **Refresh** - Reloads all puzzle step assets from project
|
||||
- **Create New** - Opens creation dialog
|
||||
|
||||
**Creating New Steps:**
|
||||
1. Click **Create New** button
|
||||
2. Enter step name (stepId auto-generates from name)
|
||||
3. Select destination folder
|
||||
4. Click Create
|
||||
5. New step appears in list and is auto-selected
|
||||
|
||||
#### Right Panel - Step Inspector
|
||||
|
||||
When a puzzle step is selected, the inspector shows:
|
||||
|
||||
**Basic Properties:**
|
||||
- **Display Name** - Editable user-friendly name for the step
|
||||
- **Step ID** - Read-only unique identifier (lowercase, underscored format)
|
||||
|
||||
**Dependencies Configuration:**
|
||||
- **Unlocked By** - List of steps that must complete before this step unlocks
|
||||
- Drag and drop `PuzzleStepSO` assets to add dependencies
|
||||
- Empty list means this is an initial step (unlocked by default)
|
||||
- **Unlocks** - List of steps that this step will unlock when completed
|
||||
- Bidirectional relationship (automatically syncs with "Unlocked By" on other steps)
|
||||
- Edit from either side of the relationship
|
||||
|
||||
**Asset Management:**
|
||||
- **Asset Path** - Shows full file path to the .asset file
|
||||
- **Delete Button** - Permanently deletes the step asset
|
||||
- Shows confirmation dialog before deletion
|
||||
- Cannot be undone after confirmation
|
||||
|
||||
**Auto-Save:** All changes save automatically to the asset with full undo/redo support (Ctrl+Z / Ctrl+Y)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### Debug Tab
|
||||
|
||||
**Availability:** Play Mode only
|
||||
|
||||
The Debug tab provides runtime testing and debugging tools for the puzzle progression system.
|
||||
|
||||
#### Toolbar
|
||||
|
||||
**Current Level Display:**
|
||||
- Shows the name of the currently loaded puzzle level
|
||||
- Updates automatically when scenes change
|
||||
- Displays "No level loaded" if puzzle system is inactive
|
||||
|
||||
**Unlock All Button:**
|
||||
- Unlocks and completes all puzzle steps in the current level
|
||||
- Processes steps in dependency order using iterative algorithm
|
||||
- Logs progression to console for debugging
|
||||
- Useful for testing late-game content or verifying completion flow
|
||||
|
||||
#### Step List
|
||||
|
||||
Each step in the current level displays:
|
||||
|
||||
**Step Header:**
|
||||
- Display name in bold text
|
||||
- Step ID in gray text below name
|
||||
|
||||
**State Indicators:**
|
||||
- 🔒 **Locked** (gray background) - Dependencies not met, step unavailable
|
||||
- 🔓 **Unlocked** (yellow background) - Available for interaction but not completed
|
||||
- ✅ **Completed** (green background) - Successfully completed
|
||||
|
||||
**Action Buttons:**
|
||||
- **Toggle Lock** - Manually lock/unlock the step
|
||||
- Bypasses normal dependency requirements
|
||||
- Useful for testing specific scenarios
|
||||
- Does not affect dependent steps automatically
|
||||
- **Complete** - Marks step as completed
|
||||
- Only enabled when step is unlocked
|
||||
- Fires completion events
|
||||
- Automatically unlocks dependent steps
|
||||
- Updates state indicators in real-time
|
||||
Reference in New Issue
Block a user