Godot 4 武器切换系统

SkillMedia

Godot 4 weapon switching system, supporting weapon type enums, weapon base class design, multiple switching logic, input bindings, and a locking mechanism.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Godot 4 武器切换系统 skill

What this skill tells your AI

The instructions your AI receives, as published by 925236118/alphaagent in addons/agent/skills/default_skills/godot-weapon-system/SKILL.md and read by ahel’s review.

完整的武器管理系统,支持多类型武器、快速切换、冷却锁定、输入绑定。

何时使用此技能

  • 实现玩家武器切换
  • 近战/远程武器系统
  • 武器冷却与锁定
  • 武器类型分类管理

武器类型枚举

# weapon_type.gd
class_name WeaponType
extends RefCounted

## 武器类型枚举
enum Type {
    NONE = -1,
    SWORD = 0,      # 近战 - 剑
    AXE = 1,        # 近战 - 斧
    HAMMER = 2,     # 近战 - 锤
    BOW = 3,        # 远程 - 弓
    CROSSBOW = 4,   # 远程 - 弩
    STAFF = 5,      # 法杖
    SHIELD = 6,     # 盾牌
    THROWING = 7,   # 投掷武器
}

## 类型名称映射
const TYPE_NAMES: Dictionary = {
    Type.SWORD: "剑",
    Type.AXE: "斧",
    Type.HAMMER: "锤",
    Type.BOW: "弓",
    Type.CROSSBOW: "弩",
    Type.STAFF: "法杖",
    Type.SHIELD: "盾牌",
    Type.THROWING: "投掷武器"
}

## 获取类型名称
static func get_name(type: Type) -> String:
    return TYPE_NAMES.get(type, "未知")

## 是否是近战武器
static func is_melee(type: Type) -> bool:
    return type in [Type.SWORD, Type.AXE, Type.HAMMER, Type.SHIELD]

## 是否是远程武器
static func is_ranged(type: Type) -> bool:
    return type in [Type.BOW, Type.CROSSBOW, Type.STAFF, Type.THROWING]

武器基类设计

WeaponData 武器数据资源

# weapon_data.gd
class_name WeaponData
extends Resource

## 武器唯一标识符
@export var id: StringName

## 武器名称
@export var weapon_name: String

## 武器类型
@export var weapon_type: WeaponType.Type = WeaponType.Type.SWORD

## 武器 Prefab 场景
@export var weapon_scene: PackedScene

## 武器图标(用于UI)
@export var icon: Texture2D

## 基础属性
@export var base_damage: int = 10
@export var attack_speed: float = 1.0
@export var attack_range: float = 1.0

## 冷却时间
@export var cooldown: float = 0.5

## 是否需要弹药
@export var needs_ammo: bool = false
@export var max_ammo: int = 0
@export var ammo_type: StringName = &""

## 特殊属性
@export var can_block: bool = false
@export var block_ratio: float = 0.5

## 动画
@export var attack_animation: StringName = &"attack"
@export var idle_animation: StringName = &"idle"

## 获取武器类型名称
func get_type_name() -> String:
    return WeaponType.get_name(weapon_type)

## 是否是近战武器
func is_melee() -> bool:
    return WeaponType.is_melee(weapon_type)

## 是否是远程武器
func is_ranged() -> bool:
    return WeaponType.is_ranged(weapon_type)

Weapon 基类

# weapon.gd
class_name Weapon
extends Node2D

## 信号:攻击开始
signal attack_started

## 信号:攻击结束
signal attack_finished

## 信号:攻击命中
signal attack_hit(target: Node)

## 信号:弹药变化
signal ammo_changed(current: int, max: int)

@export var weapon_data: WeaponData

var _owner: CharacterBody2D
var _current_ammo: int
var _cooldown_timer: float = 0.0
var _is_attacking: bool = false

func _ready() -> void:
    _owner = get_owner() as CharacterBody2D
    if weapon_data and weapon_data.needs_ammo:
        _current_ammo = weapon_data.max_ammo
        ammo_changed.emit(_current_ammo, weapon_data.max_ammo)

func _process(delta: float) -> void:
    if _cooldown_timer > 0:
        _cooldown_timer -= delta

func _physics_process(delta: float) -> void:
    pass

## 使用武器攻击
func attack() -> bool:
    if not can_attack():
        return false

    if weapon_data.needs_ammo and _current_ammo <= 0:
        return false

    _is_attacking = true
    _start_attack()
    attack_started.emit()

    if weapon_data.needs_ammo:
        _current_ammo -= 1
        ammo_changed.emit(_current_ammo, weapon_data.max_ammo)

    # 重置冷却
    _cooldown_timer = weapon_data.cooldown

    return true

func _start_attack() -> void:
    # 播放攻击动画
    if _owner.has_method("play_animation"):
        _owner.play_animation(weapon_data.attack_animation)

func _end_attack() -> void:
    _is_attacking = false
    attack_finished.emit()

## 停止攻击
func stop_attack() -> void:
    _is_attacking = false
    _end_attack()

## 是否可以攻击
func can_attack() -> bool:
    if _is_attacking:
        return false
    if _cooldown_timer > 0:
        return false
    return true

## 获取剩余冷却时间
func get_cooldown_remaining() -> float:
    return maxf(_cooldown_timer, 0.0)

## 装填弹药
func reload(amount: int = 0) -> void:
    if not weapon_data.needs_ammo:
        return

    if amount <= 0:
        _current_ammo = weapon_data.max_ammo
    else:
        _current_ammo = mini(_current_ammo + amount, weapon_data.max_ammo)

    ammo_changed.emit(_current_ammo, weapon_data.max_ammo)

## 命中处理(供Hitbox调用)
func on_hit(target: Node) -> void:
    attack_hit.emit(target)

具体武器实现

# sword.gd
class_name Sword
extends Weapon

@export var slash_effect_scene: PackedScene

func _start_attack() -> void:
    super._start_attack()

    # 生成斩击特效
    if slash_effect_scene:
        var effect := slash_effect_scene.instantiate()
        get_tree().current_scene.add_child(effect)
        effect.global_position = global_position
        effect.rotation = _owner.rotation

func on_hit(target: Node) -> void:
    if target.has_method("take_damage"):
        target.take_damage(weapon_data.base_damage)

    # 击退效果
    if target.has_method("apply_knockback"):
        var direction := (target.global_position - _owner.global_position).normalized()
        target.apply_knockback(direction, 200.0)
# bow.gd
class_name Bow
extends Weapon

@export var arrow_scene: PackedScene
@export var arrow_spawn_offset: Vector2 = Vector2(30, 0)

func _start_attack() -> void:
    super._start_attack()

    # 发射箭矢
    if arrow_scene:
        var arrow := arrow_scene.instantiate()
        get_tree().current_scene.add_child(arrow)

        var spawn_pos := global_position + arrow_spawn_offset.rotated(global_rotation)
        arrow.initialize(spawn_pos, _owner.rotation, weapon_data.base_damage)

切换逻辑

WeaponSwitcher 武器切换器

# weapon_switcher.gd
class_name WeaponSwitcher
extends Node

## 信号:武器切换
signal weapon_switched(from_weapon: Weapon, to_weapon: Weapon)

## 信号:武器被锁定
signal weapon_locked(weapon_type: WeaponType.Type, unlock_time: float)

## 信号:切换冷却开始
signal switch_cooldown_started(duration: float)

@export var weapon_slots: Array[WeaponData] = []
@export var max_secondary_weapons: int = 2

## 当前激活的武器索引
var current_weapon_index: int = -1

## 当前武器引用
var current_weapon: Weapon = null

## 武器节点字典
var _weapon_nodes: Dictionary = {}

## 切换冷却
var _switch_cooldown: float = 0.3
var _is_locked: bool = false
var _lock_until: float = 0.0

## 武器类型到索引的映射
var _type_to_index: Dictionary = {}

func _ready() -> void:
    _initialize_weapons()

func _process(delta: float) -> void:
    _update_cooldown(delta)
    _update_lock(delta)

func _update_cooldown(delta: float) -> void:
    if _switch_cooldown > 0:
        _switch_cooldown -= delta

func _update_lock(delta: float) -> void:
    if _is_locked and Time.get_ticks_msec() / 1000.0 >= _lock_until:
        _is_locked = false

func _initialize_weapons() -> void:
    # 创建所有武器节点
    for i in weapon_slots.size():
        var data: WeaponData = weapon_slots[i]
        if data.weapon_scene == null:
            continue

        var weapon: Weapon = data.weapon_scene.instantiate()
        weapon.weapon_data = data
        weapon.set_process(false)
        weapon.visible = false
        add_child(weapon)
        _weapon_nodes[i] = weapon

        # 建立类型映射
        _type_to_index[data.weapon_type] = i

    # 默认装备第一把武器
    if weapon_slots.size() > 0:
        _equip_weapon(0)

## 切换到指定索引的武器
func switch_to_index(index: int) -> bool:
    if index < 0 or index >= weapon_slots.size():
        return false

    if index == current_weapon_index:
        return true

    if not can_switch():
        return false

    _switch_cooldown = 0.3
    switch_cooldown_started.emit(_switch_cooldown)

    var previous := current_weapon
    _unequip_current()
    _equip_weapon(index)

    weapon_switched.emit(previous, current_weapon)
    return true

## 切换到指定类型
func switch_to_type(weapon_type: WeaponType.Type) -> bool:
    if _type_to_index.has(weapon_type):
        return switch_to_index(_type_to_index[weapon_type])
    return false

## 切换到下一把武器(循环)
func switch_to_next() -> bool:
    if weapon_slots.size() <= 1:
        return false

    var next_index := (current_weapon_index + 1) % weapon_slots.size()
    return switch_to_index(next_index)

## 切换到上一把武器(循环)
func switch_to_previous() -> bool:
    if weapon_slots.size() <= 1:
        return false

    var prev_index := (current_weapon_index - 1 + weapon_slots.size()) % weapon_slots.size()
    return switch_to_index(prev_index)

## 卸下当前武器
func _unequip_current() -> void:
    if current_weapon != null:
        current_weapon.set_process(false)
        current_weapon.visible = false
        current_weapon.stop_attack()

## 装备武器
func _equip_weapon(index: int) -> void:
    current_weapon_index = index
    current_weapon = _weapon_nodes.get(index)

    if current_weapon != null:
        current_weapon.visible = true
        current_weapon.set_process(true)

## 是否可以切换
func can_switch() -> bool:
    if _switch_cooldown > 0:
        return false
    if _is_locked:
        return false
    if current_weapon != null and current_weapon._is_attacking:
        return false
    return true

## 锁定特定类型武器
func lock_weapon_type(weapon_type: WeaponType.Type, duration: float) -> void:
    _is_locked = true
    _lock_until = Time.get_ticks_msec() / 1000.0 + duration
    weapon_locked.emit(weapon_type, duration)

## 解锁武器类型
func unlock_weapon_type(weapon_type: WeaponType.Type) -> void:
    _is_locked = false

## 获取当前武器数据
func get_current_weapon_data() -> WeaponData:
    if current_weapon_index >= 0 and current_weapon_index < weapon_slots.size():
        return weapon_slots[current_weapon_index]
    return null

## 获取当前武器类型
func get_current_weapon_type() -> WeaponType.Type:
    var data := get_current_weapon_data()
    if data != null:
        return data.weapon_type
    return WeaponType.Type.NONE

## 添加武器到槽位
func add_weapon(data: WeaponData) -> bool:
    if weapon_slots.size() >= max_secondary_weapons + 1:
        return false

    weapon_slots.append(data)
    var index := weapon_slots.size() - 1

    var weapon: Weapon = data.weapon_scene.instantiate()
    weapon.weapon_data = data
    weapon.set_process(false)
    weapon.visible = false
    add_child(weapon)
    _weapon_nodes[index] = weapon
    _type_to_index[data.weapon_type] = index

    return true

## 移除武器
func remove_weapon(index: int) -> bool:
    if index < 0 or index >= weapon_slots.size():
        return false

    # 如果是当前武器,切换到另一把
    if index == current_weapon_index:
        var next_index := (index + 1) % weapon_slots.size()
        if next_index != index:
            switch_to_index(next_index)
        else:
            _unequip_current()
            current_weapon_index = -1
            current_weapon = null

    weapon_slots.remove_at(index)
    _weapon_nodes.erase(index)

    return true

输入绑定

输入映射配置

# weapon_input_handler.gd
class_name WeaponInputHandler
extends Node

@export var weapon_switcher: WeaponSwitcher

## 输入映射名称
const INPUT_SLOT_1 := "weapon_slot_1"
const INPUT_SLOT_2 := "weapon_slot_2"
const INPUT_SLOT_3 := "weapon_slot_3"
const INPUT_SLOT_4 := "weapon_slot_4"
const INPUT_SLOT_5 := "weapon_slot_5"
const INPUT_NEXT_WEAPON := "next_weapon"
const INPUT_PREV_WEAPON := "prev_weapon"
const INPUT_ATTACK := "attack"
const INPUT_BLOCK := "block"
const INPUT_RELOAD := "reload"

func _ready() -> void:
    _setup_input_actions()

func _unhandled_input(event: InputEvent) -> void:
    # 攻击
    if event.is_action_pressed(INPUT_ATTACK):
        _on_attack_pressed()
    elif event.is_action_released(INPUT_ATTACK):
        _on_attack_released()

    # 格挡
    elif event.is_action_pressed(INPUT_BLOCK):
        _on_block_pressed()
    elif event.is_action_released(INPUT_BLOCK):
        _on_block_released()

    # 切换武器
    elif event.is_action_pressed(INPUT_SLOT_1):
        weapon_switcher.switch_to_index(0)
    elif event.is_action_pressed(INPUT_SLOT_2):
        weapon_switcher.switch_to_index(1)
    elif event.is_action_pressed(INPUT_SLOT_3):
        weapon_switcher.switch_to_index(2)
    elif event.is_action_pressed(INPUT_SLOT_4):
        weapon_switcher.switch_to_index(3)
    elif event.is_action_pressed(INPUT_SLOT_5):
        weapon_switcher.switch_to_index(4)

    # 循环切换
    elif event.is_action_pressed(INPUT_NEXT_WEAPON):
        weapon_switcher.switch_to_next()
    elif event.is_action_pressed(INPUT_PREV_WEAPON):
        weapon_switcher.switch_to_previous()

    # 换弹
    elif event.is_action_pressed(INPUT_RELOAD):
        _on_reload_pressed()

func _setup_input_actions() -> void:
    # 在ProjectSettings中设置这些输入映射
    # 或者动态创建
    pass

func _on_attack_pressed() -> void:
    if weapon_switcher.current_weapon != null:
        weapon_switcher.current_weapon.attack()

func _on_attack_released() -> void:
    if weapon_switcher.current_weapon != null:
        weapon_switcher.current_weapon.stop_attack()

func _on_block_pressed() -> void:
    var data := weapon_switcher.get_current_weapon_data()
    if data != null and data.can_block:
        # 播放格挡动画
        pass

func _on_block_released() -> void:
    pass

func _on_reload_pressed() -> void:
    if weapon_switcher.current_weapon != null:
        weapon_switcher.current_weapon.reload()

ProjectSettings 输入配置

[input]

attack = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"echo":false,"script":null)
 ]
}
block = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"echo":false,"script":null)
 ]
}
reload = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"echo":false,"script":null)
 ]
}
next_weapon = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"echo":false,"script":null)
 ]
}
prev_weapon = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":90,"key_label":0,"unicode":122,"echo":false,"script":null)
 ]
}
weapon_slot_1 = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":49,"key_label":0,"unicode":49,"echo":false,"script":null)
 ]
}
weapon_slot_2 = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":50,"key_label":0,"unicode":50,"echo":false,"script":null)
 ]
}
weapon_slot_3 = {
    "deadzone": 0.5,
    "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":51,"key_label":0,"unicode":51,"echo":false,"script":null)
 ]
}

锁定机制

武器锁定系统

# weapon_lock_manager.gd
class_name WeaponLockManager
extends Node

## 锁定信息
class LockInfo:
    var weapon_type: WeaponType.Type
    var unlock_time: float
    var reason: String

    func _init(type: WeaponType.Type, time: float, reason_str: String):
        weapon_type = type
        unlock_time = time
        reason = reason_str

var _locks: Dictionary = {}  # weapon_type -> LockInfo

func _process(delta: float) -> void:
    _check_locks(delta)

func _check_locks(delta: float) -> void:
    var current_time := Time.get_ticks_msec() / 1000.0
    var to_remove: Array

    for type in _locks.keys():
        var lock: LockInfo = _locks[type]
        if current_time >= lock.unlock_time:
            to_remove.append(type)

    for type in to_remove:
        _locks.erase(type)

## 锁定武器类型
func lock(weapon_type: WeaponType.Type, duration: float, reason: String = "") -> void:
    var unlock_time := Time.get_ticks_msec() / 1000.0 + duration
    _locks[weapon_type] = LockInfo.new(weapon_type, unlock_time, reason)

## 解锁武器类型
func unlock(weapon_type: WeaponType.Type) -> void:
    _locks.erase(weapon_type)

## 是否被锁定
func is_locked(weapon_type: WeaponType.Type) -> bool:
    return _locks.has(weapon_type)

## 获取剩余锁定时间
func get_remaining_lock_time(weapon_type: WeaponType.Type) -> float:
    if not _locks.has(weapon_type):
        return 0.0

    var current_time := Time.get_ticks_msec() / 1000.0
    var unlock_time: float = _locks[weapon_type].unlock_time
    return maxf(unlock_time - current_time, 0.0)

## 锁定时触发(用于UI提示)
func _on_weapon_locked(weapon_type: WeaponType.Type, remaining: float) -> void:
    print("武器类型 %s 被锁定,剩余时间: %.1f秒" % [WeaponType.get_name(weapon_type), remaining])

使用场景

# 玩家被眩晕时锁定武器
func _on_player_stunned(duration: float) -> void:
    var current_type := weapon_switcher.get_current_weapon_type()
    weapon_lock_manager.lock(current_type, duration, "眩晕")

    # 停止当前攻击
    weapon_switcher.current_weapon.stop_attack()

# 武器切换冷却
func _on_switch_cooldown_started(duration: float) -> void:
    # 更新UI冷却显示
    ui.update_weapon_switch_cooldown(duration)

UI集成

武器栏UI

# weapon_bar_ui.gd
class_name WeaponBarUI
extends Control

@export var weapon_switcher: WeaponSwitcher
@export var slot_scene: PackedScene

@onready var slots_container: HBoxContainer = %SlotsContainer

var slotuis: Array[WeaponSlotUI] = []

func _ready() -> void:
    weapon_switcher.weapon_switched.connect(_on_weapon_switched)
    weapon_switcher.weapon_locked.connect(_on_weapon_locked)
    weapon_switcher.switch_cooldown_started.connect(_on_switch_cooldown)

    _create_slots()

func _create_slots() -> void:
    for i in weapon_switcher.weapon_slots.size():
        var slot: WeaponSlotUI = slot_scene.instantiate()
        slot.slot_index = i
        slot.clicked.connect(_on_slot_clicked)
        slots_container.add_child(slot)
        slotuis.append(slot)

    _update_all_slots()

func _update_all_slots() -> void:
    for i in slotuis.size():
        var data: WeaponData = weapon_switcher.weapon_slots[i]
        slotuis[i].set_weapon_data(data)
        slotuis[i].set_selected(i == weapon_switcher.current_weapon_index)

func _on_weapon_switched(from: Weapon, to: Weapon) -> void:
    _update_all_slots()

func _on_weapon_locked(weapon_type: WeaponType.Type, unlock_time: float) -> void:
    # 更新对应类型的槽位显示锁定状态
    for slot in slotuis:
        var data: WeaponData = weapon_switcher.weapon_slots[slot.slot_index]
        if data.weapon_type == weapon_type:
            slot.set_locked(true, unlock_time)

func _on_switch_cooldown(duration: float) -> void:
    # 显示切换冷却
    for slot in slotuis:
        slot.start_cooldown(duration)

func _on_slot_clicked(index: int) -> void:
    weapon_switcher.switch_to_index(index)

武器槽UI

# weapon_slot_ui.gd
class_name WeaponSlotUI
extends PanelContainer

signal clicked(slot_index: int)

@export var slot_index: int = 0

@onready var icon_texture: TextureRect = %IconTexture
@onready var key_label: Label = %KeyLabel
@onready var lock_icon: TextureRect = %LockIcon
@onready var cooldown_overlay: ColorRect = %CooldownOverlay
@onready var selected_border: PanelContainer = %SelectedBorder

var _is_selected: bool = false
var _is_locked: bool = false
var _cooldown_timer: float = 0.0

func _ready() -> void:
    gui_input.connect(_on_gui_input)
    mouse_entered.connect(_on_mouse_entered)
    mouse_exited.connect(_on_mouse_exited)

func _process(delta: float) -> void:
    _update_cooldown(delta)

func set_weapon_data(data: WeaponData) -> void:
    if data != null and data.icon != null:
        icon_texture.texture = data.icon
    else:
        icon_texture.texture = null

    # 显示快捷键
    key_label.text = "%d" % (slot_index + 1)

func set_selected(selected: bool) -> void:
    _is_selected = selected
    selected_border.visible = selected

func set_locked(locked: bool, _unlock_time: float) -> void:
    _is_locked = locked
    lock_icon.visible = locked

func start_cooldown(duration: float) -> void:
    _cooldown_timer = duration
    cooldown_overlay.visible = true

func _update_cooldown(delta: float) -> void:
    if _cooldown_timer > 0:
        _cooldown_timer -= delta
        cooldown_overlay.modulate.a = _cooldown_timer / 0.3  # 假设冷却0.3秒
        if _cooldown_timer <= 0:
            cooldown_overlay.visible = false

func _on_gui_input(event: InputEvent) -> void:
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
        clicked.emit(slot_index)

func _on_mouse_entered() -> void:
    modulate = Color(1.2, 1.2, 1.2)

func _on_mouse_exited() -> void:
    modulate = Color(1.0, 1.0, 1.0)

使用示例

玩家角色

# player.gd
extends CharacterBody2D

@export var weapon_switcher: WeaponSwitcher
@export var weapon_input_handler: WeaponInputHandler
@export var weapon_lock_manager: WeaponLockManager

func _ready() -> void:
    # 初始化武器
    weapon_switcher.add_weapon(weapon_database.get_weapon("sword"))
    weapon_switcher.add_weapon(weapon_database.get_weapon("bow"))
    weapon_switcher.add_weapon(weapon_database.get_weapon("shield"))

func take_damage(amount: float) -> void:
    _health -= amount

    # 受伤时短暂锁定武器切换
    weapon_switcher.lock_weapon_type(weapon_switcher.get_current_weapon_type(), 0.5)

    if _health <= 0:
        die()

func die() -> void:
    # 死亡时切换到徒手
    weapon_switcher.switch_to_type(WeaponType.Type.NONE)

武器数据库

# weapon_database.gd (Autoload)
extends Node

@export var weapons: Array[WeaponData]

var _weapon_dict: Dictionary = {}

func _ready() -> void:
    for weapon in weapons:
        _weapon_dict[weapon.id] = weapon

func get_weapon(id: StringName) -> WeaponData:
    return _weapon_dict.get(id)

func has_weapon(id: StringName) -> bool:
    return _weapon_dict.has(id)

最佳实践

  1. WeaponData作为Resource - 便于序列化、编辑器编辑
  2. 分离Weapon基类 - 具体武器继承实现特有逻辑
  3. 切换冷却 - 防止快速切换导致动画混乱
  4. 类型锁定 - 特殊状态(眩晕、死亡)锁定武器
  5. 输入统一管理 - 输入处理集中在InputHandler
  6. UI解耦 - UI通过信号监听武器系统变化

Signals

GitHub stars
103
Forks
14
Last commit
Jul 2026
Advanced
Catalog kind
skill
Gateway key
godot-weapon-system
Source
github.com/925236118/alphaagent