这是第一个 Unity 开放项目的repo,是 Unity 和社区合作创建的一个小型开源游戏演示,第一款游戏是一款名为 Chop Chop 的动作冒险游戏。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

163 行
4.6 KiB

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public enum InteractionType { None = 0, PickUp, Cook, Talk };
public class InteractionManager : MonoBehaviour
{
[SerializeField] private InputReader _inputReader = default;
//Events for the different interaction types
[Header("Broadcasting on")]
[SerializeField] private ItemEventChannelSO _onObjectPickUp = default;
[SerializeField] private VoidEventChannelSO _onCookingStart = default;
[SerializeField] private DialogueActorChannelSO _startTalking = default;
[SerializeField] private InteractionUIEventChannelSO _toggleInteractionUI = default;
[Header("Listening to")]
[SerializeField] private VoidEventChannelSO _onInteractionEnded = default;
[SerializeField] private PlayableDirectorChannelSO _onCutsceneStart = default;
[ReadOnly] public InteractionType currentInteractionType; //This is checked/consumed by conditions in the StateMachine
private LinkedList<Interaction> _potentialInteractions = new LinkedList<Interaction>(); //To store the objects we the player could potentially interact with
private void OnEnable()
{
_inputReader.InteractEvent += OnInteractionButtonPress;
_onInteractionEnded.OnEventRaised += OnInteractionEnd;
_onCutsceneStart.OnEventRaised += ResetPotentialInteractions;
}
private void OnDisable()
{
_inputReader.InteractEvent -= OnInteractionButtonPress;
_onInteractionEnded.OnEventRaised -= OnInteractionEnd;
_onCutsceneStart.OnEventRaised -= ResetPotentialInteractions;
}
// Called mid-way through the AnimationClip of collecting
private void Collect()
{
GameObject itemObject = _potentialInteractions.First.Value.interactableObject;
_potentialInteractions.RemoveFirst();
if (_onObjectPickUp != null)
{
ItemSO currentItem = itemObject.GetComponent<CollectableItem>().GetItem();
_onObjectPickUp.RaiseEvent(currentItem);
}
Destroy(itemObject); //TODO: maybe move this destruction in a more general manger, to implement a removal SFX
RequestUpdateUI(false);
}
private void OnInteractionButtonPress()
{
if (_potentialInteractions.Count == 0)
return;
currentInteractionType = _potentialInteractions.First.Value.type;
switch (_potentialInteractions.First.Value.type)
{
case InteractionType.Cook:
if (_onCookingStart != null)
{
_onCookingStart.RaiseEvent();
_inputReader.EnableMenuInput();
}
break;
case InteractionType.Talk:
if (_startTalking != null)
{
_potentialInteractions.First.Value.interactableObject.GetComponent<StepController>().InteractWithCharacter();
_inputReader.EnableDialogueInput();
}
break;
//No need to do anything for Pickup type, the StateMachine will transition to the state
//and then the AnimationClip will call Collect()
}
}
//Called by the Event on the trigger collider on the child GO called "InteractionDetector"
public void OnTriggerChangeDetected(bool entered, GameObject obj)
{
if (entered)
AddPotentialInteraction(obj);
else
RemovePotentialInteraction(obj);
}
private void AddPotentialInteraction(GameObject obj)
{
Interaction newPotentialInteraction = new Interaction(InteractionType.None, obj);
if (obj.CompareTag("Pickable"))
{
newPotentialInteraction.type = InteractionType.PickUp;
}
else if (obj.CompareTag("CookingPot"))
{
newPotentialInteraction.type = InteractionType.Cook;
}
else if (obj.CompareTag("NPC"))
{
newPotentialInteraction.type = InteractionType.Talk;
}
if (newPotentialInteraction.type != InteractionType.None)
{
_potentialInteractions.AddFirst(newPotentialInteraction);
RequestUpdateUI(true);
}
}
private void RemovePotentialInteraction(GameObject obj)
{
LinkedListNode<Interaction> currentNode = _potentialInteractions.First;
while (currentNode != null)
{
if (currentNode.Value.interactableObject == obj)
{
_potentialInteractions.Remove(currentNode);
break;
}
currentNode = currentNode.Next;
}
RequestUpdateUI(_potentialInteractions.Count > 0);
}
private void RequestUpdateUI(bool visible)
{
if (visible)
_toggleInteractionUI.RaiseEvent(true, _potentialInteractions.First.Value.type);
else
_toggleInteractionUI.RaiseEvent(false, InteractionType.None);
}
private void OnInteractionEnd()
{
switch (currentInteractionType)
{
case InteractionType.Cook:
case InteractionType.Talk:
//We show the UI after cooking or talking, in case player wants to interact again
RequestUpdateUI(true);
break;
}
_inputReader.EnableGameplayInput();
}
private void ResetPotentialInteractions(PlayableDirector _playableDirector)
{
_potentialInteractions.Clear();
RequestUpdateUI(_potentialInteractions.Count > 0);
}
}