Animation.OptionsPanel Animation.LockScreen resource no found 解决

出现上图png报错解决很简单,找到图片wancms_long.png然后打开画图工具重新保存即可,接下来解决

Animation.OptionsPanel Animation.LockScreen resource no found 方法如下:

找到报错位置values-24目录打开styles.xml在图中出现两个错误位置@后面加个"*"修改之后


using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class DialogueManager : MonoBehaviour { public Image backgroundPanel; public Image avatarImage; public Text nameText; public Text messageText; public Transform optionsPanel; public Button continueButton; public GameObject optionButtonPrefab; private Dictionary<int, DialogueNode> nodeDict = new Dictionary<int, DialogueNode>(); private DialogueNode currentNode; private bool isTyping = false; private string fullMessage; private string currentDialoguePath; public delegate void DialogueEvent(int nodeId); public event DialogueEvent OnNodeStart; public event DialogueEvent OnDialogueEnd; void Start() { continueButton.onClick.RemoveAllListeners(); continueButton.onClick.AddListener(OnContinueClicked); if (continueButton == null) { Debug.LogError("继续按钮未绑定!"); } } public void OpenDialogue(string dialoguePath, int startId = 1) { currentDialoguePath = dialoguePath; LoadDialogue(dialoguePath); gameObject.SetActive(true); StartCoroutine(StartDialogueRoutine(startId)); } IEnumerator StartDialogueRoutine(int startId) { yield return new WaitForEndOfFrame(); StartDialogueNode(startId); } void LoadDialogue(string path) { nodeDict.Clear(); TextAsset jsonFile = Resources.Load<TextAsset>(path); if (jsonFile == null) { Debug.LogError("对话文件未找到: " + path); return; } DialogueTree tree = JsonUtility.FromJson<DialogueTree>( "{ \"nodes\": " + jsonFile.text + "}" ); foreach (var node in tree.nodes) { nodeDict.Add(node.id, node); } } void StartDialogueNode(int nodeId) { if (!nodeDict.ContainsKey(nodeId)) { EndDialogue(); return; } currentNode = nodeDict[nodeId]; OnNodeStart?.Invoke(nodeId); UpdateUI(); } void UpdateUI() { nameText.text = string.IsNullOrEmpty(currentNode.name) ? "" : currentNode.name; fullMessage = currentNode.msg; HandleAvatar(); StartCoroutine(TypewriterEffect()); HandleOptions(); } void HandleAvatar() { if (!string.IsNullOrEmpty(currentNode.avatar)) { Sprite avatarSprite = Resources.Load<Sprite>(currentNode.avatar); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; avatarImage.gameObject.SetActive(true); } else { Debug.LogWarning("头像未找到: " + currentNode.avatar); avatarImage.gameObject.SetActive(false); } } else { avatarImage.gameObject.SetActive(false); } } void HandleOptions() { if (currentNode.opts != null && currentNode.opts.Length > 0) { continueButton.gameObject.SetActive(false); StartCoroutine(CreateOptionButtonsWithDelay()); } else if (currentNode.nextid > 0) { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "继续"; } else { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "结束"; } } IEnumerator CreateOptionButtonsWithDelay() { yield return null; for (int i = 0; i < currentNode.opts.Length; i++) { if (currentNode.opts[i] != null) { CreateOptionButton(currentNode.opts[i]); } yield return new WaitForEndOfFrame(); } LayoutRebuilder.ForceRebuildLayoutImmediate(optionsPanel as RectTransform); } IEnumerator TypewriterEffect() { isTyping = true; messageText.text = ""; foreach (char c in fullMessage.ToCharArray()) { messageText.text += c; yield return new WaitForSeconds(0.03f); } isTyping = false; } void CreateOptionButton(DialogueOption option) { if (optionButtonPrefab == null) { Debug.LogError(“选项按钮预制体未分配!”); return; } GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel, false); RectTransform rect = buttonObj.GetComponent(); rect.localScale = Vector3.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = optionButtonPrefab.GetComponent().sizeDelta; buttonObj.SetActive(true); Button[] buttons = buttonObj.GetComponentsInChildren(true); if (buttons == null || buttons.Length == 0) { Debug.LogError($“在预制体 {buttonObj.name} 中未找到Button组件”, buttonObj); Destroy(buttonObj); return; } foreach (Button btn in buttons) { Text btnText = btn.GetComponentInChildren(true); if (btnText != null) { btnText.text = option.msg; } else { Debug.LogWarning(“未找到按钮文本组件”); } btn.onClick.RemoveAllListeners(); btn.onClick.AddListener(() => HandleOptionSelection(option)); } } void HandleOptionSelection(DialogueOption option) { int targetId = option.toId != 0 ? option.toId : option.nextid; if (nodeDict.ContainsKey(targetId)) { StartDialogueNode(targetId); } else if (targetId > 0) { Debug.LogWarning($"目标节点不存在: {targetId}"); EndDialogue(); } else { EndDialogue(); } } void OnContinueClicked() { if (currentNode == null) { CloseDialogue(); return; } if (isTyping) { messageText.text = fullMessage; isTyping = false; return; } if (currentNode.nextid > 0 && nodeDict.ContainsKey(currentNode.nextid)) { StartDialogueNode(currentNode.nextid); } else { EndDialogue(); } } public void CloseDialogue() { continueButton.onClick.RemoveAllListeners(); gameObject.SetActive(false); OnDialogueEnd?.Invoke(currentNode != null ? currentNode.id : -1); } void EndDialogue() { CloseDialogue(); if (currentNode != null) { OnDialogueEnd?.Invoke(currentNode.id); } Debug.Log("对话结束"); } public void ChangeBackground(string bgPath) { Sprite bgSprite = Resources.Load<Sprite>(bgPath); if (bgSprite != null) { backgroundPanel.sprite = bgSprite; } else { Debug.LogWarning("背景未找到: " + bgPath); } } public void ChangeAvatar(string avatarPath) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; } else { Debug.LogWarning("立绘未找到: " + avatarPath); } } } using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class DialogueManager : MonoBehaviour { public Image backgroundPanel; public Image avatarImage; public Text nameText; public Text messageText; public Transform optionsPanel; public Button continueButton; public GameObject optionButtonPrefab; private Dictionary<int, DialogueNode> nodeDict = new Dictionary<int, DialogueNode>(); private DialogueNode currentNode; private bool isTyping = false; private string fullMessage; private string currentDialoguePath; public delegate void DialogueEvent(int nodeId); public event DialogueEvent OnNodeStart; public event DialogueEvent OnDialogueEnd; void Start() { continueButton.onClick.RemoveAllListeners(); continueButton.onClick.AddListener(OnContinueClicked); if (continueButton == null) { Debug.LogError("继续按钮未绑定!"); } } public void OpenDialogue(string dialoguePath, int startId = 1) { currentDialoguePath = dialoguePath; LoadDialogue(dialoguePath); gameObject.SetActive(true); StartCoroutine(StartDialogueRoutine(startId)); } IEnumerator StartDialogueRoutine(int startId) { yield return new WaitForEndOfFrame(); StartDialogueNode(startId); } void LoadDialogue(string path) { nodeDict.Clear(); TextAsset jsonFile = Resources.Load<TextAsset>(path); if (jsonFile == null) { Debug.LogError("对话文件未找到: " + path); return; } DialogueTree tree = JsonUtility.FromJson<DialogueTree>( "{ \"nodes\": " + jsonFile.text + "}" ); foreach (var node in tree.nodes) { nodeDict.Add(node.id, node); } } void StartDialogueNode(int nodeId) { if (!nodeDict.ContainsKey(nodeId)) { EndDialogue(); return; } currentNode = nodeDict[nodeId]; OnNodeStart?.Invoke(nodeId); UpdateUI(); } void UpdateUI() { nameText.text = string.IsNullOrEmpty(currentNode.name) ? "" : currentNode.name; fullMessage = currentNode.msg; HandleAvatar(); StartCoroutine(TypewriterEffect()); HandleOptions(); } void HandleAvatar() { if (!string.IsNullOrEmpty(currentNode.avatar)) { Sprite avatarSprite = Resources.Load<Sprite>(currentNode.avatar); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; avatarImage.gameObject.SetActive(true); } else { Debug.LogWarning("头像未找到: " + currentNode.avatar); avatarImage.gameObject.SetActive(false); } } else { avatarImage.gameObject.SetActive(false); } } void HandleOptions() { if (currentNode.opts != null && currentNode.opts.Length > 0) { continueButton.gameObject.SetActive(false); StartCoroutine(CreateOptionButtonsWithDelay()); } else if (currentNode.nextid > 0) { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "继续"; } else { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "结束"; } } IEnumerator CreateOptionButtonsWithDelay() { yield return null; for (int i = 0; i < currentNode.opts.Length; i++) { if (currentNode.opts[i] != null) { CreateOptionButton(currentNode.opts[i]); } yield return new WaitForEndOfFrame(); } LayoutRebuilder.ForceRebuildLayoutImmediate(optionsPanel as RectTransform); } IEnumerator TypewriterEffect() { isTyping = true; messageText.text = ""; foreach (char c in fullMessage.ToCharArray()) { messageText.text += c; yield return new WaitForSeconds(0.03f); } isTyping = false; } void CreateOptionButton(DialogueOption option) { if (optionButtonPrefab == null) { Debug.LogError(“选项按钮预制体未分配!”); return; } GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel, false); RectTransform rect = buttonObj.GetComponent(); rect.localScale = Vector3.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = optionButtonPrefab.GetComponent().sizeDelta; buttonObj.SetActive(true); Button[] buttons = buttonObj.GetComponentsInChildren(true); if (buttons == null || buttons.Length == 0) { Debug.LogError($“在预制体 {buttonObj.name} 中未找到Button组件”, buttonObj); Destroy(buttonObj); return; } foreach (Button btn in buttons) { Text btnText = btn.GetComponentInChildren(true); if (btnText != null) { btnText.text = option.msg; } else { Debug.LogWarning(“未找到按钮文本组件”); } btn.onClick.RemoveAllListeners(); btn.onClick.AddListener(() => HandleOptionSelection(option)); } } void HandleOptionSelection(DialogueOption option) { int targetId = option.toId != 0 ? option.toId : option.nextid; if (nodeDict.ContainsKey(targetId)) { StartDialogueNode(targetId); } else if (targetId > 0) { Debug.LogWarning($"目标节点不存在: {targetId}"); EndDialogue(); } else { EndDialogue(); } } void OnContinueClicked() { if (currentNode == null) { CloseDialogue(); return; } if (isTyping) { messageText.text = fullMessage; isTyping = false; return; } if (currentNode.nextid > 0 && nodeDict.ContainsKey(currentNode.nextid)) { StartDialogueNode(currentNode.nextid); } else { EndDialogue(); } } public void CloseDialogue() { continueButton.onClick.RemoveAllListeners(); gameObject.SetActive(false); OnDialogueEnd?.Invoke(currentNode != null ? currentNode.id : -1); } void EndDialogue() { CloseDialogue(); if (currentNode != null) { OnDialogueEnd?.Invoke(currentNode.id); } Debug.Log("对话结束"); } public void ChangeBackground(string bgPath) { Sprite bgSprite = Resources.Load<Sprite>(bgPath); if (bgSprite != null) { backgroundPanel.sprite = bgSprite; } else { Debug.LogWarning("背景未找到: " + bgPath); } } public void ChangeAvatar(string avatarPath) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; } else { Debug.LogWarning("立绘未找到: " + avatarPath); } } } 现在我想让buttonperfab,setactive(true)出现在json文档里面有选项的时候,然后其他时间都是false
最新发布
08-19
using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using UnityEngine.SceneManagement; public class DialogueSystem : MonoBehaviour { private static DialogueSystem _instance; public Text nameText; public Text dialogueText; public Button continueButton; public Image avatarImage; public Button[] optionButtons; public GameObject optionsPanel; private string[] currentMessages; private int messageIndex; private List<DialogueOption> currentOptions; private const string PrefabPath = "DialogueSystem/DialogueCanvas"; public static DialogueSystem Instance { get { if (_instance != null) return _instance; _instance = FindObjectOfType<DialogueSystem>(); if (_instance != null) return _instance; GameObject prefab = Resources.Load<GameObject>(PrefabPath); if (prefab != null) { GameObject instance = Instantiate(prefab); instance.name = "DialogueSystem(Instance)"; _instance = instance.GetComponent<DialogueSystem>(); DontDestroyOnLoad(instance); return _instance; } return _instance; } } void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); return; } _instance = this; DontDestroyOnLoad(gameObject); gameObject.SetActive(false); continueButton.onClick.AddListener(ShowNextMessage); SceneManager.sceneLoaded += OnSceneLoaded; } void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { transform.SetAsLastSibling(); } public void ShowDialogue(string speaker, string[] messages, string avatarPath = null, List<DialogueOption> options = null) { gameObject.SetActive(true); transform.SetAsLastSibling(); nameText.text = speaker; if (!string.IsNullOrEmpty(avatarPath)) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); avatarImage.gameObject.SetActive(avatarSprite != null); if (avatarSprite) avatarImage.sprite = avatarSprite; } else { avatarImage.gameObject.SetActive(false); } currentMessages = messages; messageIndex = 0; currentOptions = options; continueButton.gameObject.SetActive(true); optionsPanel.SetActive(false); ShowNextMessage();//调用下一句对话 } private void ShowNextMessage()//下一句对话 { optionsPanel.SetActive(false); if (messageIndex < currentMessages.Length) { dialogueText.text = currentMessages[messageIndex++]; continueButton.gameObject.SetActive(true); } else { ShowOptions(); } } private void ShowOptions()//选项 { if (currentOptions == null || currentOptions.Count == 0) { EndDialogue(); return; } continueButton.gameObject.SetActive(false); optionsPanel.SetActive(true); for (int i = 0; i < optionButtons.Length; i++) { bool hasOption = i < currentOptions.Count; optionButtons[i].gameObject.SetActive(hasOption); if (hasOption) { DialogueOption option = currentOptions[i]; Text buttonText = optionButtons[i].GetComponentInChildren<Text>(); if (buttonText) buttonText.text = option.text; optionButtons[i].onClick.RemoveAllListeners(); optionButtons[i].onClick.AddListener(() => SelectOption(option)); } } } private void SelectOption(DialogueOption option) { option.action?.Invoke(); EndDialogue(); } private void EndDialogue() { gameObject.SetActive(false); currentMessages = null; currentOptions = null; } [System.Serializable] public class DialogueOption { public string text; public UnityEvent action; } #if UNITY_EDITOR void Reset() { nameText = GameObject.Find("NameText")?.GetComponent<Text>(); dialogueText = GameObject.Find("DialogueText")?.GetComponent<Text>(); continueButton = GameObject.Find("ContinueButton")?.GetComponent<Button>(); avatarImage = GameObject.Find("AvatarImage")?.GetComponent<Image>(); Transform optionsPanel = transform.Find("OptionsPanel"); if (optionsPanel) { optionButtons = new Button[optionsPanel.childCount]; for (int i = 0; i < optionsPanel.childCount; i++) { optionButtons[i] = optionsPanel.GetChild(i).GetComponent<Button>(); } } } #endif } using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class OpenDialogueExample : MonoBehaviour { [System.Serializable] public class DialogueSequence { public string speaker; public string avatarPath; [TextArea(3, 10)] public string[] messages; public List<DialogueOption> options; } [System.Serializable] public class DialogueOption { public string text; public int nextSequenceIndex = -1; public UnityEvent customAction; // 添加自定义事件 } public List<DialogueSequence> sequences = new List<DialogueSequence>(); private int currentSequenceIndex = 0; void Start() { if (DialogueSystem.Instance == null) { Debug.LogWarning("对话系统正在初始化..."); } StartCoroutine(StartDialogueAfterDelay(2)); } private IEnumerator StartDialogueAfterDelay(int frames = 2) { for (int i = 0; i < frames; i++) { yield return null; } if (DialogueSystem.Instance == null) { Debug.LogError("对话系统初始化失败!"); yield break; } StartDialogue(0); } public void StartDialogue(int startIndex = 0) { if (sequences.Count == 0 || startIndex < 0) return; currentSequenceIndex = startIndex; ShowCurrentSequence(); } private void ShowCurrentSequence() { if (currentSequenceIndex >= sequences.Count || DialogueSystem.Instance == null) { EndDialogue(); return; } var sequence = sequences[currentSequenceIndex]; if (string.IsNullOrEmpty(sequence.avatarPath)) { sequence.avatarPath = "Avatar"; } if (sequence.messages == null || sequence.messages.Length == 0) { Debug.LogWarning($"序列 {currentSequenceIndex} 没有消息!"); EndDialogue(); return; } var convertedOptions = ConvertOptions(sequence.options);//显示对话场景 DialogueSystem.Instance.ShowDialogue( sequence.speaker, sequence.messages, sequence.avatarPath, convertedOptions ); } private List<DialogueSystem.DialogueOption> ConvertOptions(List<DialogueOption> options)//选项 { if (options == null || options.Count == 0) return null; var converted = new List<DialogueSystem.DialogueOption>(); foreach (var option in options) { var newOption = new DialogueSystem.DialogueOption { text = option.text }; int nextIndex = option.nextSequenceIndex; newOption.action = new UnityEvent(); if (option.customAction != null) { newOption.action.AddListener(() => option.customAction.Invoke());//监听调用 } if (nextIndex >= 0) { newOption.action.AddListener(() => StartDialogue(nextIndex)); } else { newOption.action.AddListener(EndDialogue); } converted.Add(newOption); } return converted; } private void EndDialogue() { if (DialogueSystem.Instance != null) { DialogueSystem.Instance.gameObject.SetActive(false); } } } 图片没有显示出来,点击继续按钮后并没有显示下一句而是直接关闭了对话界面
08-16
using UnityEngine; using System.Collections.Generic; public class DialogueSystem : MonoBehaviour { public GameObject dialoguePrefab; // 预制体引用 private GameObject currentDialogueInstance; private DialogueManager currentManager; // 单例模式 public static DialogueSystem Instance { get; private set; } void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } // 游戏启动时自动开始对话 StartDialogueOnStart(); } // 游戏启动时自动开始对话 void StartDialogueOnStart() { // 直接打开默认对话 OpenDialogue("dialogues/story.txt/test", 1); } // 打开对话接口 public void OpenDialogue(string dialoguePath, int startId = 1) { if (currentDialogueInstance != null) { CloseCurrentDialogue(); } try { currentDialogueInstance = Instantiate(dialoguePrefab); currentManager = currentDialogueInstance.GetComponent<DialogueManager>(); if (currentManager == null) { Debug.LogError("预制体缺少DialogueManager组件!"); Destroy(currentDialogueInstance); return; } currentManager.OpenDialogue(dialoguePath, startId); } catch (System.Exception e) { Debug.LogError($"打开对话失败: {e.Message}"); } } // 关闭当前对话 public void CloseCurrentDialogue() { if (currentDialogueInstance != null) { currentManager.CloseDialogue(); Destroy(currentDialogueInstance); currentDialogueInstance = null; currentManager = null; } } } using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class DialogueManager : MonoBehaviour { public Image backgroundPanel; public Image avatarImage; public Text nameText; public Text messageText; public Transform optionsPanel; public Button continueButton; public GameObject optionButtonPrefab; // 对话数据 private Dictionary<int, DialogueNode> nodeDict = new Dictionary<int, DialogueNode>(); private DialogueNode currentNode; private bool isTyping = false; private string fullMessage; private string currentDialoguePath; // 事件回调 public delegate void DialogueEvent(int nodeId); public event DialogueEvent OnNodeStart; public event DialogueEvent OnDialogueEnd; void Start() { // 确保只绑定一次 continueButton.onClick.RemoveAllListeners(); continueButton.onClick.AddListener(OnContinueClicked); // 添加安全检查 if (continueButton == null) { Debug.LogError("继续按钮未绑定!"); } } // 外部调用接口:开始对话 public void OpenDialogue(string dialoguePath, int startId = 1) { currentDialoguePath = dialoguePath; LoadDialogue(dialoguePath); gameObject.SetActive(true); StartCoroutine(StartDialogueRoutine(startId)); } IEnumerator StartDialogueRoutine(int startId) { yield return new WaitForEndOfFrame(); // 确保UI已激活 StartDialogueNode(startId); } void LoadDialogue(string path) { nodeDict.Clear(); TextAsset jsonFile = Resources.Load<TextAsset>(path); if (jsonFile == null) { Debug.LogError("对话文件未找到: " + path); return; } DialogueTree tree = JsonUtility.FromJson<DialogueTree>( "{ \"nodes\": " + jsonFile.text + "}" ); foreach (var node in tree.nodes) { nodeDict.Add(node.id, node); } } void StartDialogueNode(int nodeId) { if (!nodeDict.ContainsKey(nodeId)) { EndDialogue(); return; } currentNode = nodeDict[nodeId]; OnNodeStart?.Invoke(nodeId); UpdateUI(); } void UpdateUI() { // 清空选项区域 foreach (Transform child in optionsPanel) { Destroy(child.gameObject); } // 更新角色信息 nameText.text = string.IsNullOrEmpty(currentNode.name) ? "" : currentNode.name; fullMessage = currentNode.msg; // 加载头像 if (!string.IsNullOrEmpty(currentNode.avatar)) { Sprite avatarSprite = Resources.Load<Sprite>(currentNode.avatar); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; avatarImage.gameObject.SetActive(true); } else { Debug.LogWarning("头像未找到: " + currentNode.avatar); avatarImage.gameObject.SetActive(false); } } else { avatarImage.gameObject.SetActive(false); } // 启动打字机效果 StartCoroutine(TypewriterEffect()); // 处理选项 if (currentNode.opts != null && currentNode.opts.Length > 0) { continueButton.gameObject.SetActive(false); for (int i = 0; i < currentNode.opts.Length; i++) { CreateOptionButton(currentNode.opts[i]); } } // 显示继续按钮 else if (currentNode.nextid > 0) { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "继续"; } // 结束对话 else { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "结束"; } } IEnumerator TypewriterEffect() { isTyping = true; messageText.text = ""; foreach (char c in fullMessage.ToCharArray()) { messageText.text += c; yield return new WaitForSeconds(0.03f); // 调整显示速度 } isTyping = false; } void CreateOptionButton(DialogueOption option) { GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel); buttonObj.GetComponentInChildren<Text>().text = option.msg; Button button = buttonObj.GetComponent<Button>(); button.onClick.RemoveAllListeners(); // 清除旧监听 button.onClick.AddListener(() => { // 添加节点存在性检查 int targetId = option.toId != 0 ? option.toId : option.nextid; if (nodeDict.ContainsKey(targetId)) { StartDialogueNode(targetId); } else { Debug.LogWarning($"目标节点不存在: {targetId}"); EndDialogue(); } }); } void OnContinueClicked() { if (currentNode == null) // 添加空值检查 { CloseDialogue(); return; } if (isTyping) { messageText.text = fullMessage; isTyping = false; return; } // 添加安全跳转检查 if (currentNode.nextid > 0 && nodeDict.ContainsKey(currentNode.nextid)) { StartDialogueNode(currentNode.nextid); } else { EndDialogue(); } } public void CloseDialogue() { // 解除所有事件绑定 continueButton.onClick.RemoveAllListeners(); // 移除选项按钮事件 foreach (Transform child in optionsPanel) { Button btn = child.GetComponent<Button>(); if (btn != null) btn.onClick.RemoveAllListeners(); } gameObject.SetActive(false); OnDialogueEnd?.Invoke(currentNode != null ? currentNode.id : -1); } void EndDialogue() { CloseDialogue(); OnDialogueEnd?.Invoke(currentNode.id); Debug.Log("对话结束"); } // 动态改变背景 public void ChangeBackground(string bgPath) { Sprite bgSprite = Resources.Load<Sprite>(bgPath); if (bgSprite != null) { backgroundPanel.sprite = bgSprite; } else { Debug.LogWarning("背景未找到: " + bgPath); } } // 动态改变角色立绘 public void ChangeAvatar(string avatarPath) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; } else { Debug.LogWarning("立绘未找到: " + avatarPath); } } } using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class DialogueManager : MonoBehaviour { public Image backgroundPanel; public Image avatarImage; public Text nameText; public Text messageText; public Transform optionsPanel; public Button continueButton; public GameObject optionButtonPrefab; // 对话数据 private Dictionary<int, DialogueNode> nodeDict = new Dictionary<int, DialogueNode>(); private DialogueNode currentNode; private bool isTyping = false; private string fullMessage; private string currentDialoguePath; // 事件回调 public delegate void DialogueEvent(int nodeId); public event DialogueEvent OnNodeStart; public event DialogueEvent OnDialogueEnd; void Start() { // 确保只绑定一次 continueButton.onClick.RemoveAllListeners(); continueButton.onClick.AddListener(OnContinueClicked); // 添加安全检查 if (continueButton == null) { Debug.LogError("继续按钮未绑定!"); } } // 外部调用接口:开始对话 public void OpenDialogue(string dialoguePath, int startId = 1) { currentDialoguePath = dialoguePath; LoadDialogue(dialoguePath); gameObject.SetActive(true); StartCoroutine(StartDialogueRoutine(startId)); } IEnumerator StartDialogueRoutine(int startId) { yield return new WaitForEndOfFrame(); // 确保UI已激活 StartDialogueNode(startId); } void LoadDialogue(string path) { nodeDict.Clear(); TextAsset jsonFile = Resources.Load<TextAsset>(path); if (jsonFile == null) { Debug.LogError("对话文件未找到: " + path); return; } DialogueTree tree = JsonUtility.FromJson<DialogueTree>( "{ \"nodes\": " + jsonFile.text + "}" ); foreach (var node in tree.nodes) { nodeDict.Add(node.id, node); } } void StartDialogueNode(int nodeId) { if (!nodeDict.ContainsKey(nodeId)) { EndDialogue(); return; } currentNode = nodeDict[nodeId]; OnNodeStart?.Invoke(nodeId); UpdateUI(); } void UpdateUI() { // 清空选项区域 foreach (Transform child in optionsPanel) { Destroy(child.gameObject); } // 更新角色信息 nameText.text = string.IsNullOrEmpty(currentNode.name) ? "" : currentNode.name; fullMessage = currentNode.msg; // 加载头像 if (!string.IsNullOrEmpty(currentNode.avatar)) { Sprite avatarSprite = Resources.Load<Sprite>(currentNode.avatar); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; avatarImage.gameObject.SetActive(true); } else { Debug.LogWarning("头像未找到: " + currentNode.avatar); avatarImage.gameObject.SetActive(false); } } else { avatarImage.gameObject.SetActive(false); } // 启动打字机效果 StartCoroutine(TypewriterEffect()); // 处理选项 if (currentNode.opts != null && currentNode.opts.Length > 0) { continueButton.gameObject.SetActive(false); for (int i = 0; i < currentNode.opts.Length; i++) { CreateOptionButton(currentNode.opts[i]); } } // 显示继续按钮 else if (currentNode.nextid > 0) { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "继续"; } // 结束对话 else { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "结束"; } } IEnumerator TypewriterEffect() { isTyping = true; messageText.text = ""; foreach (char c in fullMessage.ToCharArray()) { messageText.text += c; yield return new WaitForSeconds(0.03f); // 调整显示速度 } isTyping = false; } void CreateOptionButton(DialogueOption option) { GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel); buttonObj.GetComponentInChildren<Text>().text = option.msg; Button button = buttonObj.GetComponent<Button>(); button.onClick.RemoveAllListeners(); // 清除旧监听 button.onClick.AddListener(() => { // 添加节点存在性检查 int targetId = option.toId != 0 ? option.toId : option.nextid; if (nodeDict.ContainsKey(targetId)) { StartDialogueNode(targetId); } else { Debug.LogWarning($"目标节点不存在: {targetId}"); EndDialogue(); } }); } void OnContinueClicked() { if (currentNode == null) // 添加空值检查 { CloseDialogue(); return; } if (isTyping) { messageText.text = fullMessage; isTyping = false; return; } // 添加安全跳转检查 if (currentNode.nextid > 0 && nodeDict.ContainsKey(currentNode.nextid)) { StartDialogueNode(currentNode.nextid); } else { EndDialogue(); } } public void CloseDialogue() { // 解除所有事件绑定 continueButton.onClick.RemoveAllListeners(); // 移除选项按钮事件 foreach (Transform child in optionsPanel) { Button btn = child.GetComponent<Button>(); if (btn != null) btn.onClick.RemoveAllListeners(); } gameObject.SetActive(false); OnDialogueEnd?.Invoke(currentNode != null ? currentNode.id : -1); } void EndDialogue() { CloseDialogue(); OnDialogueEnd?.Invoke(currentNode.id); Debug.Log("对话结束"); } // 动态改变背景 public void ChangeBackground(string bgPath) { Sprite bgSprite = Resources.Load<Sprite>(bgPath); if (bgSprite != null) { backgroundPanel.sprite = bgSprite; } else { Debug.LogWarning("背景未找到: " + bgPath); } } // 动态改变角色立绘 public void ChangeAvatar(string avatarPath) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; } else { Debug.LogWarning("立绘未找到: " + avatarPath); } } } NullReferenceException: Object reference not set to an instance of an object DialogueManager.CreateOptionButton (DialogueOption option) (at Assets/DialogueSystem/DialogueManager.cs:165) DialogueManager.UpdateUI () (at Assets/DialogueSystem/DialogueManager.cs:131) DialogueManager.StartDialogueNode (System.Int32 nodeId) (at Assets/DialogueSystem/DialogueManager.cs:87) DialogueManager.OnContinueClicked () (at Assets/DialogueSystem/DialogueManager.cs:204) UnityEngine.Events.InvokableCall.Invoke () (at /Volumes/jenkins1/sharedspace/ra_2022.3/Runtime/Export/UnityEvent/UnityEvent.cs:178) UnityEngine.Events.UnityEvent.Invoke () (at /Volumes/jenkins1/sharedspace/ra_2022.3/artifacts/generated/UnityEvent/UnityEvent_0.cs:57) UnityEngine.UI.Button.Press () (at ./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70) UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at ./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114) UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at ./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57) UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at ./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272) UnityEngine.EventSystems.EventSystem:Update() (at ./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:530)我的button界面是由三个button来组成的
08-19
// DialogueSystem.cs (核心系统) using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [System.Serializable] public class DialogueOption { public string text; public string[] response; public UnityEvent action; } public class DialogueSystem : MonoBehaviour { private static DialogueSystem _instance; public static DialogueSystem Instance { get { if (_instance == null) { GameObject obj = Resources.Load<GameObject>("DialogueSystem/DialogueCanvas"); _instance = Instantiate(obj).GetComponent<DialogueSystem>(); DontDestroyOnLoad(_instance.gameObject); } return _instance; } } [Header("UI Components")] public Text nameText; public Text dialogueText; public Text continueText; public Button continueButton; public Image avatarImage; public Button[] optionButtons; public GameObject optionsPanel; private string[] messages; private int currentMessageIndex = 0; private List<DialogueOption> currentOptions = new List<DialogueOption>(); void Start() { continueButton.onClick.AddListener(ShowNextMessage); HideAllOptions(); } void OnDestroy() { continueButton.onClick.RemoveListener(ShowNextMessage); } // 优化后的显示对话方法 public void ShowDialogue(string name, string[] msgs, string avatarPath, List<DialogueOption> options = null) { nameText.text = name; avatarImage.sprite = Resources.Load<Sprite>(avatarPath); messages = msgs; currentMessageIndex = 0; currentOptions = options; ShowNextMessage(); } private void ShowNextMessage() { HideAllOptions(); if (currentMessageIndex < messages.Length) { dialogueText.text = messages[currentMessageIndex]; continueText.text = (currentMessageIndex < messages.Length - 1) ? "继续" : "完成"; currentMessageIndex++; } else { ShowOptions(); } } private void ShowOptions() { if (currentOptions != null && currentOptions.Count > 0) { continueButton.gameObject.SetActive(false); optionsPanel.SetActive(true); for (int i = 0; i < Mathf.Min(currentOptions.Count, optionButtons.Length); i++) { int index = i; DialogueOption option = currentOptions[index]; optionButtons[i].gameObject.SetActive(true); optionButtons[i].GetComponentInChildren<Text>().text = option.text; optionButtons[i].onClick.RemoveAllListeners(); optionButtons[i].onClick.AddListener(() => OnOptionSelected(option)); } } else { HideDialogue(); } } private void HideAllOptions() { optionsPanel.SetActive(false); foreach (var btn in optionButtons) btn.gameObject.SetActive(false); } private void OnOptionSelected(DialogueOption option) { option.action?.Invoke(); if (option.response != null && option.response.Length > 0) { ShowDialogue(nameText.text, option.response, avatarImage.sprite.name); } else { HideDialogue(); } } public void HideDialogue() { gameObject.SetActive(false); messages = null; currentMessageIndex = 0; } } 我希望能动态生成button不用再去搞buttonperfabe进去,要求代码量小
08-15
using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; public class DialogueSystem : MonoBehaviour { public static DialogueSystem Instance { get; private set; } public Text nameText; public Text dialogueText; public Button continueButton; public Image avatarImage; public Button[] optionButtons; public GameObject optionsPanel; private string[] currentMessages; private int messageIndex; private List<DialogueOption> currentOptions; void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); gameObject.SetActive(false); continueButton.onClick.AddListener(ShowNextMessage); } public void ShowDialogue(string speaker, string[] messages, string avatarPath, List<DialogueOption> options = null) { gameObject.SetActive(true); nameText.text = speaker; if (!string.IsNullOrEmpty(avatarPath)) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; } else { Debug.LogWarning($"头像未找到: {avatarPath}"); avatarImage.gameObject.SetActive(false); } } currentMessages = messages; messageIndex = 0; currentOptions = options; continueButton.gameObject.SetActive(true); optionsPanel.SetActive(false); ShowNextMessage(); } private void ShowNextMessage() { optionsPanel.SetActive(false); if (messageIndex < currentMessages.Length) { dialogueText.text = currentMessages[messageIndex++]; continueButton.gameObject.SetActive(true); } else ShowOptions(); } private void ShowOptions() { if (currentOptions == null || currentOptions.Count == 0) { gameObject.SetActive(false); return; } continueButton.gameObject.SetActive(false); optionsPanel.SetActive(true); for (int i = 0; i < optionButtons.Length; i++) { bool hasOption = i < currentOptions.Count; optionButtons[i].gameObject.SetActive(hasOption); if (hasOption) { DialogueOption option = currentOptions[i]; optionButtons[i].GetComponentInChildren<Text>().text = option.text; optionButtons[i].onClick.RemoveAllListeners(); optionButtons[i].onClick.AddListener(() => SelectOption(option)); } } } private void SelectOption(DialogueOption option) { option.action?.Invoke(); gameObject.SetActive(false); } [System.Serializable] public class DialogueOption { public string text; public UnityEvent action; } } 为什么DontDestroyOnLoad没有出现
08-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昆仑双开分身

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值