【Unity】对话与任务系统基础架构 (三) - 任务系统实现详解

对话与任务系统基础架构 (三) - 任务系统实现详解

前言

前两篇文章分别介绍了整体架构设计和对话系统的具体实现,这次我们来深入任务系统的核心实现。经过多次迭代优化,我们的任务系统已经能够支持多种任务类型、复杂的触发条件、完整的进度追踪和数据持久化。

本篇将从以下几个方面详细介绍:

  • 任务数据结构与配置表设计
  • 任务收集器的插件化架构
  • 任务管理器的核心逻辑
  • 进度追踪与状态管理
  • 数据持久化与存档系统
  • 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}")
        };
    }
}

小结

本篇详细介绍了任务系统的核心实现,主要包括:

  1. 数据结构设计:三层架构支持复杂任务流程
  2. 收集器系统:插件化架构,易于扩展新任务类型
  3. 管理器逻辑:完整的任务生命周期管理
  4. 数据持久化:可靠的存档和加载机制
  5. UI系统集成:完善的用户交互界面
  6. 性能优化:多种优化策略保证系统效率
  7. 扩展性设计:支持自定义任务类型扩展

至此,我们的对话与任务系统基础架构系列就全部完成了。这套系统经过实际项目的验证,具有良好的稳定性和扩展性,希望能为大家的项目开发提供参考。


系列总结:

  • 第一篇:整体架构设计,奠定了系统的基础框架
  • 第二篇:对话系统实现,解决了剧情交互的核心需求
  • 第三篇:任务系统实现,完成了游戏进度管理的闭环

核心技术要点:

  • 分层架构 + 事件驱动的设计模式
  • 数据驱动的配置管理
  • 插件化的功能扩展机制
  • 完善的数据持久化方案
  • 高效的性能优化策略

后续优化方向:

  • 任务系统的可视化编辑器
  • 更丰富的任务类型支持
  • 云存档和多端同步
  • 任务系统的热更新支持

感谢大家的关注,如果有任何问题或建议,欢迎在评论区讨论交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值