对话与任务系统基础架构 (三) - 任务系统实现详解
前言
前两篇文章分别介绍了整体架构设计和对话系统的具体实现,这次我们来深入任务系统的核心实现。经过多次迭代优化,我们的任务系统已经能够支持多种任务类型、复杂的触发条件、完整的进度追踪和数据持久化。
本篇将从以下几个方面详细介绍:
- 任务数据结构与配置表设计
- 任务收集器的插件化架构
- 任务管理器的核心逻辑
- 进度追踪与状态管理
- 数据持久化与存档系统
- UI系统集成与用户交互
任务数据结构设计
核心数据模型
我们的任务系统采用三层数据结构:任务组(TaskGroup) → 任务(Task) → 收集器(Collector)
// 任务组 - 管理一系列相关任务
[Serializable]
public class TaskGroupData
{
public int id; // 任务组ID
public string name; // 任务组名称
public string desc; // 任务组描述
public int firstTaskId; // 首个任务ID
public TaskGroupState groupState; // 任务组状态
public TaskReceivePosition receivePosition; // 接取位置类型
public List<TaskData> taskDataList; // 任务列表
// 运行时数据
public TaskData currentTask; // 当前激活任务
}
// 任务数据 - 单个任务的完整信息
[Serializable]
public class TaskData
{
public int id; // 任务ID
public int groupId; // 所属任务组ID
public string name; // 任务名称
public string desc; // 任务描述
public TaskType taskType; // 任务类型
public TaskState taskState; // 任务状态
public int nextTaskId; // 下一个任务ID
// 完成条件配置
public TaskCompleteCondition completeCondition;
// 触发事件配置
public TaskTriggerEvent triggerEvent;
// 奖励配置
public TaskReward reward;
}
任务完成条件设计
[Serializable]
public class TaskCompleteCondition
{
public TaskCompleteConditionType type; // 条件类型
public string target; // 目标对象
public int needCount; // 需要数量
public int curCount; // 当前进度
public string extraData; // 扩展数据
// 检查是否完成
public bool IsCompleted => curCount >= needCount;
// 更新进度
public void UpdateProgress(int count)
{
curCount = Mathf.Min(curCount + count, needCount);
}
}
public enum TaskCompleteConditionType
{
None = 0,
Dialogue = 1, // 完成对话
Collection = 2, // 收集物品
Interaction = 3, // 交互操作
KeyPress = 4, // 按键操作
KillMonster = 5, // 击杀怪物
ReachLocation = 6 // 到达地点
}
任务触发事件设计
[Serializable]
public class TaskTriggerEvent
{
public TaskTriggerEventType type; // 事件类型
public string eventData; // 事件数据
public void Execute()
{
switch (type)
{
case TaskTriggerEventType.StartDialogue:
TriggerStartDialogue();
break;
case TaskTriggerEventType.GiveItem:
TriggerGiveItem();
break;
case TaskTriggerEventType.ChangeScene:
TriggerChangeScene();
break;
}
}
}
public enum TaskTriggerEventType
{
None = 0,
StartDialogue = 1, // 启动对话
GiveItem = 2, // 给予物品
ChangeScene = 3, // 切换场景
PlayEffect = 4, // 播放特效
ShowTip = 5 // 显示提示
}
任务收集器插件化架构
收集器基类设计
public abstract class TaskCollectorBase : ITaskCollector, ITaskEventListener
{
protected TaskData taskData;
protected TaskCompleteCondition completeCondition;
protected EventGroup eventGroup;
public TaskData TaskData => taskData;
public bool IsCompleted => completeCondition.IsCompleted;
public TaskCollectorBase(TaskData taskData)
{
this.taskData = taskData;
this.completeCondition = taskData.completeCondition;
this.eventGroup = new EventGroup();
}
// 初始化收集器
public virtual void Init()
{
RegisterEvents();
Debug.Log($"任务收集器初始化: {taskData.name} ({taskData.taskType})");
}
// 注册事件监听
protected abstract void RegisterEvents();
// 处理任务相关事件
public abstract void OnTaskEventReceived(IEventMessage eventMessage);
// 检查任务完成状态
public abstract bool CheckTaskComplete();
// 更新任务进度
protected virtual void UpdateProgress(int count = 1)
{
int oldCount = completeCondition.curCount;
completeCondition.UpdateProgress(count);
Debug.Log($"任务进度更新: {taskData.name} {oldCount}->{completeCondition.curCount}/{completeCondition.needCount}");
// 发送进度更新事件
UniEvent.SendMessage(new TaskProgressUpdateEvent
{
TaskId = taskData.id,
OldProgress = oldCount,
NewProgress = completeCondition.curCount,
TotalProgress = completeCondition.needCount
});
// 检查是否完成
if (CheckTaskComplete())
{
OnTaskCompleted();
}
}
// 任务完成处理
protected virtual void OnTaskCompleted()
{
taskData.taskState = TaskState.CanSubmit;
Debug.Log($"任务完成: {taskData.name}");
// 发送任务完成事件
UniEvent.SendMessage(new TaskCompletedEvent { TaskId = taskData.id });
}
// 释放资源
public virtual void Release()
{
eventGroup?.RemoveAllListener();
Debug.Log($"任务收集器释放: {taskData.name}");
}
// 构建存档数据
public virtual JsonData BuildSaveData()
{
JsonData saveData = new JsonData();
saveData["taskId"] = taskData.id;
saveData["curCount"] = completeCondition.curCount;
saveData["taskState"] = (int)taskData.taskState;
return saveData;
}
// 加载存档数据
public virtual void LoadSaveData(JsonData saveData)
{
if (saveData.ContainsKey("curCount"))
{
completeCondition.curCount = (int)saveData["curCount"];
}
if (saveData.ContainsKey("taskState"))
{
taskData.taskState = (TaskState)(int)saveData["taskState"];
}
}
}
具体收集器实现
对话任务收集器
public class TaskDialogueCollector : TaskCollectorBase
{
private int targetDialogueGroupId;
public TaskDialogueCollector(TaskData taskData) : base(taskData)
{
// 解析目标对话组ID
targetDialogueGroupId = int.Parse(completeCondition.target);
}
protected override void RegisterEvents()
{
eventGroup.AddListener<TaskDialogueCollectorEvent>(OnTaskEventReceived);
}
public override void OnTaskEventReceived(IEventMessage eventMessage)
{
if (eventMessage is TaskDialogueCollectorEvent dialogueEvent)
{
if (dialogueEvent.DialogueGroupId == targetDialogueGroupId)
{
UpdateProgress();
}
}
}
public override bool CheckTaskComplete()
{
return completeCondition.IsCompleted;
}
}
收集任务收集器
public class TaskCollectionCollector : TaskCollectorBase
{
private string targetItemId;
public TaskCollectionCollector(TaskData taskData) : base(taskData)
{
targetItemId = completeCondition.target;
}
protected override void RegisterEvents()
{
eventGroup.AddListener<ItemCollectedEvent>(OnTaskEventReceived);
eventGroup.AddListener<InventoryChangedEvent>(OnTaskEventReceived);
}
public override void OnTaskEventReceived(IEventMessage eventMessage)
{
switch (eventMessage)
{
case ItemCollectedEvent itemEvent:
if (itemEvent.ItemId == targetItemId)
{
UpdateProgress(itemEvent.Count);
}
break;
case InventoryChangedEvent invEvent:
// 检查背包中的物品数量
CheckInventoryCount();
break;
}
}
private void CheckInventoryCount()
{
int currentCount = InventoryManager.Instance.GetItemCount(targetItemId);
completeCondition.curCount = Mathf.Min(currentCount, completeCondition.needCount);
}
public override bool CheckTaskComplete()
{
CheckInventoryCount();
return completeCondition.IsCompleted;
}
}
按键任务收集器
public class TaskKeyPressCollector : TaskCollectorBase
{
private KeyCode targetKey;
public TaskKeyPressCollector(TaskData taskData) : base(taskData)
{
// 解析目标按键
if (System.Enum.TryParse<KeyCode>(completeCondition.target, out KeyCode key))
{
targetKey = key;
}
}
protected override void RegisterEvents()
{
eventGroup.AddListener<TaskTestTapFEventMsg>(OnTaskEventReceived);
}
public override void OnTaskEventReceived(IEventMessage eventMessage)
{
if (eventMessage is TaskTestTapFEventMsg keyEvent)
{
if (keyEvent.TapChar == targetKey)
{
UpdateProgress();
}
}
}
public override bool CheckTaskComplete()
{
return completeCondition.IsCompleted;
}
}
收集器工厂
public static class TaskCollectorFactory
{
public static TaskCollectorBase CreateTaskCollector(TaskData taskData)
{
return taskData.taskType switch
{
TaskType.Dialogue => new TaskDialogueCollector(taskData),
TaskType.Collection => new TaskCollectionCollector(taskData),
TaskType.KeyPress => new TaskKeyPressCollector(taskData),
TaskType.Interaction => new TaskInteractionCollector(taskData),
TaskType.KillMonster => new TaskKillMonsterCollector(taskData),
_ => throw new System.NotImplementedException($"未实现的任务类型: {taskData.taskType}")
};
}
// 获取支持的任务类型列表
public static List<TaskType> GetSupportedTaskTypes()
{
return new List<TaskType>
{
TaskType.Dialogue,
TaskType.Collection,
TaskType.KeyPress,
TaskType.Interaction,
TaskType.KillMonster
};
}
}
任务管理器核心逻辑
TaskManager主要职责
public class TaskManager : MonoSingleton<TaskManager>
{
private TaskDataManager _taskDataManager;
private TaskCollectorManager _taskCollectorManager;
private ITaskInfoSaveHandle _taskInfoSaveHandle;
// 当前任务状态
public List<TaskGroupData> ActiveTaskGroups { get; private set; }
public List<TaskData> ActiveTasks { get; private set; }
public async ETTask Init()
{
// 初始化数据管理器
_taskDataManager = new TaskDataManager();
await _taskDataManager.Init();
// 初始化收集器管理器
_taskCollectorManager = new TaskCollectorManager();
_taskCollectorManager.Init();
// 初始化存档处理器
_taskInfoSaveHandle = new TaskInfoSaveHandle();
// 初始化活跃任务列表
ActiveTaskGroups = new List<TaskGroupData>();
ActiveTasks = new List<TaskData>();
// 注册事件
RegisterEvents();
// 加载存档数据
await LoadTaskData();
Debug.Log("任务管理器初始化完成");
}
private void RegisterEvents()
{
UniEvent.AddListener<TaskCompletedEvent>(OnTaskCompleted);
UniEvent.AddListener<TaskProgressUpdateEvent>(OnTaskProgressUpdate);
UniEvent.AddListener<StartDialogueChapter>(OnStartDialogue);
}
}
任务启动逻辑
public void StartTaskGroup(int groupId)
{
var taskGroup = _taskDataManager.GetTaskGroupData(groupId);
if (taskGroup == null)
{
Debug.LogError($"找不到任务组: {groupId}");
return;
}
// 检查任务组状态
if (taskGroup.groupState != TaskGroupState.CanReceive)
{
Debug.LogWarning($"任务组不可接取: {groupId}, 状态: {taskGroup.groupState}");
return;
}
// 更新任务组状态
taskGroup.groupState = TaskGroupState.InProgress;
ActiveTaskGroups.Add(taskGroup);
// 启动首个任务
StartTask(taskGroup.firstTaskId);
Debug.Log($"任务组启动: {taskGroup.name}");
// 发送任务组启动事件
UniEvent.SendMessage(new TaskGroupStartedEvent { GroupId = groupId });
}
public void StartTask(int taskId)
{
var taskData = _taskDataManager.GetTaskData(taskId);
if (taskData == null)
{
Debug.LogError($"找不到任务: {taskId}");
return;
}
// 检查任务状态
if (taskData.taskState != TaskState.CanReceive)
{
Debug.LogWarning($"任务不可接取: {taskId}, 状态: {taskData.taskState}");
return;
}
// 更新任务状态
taskData.taskState = TaskState.InProgress;
ActiveTasks.Add(taskData);
// 创建并启动收集器
var collector = _taskCollectorManager.AddTaskCollector(taskData);
if (collector != null)
{
collector.Init();
}
// 执行任务触发事件
taskData.triggerEvent?.Execute();
Debug.Log($"任务启动: {taskData.name}");
// 发送任务启动事件
UniEvent.SendMessage(new TaskStartedEvent { TaskId = taskId });
}
任务完成处理
private void OnTaskCompleted(IEventMessage msg)
{
if (msg is TaskCompletedEvent completedEvent)
{
CompleteTask(completedEvent.TaskId);
}
}
public void CompleteTask(int taskId)
{
var taskData = _taskDataManager.GetTaskData(taskId);
if (taskData == null) return;
// 更新任务状态
taskData.taskState = TaskState.Completed;
// 移除收集器
_taskCollectorManager.RemoveTaskCollectorByTaskId(taskId);
// 从活跃任务列表中移除
ActiveTasks.RemoveAll(t => t.id == taskId);
// 给予奖励
GiveTaskReward(taskData);
// 检查是否有下一个任务
if (taskData.nextTaskId > 0)
{
StartTask(taskData.nextTaskId);
}
else
{
// 检查任务组是否完成
CheckTaskGroupCompletion(taskData.groupId);
}
Debug.Log($"任务完成: {taskData.name}");
// 发送任务完成事件
UniEvent.SendMessage(new TaskFinishedEvent { TaskId = taskId });
}
private void CheckTaskGroupCompletion(int groupId)
{
var taskGroup = _taskDataManager.GetTaskGroupData(groupId);
if (taskGroup == null) return;
// 检查任务组中的所有任务是否都已完成
bool allTasksCompleted = taskGroup.taskDataList.All(t => t.taskState == TaskState.Completed);
if (allTasksCompleted)
{
taskGroup.groupState = TaskGroupState.Completed;
ActiveTaskGroups.RemoveAll(g => g.id == groupId);
Debug.Log($"任务组完成: {taskGroup.name}");
// 发送任务组完成事件
UniEvent.SendMessage(new TaskGroupCompletedEvent { GroupId = groupId });
}
}
任务奖励系统
private void GiveTaskReward(TaskData taskData)
{
if (taskData.reward == null) return;
// 经验奖励
if (taskData.reward.exp > 0)
{
PlayerManager.Instance.AddExp(taskData.reward.exp);
}
// 金币奖励
if (taskData.reward.gold > 0)
{
PlayerManager.Instance.AddGold(taskData.reward.gold);
}
// 物品奖励
if (taskData.reward.items != null && taskData.reward.items.Count > 0)
{
foreach (var item in taskData.reward.items)
{
InventoryManager.Instance.AddItem(item.itemId, item.count);
}
}
Debug.Log($"任务奖励发放: {taskData.name}");
}
[Serializable]
public class TaskReward
{
public int exp; // 经验奖励
public int gold; // 金币奖励
public List<TaskRewardItem> items; // 物品奖励
}
[Serializable]
public class TaskRewardItem
{
public string itemId; // 物品ID
public int count; // 物品数量
}
收集器管理器
public class TaskCollectorManager
{
private List<TaskCollectorBase> _activeCollectors;
private TaskCollectorBase _currentShowCollector;
public void Init()
{
_activeCollectors = new List<TaskCollectorBase>();
}
public TaskCollectorBase AddTaskCollector(TaskData taskData)
{
// 检查是否已存在相同任务的收集器
var existingCollector = _activeCollectors.FirstOrDefault(c => c.TaskData.id == taskData.id);
if (existingCollector != null)
{
Debug.LogWarning($"任务收集器已存在: {taskData.id}");
return existingCollector;
}
// 创建新的收集器
var collector = TaskCollectorFactory.CreateTaskCollector(taskData);
if (collector == null)
{
Debug.LogError($"无法创建任务收集器: {taskData.taskType}");
return null;
}
_activeCollectors.Add(collector);
// 设置为当前显示的收集器
SetCurrentShowCollector(collector);
Debug.Log($"添加任务收集器: {taskData.name}");
return collector;
}
public void RemoveTaskCollector(TaskCollectorBase collector)
{
if (collector == null) return;
collector.Release();
_activeCollectors.Remove(collector);
// 如果移除的是当前显示的收集器,切换到下一个
if (_currentShowCollector == collector)
{
_currentShowCollector = _activeCollectors.FirstOrDefault();
if (_currentShowCollector != null)
{
SetCurrentShowCollector(_currentShowCollector);
}
}
Debug.Log($"移除任务收集器: {collector.TaskData.name}");
}
public void RemoveTaskCollectorByTaskId(int taskId)
{
var collector = _activeCollectors.FirstOrDefault(c => c.TaskData.id == taskId);
if (collector != null)
{
RemoveTaskCollector(collector);
}
}
private void SetCurrentShowCollector(TaskCollectorBase collector)
{
_currentShowCollector = collector;
// 发送UI更新事件
UniEvent.SendMessage(new ChangeTaskCollectorShow { TaskCollector = collector });
}
public void Update()
{
// 更新所有支持Update的收集器
foreach (var collector in _activeCollectors)
{
if (collector is ITaskCollectorUpdate updateCollector)
{
updateCollector.Update();
}
}
}
// 获取所有活跃的收集器
public List<TaskCollectorBase> GetActiveCollectors()
{
return new List<TaskCollectorBase>(_activeCollectors);
}
// 根据任务类型获取收集器
public List<TaskCollectorBase> GetCollectorsByType(TaskType taskType)
{
return _activeCollectors.Where(c => c.TaskData.taskType == taskType).ToList();
}
}
数据持久化系统
存档数据结构
[Serializable]
public class TaskSaveData
{
public List<TaskGroupSaveData> taskGroups;
public List<TaskSaveData> tasks;
public string saveTime;
public int version;
public TaskSaveData()
{
taskGroups = new List<TaskGroupSaveData>();
tasks = new List<TaskSaveData>();
saveTime = System.DateTime.Now.ToString();
version = 1;
}
}
[Serializable]
public class TaskGroupSaveData
{
public int groupId;
public TaskGroupState groupState;
public int currentTaskId;
}
[Serializable]
public class TaskSaveData
{
public int taskId;
public TaskState taskState;
public int currentProgress;
public JsonData collectorData;
}
存档处理器实现
public class TaskInfoSaveHandle : ITaskInfoSaveHandle
{
private const string SAVE_FILE_NAME = "TaskSave.json";
public void Save(JsonData data)
{
try
{
string savePath = Path.Combine(Application.persistentDataPath, SAVE_FILE_NAME);
string jsonString = data.ToJson();
File.WriteAllText(savePath, jsonString);
Debug.Log($"任务数据保存成功: {savePath}");
}
catch (System.Exception e)
{
Debug.LogError($"任务数据保存失败: {e.Message}");
}
}
public async ETTask LoadAsync(System.Action<JsonData> callback)
{
try
{
string savePath = Path.Combine(Application.persistentDataPath, SAVE_FILE_NAME);
if (!File.Exists(savePath))
{
Debug.Log("任务存档文件不存在,使用默认数据");
callback?.Invoke(null);
return;
}
// 异步读取文件
await ETTask.Run(() =>
{
string jsonString = File.ReadAllText(savePath);
JsonData saveData = JsonMapper.ToObject(jsonString);
callback?.Invoke(saveData);
});
Debug.Log("任务数据加载成功");
}
catch (System.Exception e)
{
Debug.LogError($"任务数据加载失败: {e.Message}");
callback?.Invoke(null);
}
}
}
数据序列化与反序列化
public class TaskDataManager
{
// 构建存档数据
public JsonData BuildSaveData()
{
JsonData saveData = new JsonData();
// 保存任务组数据
JsonData groupsData = new JsonData();
groupsData.SetJsonType(JsonType.Array);
foreach (var taskGroup in _allTaskGroupData)
{
if (taskGroup.groupState != TaskGroupState.None)
{
JsonData groupData = new JsonData();
groupData["groupId"] = taskGroup.id;
groupData["groupState"] = (int)taskGroup.groupState;
groupData["currentTaskId"] = taskGroup.currentTask?.id ?? -1;
groupsData.Add(groupData);
}
}
saveData["taskGroups"] = groupsData;
// 保存任务数据
JsonData tasksData = new JsonData();
tasksData.SetJsonType(JsonType.Array);
foreach (var taskGroup in _allTaskGroupData)
{
foreach (var task in taskGroup.taskDataList)
{
if (task.taskState != TaskState.None)
{
JsonData taskData = new JsonData();
taskData["taskId"] = task.id;
taskData["taskState"] = (int)task.taskState;
taskData["currentProgress"] = task.completeCondition.curCount;
tasksData.Add(taskData);
}
}
}
saveData["tasks"] = tasksData;
// 保存收集器数据
var collectorManager = TaskManager.Instance.GetCollectorManager();
JsonData collectorsData = new JsonData();
collectorsData.SetJsonType(JsonType.Array);
foreach (var collector in collectorManager.GetActiveCollectors())
{
JsonData collectorData = collector.BuildSaveData();
collectorsData.Add(collectorData);
}
saveData["collectors"] = collectorsData;
// 保存时间戳和版本信息
saveData["saveTime"] = System.DateTime.Now.ToString();
saveData["version"] = 1;
return saveData;
}
// 加载存档数据
public void LoadSaveData(JsonData saveData)
{
if (saveData == null) return;
try
{
// 加载任务组数据
if (saveData.ContainsKey("taskGroups"))
{
JsonData groupsData = saveData["taskGroups"];
for (int i = 0; i < groupsData.Count; i++)
{
JsonData groupData = groupsData[i];
int groupId = (int)groupData["groupId"];
TaskGroupState groupState = (TaskGroupState)(int)groupData["groupState"];
var taskGroup = GetTaskGroupData(groupId);
if (taskGroup != null)
{
taskGroup.groupState = groupState;
}
}
}
// 加载任务数据
if (saveData.ContainsKey("tasks"))
{
JsonData tasksData = saveData["tasks"];
for (int i = 0; i < tasksData.Count; i++)
{
JsonData taskData = tasksData[i];
int taskId = (int)taskData["taskId"];
TaskState taskState = (TaskState)(int)taskData["taskState"];
int currentProgress = (int)taskData["currentProgress"];
var task = GetTaskData(taskId);
if (task != null)
{
task.taskState = taskState;
task.completeCondition.curCount = currentProgress;
}
}
}
Debug.Log("任务存档数据加载完成");
}
catch (System.Exception e)
{
Debug.LogError($"任务存档数据加载失败: {e.Message}");
}
}
}
UI系统集成(续)
public class TaskMainWindows : MonoBehaviour
{
[Header("UI组件")]
public Transform taskListParent;
public GameObject taskItemPrefab;
public Text currentTaskTitle;
public Text currentTaskDesc;
public Slider currentTaskProgress;
public Text progressText;
public Button closeButton;
[Header("任务分类")]
public Toggle mainTaskToggle;
public Toggle sideTaskToggle;
public Toggle completedTaskToggle;
private List<TaskItemUI> _taskItems = new List<TaskItemUI>();
private TaskType _currentFilter = TaskType.None;
private void Start()
{
InitUI();
RegisterEvents();
RefreshTaskList();
}
private void InitUI()
{
closeButton.onClick.AddListener(CloseWindow);
mainTaskToggle.onValueChanged.AddListener((isOn) => {
if (isOn) FilterTasks(TaskType.Main);
});
sideTaskToggle.onValueChanged.AddListener((isOn) => {
if (isOn) FilterTasks(TaskType.Side);
});
completedTaskToggle.onValueChanged.AddListener((isOn) => {
if (isOn) ShowCompletedTasks();
});
}
private void RegisterEvents()
{
UniEvent.AddListener<TaskStartedEvent>(OnTaskStarted);
UniEvent.AddListener<TaskProgressUpdateEvent>(OnTaskProgressUpdate);
UniEvent.AddListener<TaskCompletedEvent>(OnTaskCompleted);
UniEvent.AddListener<ChangeTaskCollectorShow>(OnCurrentTaskChanged);
}
private void OnTaskStarted(IEventMessage msg)
{
if (msg is TaskStartedEvent startedEvent)
{
RefreshTaskList();
}
}
private void OnTaskProgressUpdate(IEventMessage msg)
{
if (msg is TaskProgressUpdateEvent progressEvent)
{
UpdateTaskProgress(progressEvent.TaskId, progressEvent.NewProgress, progressEvent.TotalProgress);
}
}
private void OnCurrentTaskChanged(IEventMessage msg)
{
if (msg is ChangeTaskCollectorShow changeEvent)
{
UpdateCurrentTaskDisplay(changeEvent.TaskCollector.TaskData);
}
}
private void RefreshTaskList()
{
// 清除现有任务项
ClearTaskItems();
// 获取活跃任务列表
var activeTasks = TaskManager.Instance.ActiveTasks;
// 根据当前过滤条件显示任务
var filteredTasks = FilterTasksByType(activeTasks);
// 创建任务UI项
foreach (var task in filteredTasks)
{
CreateTaskItem(task);
}
}
private List<TaskData> FilterTasksByType(List<TaskData> tasks)
{
if (_currentFilter == TaskType.None)
return tasks;
return tasks.Where(t => t.taskType == _currentFilter).ToList();
}
private void CreateTaskItem(TaskData taskData)
{
var itemObj = Instantiate(taskItemPrefab, taskListParent);
var taskItem = itemObj.GetComponent<TaskItemUI>();
taskItem.Init(taskData);
taskItem.OnTaskSelected += OnTaskItemSelected;
_taskItems.Add(taskItem);
}
private void OnTaskItemSelected(TaskData taskData)
{
UpdateCurrentTaskDisplay(taskData);
}
private void UpdateCurrentTaskDisplay(TaskData taskData)
{
if (taskData == null) return;
currentTaskTitle.text = taskData.name;
currentTaskDesc.text = taskData.desc;
var condition = taskData.completeCondition;
currentTaskProgress.maxValue = condition.needCount;
currentTaskProgress.value = condition.curCount;
progressText.text = $"{condition.curCount}/{condition.needCount}";
}
private void UpdateTaskProgress(int taskId, int newProgress, int totalProgress)
{
var taskItem = _taskItems.FirstOrDefault(item => item.TaskData.id == taskId);
if (taskItem != null)
{
taskItem.UpdateProgress(newProgress, totalProgress);
}
// 如果是当前显示的任务,更新进度显示
if (currentTaskTitle.text == TaskManager.Instance.GetTaskData(taskId)?.name)
{
currentTaskProgress.value = newProgress;
progressText.text = $"{newProgress}/{totalProgress}";
}
}
}
任务列表项UI
public class TaskItemUI : MonoBehaviour
{
[Header("UI组件")]
public Text taskNameText;
public Text taskDescText;
public Slider progressSlider;
public Text progressText;
public Image taskTypeIcon;
public Button selectButton;
public GameObject completedMark;
public TaskData TaskData { get; private set; }
public System.Action<TaskData> OnTaskSelected;
public void Init(TaskData taskData)
{
TaskData = taskData;
taskNameText.text = taskData.name;
taskDescText.text = taskData.desc;
UpdateProgress(taskData.completeCondition.curCount, taskData.completeCondition.needCount);
UpdateTaskTypeIcon(taskData.taskType);
UpdateCompletedState(taskData.taskState);
selectButton.onClick.AddListener(() => OnTaskSelected?.Invoke(TaskData));
}
public void UpdateProgress(int current, int total)
{
progressSlider.maxValue = total;
progressSlider.value = current;
progressText.text = $"{current}/{total}";
}
private void UpdateTaskTypeIcon(TaskType taskType)
{
// 根据任务类型设置图标
string iconPath = taskType switch
{
TaskType.Main => "Icons/task_main",
TaskType.Side => "Icons/task_side",
TaskType.Daily => "Icons/task_daily",
_ => "Icons/task_default"
};
var sprite = Resources.Load<Sprite>(iconPath);
if (sprite != null)
{
taskTypeIcon.sprite = sprite;
}
}
private void UpdateCompletedState(TaskState taskState)
{
bool isCompleted = taskState == TaskState.Completed || taskState == TaskState.CanSubmit;
completedMark.SetActive(isCompleted);
// 完成的任务显示为灰色
var canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup != null)
{
canvasGroup.alpha = isCompleted ? 0.6f : 1.0f;
}
}
}
任务追踪UI
public class TaskTrackerUI : MonoBehaviour
{
[Header("UI组件")]
public Text taskNameText;
public Text taskDescText;
public Slider progressSlider;
public Text progressText;
public Button minimizeButton;
public CanvasGroup canvasGroup;
[Header("动画设置")]
public float fadeInDuration = 0.5f;
public float fadeOutDuration = 0.3f;
private TaskData _currentTask;
private Coroutine _fadeCoroutine;
private void Start()
{
RegisterEvents();
minimizeButton.onClick.AddListener(MinimizeTracker);
// 初始状态隐藏
canvasGroup.alpha = 0;
gameObject.SetActive(false);
}
private void RegisterEvents()
{
UniEvent.AddListener<ChangeTaskCollectorShow>(OnCurrentTaskChanged);
UniEvent.AddListener<TaskProgressUpdateEvent>(OnTaskProgressUpdate);
UniEvent.AddListener<TaskCompletedEvent>(OnTaskCompleted);
}
private void OnCurrentTaskChanged(IEventMessage msg)
{
if (msg is ChangeTaskCollectorShow changeEvent)
{
ShowTask(changeEvent.TaskCollector.TaskData);
}
}
private void OnTaskProgressUpdate(IEventMessage msg)
{
if (msg is TaskProgressUpdateEvent progressEvent)
{
if (_currentTask != null && _currentTask.id == progressEvent.TaskId)
{
UpdateProgress(progressEvent.NewProgress, progressEvent.TotalProgress);
// 进度更新时显示一个简短的高亮效果
StartCoroutine(HighlightProgress());
}
}
}
private void OnTaskCompleted(IEventMessage msg)
{
if (msg is TaskCompletedEvent completedEvent)
{
if (_currentTask != null && _currentTask.id == completedEvent.TaskId)
{
StartCoroutine(ShowCompletionEffect());
}
}
}
public void ShowTask(TaskData taskData)
{
_currentTask = taskData;
if (taskData == null)
{
HideTracker();
return;
}
taskNameText.text = taskData.name;
taskDescText.text = GetSimplifiedDesc(taskData.desc);
UpdateProgress(taskData.completeCondition.curCount, taskData.completeCondition.needCount);
ShowTracker();
}
private string GetSimplifiedDesc(string fullDesc)
{
// 简化描述文本,适合追踪UI显示
if (fullDesc.Length > 30)
{
return fullDesc.Substring(0, 27) + "...";
}
return fullDesc;
}
private void UpdateProgress(int current, int total)
{
progressSlider.maxValue = total;
progressSlider.value = current;
progressText.text = $"{current}/{total}";
}
private void ShowTracker()
{
gameObject.SetActive(true);
if (_fadeCoroutine != null)
{
StopCoroutine(_fadeCoroutine);
}
_fadeCoroutine = StartCoroutine(FadeIn());
}
private void HideTracker()
{
if (_fadeCoroutine != null)
{
StopCoroutine(_fadeCoroutine);
}
_fadeCoroutine = StartCoroutine(FadeOut());
}
private IEnumerator FadeIn()
{
float elapsed = 0;
float startAlpha = canvasGroup.alpha;
while (elapsed < fadeInDuration)
{
elapsed += Time.deltaTime;
canvasGroup.alpha = Mathf.Lerp(startAlpha, 1, elapsed / fadeInDuration);
yield return null;
}
canvasGroup.alpha = 1;
}
private IEnumerator FadeOut()
{
float elapsed = 0;
float startAlpha = canvasGroup.alpha;
while (elapsed < fadeOutDuration)
{
elapsed += Time.deltaTime;
canvasGroup.alpha = Mathf.Lerp(startAlpha, 0, elapsed / fadeOutDuration);
yield return null;
}
canvasGroup.alpha = 0;
gameObject.SetActive(false);
}
private IEnumerator HighlightProgress()
{
// 进度更新时的高亮效果
Color originalColor = progressText.color;
progressText.color = Color.yellow;
yield return new WaitForSeconds(0.5f);
progressText.color = originalColor;
}
private IEnumerator ShowCompletionEffect()
{
// 任务完成时的特效
progressText.text = "已完成!";
progressText.color = Color.green;
// 缩放动画
Vector3 originalScale = transform.localScale;
transform.localScale = originalScale * 1.1f;
yield return new WaitForSeconds(1f);
transform.localScale = originalScale;
// 2秒后隐藏
yield return new WaitForSeconds(1f);
HideTracker();
}
private void MinimizeTracker()
{
// 最小化追踪器,只显示进度条
taskNameText.gameObject.SetActive(false);
taskDescText.gameObject.SetActive(false);
minimizeButton.gameObject.SetActive(false);
// 调整UI布局
var rectTransform = GetComponent<RectTransform>();
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, 40);
}
}
调试与开发工具
任务系统调试面板
#if UNITY_EDITOR
[CustomEditor(typeof(TaskManager))]
public class TaskManagerEditor : Editor
{
private int _testTaskGroupId = 1001;
private int _testTaskId = 2001;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var taskManager = target as TaskManager;
if (!Application.isPlaying) return;
GUILayout.Space(10);
GUILayout.Label("任务系统调试工具", EditorStyles.boldLabel);
// 任务组测试
GUILayout.BeginHorizontal();
_testTaskGroupId = EditorGUILayout.IntField("任务组ID:", _testTaskGroupId);
if (GUILayout.Button("启动任务组"))
{
taskManager.StartTaskGroup(_testTaskGroupId);
}
GUILayout.EndHorizontal();
// 单个任务测试
GUILayout.BeginHorizontal();
_testTaskId = EditorGUILayout.IntField("任务ID:", _testTaskId);
if (GUILayout.Button("启动任务"))
{
taskManager.StartTask(_testTaskId);
}
GUILayout.EndHorizontal();
GUILayout.Space(5);
// 当前活跃任务信息
GUILayout.Label("活跃任务:", EditorStyles.boldLabel);
foreach (var task in taskManager.ActiveTasks)
{
GUILayout.BeginHorizontal();
GUILayout.Label($"{task.id}: {task.name}");
GUILayout.Label($"({task.completeCondition.curCount}/{task.completeCondition.needCount})");
if (GUILayout.Button("完成"))
{
taskManager.CompleteTask(task.id);
}
GUILayout.EndHorizontal();
}
GUILayout.Space(5);
// 系统操作
if (GUILayout.Button("保存任务数据"))
{
taskManager.SaveTaskData();
}
if (GUILayout.Button("重新加载任务数据"))
{
taskManager.ReloadTaskData();
}
if (GUILayout.Button("清除所有任务"))
{
taskManager.ClearAllTasks();
}
}
}
#endif
运行时任务状态监控
public class TaskDebugUI : MonoBehaviour
{
[Header("调试设置")]
public bool showDebugInfo = true;
public KeyCode toggleKey = KeyCode.F1;
private bool _showWindow = false;
private Vector2 _scrollPosition;
private void Update()
{
if (Input.GetKeyDown(toggleKey))
{
_showWindow = !_showWindow;
}
}
private void OnGUI()
{
if (!showDebugInfo || !_showWindow) return;
GUILayout.BeginArea(new Rect(10, 10, 400, Screen.height - 20));
GUILayout.BeginVertical("box");
GUILayout.Label("任务系统调试信息", GUI.skin.label);
_scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
// 显示活跃任务组
GUILayout.Label("活跃任务组:", GUI.skin.label);
foreach (var taskGroup in TaskManager.Instance.ActiveTaskGroups)
{
GUILayout.Label($" {taskGroup.id}: {taskGroup.name} ({taskGroup.groupState})");
}
GUILayout.Space(10);
// 显示活跃任务
GUILayout.Label("活跃任务:", GUI.skin.label);
foreach (var task in TaskManager.Instance.ActiveTasks)
{
GUILayout.Label($" {task.id}: {task.name}");
GUILayout.Label($" 状态: {task.taskState}");
GUILayout.Label($" 进度: {task.completeCondition.curCount}/{task.completeCondition.needCount}");
}
GUILayout.Space(10);
// 显示收集器信息
var collectorManager = TaskManager.Instance.GetCollectorManager();
var collectors = collectorManager.GetActiveCollectors();
GUILayout.Label($"活跃收集器 ({collectors.Count}):", GUI.skin.label);
foreach (var collector in collectors)
{
GUILayout.Label($" {collector.TaskData.name} ({collector.TaskData.taskType})");
}
GUILayout.EndScrollView();
GUILayout.EndVertical();
GUILayout.EndArea();
}
}
性能优化策略
1. 事件监听优化
public abstract class TaskCollectorBase
{
// 使用事件过滤器减少不必要的事件处理
protected virtual bool ShouldHandleEvent(IEventMessage eventMessage)
{
// 子类可以重写此方法来过滤事件
return true;
}
public void OnTaskEventReceived(IEventMessage eventMessage)
{
if (!ShouldHandleEvent(eventMessage))
return;
HandleTaskEvent(eventMessage);
}
protected abstract void HandleTaskEvent(IEventMessage eventMessage);
}
// 具体收集器中的优化示例
public class TaskDialogueCollector : TaskCollectorBase
{
protected override bool ShouldHandleEvent(IEventMessage eventMessage)
{
// 只处理对话相关事件
return eventMessage is TaskDialogueCollectorEvent;
}
}
2. 数据缓存优化
public class TaskDataManager
{
private Dictionary<int, TaskData> _taskDataCache = new Dictionary<int, TaskData>();
private Dictionary<int, TaskGroupData> _taskGroupCache = new Dictionary<int, TaskGroupData>();
public TaskData GetTaskData(int taskId)
{
if (_taskDataCache.TryGetValue(taskId, out TaskData cachedData))
{
return cachedData;
}
// 从配置表加载数据
var taskData = LoadTaskDataFromConfig(taskId);
if (taskData != null)
{
_taskDataCache[taskId] = taskData;
}
return taskData;
}
// 预加载常用任务数据
public async ETTask PreloadTaskData(List<int> taskIds)
{
var loadTasks = new List<ETTask>();
foreach (int taskId in taskIds)
{
if (!_taskDataCache.ContainsKey(taskId))
{
loadTasks.Add(LoadTaskDataAsync(taskId));
}
}
await ETTask.WhenAll(loadTasks);
}
}
3. UI更新优化
public class TaskUI : MonoBehaviour
{
private bool _isDirty = false;
private float _lastUpdateTime = 0;
private const float UPDATE_INTERVAL = 0.1f; // 限制更新频率
public void MarkDirty()
{
_isDirty = true;
}
private void Update()
{
if (_isDirty && Time.time - _lastUpdateTime > UPDATE_INTERVAL)
{
RefreshUI();
_isDirty = false;
_lastUpdateTime = Time.time;
}
}
private void RefreshUI()
{
// 批量更新UI,避免频繁的单独更新
UpdateTaskList();
UpdateProgressDisplay();
UpdateRewardDisplay();
}
}
扩展性设计
自定义任务类型扩展
// 1. 定义新的任务类型
public enum CustomTaskType
{
TimedChallenge = 100, // 限时挑战
SocialTask = 101, // 社交任务
PuzzleTask = 102 // 解谜任务
}
// 2. 实现对应的收集器
public class TimedChallengeCollector : TaskCollectorBase
{
private float _timeLimit;
private float _startTime;
public TimedChallengeCollector(TaskData taskData) : base(taskData)
{
_timeLimit = float.Parse(taskData.completeCondition.extraData);
}
public override void Init()
{
base.Init();
_startTime = Time.time;
}
protected override void RegisterEvents()
{
eventGroup.AddListener<TimedChallengeEvent>(OnTaskEventReceived);
}
public override void OnTaskEventReceived(IEventMessage eventMessage)
{
if (eventMessage is TimedChallengeEvent challengeEvent)
{
if (Time.time - _startTime <= _timeLimit)
{
UpdateProgress(challengeEvent.Score);
}
else
{
// 超时失败
OnTaskFailed();
}
}
}
private void OnTaskFailed()
{
taskData.taskState = TaskState.Failed;
UniEvent.SendMessage(new TaskFailedEvent { TaskId = taskData.id });
}
}
// 3. 在工厂中注册新类型
public static class TaskCollectorFactory
{
public static TaskCollectorBase CreateTaskCollector(TaskData taskData)
{
return taskData.taskType switch
{
// 原有类型...
TaskType.Dialogue => new TaskDialogueCollector(taskData),
// 新增类型
(TaskType)CustomTaskType.TimedChallenge => new TimedChallengeCollector(taskData),
(TaskType)CustomTaskType.SocialTask => new SocialTaskCollector(taskData),
(TaskType)CustomTaskType.PuzzleTask => new PuzzleTaskCollector(taskData),
_ => throw new System.NotImplementedException($"未实现的任务类型: {taskData.taskType}")
};
}
}
小结
本篇详细介绍了任务系统的核心实现,主要包括:
- 数据结构设计:三层架构支持复杂任务流程
- 收集器系统:插件化架构,易于扩展新任务类型
- 管理器逻辑:完整的任务生命周期管理
- 数据持久化:可靠的存档和加载机制
- UI系统集成:完善的用户交互界面
- 性能优化:多种优化策略保证系统效率
- 扩展性设计:支持自定义任务类型扩展
至此,我们的对话与任务系统基础架构系列就全部完成了。这套系统经过实际项目的验证,具有良好的稳定性和扩展性,希望能为大家的项目开发提供参考。
系列总结:
- 第一篇:整体架构设计,奠定了系统的基础框架
- 第二篇:对话系统实现,解决了剧情交互的核心需求
- 第三篇:任务系统实现,完成了游戏进度管理的闭环
核心技术要点:
- 分层架构 + 事件驱动的设计模式
- 数据驱动的配置管理
- 插件化的功能扩展机制
- 完善的数据持久化方案
- 高效的性能优化策略
后续优化方向:
- 任务系统的可视化编辑器
- 更丰富的任务类型支持
- 云存档和多端同步
- 任务系统的热更新支持
感谢大家的关注,如果有任何问题或建议,欢迎在评论区讨论交流!