Token导航 LogoToken导航TokenDH.com
开发只读github未标认证来源可访问许可证需确认审计通过

godot-ability-system戈多能力系统

Agent Skill

godot-ability-system 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

2,496

周安装

104

GitHub Stars

137

下载量

832
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:godot-ability-system(戈多能力系统)
来源仓库:https://github.com/thedivergentai/gd-agentic-skills
仓库路径:skills/godot-ability-system
安装命令:
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-ability-system
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-ability-system

简介

godot-ability-system 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。

  • 适用于 GitHub 仓库管理和代码协作相关任务。
  • 围绕仓库状态、代码变更或协作事项进行整理。
  • 安装命令:npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-ability-system。
  • 建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

SKILL.md

Ability System

Expert guidance for building flexible, extensible ability systems.

NEVER Do

  • NEVER use _process() for cooldown tracking — Use timers or manual delta tracking in _physics_process(). _process() has variable delta and causes cooldown desync in slow frames.
  • NEVER forget global cooldown (GCD) — Without GCD, players spam instant abilities. Add a small universal cooldown (0.5-1.5s) between all ability casts.
  • NEVER hardcode ability effects in manager code — Use the Strategy pattern. Each ability is a Resource with execute() method, not a giant switch statement.
  • NEVER allow ability use during animation lock — Check is_casting or animation_playing before allowing new casts. Interrupting animations breaks state machines.
  • NEVER save cooldown state without time normalization — Save "cooldown_end_time" (OS.get_unix_time() + remaining), not "remaining_time". Prevents exploits (change system clock, reload game).
  • NEVER use Singletons (Autoloads) for combat managers — Centralizing combat state in a global object makes tracking bugs difficult and breaks encapsulation. Keep abilities and stats scoped to the scenes that actually use them.
  • NEVER use Object Pooling with GDScript — GDScript uses reference counting memory management, so you generally do not need to pool instantiated abilities or projectiles. Simply instantiate and queue_free().
  • NEVER rely on deep inheritance trees — Avoid having a BaseAbility -> MagicAbility -> FireAbility inheritance hell. Use node composition instead.

Available Scripts

MANDATORY: Read the appropriate script before implementing the corresponding pattern.

ability_manager.gd

Ability orchestration with cooldown registry, can_use checks, and visual cooldown progress. Decoupled from character logic for use on players, enemies, or turrets.

ability_resource.gd

Scriptable ability resource base class with metadata, stats, and effects array. Virtual execute() method for inheritance (ProjectileAbility, BuffAbility).

buff_stat.gd

Resource-Driven Buff System setup. Extends Resource and creates highly modular, drag-and-drop ability data.


Architecture Patterns

Resource-Based Abilities

# ability_base.gd - Base class for all abilities
class_name Ability
extends Resource

@export var ability_id: String
@export var display_name: String
@export var icon: Texture2D
@export var description: String

@export_group("Costs")
@export var mana_cost: int = 0
@export var stamina_cost: int = 0
@export var health_cost: int = 0  # Life tap abilities

@export_group("Timing")
@export var cooldown: float = 5.0
@export var cast_time: float = 0.0  # 0 = instant
@export var channel_time: float = 0.0  # Channeled abilities

@export_group("Unlocking")
@export var unlock_level: int = 1
@export var prerequisites: Array[String] = []  # Other ability IDs

## Override these
func can_cast(caster: Node) -> bool:
    return true  # Additional checks (range, target, etc.)

func execute(caster: Node, target: Node = null) -> void:
    pass  # Ability effect

func on_cast_start(caster: Node) -> void:
    pass  # Animation, effects

func on_cast_complete(caster: Node) -> void:
    execute(caster)

func on_cancel(caster: Node) -> void:
    pass  # Refund resources

Concrete Ability Example

# fireball.gd
class_name FireballAbility
extends Ability

@export var damage: int = 50
@export var projectile_scene: PackedScene
@export var range: float = 500.0

func can_cast(caster: Node) -> bool:
    var target = caster.get_target()
    if not target:
        return false

    var distance := caster.global_position.distance_to(target.global_position)
    return distance <= range

func execute(caster: Node, target: Node = null) -> void:
    var projectile := projectile_scene.instantiate()
    caster.get_parent().add_child(projectile)
    projectile.global_position = caster.global_position
    projectile.target = target
    projectile.damage = damage

Ability Manager (Centralized)

Core Manager

# ability_manager.gd
class_name AbilityManager
extends Node

signal ability_cast(ability_id: String)
signal ability_ready(ability_id: String)
signal cooldown_started(ability_id: String, duration: float)

var abilities: Dictionary = {}  # ability_id → Ability
var cooldowns: Dictionary = {}  # ability_id → float (time remaining)
var is_casting: bool = false
var global_cooldown: float = 0.0  # GCD timer

@export var gcd_duration: float = 1.0  # Global cooldown

func register_ability(ability: Ability) -> void:
    abilities[ability.ability_id] = ability
    cooldowns[ability.ability_id] = 0.0

func can_use_ability(ability_id: String, caster: Node) -> bool:
    var ability := abilities.get(ability_id) as Ability
    if not ability:
        return false

    # Check GCD
    if global_cooldown > 0.0:
        return false

    # Check specific cooldown
    if cooldowns.get(ability_id, 0.0) > 0.0:
        return false

    # Check if already casting
    if is_casting and ability.cast_time > 0.0:
        return false

    # Check resources
    if not has_resources(caster, ability):
        return false

    # Ability-specific checks
    return ability.can_cast(caster)

func use_ability(ability_id: String, caster: Node, target: Node = null) -> bool:
    if not can_use_ability(ability_id, caster):
        return false

    var ability := abilities[ability_id]

    # Consume resources
    consume_resources(caster, ability)

    # Start cast
    if ability.cast_time > 0.0:
        start_cast(ability, caster, target)
    else:
        # Instant cast
        ability.execute(caster, target)
        trigger_cooldown(ability_id, ability.cooldown)

    ability_cast.emit(ability_id)
    return true

func start_cast(ability: Ability, caster: Node, target: Node) -> void:
    is_casting = true
    ability.on_cast_start(caster)

    # Create timer for cast completion
    var timer := get_tree().create_timer(ability.cast_time)
    await timer.timeout

    if is_casting:  # Not interrupted
        ability.on_cast_complete(caster)
        trigger_cooldown(ability.ability_id, ability.cooldown)

    is_casting = false

func interrupt_cast() -> void:
    if is_casting:
        is_casting = false
        # Trigger ability.on_cancel() if needed

func trigger_cooldown(ability_id: String, duration: float) -> void:
    cooldowns[ability_id] = duration
    global_cooldown = gcd_duration
    cooldown_started.emit(ability_id, duration)

func _physics_process(delta: float) -> void:
    # Tick cooldowns
    for ability_id in cooldowns.keys():
        if cooldowns[ability_id] > 0.0:
            cooldowns[ability_id] -= delta
            if cooldowns[ability_id] <= 0.0:
                ability_ready.emit(ability_id)

    # Tick GCD
    if global_cooldown > 0.0:
        global_cooldown -= delta

func has_resources(caster: Node, ability: Ability) -> bool:
    return (caster.mana >= ability.mana_cost and
            caster.stamina >= ability.stamina_cost and
            caster.health > ability.health_cost)

func consume_resources(caster: Node, ability: Ability) -> void:
    caster.mana -= ability.mana_cost
    caster.stamina -= ability.stamina_cost
    caster.health -= ability.health_cost

Advanced Patterns

Combo System

# combo_tracker.gd
extends Node

var combo_chain: Array[String] = []
var combo_window: float = 2.0  # Seconds to continue combo
var last_ability_time: float = 0.0

func register_ability_use(ability_id: String) -> void:
    var current_time := Time.get_ticks_msec() * 0.001

    # Reset if too much time passed
    if current_time - last_ability_time > combo_window:
        combo_chain.clear()

    combo_chain.append(ability_id)
    last_ability_time = current_time

    # Check for combo completion
    check_combos()

func check_combos() -> void:
    # Example: "slash" → "slash" → "spin" = "whirlwind"
    if combo_chain.size() >= 3:
        var last_three := combo_chain.slice(-3)
        if last_three == ["slash", "slash", "spin"]:
            trigger_combo_ability("whirlwind")
            combo_chain.clear()

func trigger_combo_ability(combo_id: String) -> void:
    # Execute powerful combo ability
    pass

Charge-Based Abilities

# charge_ability.gd - Abilities with multiple charges (like League of Legends Flash)
class_name ChargeAbility
extends Ability

@export var max_charges: int = 2
@export var charge_recharge_time: float = 20.0

var current_charges: int = max_charges
var recharge_timer: float = 0.0

func can_cast(caster: Node) -> bool:
    return current_charges > 0

func execute(caster: Node, target: Node = null) -> void:
    current_charges -= 1

    # Start recharging if not at max
    if current_charges < max_charges and recharge_timer == 0.0:
        recharge_timer = charge_recharge_time

func tick(delta: float) -> void:
    if recharge_timer > 0.0:
        recharge_timer -= delta
        if recharge_timer <= 0.0:
            current_charges += 1
            if current_charges < max_charges:
                recharge_timer = charge_recharge_time  # Continue recharging
            else:
                recharge_timer = 0.0

Skill Tree System

Skill Node

# skill_node.gd
class_name SkillNode
extends Resource

@export var skill_id: String
@export var display_name: String
@export var description: String
@export var icon: Texture2D

@export_group("Requirements")
@export var prerequisites: Array[String] = []  # Other skill_ids
@export var character_level_required: int = 1
@export var points_required: int = 1
@export var mutually_exclusive_with: Array[String] = []  # Can't have both

@export_group("Progression")
@export var max_rank: int = 1
@export var current_rank: int = 0

@export_group("Effects")
@export var unlocks_ability: String = ""  # Ability ID to grant
@export var stat_bonuses: Dictionary = {}  # "strength": 5, "crit_chance": 0.05

func can_unlock(player_skills: Dictionary, player_level: int, available_points: int) -> bool:
    # Already maxed
    if current_rank >= max_rank:
        return false

    # Not enough points
    if available_points < points_required:
        return false

    # Level requirement
    if player_level < character_level_required:
        return false

    # Prerequisites
    for prereq_id in prerequisites:
        if not player_skills.has(prereq_id) or player_skills[prereq_id].current_rank == 0:
            return false

    # Mutual exclusivity
    for exclusive_id in mutually_exclusive_with:
        if player_skills.has(exclusive_id) and player_skills[exclusive_id].current_rank > 0:
            return false

    return true

func unlock() -> void:
    current_rank += 1

Skill Tree Manager

# skill_tree.gd
class_name SkillTree
extends Node

signal skill_unlocked(skill_id: String, rank: int)
signal points_changed(new_total: int)

var skills: Dictionary = {}  # skill_id → SkillNode
var skill_points: int = 0

func add_skill(skill: SkillNode) -> void:
    skills[skill.skill_id] = skill

func can_unlock_skill(skill_id: String, player_level: int) -> bool:
    var skill := skills.get(skill_id) as SkillNode
    if not skill:
        return false

    return skill.can_unlock(skills, player_level, skill_points)

func unlock_skill(skill_id: String, player_level: int) -> bool:
    if not can_unlock_skill(skill_id, player_level):
        return false

    var skill := skills[skill_id]
    skill.unlock()
    skill_points -= skill.points_required

    # Apply effects
    apply_skill_effects(skill)

    skill_unlocked.emit(skill_id, skill.current_rank)
    points_changed.emit(skill_points)
    return true

func apply_skill_effects(skill: SkillNode) -> void:
    # Grant ability if specified
    if skill.unlocks_ability != "":
        var ability_manager := get_node("/root/AbilityManager")
        # Register new ability

    # Apply stat bonuses
    var player := get_tree().get_first_node_in_group("player")
    for stat_name in skill.stat_bonuses.keys():
        var bonus = skill.stat_bonuses[stat_name]
        player.set(stat_name, player.get(stat_name) + bonus)

func add_skill_points(amount: int) -> void:
    skill_points += amount
    points_changed.emit(skill_points)

func reset_tree(refund_points: bool = true) -> void:
    var total_spent := 0
    for skill in skills.values():
        total_spent += skill.current_rank * skill.points_required
        skill.current_rank = 0

    if refund_points:
        skill_points += total_spent
        points_changed.emit(skill_points)

Cooldown Strategies

Per-Ability Cooldown (Standard)

# Already shown in AbilityManager above
# Each ability has independent cooldown

Shared Cooldown (Hearthstone-style)

# All abilities of type "summon" share cooldown
var summon_cooldown: float = 0.0

func use_summon_ability(ability: Ability) -> void:
    ability.execute()
    summon_cooldown = 3.0  # All summons on 3s cooldown

Charge System (Already shown above)

Multiple uses, recharges over time.


Edge Cases

Cooldown Persistence

# save_system.gd
func save_ability_cooldowns() -> Dictionary:
    var data := {}
    var current_time := Time.get_unix_time_from_system()

    for ability_id in ability_manager.cooldowns.keys():
        var remaining := ability_manager.cooldowns[ability_id]
        if remaining > 0.0:
            data[ability_id] = current_time + remaining  # Absolute time

    return data

func load_ability_cooldowns(data: Dictionary) -> void:
    var current_time := Time.get_unix_time_from_system()

    for ability_id in data.keys():
        var end_time: float = data[ability_id]
        var remaining := max(0.0, end_time - current_time)
        ability_manager.cooldowns[ability_id] = remaining

Animation Lock

# Prevent ability spam during attack animations
func _on_animation_player_animation_started(anim_name: String) -> void:
    if anim_name.begins_with("attack_"):
        ability_manager.is_casting = true

func _on_animation_player_animation_finished(anim_name: String) -> void:
    if anim_name.begins_with("attack_"):
        ability_manager.is_casting = false

Expert Techniques & Optimizations

1. Dependency Injection for Loose Coupling

Design your ability scenes so they have no hardcoded dependencies on the player context (e.g., getting parent nodes to reduce health). Instead, the parent context should inject itself or wire the signals.

2. Duck Typing for Hit Detection

Do not enforce strict class checks. Rely on duck-typing: if collision.get_collider().has_method("hit"): collision.get_collider().hit()

3. Group Broadcasting for AoE

For Area-of-Effect abilities, assign entities to groups. Process damage efficiently by calling get_tree().call_group("enemies", "apply_damage", 50) instead of looping manually.

Reference

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.05%
按下载量换算292

Claude

32.87%
按下载量换算273

Cursor

17.9%
按下载量换算149

Gemini CLI

9.06%
按下载量换算75

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills