Godot任务追踪系统Skill godot-quest-system

这是一个用于Godot游戏引擎的任务系统,通过基于资源的任务数据、信号驱动的更新和自动加载管理器,实现任务目标跟踪、进度管理、奖励分发和分支链功能,适用于RPG游戏或任务系统开发。关键词包括Godot、任务系统、任务跟踪、信号驱动、自动加载、游戏开发。

游戏开发 0 次安装 0 次浏览 更新于 3/23/2026

name: godot-quest-system description: “使用基于资源的任务、信号驱动更新和自动加载管理器,实现任务跟踪系统(目标、进度、奖励、分支链)的专家蓝图。适用于RPG任务或任务系统。关键词:任务、目标、任务资源、任务目标、信号驱动、分支、奖励、自动加载。”

任务系统

基于资源的数据、信号驱动的更新和自动加载协调定义了可扩展的任务架构。

可用脚本

quest_manager.gd

具有目标进度和奖励分发的专家自动加载任务追踪器。

quest_graph_manager.gd

基于图的任务的运行时管理器。跟踪目标和节点进度。

在任务系统中切勿做的事情

  • 切勿在节点中存储任务数据 — 在player.gd变量中存储任务进度?场景重载时丢失。使用基于资源的任务或自动加载单例。
  • 切勿在不使用注册表的情况下使用字符串作为任务IDupdate_objective("kil_bandts", ...) 拼写错误 = 静默失败。使用常量或根据注册表验证ID。
  • 切勿忘记断开信号连接 — 任务完成但信号仍连接?下一次更新时任务再次完成 = 重复奖励。在_on_quest_completed()中断开连接。
  • 切勿轮询目标更新 — 每帧检查if enemy_count == 10 = 浪费。使用信号:enemy.died.connect(quest_manager.on_enemy_killed)
  • 切勿跳过任务的保存/加载 — 玩家完成任务5,游戏重启,任务重置?沮丧。必须持久化active_quests + completed_quests数组。
  • 切勿在不进行空值检查的情况下使用all()处理目标objectives.all(func(obj): return obj.is_complete()) 有null目标?崩溃。首先验证数组内容。

# quest.gd
class_name Quest
extends Resource

signal progress_updated(objective_id: String, progress: int)signal completed

@export var quest_id: String
@export var quest_name: String
@export_multiline var description: String
@export var objectives: Array[QuestObjective] = []
@export var rewards: Array[QuestReward] = []
@export var required_level: int = 1

func is_complete() -> bool:
    return objectives.all(func(obj): return obj.is_complete())

func check_completion() -> void:
    if is_complete():
        completed.emit()

任务目标

# quest_objective.gd
class_name QuestObjective
extends Resource

enum Type { KILL, COLLECT, TALK, REACH }

@export var objective_id: String
@export var type: Type
@export var target: String  # 敌人名称、物品ID、NPC名称、位置
@export var required_amount: int = 1
@export var current_amount: int = 0

func progress(amount: int = 1) -> void:
    current_amount += amount
    current_amount = mini(current_amount, required_amount)

func is_complete() -> bool:
    return current_amount >= required_amount

任务管理器

# quest_manager.gd (AutoLoad)
extends Node

signal quest_accepted(quest: Quest)
signal quest_completed(quest: Quest)
signal objective_updated(quest: Quest, objective: QuestObjective)

var active_quests: Array[Quest] = []
var completed_quests: Array[String] = []

func accept_quest(quest: Quest) -> void:
    if quest.quest_id in completed_quests:
        return
    
    active_quests.append(quest)
    quest.completed.connect(func(): _on_quest_completed(quest))
    quest_accepted.emit(quest)

func _on_quest_completed(quest: Quest) -> void:
    active_quests.erase(quest)
    completed_quests.append(quest.quest_id)
    
    # 给予奖励
    for reward in quest.rewards:
        reward.grant()
    
    quest_completed.emit(quest)

func update_objective(quest_id: String, objective_id: String, amount: int = 1) -> void:
    for quest in active_quests:
        if quest.quest_id == quest_id:
            for obj in quest.objectives:
                if obj.objective_id == objective_id:
                    obj.progress(amount)
                    objective_updated.emit(quest, obj)
                    quest.check_completion()
                    return

func get_active_quest(quest_id: String) -> Quest:
    for quest in active_quests:
        if quest.quest_id == quest_id:
            return quest
    return null

任务触发器

# 示例:击杀任务集成
# enemy.gd
func _on_died() -> void:
    QuestManager.update_objective("kill_bandits", "kill_bandit", 1)

# 示例:收集任务集成
# item_pickup.gd
func _on_collected() -> void:
    QuestManager.update_objective("gather_herbs", "collect_herb", 1)

# 示例:对话任务集成
# npc.gd
func interact() -> void:
    DialogueManager.start_dialogue(dialogue_id)
    QuestManager.update_objective("find_elder", "talk_to_elder", 1)

任务UI

# quest_ui.gd
extends Control

@onready var quest_list := $QuestList

func _ready() -> void:
    QuestManager.quest_accepted.connect(_on_quest_accepted)
    QuestManager.objective_updated.connect(_on_objective_updated)
    refresh_ui()

func refresh_ui() -> void:
    for child in quest_list.get_children():
        child.queue_free()
    
    for quest in QuestManager.active_quests:
        var quest_entry := create_quest_entry(quest)
        quest_list.add_child(quest_entry)

func create_quest_entry(quest: Quest) -> Control:
    var entry := VBoxContainer.new()
    
    var title := Label.new()
    title.text = quest.quest_name
    entry.add_child(title)
    
    for obj in quest.objectives:
        var obj_label := Label.new()
        obj_label.text = "%s: %d/%d" % [obj.target, obj.current_amount, obj.required_amount]
        entry.add_child(obj_label)
    
    return entry

最佳实践

  1. 信号驱动 — 发出事件,系统监听
  2. 保存进度 — 跟踪已完成任务
  3. 验证 — 接受前检查先决条件

参考

  • 相关:godot-dialogue-systemgodot-save-load-systems

相关