活动介绍

public GenericDictionary<Button, GameObject> buttonPrefabMap; private GameObject currentPrefab; public GameObject CHild;//子物体 public void LoadPrefab(Button button) { // 获取按钮对应的预制体 GameObject prefab = buttonPrefabMap[button];//GameObject // 销毁当前加载的预制体 Destroy(currentPrefab); // 加载新的预制体 currentPrefab = Instantiate(prefab,CHild.transform); } unity 修改代码 增加点击一下按钮添加模型,再次点击删除模型

时间: 2024-02-14 14:12:54 浏览: 130
可以参考以下代码实现: ```csharp public GenericDictionary<Button, GameObject> buttonPrefabMap; private GameObject currentPrefab; public GameObject child; // 子物体 private bool isPrefabLoaded = false; public void LoadPrefab(Button button) { // 如果当前已经加载了预制体,则删除它 if (isPrefabLoaded) { Destroy(currentPrefab); isPrefabLoaded = false; return; } // 获取按钮对应的预制体 GameObject prefab = buttonPrefabMap[button]; // 加载新的预制体 currentPrefab = Instantiate(prefab, child.transform); isPrefabLoaded = true; } ``` 以上代码实现了点击按钮加载模型,再次点击删除模型的功能。具体实现方式是通过一个布尔变量 `isPrefabLoaded` 来记录当前是否已经加载了预制体,如果已经加载了,则再次点击按钮时会删除当前预制体;如果没有加载,则加载新的预制体。同时,为了让加载的预制体作为子物体显示,使用了 `child` 变量来获取子物体的引用。
阅读全文

相关推荐

using System; using UnityEngine; using UnityEngine.UI; public class DialogueSystem : MonoBehaviour { /// /// 获取对话系统单例,方便在其他脚本中调用。 /// private static DialogueSystem _instance; public static DialogueSystem Instance { get { if (_instance == null) { // 从Resources文件夹加载对话系统预制体 GameObject obj = Resources.Load<GameObject>("DialogueSystem/DialogueCanvas"); _instance = Instantiate(obj).GetComponent<DialogueSystem>(); DontDestroyOnLoad(_instance.gameObject); } return _instance; } } /* --------------------------------------------------- 脚本生命周期 --------------------------------------------------- */ /// /// 脚本开始时调用 /// void Start() { // 注册继续按钮的点击事件 continueButton.onClick.AddListener(ShowNextMessage); } /// /// 脚本销毁时调用 /// void OnDestroy() { // 注销继续按钮的点击事件 continueButton.onClick.RemoveListener(ShowNextMessage); } /* ---------------------------------------------------- 对话框组件 --------------------------------------------------- */ /// /// npc名称文字组件。 /// public Text nameText; /// /// 对话内容文字组件。 /// public Text dialogueText; /// /// 继续对话提示文字组件。(可根据对话内容进行改变。例如当对话不是最后一句时,显示“继续”,是最后一句时显示“完成”。) /// public Text continueText; /// /// 继续按钮组件 /// 用于点击继续对话或结束对话。 /// public Button continueButton; /// /// 立绘图像组件。 /// public Image avatarImage; /* ---------------------------------------------------- 对话框属性 --------------------------------------------------- */ /// /// 对话内容数组 /// 用于存储对话的多条消息。 /// private string[] messages; /// /// 当前对话消息索引 /// 用于跟踪当前显示的对话消息。 /// private int currentMessageIndex = 0; /// /// 用于对话结束时的回调 /// private Action onDialogueComplete; /// /// 显示对话框 /// /// npc名称 /// 对话内容数组 /// 立绘位置 public void ShowDialogue(string name, string[] msgs, string avatarPath, Action onDialogueEnd = null) { // 设置npc名称和立绘图片 nameText.text = name; avatarImage.sprite = Resources.Load<Sprite>(avatarPath); // 初始化对话内容 messages = msgs; currentMessageIndex = 0; // 存储对话结束时的回调 onDialogueComplete = onDialogueEnd; // 显示第一条对话内容 ShowNextMessage(); } /// /// 隐藏对话框 /// public void HideDialogue() { gameObject.SetActive(false); // 重置对话内容和索引 messages = null; currentMessageIndex = 0; } /// /// 显示下一条对话信息 /// private void ShowNextMessage() { // 如果对话内容为空或未设置,显示警告并返回 if (messages == null || messages.Length == 0) { Debug.LogWarning("对话内容为空或未设置。"); return; } // 如果当前对话消息索引小于对话内容长度,显示当前消息 if (currentMessageIndex < messages.Length) { // 根据存储的对话消息索引显示当前消息 dialogueText.text = messages[currentMessageIndex]; // 显示当前对话消息 continueText.text = (currentMessageIndex < messages.Length - 1) ? "继续" : "完成"; // 如果不是最后一条消息,显示“继续”,否则显示“完成” currentMessageIndex++; // 增加对话消息索引,下一次就显示下一条消息 } // 如果对话索引大于等于对话内容长度,代表对话结束,隐藏对话框 else { // 对话结束,隐藏对话框 HideDialogue(); // 如果有对话结束时的回调,调用它 onDialogueComplete?.Invoke(); } } } using UnityEngine; public class OpenDialogueExample : MonoBehaviour { /// /// 在脚本开始时打开对话框并显示内容。 /// void Start() { // 将显示内容传入并打开对话框 DialogueSystem.Instance.ShowDialogue( name: "卡比", // npc名称 msgs: new string[] // 对话内容数组 { "你好,我是卡比!", "欢迎来到我的世界!", "你想和我一起冒险吗?" }, avatarPath: "Avatars/Kirby", // 立绘资源位置 onDialogueEnd: OnDialogueEnd // 对话结束时的回调 ); } /// /// 对话结束时的回调函数。 /// 这里可以添加对话结束后的逻辑处理,例如触发事件或更新UI等。 /// private void OnDialogueEnd() { Debug.Log("对话结束"); } } 根据我脚本的思路,我想制作选项功能,每个选项可以触发不同的对话,我希望制作一个对话模板只需要更改文本就能应用到各个场景

using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; public class GameManager : MonoBehaviour { // 素材列表 public List<GameObject> sucaiList = new List<GameObject>(); // 面板对象 public GameObject mianban; // 主游戏对象 public GameObject main; // Stop 游戏对象 public GameObject stop; // Two Main 游戏对象 public GameObject twoMain; // Speed 游戏对象 public GameObject speed; // Back 游戏对象 public GameObject back; // Control 按钮 public Button controlButton; // Small Main 游戏对象 public GameObject smallMain; // 生成的素材数量 public int shengchengcishu = 20; // 面板的宽度和高度(用于随机排列) public float panelWidth = 10f; public float panelHeight = 10f; // 开始按钮 public Button startButton; // Stop 按钮 public Button stopButton; // Help 按钮 public Button helpButton; // Back 按钮 public Button backBtn; // 音频剪辑 public AudioClip matchSound; // 添加音频剪辑引用 public AudioClip backgroundMusic; // 添加背景音乐剪辑 // Music Delete 按钮 public Button musicDeleteButton; // 新增 Music Delete 按钮引用 // 得分文本 public Text scoreText; // 新增得分文本引用 public Dictionary<GameObject, int> clickCountDict = new Dictionary<GameObject, int>(); private AudioSource audioSource; // 添加音频源组件 private bool isMusicPlaying = false; // 标志音乐是否正在播放 private int a = 0; // 得分 private bool isGameStarted = false; // 游戏是否已经开始 private GameObject previousBlock = null; // 用于存储之前点击的方块 private void Start() { // 查找场景中的面板对象和主游戏对象 if (mianban == null) { mianban = GameObject.Find("Mianban"); } if (mianban == null) { Debug.LogError("未找到名为 'Mianban' 的面板对象!"); return; } if (main == null) { main = GameObject.Find("main"); } if (main == null) { Debug.LogError("未找到名为 'main' 的主游戏对象!"); return; } // 查找 Stop、Two Main、Speed、Back 和 Small Main 对象 if (stop == null) { stop = GameObject.Find("Stop"); } if (stop == null) { Debug.LogError("未找到名为 'Stop' 的游戏对象!"); return; } if (twoMain == null) { twoMain = GameObject.Find("Two Main"); } if (twoMain == null) { Debug.LogError("未找到名为 'Two Main' 的游戏对象!"); return; } if (speed == null) { speed = GameObject.Find("Speed"); } if (speed == null) { Debug.LogError("未找到名为 'Speed' 的游戏对象!"); return; } if (back == null) { back = GameObject.Find("Back"); } if (back == null) { Debug.LogError("未找到名为 'Back' 的游戏对象!"); return; } if (smallMain == null) { smallMain = GameObject.Find("Small Main"); } if (smallMain == null) { Debug.LogError("未找到名为 'Small Main' 的游戏对象!"); return; } // 查找得分文本 if (scoreText == null) { scoreText = GameObject.Find("ScoreText").GetComponent<Text>(); } if (scoreText == null) { Debug.LogError("未找到名为 'ScoreText' 的文本对象!"); return; } // 初始状态下隐藏 Stop、Two Main、Speed、Back 对象 stop.SetActive(false); twoMain.SetActive(false); speed.SetActive(false); back.SetActive(false); // 隐藏得分文本 if (scoreText != null) { scoreText.gameObject.SetActive(false); } // 绑定按钮的点击事件 if (startButton != null) { startButton.onClick.AddListener(StartGame); } else { Debug.LogError("未找到开始按钮!"); } if (stopButton != null) { stopButton.onClick.AddListener(ShowTwoMain); } else { Debug.LogError("未找到停止按钮!"); } if (helpButton != null) { helpButton.onClick.AddListener(ShowSpeedAndBack); } else { Debug.LogError("未找到帮助按钮!"); } if (backBtn != null) { backBtn.onClick.AddListener(HideSpeedAndBack); } else { Debug.LogError("未找到返回按钮!"); } if (controlButton != null) { controlButton.onClick.AddListener(HideTwoMain); } else { Debug.LogError("未找到控制按钮!"); } if (smallMain != null) { smallMain.GetComponent<Button>().onClick.AddListener(ReturnToStartAndClearSucai); } else { Debug.LogError("未找到小主按钮!"); } if (musicDeleteButton != null) { musicDeleteButton.onClick.AddListener(ToggleMusic); // 绑定 Music Delete 按钮的点击事件 } else { Debug.LogError("未找到 Music Delete 按钮!"); } // 添加音频源组件 audioSource = GetComponent<AudioSource>(); if (audioSource == null) { audioSource = gameObject.AddComponent<AudioSource>(); } // 设置背景音乐 if (backgroundMusic != null) { audioSource.clip = backgroundMusic; audioSource.loop = true; // 设置背景音乐循环播放 } else { Debug.LogError("背景音乐未设置!"); } // 自动播放背景音乐 StartBackgroundMusic(); } // 显示 Speed 和 Back 的方法 public void ShowSpeedAndBack() { // 显示 Speed 对象 speed.SetActive(true); // 显示 Back 对象 back.SetActive(true); } // 隐藏 Speed 和 Back 的方法 public void HideSpeedAndBack() { // 隐藏 Speed 对象 speed.SetActive(false); // 隐藏 Back 对象 back.SetActive(false); } // 开始游戏的方法 public void StartGame() { // 隐藏主游戏对象 main.SetActive(false); // 显示 Stop 对象 stop.SetActive(true); // 显示得分文本 if (scoreText != null) { scoreText.gameObject.SetActive(true); } // 重置得分 a = 0; UpdateScoreText(); // 生成素材 shengchengsucai(); // 设置游戏已开始 isGameStarted = true; } // 显示 Two Main 的方法 public void ShowTwoMain() { // 显示 Two Main 对象 twoMain.SetActive(true); } // 隐藏 Two Main 的方法 public void HideTwoMain() { // 隐藏 Two Main 对象 twoMain.SetActive(false); } // 返回到初始界面并清除素材的方法 public void ReturnToStartAndClearSucai() { // 显示主游戏对象 main.SetActive(true); // 隐藏 Stop、Two Main、Speed、Back 对象 stop.SetActive(false); twoMain.SetActive(false); speed.SetActive(false); back.SetActive(false); // 隐藏得分文本 if (scoreText != null) { scoreText.gameObject.SetActive(false); } // 清空面板上的素材 foreach (Transform child in mianban.transform) { Destroy(child.gameObject); } // 重置得分 a = 0; UpdateScoreText(); // 设置游戏未开始 isGameStarted = false; } // 生成素材的方法 public void shengchengsucai() { // 确保素材列表不为空且有素材 if (sucaiList == null || sucaiList.Count == 0) { Debug.LogError("素材列表为空,请确保已正确设置 sucaiList!"); return; } // 清空面板上的现有素材 foreach (Transform child in mianban.transform) { Destroy(child.gameObject); } List<GameObject> tempSucaiList = new List<GameObject>(sucaiList); // 如果生成数量大于素材数量,重复使用素材 if (shengchengcishu > tempSucaiList.Count) { int repeatTimes = shengchengcishu / tempSucaiList.Count; int remainder = shengchengcishu % tempSucaiList.Count; for (int i = 0; i < repeatTimes; i++) { tempSucaiList.AddRange(sucaiList); } tempSucaiList.AddRange(sucaiList.GetRange(0, remainder)); } // 打乱素材顺序 ShuffleList(tempSucaiList); for (int i = 0; i < shengchengcishu; i++) { // 随机生成位置(假设面板中心为原点) float randomX = Random.Range(-panelWidth / 2, panelWidth / 2); float randomY = Random.Range(-panelHeight / 2, panelHeight / 2); GameObject fuzhiwu = Instantiate(tempSucaiList[i], mianban.transform); fuzhiwu.name = tempSucaiList[i].name + "_实例_" + i; fuzhiwu.transform.localPosition = new Vector3(randomX, randomY, 0); // 设置对象的标签为 "Block" fuzhiwu.tag = "Block"; // 为每个素材添加 GameBlock 脚本组件,并设置初始选中状态为 false GameBlock gameBlock = fuzhiwu.AddComponent<GameBlock>(); gameBlock.SetSelected(false); // 确保每个素材有 Button 组件 if (!fuzhiwu.TryGetComponent<Button>(out _)) { fuzhiwu.AddComponent<Button>(); } // 绑定点击事件到消除方法 fuzhiwu.GetComponent<Button>().onClick.AddListener(() => EliminateBlock(fuzhiwu)); } } // 打乱列表顺序的方法 private void ShuffleList<T>(List<T> list) { for (int i = list.Count - 1; i > 0; i--) { int j = Random.Range(0, i + 1); T temp = list[i]; list[i] = list[j]; list[j] = temp; } } // 重置所有方块颜色的方法 public void ResetAllBlocks() { GameObject[] allBlocks = GameObject.FindGameObjectsWithTag("Block"); foreach (GameObject block in allBlocks) { GameBlock gameBlock = block.GetComponent<GameBlock>(); if (gameBlock != null && block != null) { gameBlock.SetSelected(false); } } // 播放音频 if (audioSource != null && matchSound != null) { audioSource.PlayOneShot(matchSound); // 播放音频 } else { Debug.LogWarning("音频源或音频剪辑未设置,无法播放音频!"); } } // 播放音频的方法 public void PlayMatchSound() { if (audioSource != null && matchSound != null) { audioSource.PlayOneShot(matchSound); } else { Debug.LogWarning("音频源或音频剪辑未设置,无法播放音频!"); } } // 切换音乐播放状态的方法 public void ToggleMusic() { if (isMusicPlaying) { if (audioSource != null) { audioSource.Pause(); // 暂停音频源的播放 isMusicPlaying = false; } else { Debug.LogWarning("音频源未设置,无法暂停播放!"); } } else { if (audioSource != null) { audioSource.UnPause(); // 恢复音频源的播放 isMusicPlaying = true; } else { Debug.LogWarning("音频源未设置,无法恢复播放!"); } } } // 开始播放背景音乐的方法 public void StartBackgroundMusic() { if (audioSource != null && backgroundMusic != null) { audioSource.Play(); // 开始播放背景音乐 isMusicPlaying = true; } else { Debug.LogWarning("音频源或背景音乐未设置,无法播放背景音乐!"); } } // 更新得分文本的方法 private void UpdateScoreText() { if (scoreText != null) { scoreText.text = "Score: " + a; Debug.Log("Score updated to: " + a); } else { Debug.LogError("得分文本对象未设置!"); } } // 消除方块的方法 public void EliminateBlock(GameObject block) { if (!isGameStarted) { return; } if (previousBlock == null) { // 第一次点击,记录方块 previousBlock = block; block.GetComponent<GameBlock>().SetSelected(true); } else { // 第二次点击,检查是否与第一个方块的前缀相同且后缀不同 // 比较方块名称的前缀 string blockName1 = previousBlock.name.Split('_')[0]; string blockName2 = block.name.Split('_')[0]; // 比较方块名称的后缀 string suffix1 = previousBlock.name.Split('_')[1]; string suffix2 = block.name.Split('_')[1]; if (blockName1 == blockName2 && suffix1 != suffix2) { // 方块前缀相同且后缀不同,增加得分并销毁方块 a += 10; UpdateScoreText(); // 播放消除音效 if (audioSource != null && matchSound != null) { audioSource.PlayOneShot(matchSound); } else { Debug.LogWarning("音频源或音频剪辑未设置,无法播放消除音效!"); } // 销毁方块 Destroy(previousBlock); Destroy(block); previousBlock = null; } else { // 方块不同,恢复选中状态 previousBlock.GetComponent<GameBlock>().SetSelected(false); previousBlock = block; block.GetComponent<GameBlock>().SetSelected(true); } } } // 清空点击计数的方法 public void ClearClickCountDict() { clickCountDict.Clear(); } // 显示主游戏对象的方法 public void ShowMainObject() { if (main != null) { main.SetActive(true); } } // 隐藏 Stop 对象的方法 public void HideStopObject() { if (stop != null) { stop.SetActive(false); } } }加分面板无法更新

using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; public class AvatarSelector : MonoBehaviour { [Header("UI References")] public GameObject avatarButtonPrefab; public Transform contentParent; public Image selectedAvatarDisplay; [Header("Avatar Settings")] public Sprite[] avatarSprites; private List<Button> avatarButtons = new List<Button>(); private int selectedIndex = -1; void Start() { CreateAvatarButtons(); // 默认选择第一个头像 if(avatarSprites.Length > 0) { SelectAvatar(0); } } void CreateAvatarButtons() { // 清除现有按钮 foreach(Transform child in contentParent) { Destroy(child.gameObject); } avatarButtons.Clear(); // 创建新按钮 for(int i = 0; i < avatarSprites.Length; i++) { int index = i; // 捕获当前索引 GameObject buttonObj = Instantiate(avatarButtonPrefab, contentParent); Button button = buttonObj.GetComponent<Button>(); Image image = buttonObj.GetComponent<Image>(); Outline outline = buttonObj.GetComponent<Outline>(); // 设置头像 if(image != null) { image.sprite = avatarSprites[index]; } // 添加点击事件 button.onClick.AddListener(() => SelectAvatar(index)); // 添加到列表 avatarButtons.Add(button); } } void SelectAvatar(int index) { // 取消之前的选择 if(selectedIndex >= 0 && selectedIndex < avatarButtons.Count) { Outline prevOutline = avatarButtons[selectedIndex].GetComponent<Outline>(); if(prevOutline != null) { prevOutline.enabled = false; } } // 设置新的选择 if(index >= 0 && index < avatarButtons.Count) { Outline outline = avatarButtons[index].GetComponent<Outline>(); if(outline != null) { outline.enabled = true; } // 更新显示的头像 if(selectedAvatarDisplay != null && avatarSprites.Length > index) { selectedAvatarDisplay.sprite = avatarSprites[index]; } selectedIndex = index; // 保存选择 PlayerPrefs.SetInt("SelectedAvatar", index); Debug.Log($"Selected avatar index: {index}"); } } }分析代码

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() { // 清空选项区域 if (optionsPanel != null) { for (int i = optionsPanel.childCount - 1; i >= 0; i--) { Destroy(optionsPanel.GetChild(i).gameObject); } } 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++) { if (currentNode.opts[i] != null) // 空检查 { 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) { if (optionButtonPrefab == null) { Debug.LogError("选项按钮预制体未分配!"); return; } GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel); buttonObj.SetActive(true); Button primaryButton = buttonObj.GetComponentInChildren<Button>(true); Text primaryText = buttonObj.GetComponentInChildren<Text>(true); primaryText.text = option.msg; primaryButton.onClick.RemoveAllListeners(); primaryButton.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(); 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 System; using UnityEngine; using UnityEngine.Serialization; namespace UnityEngine.EventSystems { [AddComponentMenu("Event/Standalone Input Module")] /// /// A BaseInputModule designed for mouse / keyboard / controller input. /// /// <remarks> /// Input module for working with, mouse, keyboard, or controller. /// </remarks> public class StandaloneInputModule : PointerInputModule { private float m_PrevActionTime; private Vector2 m_LastMoveVector; private int m_ConsecutiveMoveCount = 0; private Vector2 m_LastMousePosition; private Vector2 m_MousePosition; private GameObject m_CurrentFocusedGameObject; private PointerEventData m_InputPointerEvent; private const float doubleClickTime = 0.3f; protected StandaloneInputModule() { } [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)] public enum InputMode { Mouse, Buttons } [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)] public InputMode inputMode { get { return InputMode.Mouse; } } [SerializeField] private string m_HorizontalAxis = "Horizontal"; /// /// Name of the vertical axis for movement (if axis events are used). /// [SerializeField] private string m_VerticalAxis = "Vertical"; /// /// Name of the submit button. /// [SerializeField] private string m_SubmitButton = "Submit"; /// /// Name of the submit button. /// [SerializeField] private string m_CancelButton = "Cancel"; [SerializeField] private float m_InputActionsPerSecond = 10; [SerializeField] private float m_RepeatDelay = 0.5f; [SerializeField] [FormerlySerializedAs("m_AllowActivationOnMobileDevice")] [HideInInspector] private bool m_ForceModuleActive; [Obsolete("allowActivationOnMobileDevice has been deprecated. Use forceModuleActive instead (UnityUpgradable) -> forceModuleActive")] public bool allowActivationOnMobileDevice { get { return m_ForceModuleActive; } set { m_ForceModuleActive = value; } } /// /// Force this module to be active. /// /// <remarks> /// If there is no module active with higher priority (ordered in the inspector) this module will be forced active even if valid enabling conditions are not met. /// </remarks> [Obsolete("forceModuleActive has been deprecated. There is no need to force the module awake as StandaloneInputModule works for all platforms")] public bool forceModuleActive { get { return m_ForceModuleActive; } set { m_ForceModuleActive = value; } } /// /// Number of keyboard / controller inputs allowed per second. /// public float inputActionsPerSecond { get { return m_InputActionsPerSecond; } set { m_InputActionsPerSecond = value; } } /// /// Delay in seconds before the input actions per second repeat rate takes effect. /// /// <remarks> /// If the same direction is sustained, the inputActionsPerSecond property can be used to control the rate at which events are fired. However, it can be desirable that the first repetition is delayed, so the user doesn't get repeated actions by accident. /// </remarks> public float repeatDelay { get { return m_RepeatDelay; } set { m_RepeatDelay = value; } } /// /// Name of the horizontal axis for movement (if axis events are used). /// public string horizontalAxis { get { return m_HorizontalAxis; } set { m_HorizontalAxis = value; } } /// /// Name of the vertical axis for movement (if axis events are used). /// public string verticalAxis { get { return m_VerticalAxis; } set { m_VerticalAxis = value; } } /// /// Maximum number of input events handled per second. /// public string submitButton { get { return m_SubmitButton; } set { m_SubmitButton = value; } } /// /// Input manager name for the 'cancel' button. /// public string cancelButton { get { return m_CancelButton; } set { m_CancelButton = value; } } private bool ShouldIgnoreEventsOnNoFocus() { #if UNITY_EDITOR return !UnityEditor.EditorApplication.isRemoteConnected; #else return true; #endif } public override void UpdateModule() { if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus()) { if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging) { ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject); } m_InputPointerEvent = null; return; } m_LastMousePosition = m_MousePosition; m_MousePosition = input.mousePosition; } private void ReleaseMouse(PointerEventData pointerEvent, GameObject currentOverGo) { ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); var pointerClickHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // PointerClick and Drop events if (pointerEvent.pointerClick == pointerClickHandler && pointerEvent.eligibleForClick) { ExecuteEvents.Execute(pointerEvent.pointerClick, pointerEvent, ExecuteEvents.pointerClickHandler); } if (pointerEvent.pointerDrag != null && pointerEvent.dragging) { ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler); } pointerEvent.eligibleForClick = false; pointerEvent.pointerPress = null; pointerEvent.rawPointerPress = null; pointerEvent.pointerClick = null; if (pointerEvent.pointerDrag != null && pointerEvent.dragging) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler); pointerEvent.dragging = false; pointerEvent.pointerDrag = null; // redo pointer enter / exit to refresh state // so that if we moused over something that ignored it before // due to having pressed on something else // it now gets it. if (currentOverGo != pointerEvent.pointerEnter) { HandlePointerExitAndEnter(pointerEvent, null); HandlePointerExitAndEnter(pointerEvent, currentOverGo); } m_InputPointerEvent = pointerEvent; } public override bool ShouldActivateModule() { if (!base.ShouldActivateModule()) return false; var shouldActivate = m_ForceModuleActive; shouldActivate |= input.GetButtonDown(m_SubmitButton); shouldActivate |= input.GetButtonDown(m_CancelButton); shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_HorizontalAxis), 0.0f); shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_VerticalAxis), 0.0f); shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f; shouldActivate |= input.GetMouseButtonDown(0); if (input.touchCount > 0) shouldActivate = true; return shouldActivate; } /// /// See BaseInputModule. /// public override void ActivateModule() { if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus()) return; base.ActivateModule(); m_MousePosition = input.mousePosition; m_LastMousePosition = input.mousePosition; var toSelect = eventSystem.currentSelectedGameObject; if (toSelect == null) toSelect = eventSystem.firstSelectedGameObject; eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData()); } /// /// See BaseInputModule. /// public override void DeactivateModule() { base.DeactivateModule(); ClearSelection(); } public override void Process() { if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus()) return; bool usedEvent = SendUpdateEventToSelectedObject(); // case 1004066 - touch / mouse events should be processed before navigation events in case // they change the current selected gameobject and the submit button is a touch / mouse button. // touch needs to take precedence because of the mouse emulation layer if (!ProcessTouchEvents() && input.mousePresent) ProcessMouseEvent(); if (eventSystem.sendNavigationEvents) { if (!usedEvent) usedEvent |= SendMoveEventToSelectedObject(); if (!usedEvent) SendSubmitEventToSelectedObject(); } } private bool ProcessTouchEvents() { for (int i = 0; i < input.touchCount; ++i) { Touch touch = input.GetTouch(i); if (touch.type == TouchType.Indirect) continue; bool released; bool pressed; var pointer = GetTouchPointerEventData(touch, out pressed, out released); ProcessTouchPress(pointer, pressed, released); if (!released) { ProcessMove(pointer); ProcessDrag(pointer); } else RemovePointerData(pointer); } return input.touchCount > 0; } /// /// This method is called by Unity whenever a touch event is processed. Override this method with a custom implementation to process touch events yourself. /// /// Event data relating to the touch event, such as position and ID to be passed to the touch event destination object. /// This is true for the first frame of a touch event, and false thereafter. This can therefore be used to determine the instant a touch event occurred. /// This is true only for the last frame of a touch event. /// <remarks> /// This method can be overridden in derived classes to change how touch press events are handled. /// </remarks> protected void ProcessTouchPress(PointerEventData pointerEvent, bool pressed, bool released) { var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject; // PointerDown notification if (pressed) { pointerEvent.eligibleForClick = true; pointerEvent.delta = Vector2.zero; pointerEvent.dragging = false; pointerEvent.useDragThreshold = true; pointerEvent.pressPosition = pointerEvent.position; pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast; DeselectIfSelectionChanged(currentOverGo, pointerEvent); if (pointerEvent.pointerEnter != currentOverGo) { // send a pointer enter to the touched element if it isn't the one to select... HandlePointerExitAndEnter(pointerEvent, currentOverGo); pointerEvent.pointerEnter = currentOverGo; } var resetDiffTime = Time.unscaledTime - pointerEvent.clickTime; if (resetDiffTime >= doubleClickTime) { pointerEvent.clickCount = 0; } // search for the control that will receive the press // if we can't find a press handler set the press // handler to be what would receive a click. var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler); var newClick = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // didnt find a press handler... search for a click handler if (newPressed == null) newPressed = newClick; // Debug.Log("Pressed: " + newPressed); float time = Time.unscaledTime; if (newPressed == pointerEvent.lastPress) { var diffTime = time - pointerEvent.clickTime; if (diffTime < doubleClickTime) ++pointerEvent.clickCount; else pointerEvent.clickCount = 1; pointerEvent.clickTime = time; } else { pointerEvent.clickCount = 1; } pointerEvent.pointerPress = newPressed; pointerEvent.rawPointerPress = currentOverGo; pointerEvent.pointerClick = newClick; pointerEvent.clickTime = time; // Save the drag handler as well pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo); if (pointerEvent.pointerDrag != null) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag); } // PointerUp notification if (released) { // Debug.Log("Executing pressup on: " + pointer.pointerPress); ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); // Debug.Log("KeyCode: " + pointer.eventData.keyCode); // see if we mouse up on the same element that we clicked on... var pointerClickHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // PointerClick and Drop events if (pointerEvent.pointerClick == pointerClickHandler && pointerEvent.eligibleForClick) { ExecuteEvents.Execute(pointerEvent.pointerClick, pointerEvent, ExecuteEvents.pointerClickHandler); } if (pointerEvent.pointerDrag != null && pointerEvent.dragging) { ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler); } pointerEvent.eligibleForClick = false; pointerEvent.pointerPress = null; pointerEvent.rawPointerPress = null; pointerEvent.pointerClick = null; if (pointerEvent.pointerDrag != null && pointerEvent.dragging) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler); pointerEvent.dragging = false; pointerEvent.pointerDrag = null; // send exit events as we need to simulate this on touch up on touch device ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler); pointerEvent.pointerEnter = null; } m_InputPointerEvent = pointerEvent; } /// /// Calculate and send a submit event to the current selected object. /// /// <returns>If the submit event was used by the selected object.</returns> protected bool SendSubmitEventToSelectedObject() { if (eventSystem.currentSelectedGameObject == null) return false; var data = GetBaseEventData(); if (input.GetButtonDown(m_SubmitButton)) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler); if (input.GetButtonDown(m_CancelButton)) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler); return data.used; } private Vector2 GetRawMoveVector() { Vector2 move = Vector2.zero; move.x = input.GetAxisRaw(m_HorizontalAxis); move.y = input.GetAxisRaw(m_VerticalAxis); if (input.GetButtonDown(m_HorizontalAxis)) { if (move.x < 0) move.x = -1f; if (move.x > 0) move.x = 1f; } if (input.GetButtonDown(m_VerticalAxis)) { if (move.y < 0) move.y = -1f; if (move.y > 0) move.y = 1f; } return move; } /// /// Calculate and send a move event to the current selected object. /// /// <returns>If the move event was used by the selected object.</returns> protected bool SendMoveEventToSelectedObject() { float time = Time.unscaledTime; Vector2 movement = GetRawMoveVector(); if (Mathf.Approximately(movement.x, 0f) && Mathf.Approximately(movement.y, 0f)) { m_ConsecutiveMoveCount = 0; return false; } bool similarDir = (Vector2.Dot(movement, m_LastMoveVector) > 0); // If direction didn't change at least 90 degrees, wait for delay before allowing consequtive event. if (similarDir && m_ConsecutiveMoveCount == 1) { if (time <= m_PrevActionTime + m_RepeatDelay) return false; } // If direction changed at least 90 degree, or we already had the delay, repeat at repeat rate. else { if (time <= m_PrevActionTime + 1f / m_InputActionsPerSecond) return false; } var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f); if (axisEventData.moveDir != MoveDirection.None) { ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler); if (!similarDir) m_ConsecutiveMoveCount = 0; m_ConsecutiveMoveCount++; m_PrevActionTime = time; m_LastMoveVector = movement; } else { m_ConsecutiveMoveCount = 0; } return axisEventData.used; } protected void ProcessMouseEvent() { ProcessMouseEvent(0); } [Obsolete("This method is no longer checked, overriding it with return true does nothing!")] protected virtual bool ForceAutoSelect() { return false; } /// /// Process all mouse events. /// protected void ProcessMouseEvent(int id) { var mouseData = GetMousePointerEventData(id); var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData; m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject; // Process the first mouse button fully ProcessMousePress(leftButtonData); ProcessMove(leftButtonData.buttonData); ProcessDrag(leftButtonData.buttonData); // Now process right / middle clicks ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData); ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData); ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData); ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData); if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f)) { var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject); ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler); } } protected bool SendUpdateEventToSelectedObject() { if (eventSystem.currentSelectedGameObject == null) return false; var data = GetBaseEventData(); ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler); return data.used; } /// /// Calculate and process any mouse button state changes. /// protected void ProcessMousePress(MouseButtonEventData data) { var pointerEvent = data.buttonData; var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject; // PointerDown notification if (data.PressedThisFrame()) { pointerEvent.eligibleForClick = true; pointerEvent.delta = Vector2.zero; pointerEvent.dragging = false; pointerEvent.useDragThreshold = true; pointerEvent.pressPosition = pointerEvent.position; pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast; DeselectIfSelectionChanged(currentOverGo, pointerEvent); var resetDiffTime = Time.unscaledTime - pointerEvent.clickTime; if (resetDiffTime >= doubleClickTime) { pointerEvent.clickCount = 0; } // search for the control that will receive the press // if we can't find a press handler set the press // handler to be what would receive a click. var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler); var newClick = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // didnt find a press handler... search for a click handler if (newPressed == null) newPressed = newClick; // Debug.Log("Pressed: " + newPressed); float time = Time.unscaledTime; if (newPressed == pointerEvent.lastPress) { var diffTime = time - pointerEvent.clickTime; if (diffTime < doubleClickTime) ++pointerEvent.clickCount; else pointerEvent.clickCount = 1; pointerEvent.clickTime = time; } else { pointerEvent.clickCount = 1; } pointerEvent.pointerPress = newPressed; pointerEvent.rawPointerPress = currentOverGo; pointerEvent.pointerClick = newClick; pointerEvent.clickTime = time; // Save the drag handler as well pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo); if (pointerEvent.pointerDrag != null) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag); m_InputPointerEvent = pointerEvent; } // PointerUp notification if (data.ReleasedThisFrame()) { ReleaseMouse(pointerEvent, currentOverGo); } } protected GameObject GetCurrentFocusedGameObject() { return m_CurrentFocusedGameObject; } } } [ { "id":1, "msg":"帝帝帝大王正指挥瓦多迪建造'苹果能量塔',突然发现核心能源——星光苹果被偷。", "nextid":2 }, { "id": 2, "name": "DDD", "avatar": "Avatars/DDD", "msg": "(暴跳如雷)我的超级苹果!没有它能量塔就是废铁!等等…这粉色绒毛!(捡起沙滩上的绒毛)卡比——!!", "nextid":3 }, { "id":3, "msg": "(星之卡比从礁石后探头,抱着发光的苹果啃得正欢)", "nextid":4 }, { "id": 4, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": " Poyo?(无辜眨眼,苹果汁滴在沙子上泛起星光)", "opts": [ { "msg": "主动归还苹果,但要求交换条件", "toId": 8 }, { "msg": "转身逃跑引发追逐战", "toId": 5 } ] }, { "id": 5, "name": "DDD", "avatar": "Avatars/DDD", "msg": " 可恶的粉球,给我站住不许跑!!!", "nextid":6 }, { "id": 6, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": "Poyo!Poyo!", "nextid":7 }, { "id": 7, "msg": "就这样两人一直追逐下去........但是最终还是选择和解", "nextid":8 }, { "id": 8, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": " Poyo-poyo!(指向远方迷雾海域)", "nextid":9 }, { "id": 9, "name": "DDD", "avatar": "Avatars/DDD", "msg": " 什么?你说海妖偷走了其他苹果?(狐疑)哼!本大王才不会被骗…(突然巨浪袭来)", "nextid":10 }, { "id": 10, "msg": " 巨型海妖现身,触手卷走苹果能量塔的核心部件,两人被困在腐朽的船舱,海水不断渗入。", "nextid":11 }, { "id": 11, "name": "DDD", "avatar": "Avatars/DDD", "msg": " 锤子卡在木梁里)可恶!粉球球,现在我们是一根绳上的蚂蚱了!", "nextid":12 }, { "id": 12, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": "(变身潜水卡比,照亮黑暗)Poyo! ", "nextid":13 }, { "id": 13, "msg": " 逃生途中发现古代石板,记载着苹果能量的秘密。", "nextid":14 }, { "id": 14, "name": "MetaKnight‌", "avatar": "Avatars/MetaKnight‌", "msg": "(突然从天而降)停下!那石板会唤醒古代灾厄!(剑指帝帝帝)你又在谋划什么? ", "nextid":15 }, { "id": 15, "name": "DDD", "avatar": "Avatars/DDD", "msg": "( 本大王需要苹果救妹妹蒂芙!她的石化病…(罕见露出脆弱) ", "nextid":16 }, { "id":16, "name":"Kriby", "msg":"Poyo?(那我现在应该怎么做呢?)", "opts": [ { "msg":"卡比调和冲突,提议三方合作", "nextid":17 }, { "msg":"卡比独自吞下石板引发能量暴走", "nextid":22 } ] }, { "id":17, "msg":"三人抵达星云神殿,发现苹果能量可治愈石化病,但会毁灭梦幻岛生态。", "nextid":18 }, { "id":18, "name":"DDD", "avatar":"Avatars/DDD", "msg":"(颤抖握锤)蒂芙还是岛屿…靠你了(为卡比提供能量)", "nextid":19 }, { "id":19, "name":"MetaKnight‌", "avatar":"Avatars/MetaKnight‌", "msg":"(收剑入鞘)或许是时候该发力了(为卡比提供能量)", "nextid":20 }, { "id":20, "name":"Kriby", "avatar":"Avatars/Kirby", "msg":"(跳到祭坛中央,全身发光)POYO——!", "nextid":21 }, { "id":21, "msg":"能量不断被吸入卡比体内,在短暂光芒之后,卡比稳定下来后让帝帝帝将苹果带回,蒂芙苏醒,帝帝帝含泪道谢" }, { "id":22, "msg":"卡比吸收过量能量裂变成暗黑卡比,引发新危机" } ]仔细检查代码是否有问题为什么会是NULL

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(); } // 实例化新对话 currentDialogueInstance = Instantiate(dialoguePrefab); currentManager = currentDialogueInstance.GetComponent<DialogueManager>(); // 开始对话 currentManager.OpenDialogue(dialoguePath, startId); } // 关闭当前对话 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() { // 初始隐藏 gameObject.SetActive(false); continueButton.onClick.AddListener(OnContinueClicked); } // 外部调用接口:开始对话 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; buttonObj.GetComponent<Button>().onClick.AddListener(() => { // 优先使用toId,其次使用nextid int targetId = option.toId != 0 ? option.toId : option.nextid; StartDialogueNode(targetId); }); } void OnContinueClicked() { if (isTyping) { // 快速完成当前文本 StopAllCoroutines(); messageText.text = fullMessage; isTyping = false; return; } if (currentNode.nextid > 0) { StartDialogueNode(currentNode.nextid); } else { EndDialogue(); } } public void CloseDialogue() { gameObject.SetActive(false); StopAllCoroutines(); } 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 System.Collections.Generic; [System.Serializable] public class DialogueOption { public string msg; public int toId; public int nextid; } [System.Serializable] public class DialogueNode { public int id; public string name; public string avatar; public string msg; public int nextid; public DialogueOption[] opts; } [System.Serializable] public class DialogueTree { public List<DialogueNode> nodes = new List<DialogueNode>(); }为什么我的面板显示不出来

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() { if (optionsPanel != null) { for (int i = optionsPanel.childCount - 1; i >= 0; i--) { Destroy(optionsPanel.GetChild(i).gameObject); } } 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++) { if (currentNode.opts[i] != null) // 空检查 { 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) { if (optionButtonPrefab == null) { Debug.LogError("选项按钮预制体未分配!"); return; } GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel); buttonObj.SetActive(true); Button primaryButton = buttonObj.GetComponent<Button>(); if (primaryButton == null) { foreach (Transform child in buttonObj.transform) { primaryButton = child.GetComponent<Button>(); if (primaryButton != null) break; } } if (primaryButton == null) { primaryButton = buttonObj.GetComponentInChildren<Button>(true); if (primaryButton == null) { Debug.LogError($"在预制体 {buttonObj.name} 及其子对象中未找到Button组件", buttonObj); Destroy(buttonObj); return; } } Text primaryText = primaryButton.GetComponentInChildren<Text>(true); primaryText.text = option.msg; primaryButton.onClick.RemoveAllListeners(); primaryButton.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(); 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() { if (optionsPanel != null) { for (int i = optionsPanel.childCount - 1; i >= 0; i--) { Destroy(optionsPanel.GetChild(i).gameObject); } } 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++) { if (currentNode.opts[i] != null) // 空检查 { 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) { if (optionButtonPrefab == null) { Debug.LogError(“选项按钮预制体未分配!”); return; } GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel); buttonObj.SetActive(true); Button primaryButton = buttonObj.GetComponent<Button>(); if (primaryButton == null) { foreach (Transform child in buttonObj.transform) { primaryButton = child.GetComponent<Button>(); if (primaryButton != null) break; } } if (primaryButton == null) { primaryButton = buttonObj.GetComponentInChildren<Button>(true); if (primaryButton == null) { Debug.LogError($"在预制体 {buttonObj.name} 及其子对象中未找到Button组件", buttonObj); Destroy(buttonObj); return; } } Text primaryText = primaryButton.GetComponentInChildren<Text>(true); primaryText.text = option.msg; primaryButton.onClick.RemoveAllListeners(); primaryButton.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(); foreach (Transform child in optionsPanel) { Button btn = child.GetComponent(); 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); } } } 我需要修改实例化机制差异导致的克隆过程的数据丢失

大家在看

recommend-type

高频双调谐谐振放大电路设计3MHz+电压200倍放大.zip

高频双调谐谐振放大电路设计3MHz+电压200倍放大.zip
recommend-type

只输入固定-vc实现windows多显示器编程的方法

P0.0 只输入固定 P0.1 P0CON.1 P0.2 P0CON.2 PORT_SET.PORT_REFEN P0.3 P0CON.3 自动“偷”从C2的交易应用程序在. PORT_SET.PORT_CLKEN PORT_SET.PORT_CLKOUT[0] P0.4 P0CON.4 C2调试的LED驱动器的时钟输入,如果作为 未启用. P0.5 PORT_CTRL.PORT_LED[1:0] 输出港口被迫为.阅读 实际LED驱动器的状态(开/关) 用户应阅读 RBIT_DATA.GPIO_LED_DRIVE 14只脚 不能用于在开发系统中,由于C2交易扰 乱输出. 参考区间的时钟频率 对抗 控制控制 评论评论 NVM的编程电压 VPP = 6.5 V 矩阵,和ROFF工业* PORT_CTRL 2 GPIO 1 矩阵,和ROFF工业* PORT_CTRL 3 参考 clk_ref GPIO 矩阵 4 C2DAT 产量 CLK_OUT GPIO 5 C2CLK LED驱动器 1 2 工业* PORT_CTRL 1 2 3 1 2 6 产量 CLK_OUT GPIO 1 2 1 1 1 PORT_SET.PORT_CLKEN PORT_SET.PORT_CLKOUT[1] P0.6 P0CON.6 P0.7 P0CON.7 P1.0 P1CON.0 P1.1 P1CON.1 7 8 9 GPIO GPIO GPIO 14只脚 14只脚 14只脚 *注:工业注:工业 代表“独立报”设置. “ 矩阵矩阵 and Roff 模式控制模拟垫电路. 116 修订版修订版1.0
recommend-type

半导体Semi ALD Tungsten W and TiN for Advanced Contact Application

ALD Tungsten, W and TiN for Advanced Contact Application
recommend-type

声纹识别数据集 IDMT-ISA-ELECTRIC-ENGINE

包含发动机正常、高负荷、损坏三种状态.wav声音片段,每种状态包含几百个片段,每个片段时长3S,可用于声纹类型识别,包含数据集介绍文档。
recommend-type

StepInt3-Plugin-x64:StepInt3插件(x64)-x64dbg的插件

StepInt3插件(x64)-x64dbg的插件 有关此插件的x86版本,请访问 概述 一个插件来解决int3断点异常 特征 自动跳过int3断点异常 从插件菜单启用/禁用的选项 如何安装 如果当前正在运行x64dbg(x64dbg 64位),请停止并退出。 将StepInt3.dp64复制到x64dbg\x64\plugins文件夹中。 启动x64dbg 信息 由撰写 使用 RadASM项目(.rap)用于管理和编译插件。 RadASM IDE可以在下载 该插件的x64版本使用 要构建此x64版本,还需要。 x64dbg x64dbg github x64dbg开关

最新推荐

recommend-type

kernel-4.19.90-52.29.v2207.ky10.x86-64.rpm

kernel-4.19.90-52.29.v2207.ky10.x86-64.rpm
recommend-type

2025年检验检测机构评审准则宣贯试题(附答案).pdf

2025年检验检测机构评审准则宣贯试题(附答案).pdf
recommend-type

STM32F4 SDIO应用示例代码

STM32F4 SDIO应用示例代码
recommend-type

【Python毕设】5p125基于协同过滤算法的招聘信息推荐系统_django+spider.zip

项目资源包含:可运行源码+sql文件+LW; python3.8+Django+mysql5.7+vue+spider 适用人群:学习不同技术领域的小白或进阶学习者;可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 当人们打开系统的网址后,首先看到的就是首页界面。在这里,人们能够看到系统的导航条,通过导航条导航进入各功能展示页面进行操作。在个人中心页面输入个人信息可以进行更新操作; 管理员进入主页面,主要功能包括对个人中心、用户管理、招聘信息管理、留言板管理、系统管理等功能进行操作。
recommend-type

2025年高处作业吊篮安装拆卸工应知应会考试题库(含答案) .pdf

2025年高处作业吊篮安装拆卸工应知应会考试题库(含答案) .pdf
recommend-type

多数据源管理与分表实践:MybatisPlus与ShardingJdbc整合

根据给定的文件信息,我们可以详细地解读其中涉及到的关键知识点,这些知识点包括Mybatis Plus的使用、ShardingJdbc的数据分片策略、Swagger的API文档生成能力,以及如何通过注解方式切换数据源。以下是详细的知识点分析: ### Mybatis Plus Mybatis Plus是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。Mybatis Plus提供了如CRUD、分页、多数据源等一些列增强功能,并且可以与Spring、Spring Boot无缝集成。 #### 使用Mybatis Plus的优势: 1. **简化CRUD操作**:Mybatis Plus自带通用的Mapper和Service,减少代码量,提高开发效率。 2. **支持多种数据库**:支持主流的数据库如MySQL、Oracle、SQL Server等。 3. **逻辑删除**:可以在数据库层面实现记录的软删除功能,无需手动在业务中进行判断。 4. **分页插件**:提供默认的分页功能,支持自定义SQL、Lambda表达式等。 5. **性能分析插件**:方便分析SQL性能问题。 6. **代码生成器**:可以一键生成实体类、Mapper、Service和Controller代码,进一步提高开发效率。 #### 关键点: - **代码生成器**:位于`com.example.demo.common.codegenerator`包下的`GeneratorConfig`类中,用户需要根据实际的数据库配置更改数据库账号密码。 ### ShardingJdbc ShardingJDBC是当当网开源的轻量级Java框架,它在JDBC的层次提供了数据分片的能力。通过ShardingJDBC,可以在应用层面进行分库分表、读写分离、分布式主键等操作。 #### 分库分表: - 通过ShardingJDBC可以配置分库分表的策略,例如按照某个字段的值来决定记录应该保存在哪个分库或分表中。 - **Sharding策略**:可以定义多种分片策略,如模运算、查找表、时间范围等。 #### 关键点: - **注解切换数据源**:文件中提到通过注解的方式切换数据源,这允许开发者在编写代码时通过简单注解即可控制数据访问的路由规则。 ### Swagger Swagger是一个规范且完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。Swagger文件可让机器读取以了解远程服务的功能,并且可以作为浏览器插件,以便用户与远程服务互动。 #### 使用Swagger的优势: 1. **API文档自动生成**:Swagger可以根据代码中的注释直接生成文档。 2. **动态接口测试**:可以动态地对API接口进行测试。 3. **交互式文档**:提供交互式的API文档,可以实时地在线测试API。 #### 关键点: - **动态文档**:项目中集成Swagger后,可以在开发过程中动态更新API文档,便于团队协作和文档维护。 ### 如何使用 1. **准备工作**:在解压之前,需要更改数据源的IP、账号和密码,并执行resources下的SQL脚本。 2. **数据源配置**:在实际使用中,需要根据实际情况更改GeneratorConfig类中的dataSourceConfig()的数据库账号密码。 3. **代码生成**:启动代码生成器,根据设定的模板和策略生成相应的代码,包含实体类、Mapper、Service和Controller等。 4. **分库分表配置**:配置ShardingJDBC的分库分表策略,包括分片键和分片算法等。 5. **API文档**:集成Swagger,自动生成API文档并提供动态测试功能。 ### 结语 通过本文件所描述的内容,我们可以了解到如何利用Mybatis Plus、ShardingJdbc、Swagger这三大工具配合实现复杂的数据库操作和维护,以及如何通过注解在不同数据源之间灵活切换。用户在使用时应严格按照文件中的指示进行操作,确保数据库连接信息的正确配置,并结合代码生成器快速搭建项目基础结构。同时,应充分理解ShardingJdbc的分库分表策略,以及Swagger的API文档管理功能,以优化开发流程和提高工作效率。如果以上内容使用得当,这将是一个能够有效提升项目开发和维护质量的强大工具集。
recommend-type

BLE广播机制深度解析:XN297_TO_BLE.zip中的创新实践与应用指南

# 摘要 本文全面分析了蓝牙低功耗(BLE)广播机制的理论与实践应用,特别关注了XN297_TO_BLE.zip的开发与优化。通过详细探讨BLE广播的工作原理、数据包结构、以及XN297_TO_BLE.zip的设计理念与架构,本文为开发者提供了深入了解和实践BLE技术的框架。文中不仅介绍了如何搭建开发环境和编程实践,还深入讨论了
recommend-type

我用的就是idea的内置maven呀

<think>好的,用户现在提到他们使用的是IDEA的内置Maven,但之前遇到了“mvn不是内部或外部命令”的问题。我需要仔细分析可能的场景和用户的需求。 首先,用户可能是在IDEA内部使用Maven时没有问题,但在外部命令行中使用mvn命令时遇到了问题。这说明用户可能混淆了IDEA内置Maven和系统环境变量配置的关系。内置的Maven只在IDEA内部有效,并不会自动配置系统的环境变量,因此当用户在命令行中直接运行mvn时,系统找不到该命令,导致报错。 接下来,我需要确定用户的具体使用场景。用户可能是在尝试通过命令行执行Maven命令,或者是在其他需要系统环境变量支持的地方使用mvn。
recommend-type

环保主题植树节PPT模板设计赏析

标题“清新淡雅绿色环保植树节ppt模板”和描述“茂密的一棵卡通树,散落的绿叶,藤蔓线条,清新淡雅,绿色环保,312植树节ppt模板”共同体现了该PPT模板的设计风格和主题。该模板旨在宣传和庆祝植树节,同时强调了环保的理念。以下是对标题和描述中所蕴含知识点的详细说明: 1. 植树节的概念 植树节,是为了提高人们对森林资源的认识、倡导植树造林而设定的节日。不同国家的植树节日期可能不同,而在中国,“312”植树节(每年的3月12日)被广泛认知和庆祝。这个节日起源于20世纪初,是纪念孙中山先生的逝世纪念日,并逐渐演变为全民植树造林的活动日。 2. 绿色环保理念 绿色环保是指在人类活动中,采取相应的措施减少对环境的破坏,保护地球的自然资源和生态系统。这包括节能减排、资源循环利用、减少废弃物产生、提高能源效率等方面。该PPT模板采用“清新淡雅”的视觉元素,通过卡通形象和自然元素来传递环保的理念,使人们对环保有更深的认同感。 3. 卡通风格设计 模板使用了卡通风格来呈现内容,卡通风格设计通常更加生动、活泼,易于吸引观众的注意力,尤其适合儿童及青少年教育和宣传场合。卡通化的树木和藤蔓线条,可以更好地将植树节这一主题与观众尤其是年轻一代进行连接。 4. 清新淡雅的设计风格 “清新淡雅”是一种设计理念,强调色彩的温和、简洁的布局和舒适的视觉体验。在设计中,它通常表现为使用柔和的色调、简单的图形和没有过多装饰的版面,以创造出一种宁静、舒适的感觉。这种风格的模板适合用于教育、公益宣传等场合,易于传达温暖、积极的信息。 5. PPT模板的应用 PPT(PowerPoint演示文稿)是微软公司开发的一款演示软件,广泛用于商业汇报、教育授课、会议演讲和各类展示活动。一个精心设计的PPT模板可以提高演示的专业性和观赏性,同时通过统一的风格和格式,帮助使用者节省准备演示的时间和精力。模板中预设的版式、字体和配色可以被用户根据自己的需求进行调整和补充内容。 结合以上知识点,可以得出这个植树节PPT模板的设计意图和使用价值。它不仅具有美化演示文稿的作用,而且通过其环保主题和设计风格,传达了植树造林、保护环境的重要性。模板的视觉元素如卡通树木和藤蔓线条等,使得环保理念的表达更为直观和亲民,适合在植树节等环保主题活动上使用。
recommend-type

BLE调试必备:XN297_TO_BLE.zip故障排除与性能监控手册

# 摘要 本文详细介绍了BLE技术的基础知识,并针对XN297_TO_BLE.zip这一软件包进行了深入分析。通过对安装、配置、故障排查、性能优化、高级功能实现及案例研究等方面的探讨,提供了全面的实施指导和最佳实践。文章首先概括了BLE技术的核心要点,随后重点阐述了XN297_TO_BLE.zip的安装、初始配置以及功能验证,特别是在连接故障诊断、数据同步问题解决、性能