赞
踩
目录
一个对话框需要什么呢?我们先来想想:
首先需要一个字符串,表示内容,
为了方便对话间的跳转,我们还需要给每个对话唯一标识,因此需要ID
对话是由人说的,我们还需要人物头像
具体如下:
首先需要一个对话信息:
数据如下:含有当前对话的id、头像、文本以及选项
- [System.Serializable]
- public class DialoguePiece {
- public string ID;
- public Sprite image;
- public string text;
-
- public List<DialogueOption> options = new List<DialogueOption>();
-
-
- }
另一方面,每个对话可能会有选项,每个选项本身也有内容,并且一些选项可能意味着是否要接取任务,以及选择选项后,我们需要跳转到不同的对话,于是需要一个targetID
于是选项的数据结构如下:
- [System.Serializable]
- public class DialogueOption
- {
- public string text;
- public string targetID;
- public bool takeQuest;
- }
我们将所有的对话信息存储在SO中,因此:
- [CreateAssetMenu(fileName ="New Dialogue",menuName ="Dialogue/Dialogue Data")]
- public class DialougeData_SO : ScriptableObject
- {
-
- public List<DialoguePiece> dialoguePieces = new List<DialoguePiece>();
- }
此时完整的一个对话SO如下:
完整的数据结构如下
逻辑:在Dialogue Data中有若干个piece,每个piece中有若干个ID、Text、Image和Quest,还包含有List<Option>
如果有Option,我们就通过获取其Target ID。
创建一个面板:
设定Panel
添加vertical layout Group:
添加对话框还有按钮并设定其位置:
再添加一个头像:
在这种情况下, 如果有button有text的话,布局就会比较乱,因此此处将头像图片放在Main Text下,并且锚点放在左边,这样锚点就是在对话框的左边了。
接下来还需要给Dialogue Panel添加verticalLayoutGroup,这样子物体才可以使用content size filter。
此时头像的图片是以文字为基准点,所以就在对话框的外面了:
这样可以使得按钮在比较靠右的位置。
为了使其能在竖直方向上拉伸:
然后在DialoguePanel和Main Text中都添加content Size Fitter
这样就可以根据文本数量的多少改变框的大小。
问题在于字少的时候,头像会超出位置。
设定一个最小高度即可:
记得给文字设定居中:
给Button设定如下选项:
接下来为选择面板添加Button:
将按钮拉长,并选择居于右部,就会发现此时Button位于右边。
选择text,改变其对话框长度:
多复制几个按钮,并将面板透明度设置为0:
导入素材后,要将场景素材升级到URP
别忘记添加基本的必要组件
接下来实现在对话框中显示显示对话内容的效果。
首先要先将之前创建的UI的那些组件用脚本控制:
(UpdateDialogueData是用于根据传入的对话信息进行更新的函数,后续会补充完整)
- public class DialogueUI : Singleton<DialogueUI>
- {
- [Header("Basic Elements")]
- public Image icon;
- public Text mainText;
- public Button nextButton;
-
- public GameObject dialoguePanel;
-
- [Header("Data")]
- public DialougeData_SO currentData;
- int currentIndex = 0;
-
- public void UpdateDialogueData(DialougeData_SO data)
- {
- currentData = data;
- currentIndex = 0;
- }
-
- }
把那些栏拖拽到里面
给NPC 添加 DialogueController 脚本,用于控制对话
当触发和npc的对话,打开对话面板时,我们就要传给对话UI面板给对话数据:
以一个简单的例子:
进行赋值
具体根据对话数据存储的头像,对话语句进行更新
如果对话数据不止一条对话内容,则我们可以继续往下更新对话
这样即可实现点击进入下一行对话,没有对话时面板消失。
将Button作为预制体:
创建对话的选项OptionUI的脚本,并用该脚本控制选项的组件:
为了实现在对话里生成选项,首先得为选项单独创建一个面板,并在脚本中获取选项所在的Panel及脚本:
因为对话会切换,所以选项也需要生成与销毁
接下来实现选项的销毁与创建:
在选项的UI脚本中,还需要根据传入的参数设定UI
这样即可实现生成选项:
接下来实现点击选项的事件:
我们希望根据选项所存储的下一个对话的ID实现跳转:
所以需要在optionUI里添加下一个对话ID的变量
然后在选项中更新:
为了降低耦合度,使用委托来实现接下来添加点击时需要执行的事件:
给Button添加Onclick事件
获取了ID之后,然后就通过ID去对话的List中去获取该对话信息:
实现打字的效果:下载DOTween插件。
这样即可实现打字效果
但是此处还有一个问题,在于当next按钮消失时布局会发生改变。
还有currentIndex的顺序++,这个和选项无关
创建canvas:
创建一个panel附上图片,然后为实现任务左侧的滚动栏:
然后将滚动的栏删掉变成这样,(删除滑动条后记得调整viewport大小)
设定vertical group:
添加item slot:
以及item tooltip
思考一下,一个任务需要什么?需要有任务的名字、描述、要求、完成的状态。
任务的需求,我们以物品或者杀的怪物来举例,我们需要名字,需要的数量,有的数量,于是不难得出数据结构如下:
(任务可能有多个需求,所以需要用List来存储)
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [CreateAssetMenu(fileName = "New Quest", menuName = "Quest/Quest Data")]
- public class QuestData_SO : ScriptableObject
- {
- [System.Serializable]
- public class QuestRequire
- {
- public string name;
- public int requireAmount;
- public int currentAmount;
- }
-
-
- public string questName;
- [TextArea]
- public string description;
-
- //需要三种任务完成的状态,npc才会有不同的反应
- public bool isStarted;
- public bool isComplete;
- public bool isFinised;
-
- public List<QuestRequire> questRequires = new List<QuestRequire>();
-
- }
此处在这里将任务所需的怪物变量改的名字相同:
在对话一栏中加入任务作为成员变量,因为,我们有时候需要根据对话来接受任务
然后设置对话:
别忘了,任务还需要有奖励:
添加奖励:
(bug记录:DondestroyOnLoad的物体不能是子物体,因此:不能放在别人的子集)
接下来书写管理任务的管理器:用于管理全部的任务信息,使用List来存储全部的任务以及一些控制任务的函数。
- public class QuestManager : Singleton<QuestManager>
- {
- public List<QuestTask> tasks = new List<QuestTask>();
- }
具体的任务的书写如下:包含任务数据,以及任务的三种状态。
-
- public class QuestTask
- {
- public QuestData_SO questData;
- public bool IsStarted {
- get { return questData.isStarted; }
- set { questData.isStarted = value; }
- }
-
- public bool IsComplete
- {
- get { return questData.isComplete; }
- set { questData.isComplete = value; }
- }
-
- public bool IsFinished
- {
- get { return questData.isFinished; }
- set { questData.isFinished = value; }
- }
-
- }
-
-
有了存储任务的数据结构后,作为一个管理器,还需要基础的增、查、获取的功能:
- public bool HaveQuest(QuestData_SO data)//判断是否有这个任务
- {
- //在头文件中引入Ling,可以用于查找链表中的内容
- if (data != null)
- return tasks.Any(q => q.questData.questName == data.questName);
- else return false;
- }
-
- //根据任务数据的名字查找链表中的某一个任务
- public QuestTask GetTask(QuestData_SO data)
- {
- return tasks.Find(q => q.questData.questName == data.questName);
- }
上面有了查和获取,
增加任务的功能只需要直接往List中调用Add函数即可。
而什么时候需要添加任务呢?就是当玩家和NPC进行对话的时候来处理。
具体如下:
思路很简单,当玩家在对话中做出选择,判断本次的选项中是否含有任务,然后判断玩家是否选择了接任务的选项,如果含有,则判断该任务是否在列表中了,如果不在列表中,则将该任务实例化,并且加入到QuestManager的单例的List中。
这样即可实现对话后加任务的思路。
除此之外,我们接取任务后还希望设置任务的状态为开始状态:
但是直接修改并没有用,这只是修改的临时变量的值。
因此需要在QuestManager中根据任务的数据来查找管理器的链表中对应的任务
随后在此处设定开始:
接下来继续创建任务按钮以及任务需求的面板,并用脚本进行控制。
这个Button是最终面板中的这里:
任务按钮需要哪些东西呢?由于我们希望点击任务的名字可以跳转到该任务并展示信息,所以需要按钮,以及任务的内容text。
所以button的控制脚本如下(任务按钮会存储该任务的信息,所以需要QuestData——SO变量)
为每个按钮做一个预制体,并且用脚本去控制
完善上面的脚本,并且书写设定按钮的函数。
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class QuestNameButton : MonoBehaviour
- {
- public Text questNameText;
- public QuestData_SO currentData;
- //public Text questContentText;
-
- public void SetupNameButton(QuestData_SO quesData)
- {
- currentData = quesData;
-
- if (quesData.isComplete)
- questNameText.text = quesData.questName + "(完成)";
- else
- questNameText.text = quesData.questName;
- }
-
- private void Awake()
- {
- GetComponent<Button>().onClick.AddListener(UpdateQuestContent);
- }
- void UpdateQuestContent()
- {
- //questContentText.text = currentData.description;
- QuestUI.Instance.SetupRequireList(currentData);
-
- foreach(Transform item in QuestUI.Instance.rewardTransform)
- {
- Destroy(item.gameObject);
- }
-
-
- foreach(var item in currentData.rewards)//奖励可能不止一个所以需要循环列表
- {
- QuestUI.Instance.SetupRewardItem(item.itemData, item.amount);
- }
- }
- }
此处设定任务内容有两种方式,一种是,我们使用单例的QuestUI(也就是实际上的Quest Manager)来统一显示这些数据
由于很多数据的显示我们是通过一个统一的管理器QuestUI来实现的,所以需要将相关的一些UI组件交由脚本来控制
继续完善任务控制脚本所需的组件:
接下来书写任务需求的脚本,它与UI面板中,它储存的是每个任务的需求和名字。
可以看到每个任务都带有这个脚本
接下来将单独的每个需求做成预制体,并将任务需求所在的Panel交由QuestUI来统一控制:
任务的奖励
奖励就是实际的物品Item
并且还需要获取奖励所在的面板
展示物品信息的代码如下
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- public class ShowTooltip : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
- {
- private ItemUI currentItemUI;
-
- void Awake()
- {
- currentItemUI = GetComponent<ItemUI>();
- }
- public void OnPointerEnter(PointerEventData eventData)
- {
- Debug.Log("mouse in slot");
- QuestUI.Instance.tooltip.gameObject.SetActive(true);
- QuestUI.Instance.tooltip.SetupTooltip(currentItemUI.currentItemData);
- }
-
- public void OnPointerExit(PointerEventData eventData)
- {
- QuestUI.Instance.tooltip.gameObject.SetActive(false);
- }
- }
QuestUI完整代码
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class QuestUI : Singleton<QuestUI>
- {
- [Header("Elements")]
- public GameObject quesPanel;
- public ItemToolTip tooltip;
- bool isOpen;
-
- [Header("Quest Name")]
- public RectTransform questListTransform;
- public QuestNameButton questNameButton;
-
- [Header("Text Content")]
- public Text quesContentText;
-
- [Header("Requirement")]
- public RectTransform requireTransform;
- public QuestRequirement requirement;
-
- [Header("Reward Panel")]
- public RectTransform rewardTransform;
- public ItemUI rewardUI;
-
- private void Update()
- {
- if (Input.GetKeyDown(KeyCode.Q))
- {
- isOpen = !isOpen;
- quesPanel.SetActive(isOpen);
- quesContentText.text = string.Empty;
- SetupQuestList();
- }
-
-
- if (!isOpen)
- tooltip.gameObject.SetActive(false);
- }
-
- public void SetupQuestList()
- {
- //清除原来已有的任务
- foreach(Transform item in questListTransform)
- {
- Destroy(item.gameObject);
- }
- foreach(Transform item in rewardTransform)
- {
- Destroy(item.gameObject);
- }
- foreach (Transform item in requireTransform)
- {
- Destroy(item.gameObject);
- }
-
- //遍历列表中的list,接取任务
- foreach(var task in QuestManager.Instance.tasks)
- {
- var newTask = Instantiate(questNameButton, questListTransform);
- newTask.SetupNameButton(task.questData);
- //newTask.questContentText = quesContentText;
- }
-
-
- }
-
- public void SetupRequireList(QuestData_SO questData)
- {
- quesContentText.text = questData.description;
- //将涉及到QuestNameButton中的三处questContentText关闭,不使用在里面传东西然后赋值的形式了,改为在此处直接修改
-
- foreach (Transform item in requireTransform)
- {
- Destroy(item.gameObject);
- }
- foreach(var require in questData.questRequires)
- {
- var q = Instantiate(requirement, requireTransform);
- q.SetupRequirement(require.name, require.requireAmount, require.currentAmount);
- }
- }
-
- public void SetupRewardItem(ItemData_SO itemData,int amount)
- {
- var item = Instantiate(rewardUI, rewardTransform);
- item.SetupItemUI(itemData, amount);
- }
-
- }
添加按钮的监听事件:显示任务的描述(实现当按下按钮时会更新信息的操作)
实现显示任务的需求
首先在需求的预制体里写一个供外部调用的接口
然后在管理器中调用该接口
在按钮点击事件中调用该函数:
这样即可显示:
但是任务信息和需求重叠在了一起。
在这里可以使得它强制布局:
这样显示就正常了
对于任务信息的显示,除了之前的那种方法:
回顾一下之前的方法:
在QuestNameButton这个预制体的脚本里面给每个任务对应的text里声明该变量:
然后在设定任务时,将任务的需求的那个text赋值给它。
然后根据按钮更新数据的时候,再从任务的SO中获取任务内容再赋值:
这样的过程比较冗余。
现在删去其中在另外一个脚本QuestNameButton中声明变量并且传值然后修改的过程,直接在QuestUI中统一修改:
接下来实现展现需求的代码:
在questUI中,调用之前写的slotItem的方法:
这样即可实现
注意布局
接下来实现鼠标放到上面时显示信息的功能:
脚本并非挂在那个tooltip上,否则因为初始它是不可见的所以没法调用,应该放在reward item slot上。
那么和之前一样,需要实现接口即可:
然后放到上面时就显示设置active为true然后显示信息。
然后设置setupTooltip:
但是有个问题在于:
这个东西返回的是背包里的数据:
而不是实际存在的值。
所以此处需要添加新的变量:
将原来那个函数修改成这样:
这样即可实现,但是发现会出现遮挡现象:
将其放在最下方,就不会被遮挡了:
然后还有个问题在于背包关闭再次打开时,这个还是存在:这是因为即使关闭面板栏,tooltip依然是Active状态。
这样即可解决。
接下来实现多个任务时,出现了这样的问题:
任务来回切换会导致item Slot变多:
更新时清除奖励:
任务进度:检查背包中的物品数量和任务所需的物品数量是否相同,
敌人死亡时进行调用
代码中如果出现两个任务,则两个任务中的都要对应减少。
书写检查任务的函数
提问:为什么有些函数放在QuestUI中有些函数放在QuestManager中,有些函数放在QuestData_SO中呢?
QuestUI是用来处理和UI界面的显示相关的函数。是MVC模式中的模型 Model
QuestData_SO中需要的函数很少,只需要涉及到修改状态数据的函数。是MVC中的视图View
而QuestManager用来处理读取数据以及和UI界面交互的功能。是MVC中的控制器Controller
拾取物品时也进行调用:
这样即可实现完成任务。
但是我们发现使用物品后,任务不会更新。
在此处进行修改:
有个问题在于如果接任务前背包就有两个蘑菇了,此时并不会任务面板并不会更新;
所以需要在InventoryManager中设定一个刚开始的函数中就去检查背包中的物品
检查任务物品:
由于一个questRequire中有多个物品:
因此需要一个包含其名字的list,循环时要判断每一个是否有
创建一个包含名字的链表:
这样就可以实现接受任务时就检查是否完成。
在questGiver里获取当前任务的任务状态:
根据任务完成的状态,需要给予npc不同的对话,所以给npc创建一个脚本:
然后有QuestGiver去修改Dialogue Controller里面的数据
QuestGiver包含多种对话
- [RequireComponent(typeof(DialogueController))]
- public class QuestGiver : MonoBehaviour
- {
- DialogueController controller;
- QuestData_SO currentQuest;
-
- public DialougeData_SO startDialogue;
- public DialougeData_SO progressDialogue;
- public DialougeData_SO completeDialogue;
- public DialougeData_SO finishDialogue;
-
- private void Awake()
- {
- controller = GetComponent<DialogueController>();
- }
- }
-
对于发布任务的人,我们需要让它拿到任务的完成状态,才能根据不同状态执行不同对话:
然后赋值给当前任务:
在questGiver的update函数中则根据不同的状态进行切换。
然后自行设定四个对话的内容并传入:
有个bug会产生,问题在于不要出现这种情况
这样就实现了任务不同状态时的不同对话。
添加一个功能:
当玩家远离时则自动关闭对话:
、
拿到任务奖励需扣除报酬,那么可以这样,将奖励设置为-2:
接受完任务后,背包和栏里面的物品会更新,因此需要写一个根据任务里的物品判断背包是否有该物品的函数
在任务数据里书写给予奖励的函数:
- public void GiveRewards()
- {
- foreach(var reward in rewards)
- {
- if (reward.amount < 0)
- {
- int requireCount = Mathf.Abs(reward.amount);
-
- //优先在背包里找是否有该物品,
- if (InventoryManager.Instance.QuestItemInBag(reward.itemData) != null)
- {
- //这种情况是背包里的东西不够,那就先在背包里扣除一部分,
- if (InventoryManager.Instance.QuestItemInBag(reward.itemData).amount <= requireCount)
- {
- requireCount -= InventoryManager.Instance.QuestItemInBag(reward.itemData).amount;//所需的数量减少
- InventoryManager.Instance.QuestItemInBag(reward.itemData).amount = 0;//背包里的商品扣除为0
-
- //背包里东西不够,剩下的部分从行动栏里扣除
- if (InventoryManager.Instance.QuestItemInAction(reward.itemData) != null)
- {
- InventoryManager.Instance.QuestItemInAction(reward.itemData).amount -= requireCount;
- }
-
- }
- //这种情况就是背包里的东西直接够,那直接扣除就好
- else
- {
- InventoryManager.Instance.QuestItemInBag(reward.itemData).amount -= requireCount;
- }
-
- }
- //这种情况是背包里一点东西都没有,那就直接扣除行动栏里的物品
- else
- {
- InventoryManager.Instance.QuestItemInAction(reward.itemData).amount -= requireCount;
- }
- }
- else
- {
- InventoryManager.Instance.inventoryData.AddItem(reward.itemData, reward.amount);
- }
-
- InventoryManager.Instance.inventoryUI.RefreshUI();
- InventoryManager.Instance.actionUI.RefreshUI();
- }
- }
在OptionUI中执行给与奖励:
这里做的时候出现了一个bug,问题在于之前的对话中没添加quest:
这样即可实现交付任务和扣除东西。
但是有个问题在于:
蘑菇会显示负数。
改动如下:
接下来还有一个小小问题,在于任务完成了,继续拾取蘑菇,任务进度还是会更新,解决方法:
然后在执行更新需求的代码里:
如果完成了则执行完成的设定
在对话时,我们希望保持鼠标是固定的样式:
为了避免已完成的任务再次受到数据更新的影响:
QuestManager里面保存的数据以List类型保存,而里面的数据不是SO类型的,所以不能用之前那样的方法保存
以前的保存都是通过Object来保存的:
因此此处实现一个非SO类型的保存方法:
虽然也可以通过将其改成SO的方式来实现,但此处换种方式:
注意到tasks虽然不是SO,但是task里面的QuestData是SO类型的,我们可以保存它
书写保存和Load的方法:
- public void SaveQuestManager()
- {
- PlayerPrefs.SetInt("QuestCount", tasks.Count);
- for(int i = 0; i < tasks.Count; i++)
- {
- SaveManager.Instance.Save(tasks[i].questData, "task" + i);
- }
- }
-
-
- //加载数据的方式是通过重新新创建一个SO,然后让SO读取数据,然后再加入到tasks链表当中
- public void LoadQuestManager()
- {
- var quesCount = PlayerPrefs.GetInt("QuestCount");
- for(int i = 0; i < quesCount; i++)
- {
- var newQuest = ScriptableObject.CreateInstance<QuestData_SO>();//
- SaveManager.Instance.Load(newQuest, "task" + i);
- tasks.Add(new QuestTask { questData = newQuest });
- }
- }
读取数据的方法可以放在初始时:
在QuestManager中添加
这样即可实现切换场景保存任务:
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public enum ItemType { Useable,Weapon,Armor}
- [CreateAssetMenu(fileName ="New Item",menuName ="Inventory/Item Data")]
- public class ItemData_SO : ScriptableObject
- {
- public ItemType itemType;
- public string itemName;
- public Sprite itemIcon;
- public int itemAmount;//这个物品有多少数量
-
- [TextArea]
- public string description = "";
-
- public bool stackable;//是否可堆叠
-
-
- [Header("Weapon")]
- public GameObject WeaponPrefab;
-
- public AttackData_SO weaponData;
- public AnimatorOverrideController weaponAnimator;
-
- [Header("Useable Item")]
- public UseableItemData_SO useableData;
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class ItemPickUp : MonoBehaviour
- {
- public ItemData_SO itemData;
-
- private void OnTriggerEnter(Collider other)
- {
- if (other.CompareTag("Player"))
- {
- Debug.Log("OnTrigger");
- //GameManager.Instance.playerStats.EquipWeapon(itemData);
- InventoryManager.Instance.inventoryData.AddItem(itemData, itemData.itemAmount);
- InventoryManager.Instance.inventoryUI.RefreshUI();
-
- QuestManager.Instance.UpdateQuestProgress(itemData.itemName, itemData.itemAmount);
- //装备武器
- Destroy(gameObject);
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class InventoryManager : Singleton<InventoryManager>
- {
-
- public class DragData
- {
- public SlotHolder orginalHolder;
- public RectTransform originalParent;
- }
- [Header("Inventory Data")]
- //使用类似之前那样的模板,游戏新开始时复制一份的操作
- //TODO:最后添加模板用于保存数据
- public InventoryData_SO inventoryTemplate;
- public InventoryData_SO inventoryData;
-
- public InventoryData_SO actionTemplate;
- public InventoryData_SO actionData;
-
- public InventoryData_SO equipmentTemplate;
- public InventoryData_SO equipmentData;
-
- [Header("Containers")]
- public ContainerUI inventoryUI;
- public ContainerUI actionUI;
- public ContainerUI equipmentUI;
-
- [Header("Drag Canvas")]
- public Canvas dragCanvas;
-
- public DragData currentDrag;
- protected override void Awake()
- {
- base.Awake();
- if (inventoryTemplate != null)
- inventoryData = Instantiate(inventoryTemplate);
- if (actionTemplate != null)
- actionData = Instantiate(actionTemplate);
- if (equipmentTemplate != null)
- equipmentData = Instantiate(equipmentTemplate);
- }
- private void Start()
- {
- LoadData();
- inventoryUI.RefreshUI();
- actionUI.RefreshUI();
- equipmentUI.RefreshUI();
- }
-
- [Header("UI Panel")]
- public GameObject bagPanel;
- public GameObject statsPanel;
- bool isOpen;
-
- [Header("Stats Text")]
- public Text healthText;
- public Text attackText;
-
- [Header("Tooltip")]
- public ItemToolTip tooltip;
-
- void Update()
- {
- if (Input.GetKeyDown(KeyCode.B))
- {
- isOpen = !isOpen;
- bagPanel.SetActive(isOpen);
- statsPanel.SetActive(isOpen);
- }
-
- UpdateStatsText(GameManager.Instance.playerStats.MaxHealth, GameManager.Instance.playerStats.attackData.minDamage,
- GameManager.Instance.playerStats.attackData.maxDamage);
- }
-
- public void UpdateStatsText(int health,int min,int max)
- {
- healthText.text = health.ToString();
- attackText.text = min + " - " + max;
- }
-
- #region 检查拖拽物品是否在每一个slot范围内
- public bool CheckInInventoryUI(Vector3 position)//此处这个位置是要传输进来的位置
- {
- for(int i = 0; i < inventoryUI.slotHolders.Length; i++)
- {
- RectTransform t = inventoryUI.slotHolders[i].transform as RectTransform;
- if (RectTransformUtility.RectangleContainsScreenPoint(t, position))//判断当前位置是否物品栏里
- {
- return true;
- }
-
- }
- return false;
- }
-
- public bool CheckInActionUI(Vector3 position)//此处这个位置是要传输进来的位置
- {
- for (int i = 0; i < actionUI.slotHolders.Length; i++)
- {
- RectTransform t = actionUI.slotHolders[i].transform as RectTransform;
- if (RectTransformUtility.RectangleContainsScreenPoint(t, position))//判断当前位置是否物品栏里
- {
- return true;
- }
-
- }
- return false;
- }
-
- public bool CheckInEquipmentUI(Vector3 position)//此处这个位置是要传输进来的位置
- {
- for (int i = 0; i < equipmentUI.slotHolders.Length; i++)
- {
- RectTransform t = equipmentUI.slotHolders[i].transform as RectTransform;
- if (RectTransformUtility.RectangleContainsScreenPoint(t, position))//判断当前位置是否物品栏里
- {
- return true;
- }
-
- }
- return false;
- }
- #endregion
-
-
- public void SaveData()
- {
- SaveManager.Instance.Save(inventoryData, inventoryData.name);
- SaveManager.Instance.Save(actionData, actionData.name);
- SaveManager.Instance.Save(equipmentData, equipmentData.name);
-
- }
-
- public void LoadData()
- {
- SaveManager.Instance.Load(inventoryData, inventoryData.name);
- SaveManager.Instance.Load(actionData, actionData.name);
- SaveManager.Instance.Load(equipmentData, equipmentData.name);
- }
-
- #region 检测任务物品
- public void CheckQuestItemInBag(string questItemName)
- {
- foreach(var item in inventoryData.items)
- {
- if (item.itemData != null)
- {
- if (item.itemData.itemName == questItemName)
- QuestManager.Instance.UpdateQuestProgress(item.itemData.itemName, item.amount);
- }
- }
-
- foreach (var item in actionData .items)
- {
- if (item.itemData != null)
- {
- if (item.itemData.itemName == questItemName)
- QuestManager.Instance.UpdateQuestProgress(item.itemData.itemName, item.amount);
- }
- }
-
- }
- #endregion
-
-
- //检测背包和快捷栏里的物体是否有和任务相同的
- public InventoryItem QuestItemInBag(ItemData_SO questItem)
- {
- return inventoryData.items.Find(i => i.itemData == questItem);
- }
-
- public InventoryItem QuestItemInAction(ItemData_SO questItem)
- {
- return actionData.items.Find(i => i.itemData == questItem);
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- public enum SlotType { BAG,WEAPON,ARMOR,ACTION}
- public class SlotHolder : MonoBehaviour,IPointerClickHandler,IPointerEnterHandler,IPointerExitHandler
- {
- // Start is called before the first frame update
- public SlotType slotType;//这个需要用来告诉属于哪一个UI面板,因为后面会有背包、行动
- public ItemUI itemUI; //这是SlotHolder的子物体,Image和Text的父物体。
-
-
-
- //SlotHolder可以理解为格子里的物品的UI信息。
- //获取是为了给子物体中的image和text进行修改
-
-
- public void UpdateItem()
- {
- switch (slotType)
- {
- case SlotType.BAG:
- itemUI.Bag = InventoryManager.Instance.inventoryData;
- break;
- case SlotType.WEAPON:
- itemUI.Bag = InventoryManager.Instance.equipmentData;
- //装备武器 切换武器
- if (itemUI.Bag.items[itemUI.Index].itemData != null)
- {
- GameManager.Instance.playerStats.ChangeWeapon(itemUI.Bag.items[itemUI.Index].itemData);
- }
- else
- {
- GameManager.Instance.playerStats.UnEquipWeapon();
- }
- break;
- case SlotType.ARMOR:
- itemUI.Bag = InventoryManager.Instance.equipmentData;
- break;
- case SlotType.ACTION:
- itemUI.Bag = InventoryManager.Instance.actionData;
-
- break;
- }
-
- var item = itemUI.Bag.items[itemUI.Index];//找到数据库中对应序号的对应物品
- itemUI.SetupItemUI(item.itemData, item.amount);
- }
-
- public void OnPointerClick(PointerEventData eventData)
- {
- if (eventData.clickCount % 2 == 0)//代表是双击的话
- {
- UseItem();
- }
- }
- public void UseItem()
- {
- if (itemUI.GetItem().itemType == ItemType.Useable&&itemUI.Bag.items[itemUI.Index].amount>0)
- {
- GameManager.Instance.playerStats.ApplyHealth(itemUI.GetItem().useableData.healthPoint);
- itemUI.Bag.items[itemUI.Index].amount -= 1;
-
- QuestManager.Instance.UpdateQuestProgress(itemUI.GetItem().itemName, -1);
- }
- UpdateItem();
- }
-
- public void OnPointerEnter(PointerEventData eventData)
- {
- if (itemUI.GetItem())
- {
- InventoryManager.Instance.tooltip.SetupTooltip(itemUI.GetItem());
- InventoryManager.Instance.tooltip.gameObject.SetActive(true);
- }
- }
-
- public void OnPointerExit(PointerEventData eventData)
- {
- InventoryManager.Instance.tooltip.gameObject.SetActive(false);
- }
-
- void OnDisable()
- {
- InventoryManager.Instance.tooltip.gameObject.SetActive(false);
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- [RequireComponent(typeof(ItemUI))]
- public class DragItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
- {
- ItemUI currentItemUI;
- //
- SlotHolder currentHolder;
- SlotHolder targetHolder;
-
- void Awake()
- {
- currentItemUI = GetComponent<ItemUI>();
- currentHolder = GetComponentInParent<SlotHolder>();//原先的格子的信息
- }
- public void OnBeginDrag(PointerEventData eventData)
- {
- InventoryManager.Instance.currentDrag = new InventoryManager.DragData();
- InventoryManager.Instance.currentDrag.orginalHolder = GetComponentInParent<SlotHolder>();
- InventoryManager.Instance.currentDrag.originalParent = (RectTransform)transform.parent;
- //记录原始数据
- transform.SetParent(InventoryManager.Instance.dragCanvas.transform,true);
- }
-
- public void OnDrag(PointerEventData eventData)
- {
- //跟随鼠标位置移动
- transform.position = eventData.position;
- }
-
- public void OnEndDrag(PointerEventData eventData)
- {
- //放下物品 交换数据
- if (EventSystem.current.IsPointerOverGameObject())//是否指向UI组件
- {
- if(InventoryManager.Instance.CheckInActionUI(eventData.position)
- || InventoryManager.Instance.CheckInInventoryUI(eventData.position)
- || InventoryManager.Instance.CheckInEquipmentUI(eventData.position))
- //判断是否在三个栏里面的格子里
- {
- if (eventData.pointerEnter.gameObject.GetComponent<SlotHolder>())
- targetHolder = eventData.pointerEnter.gameObject.GetComponent<SlotHolder>();
- else
- targetHolder = eventData.pointerEnter.gameObject.GetComponentInParent<SlotHolder>();
- //如果没找到,此时是因为被图片所挡住了,那么就获取其父类的component
-
- Debug.Log(eventData.pointerEnter.gameObject);
- //判断鼠标选中的物体是否有slot holder,
-
- //判断是否目标holder是我的原holder
- if(targetHolder!=InventoryManager.Instance.currentDrag.orginalHolder)
- //由于例如食物不能放在武器栏里,所以需要对其做区分
- switch (targetHolder.slotType)
- {
- case SlotType.BAG:
- SwapItem();
- break;
-
- //下面这些if的判断就确保了只有相同的物品才能实现交换
- case SlotType.WEAPON:
- if (currentItemUI.Bag.items[currentItemUI.Index].itemData.itemType == ItemType.Weapon)
- SwapItem();
- break;
-
- case SlotType.ARMOR:
- if (currentItemUI.Bag.items[currentItemUI.Index].itemData.itemType == ItemType.Armor)
- SwapItem();
- break;
-
- case SlotType.ACTION:
- if(currentItemUI.Bag.items[currentItemUI.Index].itemData.itemType==ItemType.Useable)
- SwapItem();
- break;
-
- }
-
- currentHolder.UpdateItem();//交换完毕后需要更新数据
- targetHolder.UpdateItem();
-
-
- }
- }
-
- transform.SetParent(InventoryManager.Instance.currentDrag.originalParent);
-
- RectTransform t = transform as RectTransform;
- t.offsetMax = -Vector3.one * 5;
- t.offsetMin = Vector2.one * 5;
-
-
- }
-
- public void SwapItem()
- {
- //targetHolder是鼠标指向的位置的格子。
- //获取目标格子上面显示的UI,UI图片对应它身上属于哪个背包的哪一个序号的物品
- var targetItem = targetHolder.itemUI.Bag.items[targetHolder.itemUI.Index];//实际上就是获取鼠标指向的物品item
-
- var tempItem = currentHolder.itemUI.Bag.items[currentHolder.itemUI.Index];//点击前的鼠标的格子的信息
-
- //如果是相同的物品就进行合并
- bool isSameItem = tempItem.itemData == targetItem.itemData;
- if (isSameItem && targetItem.itemData.stackable)//并且还要可堆叠才行
- {
- targetItem.amount += tempItem.amount;
- tempItem.itemData = null;
- tempItem.amount = 0;
- }
- else
- {
- currentHolder.itemUI.Bag.items[currentHolder.itemUI.Index] = targetItem;
- //targetItem=tempItem;这样的写法不行因为targetItem只是我们获取的一个变量,应该直接用其本身去更换,即下一行的写法
- targetHolder.itemUI.Bag.items[targetHolder.itemUI.Index] = tempItem;
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- public class DragPanel : MonoBehaviour,IDragHandler,IPointerDownHandler
- {
- RectTransform rectTransform;
-
- Canvas canvas;
- void Awake()
- {
- rectTransform = GetComponent<RectTransform>();
- canvas = InventoryManager.Instance.GetComponent<Canvas>();
- }
- public void OnDrag(PointerEventData eventData)
- {
- rectTransform.anchoredPosition += eventData.delta/canvas.scaleFactor;//让其锚点的位置的改变量和鼠标的改变量相同即可
- }
-
- public void OnPointerDown(PointerEventData eventData)
- {
- rectTransform.SetSiblingIndex(2);
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class ContainerUI : MonoBehaviour
- {
- public SlotHolder[] slotHolders;
-
- public void RefreshUI()
- {
- for(int i = 0; i < slotHolders.Length; i++)
- {
- slotHolders[i].itemUI.Index = i;
- slotHolders[i].UpdateItem();
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class ItemToolTip : MonoBehaviour
- {
- public Text itemNameText;
- public Text itemInfoText;
- RectTransform rectTransform;
-
- private void Awake()
- {
- rectTransform = GetComponent<RectTransform>();
- }
- public void SetupTooltip(ItemData_SO item)
- {
- itemNameText.text = item.itemName;
- itemInfoText.text = item.description;
- }
-
- void OnEnable()
- {
- //开始时会闪烁是因为没有定位好坐标,开始时先更新一下即可避免这种效果
- UpdatePosition();
-
- }
- private void Update()
- {
- UpdatePosition();
- }
- public void UpdatePosition()
- {
- Vector3 mousePos = Input.mousePosition;
- rectTransform.position = mousePos;
-
- Vector3[] corners = new Vector3[4];
- rectTransform.GetWorldCorners(corners);
-
- float width = corners[3].x - corners[0].x;
- float height = corners[1].y - corners[0].y;
-
- if (mousePos.y < height)
- rectTransform.position = mousePos + Vector3.up * height * 0.6f;
- else if (Screen.width - mousePos.x > width)
- rectTransform.position = mousePos + Vector3.right * width * 0.6f;
- else
- rectTransform.position = mousePos + Vector3.left * width * 0.6f;
-
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class ItemUI : MonoBehaviour
- {
- public Image icon = null;
- public Text amount = null;
-
- public InventoryData_SO Bag { get; set; }
- public InventoryData_SO Action { get; set; }
- public InventoryData_SO Equipment { get; set; }
-
- public ItemData_SO currentItemData;
-
- public int Index { get; set; } = -1;//初始值设为-1是因为一开始序号是从0开始的,避免一开始去setup每个格子的时候出现数据的错位排序
-
- public void SetupItemUI(ItemData_SO item,int itemAmount)
- {
- if (itemAmount == 0)
- {
- Bag.items[Index].itemData = null;
- icon.gameObject.SetActive(false);
- return;
- }
-
- //想要实现如果数量小于0则不显示,不能在上面的if条件改成<=0,因为此时并没有实际的背包
-
- if (itemAmount < 0) item = null;//只需要跳过下面的null部分就行了,并且需要设置active为false
- if (item != null)
- {
- icon.sprite = item.itemIcon;
- amount.text = itemAmount.ToString();
- icon.gameObject.SetActive(true);//默认是可见的,此处设为不可见
-
- currentItemData = item;
-
- }
- else
- icon.gameObject.SetActive(false);
- }
-
- public ItemData_SO GetItem()
- {
- return Bag.items[Index].itemData;
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class LootSpawner : MonoBehaviour
- {
- [System.Serializable]
- public class LootItem
- {
- public GameObject item;
- [Range(0, 1)]
- public float weight;
- }
-
- public LootItem[] lootItems;
-
- public void Spawnloot()
- {
- float currentValue = Random.value;
-
- for(int i = 0; i < lootItems.Length; i++)
- {
- if (currentValue <= lootItems[i].weight)
- {
- GameObject obj = Instantiate(lootItems[i].item);
- obj.transform.position = transform.position + Vector3.up * 2;
- break;//确保一次只掉落一个物品
- }
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class ActionButton : MonoBehaviour
- {
- public KeyCode actionKey;
- private SlotHolder currentSlotHolder;
-
- void Awake()
- {
- currentSlotHolder = GetComponent<SlotHolder>();
-
- }
-
- private void Update()
- {
- if (Input.GetKeyDown(actionKey) && currentSlotHolder.itemUI.GetItem())
- currentSlotHolder.UseItem();
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [CreateAssetMenu(fileName ="Useable Item",menuName ="Inventory/Useable Item Data")]
- public class UseableItemData_SO : ScriptableObject
- {
- //所有你想改变的数据
- public int healthPoint;
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class DialogueController : MonoBehaviour
- {
- public DialougeData_SO currentData;
- bool canTalk = false;
-
- private void OnTriggerEnter(Collider other)
- {
- if (other.CompareTag("Player") && currentData != null)
- {
- canTalk = true;
- Debug.Log("can talk is true");
-
- }
- }
-
- private void OnTriggerExit(Collider other)
- {
- if (other.CompareTag("Player"))
- {
- DialogueUI.Instance.dialoguePanel.SetActive(false);
- }
- }
-
- private void Update()
- {
- if (canTalk && Input.GetKeyDown(KeyCode.F))//TODO:此处是否可以改编成使用事件的形式?
- {
- OpenDialogue();
- }
- }
-
- void OpenDialogue()
- {
- //打开UI面板
- //传输对话内容信息
- DialogueUI.Instance.UpdateDialogueData(currentData);
- DialogueUI.Instance.UpdateMainDialogue(currentData.dialoguePieces[0]);
- }
-
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [System.Serializable]
- public class DialogueOption
- {
- public string text;
- public string targetID;
- public bool takeQuest;
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [System.Serializable]
- public class DialoguePiece {
- public string ID;
- public Sprite image;
-
- [TextArea]
- public string text;
-
- public QuestData_SO quest;
-
- public List<DialogueOption> options = new List<DialogueOption>();
-
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [CreateAssetMenu(fileName ="New Dialogue",menuName ="Dialogue/Dialogue Data")]
- public class DialougeData_SO : ScriptableObject
- {
-
- public List<DialoguePiece> dialoguePieces = new List<DialoguePiece>();
- public Dictionary<string, DialoguePiece> dialogueIndex = new Dictionary<string, DialoguePiece>();
-
-
-
- public QuestData_SO GetQuest()
- {
- QuestData_SO currentQuest = null;
- //循环对话中的任务,找到该任务并返回
- foreach (var piece in dialoguePieces)
- {
- if (piece.quest != null)
- currentQuest = piece.quest;
- }
- return currentQuest;
- }
-
-
- //如果是在Unity编辑器中,则字典随时改变时则进行修改,如果是打包则字典信息不会更改
- #if UNITY_EDITOR
- void OnValidate()//一旦这个脚本中的数据被更改时会自动调用
- {
- dialogueIndex.Clear();
- //一旦信息有所更新,就会将信息存储在字典中
- foreach(var piece in dialoguePieces)
- {
- if (!dialogueIndex.ContainsKey(piece.ID))
- dialogueIndex.Add(piece.ID, piece);
- }
- }
- #else
- void Awake()//保证在打包执行的游戏里第一时间获得对话的所有字典匹配
- {
- dialogueIndex.Clear();
- foreach (var piece in dialoguePieces)
- {
- if (!dialogueIndex.ContainsKey(piece.ID))
- dialogueIndex.Add(piece.ID, piece);
- }
- }
- #endif
-
-
-
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- using DG.Tweening;
-
- public class DialogueUI : Singleton<DialogueUI>
- {
- [Header("Basic Elements")]
- public Image icon;
- public Text mainText;
- public Button nextButton;
-
- public GameObject dialoguePanel;
-
- [Header("Data")]
- public DialougeData_SO currentData;
-
- int currentIndex = 0;
-
- [Header("Options")]
- public RectTransform optionPanel;
- public OptionUI optionPrefab;
-
-
- protected override void Awake()
- {
- base.Awake();
- nextButton.onClick.AddListener(ContinueDialogue);//点击时如果后续还有对话则继续进行
- }
-
- void ContinueDialogue()
- {
- if (currentIndex < currentData.dialoguePieces.Count)
- {
- UpdateMainDialogue(currentData.dialoguePieces[currentIndex]);
- }
- else dialoguePanel.SetActive(false);
- }
-
- public void UpdateDialogueData(DialougeData_SO data)
- {
- currentData = data;
- currentIndex = 0;//保证每次都是从头开始对话
- }
-
-
- public void UpdateMainDialogue(DialoguePiece piece)
- {
- dialoguePanel.SetActive(true);
- currentIndex++;
-
- if (piece.image != null)
- {
- icon.enabled = true;
- icon.sprite = piece.image;
- }
- else icon.enabled = false;
-
- mainText.text = "";
- //mainText.text = piece.text;
- mainText.DOText(piece.text, 1f);
-
- //如果后续还有对话就按next,没有就不按next
- if (piece.options.Count == 0 && currentData.dialoguePieces.Count > 0)
- {
- nextButton.interactable = true;
- nextButton.gameObject.SetActive(true);
- //currentIndex++;//不应该放在这里++,应该每运行一次都让index++,因此应该放在上面
- }
- else
- {
- //nextButton.gameObject.SetActive(false);
- nextButton.transform.GetChild(0).gameObject.SetActive(false);//让字看不见
- nextButton.interactable = false;//并且删除交互功能
- }
- CreateOptions(piece);//根据对话来创建选项
- }
-
- void CreateOptions(DialoguePiece piece)
- {
- if (optionPanel.childCount > 0)//销毁旧的选项
- {
- for(int i = 0; i < optionPanel.childCount; i++)
- {
- Destroy(optionPanel.GetChild(i).gameObject);
- }
- }
-
- //生成新的选项,并且调用选项,传入对话的选项信息,来更新option所显示的信息
- for (int i = 0; i < piece.options.Count; i++)
- {
- var option = Instantiate(optionPrefab, optionPanel);
- option.UpdateOption(piece,piece.options[i]);
- }
-
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class OptionUI : MonoBehaviour
- {
- public Text optionText;
- private Button thisButton;
- private DialoguePiece currentPiece;
-
-
- private bool takeQuest;
- private string nextPieceID;
- void Awake()
- {
- thisButton = GetComponent<Button>();
- thisButton.onClick.AddListener(OnOptionClicked);
- }
-
- public void UpdateOption(DialoguePiece piece,DialogueOption option)
- {
- currentPiece = piece;
- optionText.text = option.text;
- nextPieceID = option.targetID;
- takeQuest = option.takeQuest;
- }
-
-
- public void OnOptionClicked()
- {
- if (currentPiece.quest != null)//如果当前选项含有任务
- {
- //则获取该任务
- var newTask = new QuestManager.QuestTask
- {
- questData = Instantiate(currentPiece.quest)//将quest信息实例化然后赋值给QuestTask类里面的questData
- };
- if (takeQuest)
- {
- Debug.Log("takeQuest is true");
-
- //判断是否在列表中
- if (QuestManager.Instance.HaveQuest(newTask.questData))
- {
- Debug.Log("Quest in list");
-
- //判断是否完成,若完成则给予奖励
- if (QuestManager.Instance.GetTask(newTask.questData).IsComplete)
- {
- Debug.Log("任务完成,给予奖励");
- newTask.questData.GiveRewards();
- QuestManager.Instance.GetTask(newTask.questData).IsFinished = true;
- }
- }
- else
- {
- QuestManager.Instance.tasks.Add(newTask);
- //newTask.IsStarted = true;这样的做法并没有用,这样只是修改的临时变量
- QuestManager.Instance.GetTask(newTask.questData).IsStarted = true;
- //添加到任务列表
-
- foreach (var requireItem in newTask.questData.RequireTargetName())
- {
- InventoryManager.Instance.CheckQuestItemInBag(requireItem);
- }
- }
- }
- }
-
- if (nextPieceID == "")
- {
- DialogueUI.Instance.dialoguePanel.SetActive(false);
- return;
- }
- else
- {
- //用ID去获取下一个对话
- DialogueUI.Instance.UpdateMainDialogue(DialogueUI.Instance.currentData.dialogueIndex[nextPieceID]);
- }
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- using System.Linq;
-
- [CreateAssetMenu(fileName ="New Quest",menuName ="Quest/Quest Data")]
- public class QuestData_SO : ScriptableObject
- {
- [System.Serializable]
- public class QuestRequire
- {
- public string name;
- public int requireAmount;
- public int currentAmount;
- }
-
-
- public string questName;
- [TextArea]
- public string description;
-
- //需要三种任务完成的状态,npc才会有不同的反应
- public bool isStarted;
- public bool isComplete;
- public bool isFinished;
-
- public List<QuestRequire> questRequires = new List<QuestRequire>();
- public List<InventoryItem> rewards = new List<InventoryItem>();
-
- public void CheckQuestProgress()
- {
- var finishRequires = questRequires.Where(r => r.requireAmount <= r.currentAmount);
- isComplete = finishRequires.Count() == questRequires.Count;
-
- if (isComplete)
- {
- Debug.Log("任务完成");
- }
- }
-
-
- //当前任务需要收集/消灭的目标名字列表
- public List<string> RequireTargetName()
- {
- List<string> targetNameList = new List<string>();
- foreach(var require in questRequires)
- {
- targetNameList.Add(require.name);
- }
- return targetNameList;
- }
-
-
- public void GiveRewards()
- {
- foreach(var reward in rewards)
- {
- if (reward.amount < 0)
- {
- int requireCount = Mathf.Abs(reward.amount);
-
- //优先在背包里找是否有该物品,
- if (InventoryManager.Instance.QuestItemInBag(reward.itemData) != null)
- {
- //这种情况是背包里的东西不够,那就先在背包里扣除一部分,
- if (InventoryManager.Instance.QuestItemInBag(reward.itemData).amount <= requireCount)
- {
- requireCount -= InventoryManager.Instance.QuestItemInBag(reward.itemData).amount;//所需的数量减少
- InventoryManager.Instance.QuestItemInBag(reward.itemData).amount = 0;//背包里的商品扣除为0
-
- //背包里东西不够,剩下的部分从行动栏里扣除
- if (InventoryManager.Instance.QuestItemInAction(reward.itemData) != null)
- InventoryManager.Instance.QuestItemInAction(reward.itemData).amount -= requireCount;
-
- }
- //这种情况就是背包里的东西直接够,那直接扣除就好
- else
- {
- InventoryManager.Instance.QuestItemInBag(reward.itemData).amount -= requireCount;
- }
-
- }
- //这种情况是背包里一点东西都没有,那就直接扣除行动栏里的物品
- else
- {
- InventoryManager.Instance.QuestItemInAction(reward.itemData).amount -= requireCount;
- }
- }
- else
- {
- InventoryManager.Instance.inventoryData.AddItem(reward.itemData, reward.amount);
- }
-
- InventoryManager.Instance.inventoryUI.RefreshUI();
- InventoryManager.Instance.actionUI.RefreshUI();
- }
- }
-
-
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [RequireComponent(typeof(DialogueController))]
- public class QuestGiver : MonoBehaviour
- {
- DialogueController controller;
- QuestData_SO currentQuest;
-
- public DialougeData_SO startDialogue;
- public DialougeData_SO progressDialogue;
- public DialougeData_SO completeDialogue;
- public DialougeData_SO finishDialogue;
-
- private void Awake()
- {
- controller = GetComponent<DialogueController>();
- }
-
- #region 获得任务状态
- public bool IsStarted
- {
- get
- {
- if (QuestManager.Instance.HaveQuest(currentQuest))
- {
- return QuestManager.Instance.GetTask(currentQuest).IsStarted;
- }
- else return false;
- }
- }
-
- public bool IsComplete
- {
- get
- {
- if (QuestManager.Instance.HaveQuest(currentQuest))
- {
- return QuestManager.Instance.GetTask(currentQuest).IsComplete;
- }
- else return false;
- }
- }
-
- public bool IsFinished
- {
- get
- {
- if (QuestManager.Instance.HaveQuest(currentQuest))
- {
- return QuestManager.Instance.GetTask(currentQuest).IsFinished;
- }
- else return false;
- }
- }
- #endregion
-
- private void Start()
- {
- controller.currentData = startDialogue;
- currentQuest = controller.currentData.GetQuest();
- }
-
- //根据状态切换对话
- void Update()
- {
- if (IsStarted)
- {
- if (IsComplete)
- {
- controller.currentData = completeDialogue;
- }
- else
- {
- controller.currentData = progressDialogue;
- }
- }
-
- if (IsFinished)
- {
- controller.currentData = finishDialogue;
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using System.Linq;
-
- public class QuestManager : Singleton<QuestManager>
- {
- [System.Serializable]
- public class QuestTask
- {
- public QuestData_SO questData;
- public bool IsStarted {
- get { return questData.isStarted; }
- set { questData.isStarted = value; }
- }
-
- public bool IsComplete
- {
- get { return questData.isComplete; }
- set { questData.isComplete = value; }
- }
-
- public bool IsFinished
- {
- get { return questData.isFinished; }
- set { questData.isFinished = value; }
- }
-
- }
-
- public List<QuestTask> tasks = new List<QuestTask>();
-
- //敌人死亡,拾取物品时调用
- public void UpdateQuestProgress(string requireName,int amount)
- {
- foreach(var task in tasks)
- {
-
- if (task.IsFinished)
- continue;//为了避免已完成的任务受到影响
-
- var matchTask = task.questData.questRequires.Find(r => r.name == requireName);
- if (matchTask != null)
- matchTask.currentAmount += amount;
-
- task.questData.CheckQuestProgress();
- }
- }
-
- public bool HaveQuest(QuestData_SO data)//判断是否有这个任务
- {
- //在头文件中引入Ling,可以用于查找链表中的内容
- if (data != null)
- return tasks.Any(q => q.questData.questName == data.questName);
- else return false;
- }
-
- //根据任务数据的名字查找链表中的某一个任务
- public QuestTask GetTask(QuestData_SO data)
- {
- return tasks.Find(q => q.questData.questName == data.questName);
- }
-
- private void Start()
- {
- LoadQuestManager();
- }
-
-
- public void SaveQuestManager()
- {
- PlayerPrefs.SetInt("QuestCount", tasks.Count);
- for(int i = 0; i < tasks.Count; i++)
- {
- SaveManager.Instance.Save(tasks[i].questData, "task" + i);
- }
- }
-
-
- //加载数据的方式是通过重新新创建一个SO,然后让SO读取数据,然后再加入到tasks链表当中
- public void LoadQuestManager()
- {
- var quesCount = PlayerPrefs.GetInt("QuestCount");
- for(int i = 0; i < quesCount; i++)
- {
- var newQuest = ScriptableObject.CreateInstance<QuestData_SO>();//
- SaveManager.Instance.Load(newQuest, "task" + i);
- tasks.Add(new QuestTask { questData = newQuest });
- }
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class QuestNameButton : MonoBehaviour
- {
- public Text questNameText;
- public QuestData_SO currentData;
- //public Text questContentText;
-
- public void SetupNameButton(QuestData_SO quesData)
- {
- currentData = quesData;
-
- if (quesData.isComplete)
- questNameText.text = quesData.questName + "(完成)";
- else
- questNameText.text = quesData.questName;
- }
-
- private void Awake()
- {
- GetComponent<Button>().onClick.AddListener(UpdateQuestContent);
- }
- void UpdateQuestContent()
- {
- //questContentText.text = currentData.description;
- QuestUI.Instance.SetupRequireList(currentData);
-
- foreach(Transform item in QuestUI.Instance.rewardTransform)
- {
- Destroy(item.gameObject);
- }
-
-
- foreach(var item in currentData.rewards)//奖励可能不止一个所以需要循环列表
- {
- QuestUI.Instance.SetupRewardItem(item.itemData, item.amount);
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class QuestRequirement : MonoBehaviour
- {
- private Text requireName;
- private Text progressNumber;
-
-
- private void Awake()
- {
- requireName = GetComponent<Text>();
- progressNumber = transform.GetChild(0).GetComponent<Text>();
- }
-
- public void SetupRequirement(string name,int amount,int currentAmount)
- {
- requireName.text = name;
- progressNumber.text = currentAmount.ToString() + "/" + amount.ToString();
- }
-
- public void SetupRequirement(string name, bool isFinished)
- {
- if (isFinished)
- {
- requireName.text = name;
- progressNumber.text = "完成";
- requireName.color = Color.gray;
- progressNumber.color = Color.gray;
- }
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class QuestUI : Singleton<QuestUI>
- {
- [Header("Elements")]
- public GameObject quesPanel;
- public ItemToolTip tooltip;
- bool isOpen;
-
- [Header("Quest Name")]
- public RectTransform questListTransform;
- public QuestNameButton questNameButton;
-
- [Header("Text Content")]
- public Text quesContentText;
-
- [Header("Requirement")]
- public RectTransform requireTransform;
- public QuestRequirement requirement;
-
- [Header("Reward Panel")]
- public RectTransform rewardTransform;
- public ItemUI rewardUI;
-
- private void Update()
- {
- if (Input.GetKeyDown(KeyCode.Q))
- {
- isOpen = !isOpen;
- quesPanel.SetActive(isOpen);
- quesContentText.text = string.Empty;
- SetupQuestList();
- }
-
-
- if (!isOpen)
- tooltip.gameObject.SetActive(false);
- }
-
- public void SetupQuestList()
- {
- //清除原来已有的任务
- foreach(Transform item in questListTransform)
- {
- Destroy(item.gameObject);
- }
- foreach(Transform item in rewardTransform)
- {
- Destroy(item.gameObject);
- }
- foreach (Transform item in requireTransform)
- {
- Destroy(item.gameObject);
- }
-
- //遍历列表中的list,接取任务
- foreach(var task in QuestManager.Instance.tasks)
- {
- var newTask = Instantiate(questNameButton, questListTransform);
- newTask.SetupNameButton(task.questData);
- //newTask.questContentText = quesContentText;
- }
-
-
- }
-
- public void SetupRequireList(QuestData_SO questData)
- {
- quesContentText.text = questData.description;
- //将涉及到QuestNameButton中的三处questContentText关闭,不使用在里面传东西然后赋值的形式了,改为在此处直接修改
-
- foreach (Transform item in requireTransform)
- {
- Destroy(item.gameObject);
- }
- foreach(var require in questData.questRequires)
- {
- var q = Instantiate(requirement, requireTransform);
- if (questData.isFinished)
- q.SetupRequirement(require.name, true);
- else
- q.SetupRequirement(require.name, require.requireAmount, require.currentAmount);
- }
- }
-
- public void SetupRewardItem(ItemData_SO itemData,int amount)
- {
- var item = Instantiate(rewardUI, rewardTransform);
- item.SetupItemUI(itemData, amount);
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- public class ShowTooltip : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
- {
- private ItemUI currentItemUI;
-
- void Awake()
- {
- currentItemUI = GetComponent<ItemUI>();
- }
- public void OnPointerEnter(PointerEventData eventData)
- {
- Debug.Log("mouse in slot");
- QuestUI.Instance.tooltip.gameObject.SetActive(true);
- QuestUI.Instance.tooltip.SetupTooltip(currentItemUI.currentItemData);
- }
-
- public void OnPointerExit(PointerEventData eventData)
- {
- QuestUI.Instance.tooltip.gameObject.SetActive(false);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。