Interactables fully working now
This commit is contained in:
@@ -50,7 +50,7 @@ public class GameManager : MonoBehaviour
|
|||||||
public float ManualMoveSmooth => gameSettings != null ? gameSettings.manualMoveSmooth : 8f;
|
public float ManualMoveSmooth => gameSettings != null ? gameSettings.manualMoveSmooth : 8f;
|
||||||
public float ThresholdFar => gameSettings != null ? gameSettings.thresholdFar : 2.5f;
|
public float ThresholdFar => gameSettings != null ? gameSettings.thresholdFar : 2.5f;
|
||||||
public float ThresholdNear => gameSettings != null ? gameSettings.thresholdNear : 0.5f;
|
public float ThresholdNear => gameSettings != null ? gameSettings.thresholdNear : 0.5f;
|
||||||
public float StopThreshold => gameSettings != null ? gameSettings.stopThreshold : 0.1f;
|
public float StopThreshold => gameSettings != null ? gameSettings.stopThreshold : 0.5f;
|
||||||
public float MoveSpeed => gameSettings != null ? gameSettings.moveSpeed : 5f;
|
public float MoveSpeed => gameSettings != null ? gameSettings.moveSpeed : 5f;
|
||||||
public float StopDistance => gameSettings != null ? gameSettings.stopDistance : 0.1f;
|
public float StopDistance => gameSettings != null ? gameSettings.stopDistance : 0.1f;
|
||||||
public bool UseRigidbody => gameSettings != null ? gameSettings.useRigidbody : true;
|
public bool UseRigidbody => gameSettings != null ? gameSettings.useRigidbody : true;
|
||||||
|
|||||||
3
Assets/Scripts/Data.meta
Normal file
3
Assets/Scripts/Data.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e0b15b90103942c3b0e630462ecc5de1
|
||||||
|
timeCreated: 1757518020
|
||||||
1
Assets/Scripts/Data/ItemCombinationManager.cs
Normal file
1
Assets/Scripts/Data/ItemCombinationManager.cs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
3
Assets/Scripts/Data/ItemCombinationManager.cs.meta
Normal file
3
Assets/Scripts/Data/ItemCombinationManager.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a54fc1a3945f46c580a83e74f9436526
|
||||||
|
timeCreated: 1757518020
|
||||||
@@ -13,7 +13,7 @@ public class CombineWithBehavior : InteractionRequirementBase
|
|||||||
/// <returns>True if the combination was successful, false otherwise.</returns>
|
/// <returns>True if the combination was successful, false otherwise.</returns>
|
||||||
public override bool TryInteract(FollowerController follower)
|
public override bool TryInteract(FollowerController follower)
|
||||||
{
|
{
|
||||||
var heldItem = follower.CurrentlyHeldItem;
|
var heldItem = follower.GetHeldPickupObject();
|
||||||
var pickup = GetComponent<Pickup>();
|
var pickup = GetComponent<Pickup>();
|
||||||
if (heldItem == null)
|
if (heldItem == null)
|
||||||
{
|
{
|
||||||
@@ -27,36 +27,17 @@ public class CombineWithBehavior : InteractionRequirementBase
|
|||||||
OnFailure?.Invoke();
|
OnFailure?.Invoke();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var rule = GameManager.Instance.GetCombinationRule(heldItem, pickup.itemData);
|
var combinedItem = InteractionOrchestrator.Instance.CombineItems(heldItem, pickup.gameObject);
|
||||||
if (rule != null && rule.resultPrefab != null)
|
if (combinedItem != null)
|
||||||
{
|
{
|
||||||
// Instantiate the result prefab at the pickup's position
|
InteractionOrchestrator.Instance.PickupItem(follower, combinedItem);
|
||||||
var resultObj = GameObject.Instantiate(rule.resultPrefab, pickup.transform.position, Quaternion.identity);
|
follower.justCombined = true;
|
||||||
var resultPickup = resultObj.GetComponent<Pickup>();
|
OnSuccess?.Invoke();
|
||||||
if (resultPickup != null)
|
return true;
|
||||||
{
|
|
||||||
// Hide and parent to follower
|
|
||||||
resultObj.SetActive(false);
|
|
||||||
resultObj.transform.SetParent(follower.transform);
|
|
||||||
// Set held item and icon from the spawned prefab
|
|
||||||
follower.SetHeldItem(resultPickup.itemData, resultPickup.iconRenderer);
|
|
||||||
// Cache the spawned object as the held item
|
|
||||||
follower.CacheHeldPickupObject(resultObj);
|
|
||||||
follower.justCombined = true;
|
|
||||||
OnSuccess?.Invoke();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogWarning("Result prefab does not have a Pickup component.");
|
|
||||||
GameObject.Destroy(resultObj);
|
|
||||||
OnFailure?.Invoke();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// DebugUIMessage.Show($"Cannot combine {heldItem.itemName ?? \"an item\"} with {pickup.itemData.itemName ?? \"target item\"}.");
|
// DebugUIMessage.Show($"Cannot combine {follower.CurrentlyHeldItem?.itemName ?? "an item"} with {pickup.itemData.itemName ?? "target item"}.");
|
||||||
OnFailure?.Invoke();
|
OnFailure?.Invoke();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,4 +151,68 @@ public class InteractionOrchestrator : MonoBehaviour
|
|||||||
interactable.CompleteInteraction(false);
|
interactable.CompleteInteraction(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- ITEM MANAGEMENT API ---
|
||||||
|
public void PickupItem(FollowerController follower, GameObject item)
|
||||||
|
{
|
||||||
|
if (item == null || follower == null) return;
|
||||||
|
item.SetActive(false);
|
||||||
|
item.transform.SetParent(null);
|
||||||
|
follower.SetHeldItemFromObject(item);
|
||||||
|
// Optionally: fire event, update UI, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DropItem(FollowerController follower, Vector3 position)
|
||||||
|
{
|
||||||
|
var item = follower.GetHeldPickupObject();
|
||||||
|
if (item == null) return;
|
||||||
|
item.transform.position = position;
|
||||||
|
item.transform.SetParent(null);
|
||||||
|
item.SetActive(true);
|
||||||
|
follower.ClearHeldItem();
|
||||||
|
// Optionally: fire event, update UI, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SlotItem(SlotItemBehavior slot, GameObject item)
|
||||||
|
{
|
||||||
|
if (slot == null || item == null) return;
|
||||||
|
item.SetActive(false);
|
||||||
|
item.transform.SetParent(null);
|
||||||
|
slot.SetSlottedObject(item);
|
||||||
|
// Optionally: update visuals, fire event, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SwapItems(FollowerController follower, SlotItemBehavior slot)
|
||||||
|
{
|
||||||
|
var heldObj = follower.GetHeldPickupObject();
|
||||||
|
var slotObj = slot.GetSlottedObject();
|
||||||
|
// 1. Slot the follower's held object
|
||||||
|
SlotItem(slot, heldObj);
|
||||||
|
// 2. Give the slot's object to the follower
|
||||||
|
PickupItem(follower, slotObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameObject CombineItems(GameObject itemA, GameObject itemB)
|
||||||
|
{
|
||||||
|
if (itemA == null || itemB == null) return null;
|
||||||
|
var pickupA = itemA.GetComponent<Pickup>();
|
||||||
|
var pickupB = itemB.GetComponent<Pickup>();
|
||||||
|
if (pickupA == null || pickupB == null) {
|
||||||
|
if (itemA != null) Destroy(itemA);
|
||||||
|
if (itemB != null) Destroy(itemB);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var rule = GameManager.Instance.GetCombinationRule(pickupA.itemData, pickupB.itemData);
|
||||||
|
Vector3 spawnPos = itemA.transform.position;
|
||||||
|
if (rule != null && rule.resultPrefab != null) {
|
||||||
|
var newItem = Instantiate(rule.resultPrefab, spawnPos, Quaternion.identity);
|
||||||
|
Destroy(itemA);
|
||||||
|
Destroy(itemB);
|
||||||
|
return newItem;
|
||||||
|
}
|
||||||
|
// If no combination found, just destroy both
|
||||||
|
Destroy(itemA);
|
||||||
|
Destroy(itemB);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,12 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
|
|
||||||
private GameObject _cachedSlottedObject = null;
|
private GameObject _cachedSlottedObject = null;
|
||||||
|
|
||||||
// Helper for slotting an object, with option to skip destruction (for swap)
|
public GameObject GetSlottedObject()
|
||||||
private void SetSlottedObject(GameObject obj)
|
{
|
||||||
|
return _cachedSlottedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSlottedObject(GameObject obj)
|
||||||
{
|
{
|
||||||
_cachedSlottedObject = obj;
|
_cachedSlottedObject = obj;
|
||||||
if (_cachedSlottedObject != null)
|
if (_cachedSlottedObject != null)
|
||||||
@@ -31,32 +35,6 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveSlottedObject()
|
|
||||||
{
|
|
||||||
if (_cachedSlottedObject != null)
|
|
||||||
{
|
|
||||||
Destroy(_cachedSlottedObject);
|
|
||||||
_cachedSlottedObject = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CacheSlottedObject(GameObject obj)
|
|
||||||
{
|
|
||||||
// Only destroy if not swapping
|
|
||||||
RemoveSlottedObject();
|
|
||||||
SetSlottedObject(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RestoreSlottedObject()
|
|
||||||
{
|
|
||||||
if (_cachedSlottedObject != null)
|
|
||||||
{
|
|
||||||
_cachedSlottedObject.transform.SetParent(null);
|
|
||||||
// Do NOT activate or move the object here; it stays hidden until dropped
|
|
||||||
// Activation is handled by the drop logic elsewhere
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to interact with the slot, handling slotting, swapping, or picking up items.
|
/// Attempts to interact with the slot, handling slotting, swapping, or picking up items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -75,9 +53,7 @@ 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)
|
InteractionOrchestrator.Instance.PickupItem(follower, _cachedSlottedObject);
|
||||||
RestoreSlottedObject();
|
|
||||||
follower.SetHeldItemFromObject(_cachedSlottedObject);
|
|
||||||
_cachedSlottedObject = null;
|
_cachedSlottedObject = null;
|
||||||
currentlySlottedItem = null;
|
currentlySlottedItem = null;
|
||||||
UpdateSlottedSprite();
|
UpdateSlottedSprite();
|
||||||
@@ -86,20 +62,9 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
// CASE 2: Held item, slot has item -> swap
|
// CASE 2: Held item, slot has item -> swap
|
||||||
if (heldItem != null && _cachedSlottedObject != null)
|
if (heldItem != null && _cachedSlottedObject != null)
|
||||||
{
|
{
|
||||||
var followerHeldObj = heldObj;
|
InteractionOrchestrator.Instance.SwapItems(follower, this);
|
||||||
var followerHeldItem = heldItem;
|
currentlySlottedItem = heldItem;
|
||||||
var slotObj = _cachedSlottedObject;
|
|
||||||
var slotItemData = currentlySlottedItem;
|
|
||||||
|
|
||||||
// 1. Slot the follower's held object (do NOT destroy the old one)
|
|
||||||
SetSlottedObject(followerHeldObj);
|
|
||||||
currentlySlottedItem = followerHeldItem;
|
|
||||||
UpdateSlottedSprite();
|
UpdateSlottedSprite();
|
||||||
|
|
||||||
// 2. Give the slot's object to the follower (do NOT activate or move it)
|
|
||||||
RestoreSlottedObject();
|
|
||||||
follower.SetHeldItemFromObject(slotObj);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// CASE 3: Held item, slot empty -> slot the held item
|
// CASE 3: Held item, slot empty -> slot the held item
|
||||||
@@ -110,7 +75,7 @@ public class SlotItemBehavior : InteractionRequirementBase
|
|||||||
DebugUIMessage.Show("Can't place that here.");
|
DebugUIMessage.Show("Can't place that here.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CacheSlottedObject(heldObj);
|
InteractionOrchestrator.Instance.SlotItem(this, heldObj);
|
||||||
currentlySlottedItem = heldItem;
|
currentlySlottedItem = heldItem;
|
||||||
UpdateSlottedSprite();
|
UpdateSlottedSprite();
|
||||||
follower.ClearHeldItem();
|
follower.ClearHeldItem();
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ public class FollowerController : Character
|
|||||||
if (pickup != null)
|
if (pickup != null)
|
||||||
{
|
{
|
||||||
SetHeldItem(pickup.itemData, pickup.iconRenderer);
|
SetHeldItem(pickup.itemData, pickup.iconRenderer);
|
||||||
CacheHeldPickupObject(obj);
|
_cachedPickupObject = obj;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -335,11 +335,7 @@ public class FollowerController : Character
|
|||||||
|
|
||||||
public void ClearHeldItem()
|
public void ClearHeldItem()
|
||||||
{
|
{
|
||||||
if (_cachedPickupObject != null)
|
_cachedPickupObject = null;
|
||||||
{
|
|
||||||
// Destroy(_cachedPickupObject);
|
|
||||||
_cachedPickupObject = null;
|
|
||||||
}
|
|
||||||
_currentlyHeldItem = null;
|
_currentlyHeldItem = null;
|
||||||
if (heldObjectRenderer != null)
|
if (heldObjectRenderer != null)
|
||||||
{
|
{
|
||||||
@@ -348,6 +344,11 @@ public class FollowerController : Character
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DropHeldItemAt(Vector3 position)
|
||||||
|
{
|
||||||
|
InteractionOrchestrator.Instance.DropItem(this, position);
|
||||||
|
}
|
||||||
|
|
||||||
private System.Collections.IEnumerator PickupSequence(Vector2 itemPosition, Transform playerTransform)
|
private System.Collections.IEnumerator PickupSequence(Vector2 itemPosition, Transform playerTransform)
|
||||||
{
|
{
|
||||||
_isManualFollowing = false;
|
_isManualFollowing = false;
|
||||||
@@ -376,26 +377,21 @@ public class FollowerController : Character
|
|||||||
var slotBehavior = pickup.GetComponent<SlotItemBehavior>();
|
var slotBehavior = pickup.GetComponent<SlotItemBehavior>();
|
||||||
if (slotBehavior != null)
|
if (slotBehavior != null)
|
||||||
{
|
{
|
||||||
// Slot item: do not destroy or swap, just return to player
|
// Slot item: orchestrator handles slotting
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (justCombined)
|
if (justCombined)
|
||||||
{
|
{
|
||||||
GameObject.Destroy(pickup.gameObject);
|
InteractionOrchestrator.Instance.CombineItems(pickup.gameObject, _cachedPickupObject);
|
||||||
justCombined = false;
|
justCombined = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Swap logic: if holding an item, drop it here
|
// Swap logic: if holding an item, drop it here
|
||||||
if (_currentlyHeldItem != null && _cachedPickupObject != null)
|
if (_currentlyHeldItem != null && _cachedPickupObject != null)
|
||||||
{
|
{
|
||||||
// Drop the cached object at the pickup's position
|
InteractionOrchestrator.Instance.DropItem(this, pickup.transform.position);
|
||||||
_cachedPickupObject.transform.position = pickup.transform.position;
|
|
||||||
_cachedPickupObject.transform.SetParent(null);
|
|
||||||
_cachedPickupObject.SetActive(true);
|
|
||||||
_cachedPickupObject = null;
|
|
||||||
}
|
}
|
||||||
SetHeldItem(pickup.itemData, pickup.iconRenderer);
|
InteractionOrchestrator.Instance.PickupItem(this, pickup.gameObject);
|
||||||
CacheHeldPickupObject(pickup.gameObject);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,27 +421,6 @@ public class FollowerController : Character
|
|||||||
_pickupCoroutine = null;
|
_pickupCoroutine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Drop the held item at the specified position, unparenting and activating it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="position">The world position to drop the item at.</param>
|
|
||||||
public void DropHeldItemAt(Vector3 position)
|
|
||||||
{
|
|
||||||
if (_cachedPickupObject != null)
|
|
||||||
{
|
|
||||||
_cachedPickupObject.transform.position = position;
|
|
||||||
_cachedPickupObject.transform.SetParent(null);
|
|
||||||
_cachedPickupObject.SetActive(true);
|
|
||||||
_cachedPickupObject = null;
|
|
||||||
_currentlyHeldItem = null;
|
|
||||||
if (heldObjectRenderer != null)
|
|
||||||
{
|
|
||||||
heldObjectRenderer.sprite = null;
|
|
||||||
heldObjectRenderer.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnDrawGizmos()
|
void OnDrawGizmos()
|
||||||
{
|
{
|
||||||
if (debugDrawTarget && Application.isPlaying)
|
if (debugDrawTarget && Application.isPlaying)
|
||||||
|
|||||||
Reference in New Issue
Block a user