2026-06-19 UI, UI로직
This commit is contained in:
29
Assets/My project/Dialogue Scripts/UI/ChoiceData.cs
Normal file
29
Assets/My project/Dialogue Scripts/UI/ChoiceData.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
[System.Serializable]
|
||||
public class ChoiceData
|
||||
{
|
||||
[Header("Choice Text")]
|
||||
[TextArea(1, 2)]
|
||||
public string choiceText;
|
||||
|
||||
[Header("Branch To Another Dialogue")]
|
||||
[Tooltip("다른 DialogueData로 이동합니다. 이 값이 있으면 nextNodeId, nextNodeIndex보다 우선됩니다.")]
|
||||
public DialogueData nextDialogue;
|
||||
|
||||
[Header("Branch Inside Current Dialogue")]
|
||||
[Tooltip("현재 DialogueData 안에서 이동할 노드 ID입니다.")]
|
||||
public string nextNodeId;
|
||||
|
||||
[Tooltip("-1이면 사용하지 않습니다. 현재 DialogueData 안에서 특정 노드 번호로 이동합니다.")]
|
||||
public int nextNodeIndex = -1;
|
||||
|
||||
[Header("End")]
|
||||
[Tooltip("이 선택지를 누르면 대화를 종료합니다.")]
|
||||
public bool endDialogue;
|
||||
|
||||
[Header("Optional Event")]
|
||||
[Tooltip("선택지를 눌렀을 때 실행할 이벤트입니다. 퀘스트 시작, 아이템 지급 등에 사용할 수 있습니다.")]
|
||||
public UnityEvent onSelected;
|
||||
}
|
||||
2
Assets/My project/Dialogue Scripts/UI/ChoiceData.cs.meta
Normal file
2
Assets/My project/Dialogue Scripts/UI/ChoiceData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00c80393d9221c543af1f245de1c40fc
|
||||
65
Assets/My project/Dialogue Scripts/UI/DialogueBillboard.cs
Normal file
65
Assets/My project/Dialogue Scripts/UI/DialogueBillboard.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class DialogueBillboard : MonoBehaviour
|
||||
{
|
||||
[Header("Target")]
|
||||
[SerializeField] private Transform target;
|
||||
[SerializeField] private Camera targetCamera;
|
||||
|
||||
[Header("Position")]
|
||||
[SerializeField] private Vector3 offset = new Vector3(0f, 2f, 0f);
|
||||
|
||||
[Header("Look At Camera")]
|
||||
[SerializeField] private bool faceCamera = true;
|
||||
[SerializeField] private bool lockYAxis = false;
|
||||
[SerializeField] private bool rotate180AfterLookAt = true;
|
||||
|
||||
public Transform Target => target;
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
transform.position = target.position + offset;
|
||||
|
||||
if (!faceCamera)
|
||||
return;
|
||||
|
||||
if (targetCamera == null)
|
||||
targetCamera = Camera.main;
|
||||
|
||||
if (targetCamera == null)
|
||||
return;
|
||||
|
||||
Vector3 lookPosition = targetCamera.transform.position;
|
||||
|
||||
if (lockYAxis)
|
||||
lookPosition.y = transform.position.y;
|
||||
|
||||
transform.LookAt(lookPosition);
|
||||
|
||||
if (rotate180AfterLookAt)
|
||||
transform.Rotate(0f, 180f, 0f);
|
||||
}
|
||||
|
||||
public void SetTarget(Transform newTarget)
|
||||
{
|
||||
target = newTarget;
|
||||
}
|
||||
|
||||
public void ClearTarget()
|
||||
{
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void SetCamera(Camera newCamera)
|
||||
{
|
||||
targetCamera = newCamera;
|
||||
}
|
||||
|
||||
public void SetOffset(Vector3 newOffset)
|
||||
{
|
||||
offset = newOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d898806f1a151c44933dc01f69acfc0
|
||||
69
Assets/My project/Dialogue Scripts/UI/DialogueData.cs
Normal file
69
Assets/My project/Dialogue Scripts/UI/DialogueData.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "New Dialogue",
|
||||
menuName = "Dialogue/Dialogue Data")]
|
||||
public class DialogueData : ScriptableObject
|
||||
{
|
||||
public DialogueNode[] nodes;
|
||||
|
||||
public bool HasNodes
|
||||
{
|
||||
get
|
||||
{
|
||||
return nodes != null && nodes.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValidIndex(int index)
|
||||
{
|
||||
return nodes != null && index >= 0 && index < nodes.Length;
|
||||
}
|
||||
|
||||
public bool TryGetNode(int index, out DialogueNode node)
|
||||
{
|
||||
node = null;
|
||||
|
||||
if (!IsValidIndex(index))
|
||||
return false;
|
||||
|
||||
node = nodes[index];
|
||||
return node != null;
|
||||
}
|
||||
|
||||
public int GetNodeIndexById(string nodeId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(nodeId))
|
||||
return -1;
|
||||
|
||||
if (nodes == null)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < nodes.Length; i++)
|
||||
{
|
||||
if (nodes[i] == null)
|
||||
continue;
|
||||
|
||||
if (nodes[i].nodeId == nodeId)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
if (nodes == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < nodes.Length; i++)
|
||||
{
|
||||
if (nodes[i] == null)
|
||||
continue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(nodes[i].nodeId))
|
||||
nodes[i].nodeId = $"Node_{i:00}";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13d3b4b8c4cf18d40865a5497e1e1f29
|
||||
272
Assets/My project/Dialogue Scripts/UI/DialogueManager.cs
Normal file
272
Assets/My project/Dialogue Scripts/UI/DialogueManager.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class DialogueManager : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private DialogueUI ui;
|
||||
[SerializeField] private DialogueBillboard billboard;
|
||||
|
||||
[Header("Starting Dialogue")]
|
||||
[SerializeField] private DialogueData startingDialogue;
|
||||
[SerializeField] private Transform startingTarget;
|
||||
[SerializeField] private bool startOnAwake = false;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private bool allowRestartWhileOpen = true;
|
||||
[SerializeField] private bool showDebugLog = true;
|
||||
|
||||
private DialogueData currentDialogue;
|
||||
private int currentNodeIndex = -1;
|
||||
private Transform currentNpcTarget;
|
||||
|
||||
public bool IsDialogueActive { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
AutoFindReferences();
|
||||
ValidateReferences();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (ui != null)
|
||||
{
|
||||
ui.SetVisible(false);
|
||||
ui.ClearChoices();
|
||||
}
|
||||
|
||||
if (startOnAwake && startingDialogue != null)
|
||||
StartDialogue(startingDialogue, startingTarget);
|
||||
}
|
||||
|
||||
private void AutoFindReferences()
|
||||
{
|
||||
if (ui == null)
|
||||
ui = FindFirstObjectByType<DialogueUI>();
|
||||
|
||||
if (billboard == null)
|
||||
billboard = FindFirstObjectByType<DialogueBillboard>();
|
||||
}
|
||||
|
||||
private void ValidateReferences()
|
||||
{
|
||||
if (ui == null)
|
||||
Debug.LogWarning("[DialogueManager] DialogueUI가 연결되지 않았습니다.");
|
||||
|
||||
if (billboard == null)
|
||||
Debug.LogWarning("[DialogueManager] DialogueBillboard가 연결되지 않았습니다. VR 위치 추적 기능은 동작하지 않습니다.");
|
||||
}
|
||||
|
||||
public void StartDialogue(DialogueData dialogue)
|
||||
{
|
||||
StartDialogue(dialogue, currentNpcTarget);
|
||||
}
|
||||
|
||||
public void StartDialogue(DialogueData dialogue, Transform npc)
|
||||
{
|
||||
if (dialogue == null)
|
||||
{
|
||||
Debug.LogWarning("[DialogueManager] 시작할 DialogueData가 null입니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allowRestartWhileOpen && IsDialogueActive)
|
||||
return;
|
||||
|
||||
if (!dialogue.HasNodes)
|
||||
{
|
||||
Debug.LogWarning($"[DialogueManager] DialogueData '{dialogue.name}'에 노드가 없습니다.");
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
currentDialogue = dialogue;
|
||||
currentNodeIndex = 0;
|
||||
currentNpcTarget = npc;
|
||||
IsDialogueActive = true;
|
||||
|
||||
if (ui != null)
|
||||
ui.SetVisible(true);
|
||||
|
||||
if (billboard != null)
|
||||
billboard.SetTarget(npc);
|
||||
|
||||
ShowCurrentNode();
|
||||
|
||||
if (showDebugLog)
|
||||
Debug.Log($"[DialogueManager] Dialogue Start: {dialogue.name}");
|
||||
}
|
||||
|
||||
public void StartDialogueFromNPC(DialogueData dialogue, Transform npc)
|
||||
{
|
||||
StartDialogue(dialogue, npc);
|
||||
}
|
||||
|
||||
public void NextDialogue()
|
||||
{
|
||||
if (!IsDialogueActive)
|
||||
return;
|
||||
|
||||
GoToNodeIndex(currentNodeIndex + 1);
|
||||
}
|
||||
|
||||
public void GoToNodeIndex(int index)
|
||||
{
|
||||
if (currentDialogue == null)
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentDialogue.IsValidIndex(index))
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
currentNodeIndex = index;
|
||||
ShowCurrentNode();
|
||||
}
|
||||
|
||||
public void GoToNodeId(string nodeId)
|
||||
{
|
||||
if (currentDialogue == null)
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
int index = currentDialogue.GetNodeIndexById(nodeId);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
Debug.LogWarning($"[DialogueManager] nodeId '{nodeId}'를 찾을 수 없습니다.");
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
GoToNodeIndex(index);
|
||||
}
|
||||
|
||||
private void ShowCurrentNode()
|
||||
{
|
||||
if (currentDialogue == null)
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentDialogue.TryGetNode(currentNodeIndex, out DialogueNode node))
|
||||
{
|
||||
Debug.LogWarning("[DialogueManager] 현재 노드를 가져올 수 없습니다.");
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ui == null)
|
||||
return;
|
||||
|
||||
ui.SetSpeaker(node.speaker);
|
||||
ui.SetDialogueText(node.dialogue);
|
||||
|
||||
if (HasChoices(node))
|
||||
{
|
||||
ui.SetNextButtonVisible(false);
|
||||
ui.CreateChoices(node.choices, OnChoiceClicked);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui.ClearChoices();
|
||||
ui.SetNextButtonVisible(true);
|
||||
ui.SetupNextButton(NextDialogue);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasChoices(DialogueNode node)
|
||||
{
|
||||
return node != null &&
|
||||
node.choices != null &&
|
||||
node.choices.Length > 0;
|
||||
}
|
||||
|
||||
private void OnChoiceClicked(int choiceIndex)
|
||||
{
|
||||
if (!IsDialogueActive)
|
||||
return;
|
||||
|
||||
if (currentDialogue == null)
|
||||
return;
|
||||
|
||||
if (!currentDialogue.TryGetNode(currentNodeIndex, out DialogueNode node))
|
||||
return;
|
||||
|
||||
if (node.choices == null ||
|
||||
choiceIndex < 0 ||
|
||||
choiceIndex >= node.choices.Length)
|
||||
return;
|
||||
|
||||
ChoiceData choice = node.choices[choiceIndex];
|
||||
|
||||
if (choice == null)
|
||||
return;
|
||||
|
||||
HandleChoice(choice);
|
||||
}
|
||||
|
||||
private void HandleChoice(ChoiceData choice)
|
||||
{
|
||||
choice.onSelected?.Invoke();
|
||||
|
||||
if (choice.endDialogue)
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (choice.nextDialogue != null)
|
||||
{
|
||||
StartDialogue(choice.nextDialogue, currentNpcTarget);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(choice.nextNodeId))
|
||||
{
|
||||
GoToNodeId(choice.nextNodeId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (choice.nextNodeIndex >= 0)
|
||||
{
|
||||
GoToNodeIndex(choice.nextNodeIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
NextDialogue();
|
||||
}
|
||||
|
||||
public void EndDialogue()
|
||||
{
|
||||
if (ui != null)
|
||||
{
|
||||
ui.ClearChoices();
|
||||
ui.SetNextButtonVisible(false);
|
||||
ui.SetVisible(false);
|
||||
}
|
||||
|
||||
if (billboard != null)
|
||||
billboard.ClearTarget();
|
||||
|
||||
currentDialogue = null;
|
||||
currentNodeIndex = -1;
|
||||
currentNpcTarget = null;
|
||||
IsDialogueActive = false;
|
||||
|
||||
if (showDebugLog)
|
||||
Debug.Log("[DialogueManager] Dialogue End");
|
||||
}
|
||||
|
||||
public void CloseDialogue()
|
||||
{
|
||||
EndDialogue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c47d7447ac35ae3478ab1dcbcd4da900
|
||||
19
Assets/My project/Dialogue Scripts/UI/DialogueNode.cs
Normal file
19
Assets/My project/Dialogue Scripts/UI/DialogueNode.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class DialogueNode
|
||||
{
|
||||
[Header("Node ID")]
|
||||
[Tooltip("선택지에서 nextNodeId로 이동할 때 사용하는 ID입니다.")]
|
||||
public string nodeId;
|
||||
|
||||
[Header("Speaker")]
|
||||
public NPCProfile speaker;
|
||||
|
||||
[Header("Dialogue")]
|
||||
[TextArea(3, 5)]
|
||||
public string dialogue;
|
||||
|
||||
[Header("Choices")]
|
||||
public ChoiceData[] choices;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96966b084e2dff74dbe4265e7c3dece5
|
||||
167
Assets/My project/Dialogue Scripts/UI/DialogueUI.cs
Normal file
167
Assets/My project/Dialogue Scripts/UI/DialogueUI.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class DialogueUI : MonoBehaviour
|
||||
{
|
||||
[Header("Panel")]
|
||||
[SerializeField] private GameObject dialoguePanel;
|
||||
|
||||
[Header("Speaker UI")]
|
||||
[SerializeField] private Image portraitImage;
|
||||
[SerializeField] private TMP_Text nameText;
|
||||
|
||||
[Header("Dialogue UI")]
|
||||
[SerializeField] private TMP_Text dialogueText;
|
||||
[SerializeField] private Button nextButton;
|
||||
|
||||
[Header("Choice UI")]
|
||||
[SerializeField] private Transform choiceRoot;
|
||||
[SerializeField] private Button choiceButtonPrefab;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private bool hidePortraitWhenNoSpeaker = true;
|
||||
|
||||
private readonly List<Button> spawnedChoiceButtons = new List<Button>();
|
||||
|
||||
public GameObject DialoguePanel => dialoguePanel;
|
||||
|
||||
public bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return dialoguePanel != null && dialoguePanel.activeSelf;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
SetVisible(false);
|
||||
ClearChoices();
|
||||
}
|
||||
|
||||
public void SetVisible(bool visible)
|
||||
{
|
||||
if (dialoguePanel != null)
|
||||
dialoguePanel.SetActive(visible);
|
||||
}
|
||||
|
||||
public void SetSpeaker(NPCProfile speaker)
|
||||
{
|
||||
if (speaker == null)
|
||||
{
|
||||
if (nameText != null)
|
||||
nameText.text = string.Empty;
|
||||
|
||||
if (portraitImage != null)
|
||||
{
|
||||
portraitImage.sprite = null;
|
||||
portraitImage.enabled = !hidePortraitWhenNoSpeaker;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameText != null)
|
||||
nameText.text = speaker.displayName;
|
||||
|
||||
if (portraitImage != null)
|
||||
{
|
||||
portraitImage.sprite = speaker.portrait;
|
||||
portraitImage.enabled = speaker.portrait != null || !hidePortraitWhenNoSpeaker;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDialogueText(string text)
|
||||
{
|
||||
if (dialogueText != null)
|
||||
dialogueText.text = text;
|
||||
}
|
||||
|
||||
public void SetupNextButton(UnityAction onClick)
|
||||
{
|
||||
if (nextButton == null)
|
||||
return;
|
||||
|
||||
nextButton.onClick.RemoveAllListeners();
|
||||
|
||||
if (onClick != null)
|
||||
nextButton.onClick.AddListener(onClick);
|
||||
}
|
||||
|
||||
public void SetNextButtonVisible(bool visible)
|
||||
{
|
||||
if (nextButton != null)
|
||||
nextButton.gameObject.SetActive(visible);
|
||||
}
|
||||
|
||||
public void CreateChoices(ChoiceData[] choices, Action<int> onChoiceClicked)
|
||||
{
|
||||
ClearChoices();
|
||||
|
||||
if (choices == null || choices.Length == 0)
|
||||
return;
|
||||
|
||||
if (choiceRoot == null)
|
||||
{
|
||||
Debug.LogWarning("[DialogueUI] choiceRoot가 연결되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (choiceButtonPrefab == null)
|
||||
{
|
||||
Debug.LogWarning("[DialogueUI] choiceButtonPrefab이 연결되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < choices.Length; i++)
|
||||
{
|
||||
ChoiceData choice = choices[i];
|
||||
|
||||
if (choice == null)
|
||||
continue;
|
||||
|
||||
Button button = Instantiate(choiceButtonPrefab, choiceRoot);
|
||||
button.gameObject.SetActive(true);
|
||||
|
||||
TMP_Text label = button.GetComponentInChildren<TMP_Text>(true);
|
||||
|
||||
if (label != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(choice.choiceText))
|
||||
label.text = "(빈 선택지)";
|
||||
else
|
||||
label.text = choice.choiceText;
|
||||
}
|
||||
|
||||
int capturedIndex = i;
|
||||
|
||||
button.onClick.RemoveAllListeners();
|
||||
button.onClick.AddListener(() =>
|
||||
{
|
||||
onChoiceClicked?.Invoke(capturedIndex);
|
||||
});
|
||||
|
||||
spawnedChoiceButtons.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearChoices()
|
||||
{
|
||||
for (int i = spawnedChoiceButtons.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (spawnedChoiceButtons[i] == null)
|
||||
continue;
|
||||
|
||||
if (Application.isPlaying)
|
||||
Destroy(spawnedChoiceButtons[i].gameObject);
|
||||
else
|
||||
DestroyImmediate(spawnedChoiceButtons[i].gameObject);
|
||||
}
|
||||
|
||||
spawnedChoiceButtons.Clear();
|
||||
}
|
||||
}
|
||||
2
Assets/My project/Dialogue Scripts/UI/DialogueUI.cs.meta
Normal file
2
Assets/My project/Dialogue Scripts/UI/DialogueUI.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d2d7ee850fd53d448c92a76c5ee854b
|
||||
47
Assets/My project/Dialogue Scripts/UI/NPCInteract.cs
Normal file
47
Assets/My project/Dialogue Scripts/UI/NPCInteract.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class NPCInteract : MonoBehaviour
|
||||
{
|
||||
[Header("Dialogue Data")]
|
||||
[SerializeField] private DialogueData dialogue;
|
||||
|
||||
[Header("Reference")]
|
||||
[SerializeField] private DialogueManager manager;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private bool autoFindManager = true;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (manager == null && autoFindManager)
|
||||
manager = FindFirstObjectByType<DialogueManager>();
|
||||
}
|
||||
|
||||
public void Interact()
|
||||
{
|
||||
if (dialogue == null)
|
||||
{
|
||||
Debug.LogWarning($"[NPCInteract] {name}에 DialogueData가 연결되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager == null)
|
||||
{
|
||||
Debug.LogWarning($"[NPCInteract] {name}에 DialogueManager가 연결되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
manager.StartDialogueFromNPC(dialogue, transform);
|
||||
}
|
||||
|
||||
public void SetDialogue(DialogueData newDialogue)
|
||||
{
|
||||
dialogue = newDialogue;
|
||||
}
|
||||
|
||||
public void SetManager(DialogueManager newManager)
|
||||
{
|
||||
manager = newManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 031ff22c2a7ccda46b524922b5acaefe
|
||||
11
Assets/My project/Dialogue Scripts/UI/NPCProfile.cs
Normal file
11
Assets/My project/Dialogue Scripts/UI/NPCProfile.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "New NPC Profile",
|
||||
menuName = "Dialogue/NPC Profile")]
|
||||
public class NPCProfile : ScriptableObject
|
||||
{
|
||||
[Header("NPC Info")]
|
||||
public string displayName;
|
||||
|
||||
public Sprite portrait;
|
||||
}
|
||||
2
Assets/My project/Dialogue Scripts/UI/NPCProfile.cs.meta
Normal file
2
Assets/My project/Dialogue Scripts/UI/NPCProfile.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 746ac9c211712334e8701c49211cf302
|
||||
Reference in New Issue
Block a user