You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Godot中实现稳定无异常的高速自动射击计时器系统?

解决Godot自动步枪射速不稳定(漏射/乱射)问题

问题根源

当前实现的核心问题在于用_input()处理持续射击逻辑,_input()是响应离散输入事件的(如按键按下、抬起),而按住按键时,系统的事件触发频率不稳定,尤其是射速较快(0.2秒/发)时,容易出现事件触发不及时导致漏射;同时one_shot计时器在快速重复启动时可能出现计时重置,进一步加剧射击不稳定。


方案一:用时间戳+_process()实现稳定射速

这种方式直接跟踪射击时间差,每一帧检查是否达到射击间隔,逻辑简单且可靠,适合自动射击场景。

  1. 定义变量记录上次射击时间:
var last_shoot_time: float = 0.0
  1. 替换原_input()为_process()处理射击逻辑:
func _process(delta: float) -> void:
    # 检查是否满足射击条件:未换弹、有弹药、按键按住
    if not reloading and ammo_in_mag > 0 and (Input.is_action_pressed("space") or Input.is_action_pressed("leftclick")):
        # 将当前时间转换为秒(Time.get_ticks_msec()返回毫秒)
        var current_time = Time.get_ticks_msec() / 1000.0
        # 获取当前枪械的射速间隔
        var fire_interval = Global.currentGuns[2]
        
        # 检查是否达到射击间隔
        if current_time - last_shoot_time >= fire_interval:
            # 实例化子弹
            var bullet_instance = bullet.instantiate()
            add_child(bullet_instance)
            # 更新弹药计数和UI
            ammo_in_mag -= 1
            $CanvasLayer/Control/Label.text = "Ammo: " + str(ammo_in_mag)
            # 更新上次射击时间
            last_shoot_time = current_time
  1. 移除原有的firerate_timer和can_shoot相关代码(包括_ready()里的计时器创建和_on_shoot_timer_timeout()函数)。

方案二:用循环计时器+输入事件控制启停

如果想保留计时器逻辑,可改为循环计时器,通过按键按下/抬起事件控制计时器启停,确保每次超时触发一次射击。

  1. 修改_ready()中的计时器设置:
func _ready() -> void:
    reloade = Timer.new()
    $ZombieSpawntime.start()
    firerate_timer = Timer.new()
    firerate_timer.wait_time = Global.currentGuns[2]
    firerate_timer.one_shot = false  # 设置为循环计时
    firerate_timer.timeout.connect(self._on_shoot_timer_timeout)
    add_child(firerate_timer)
  1. 重构_input()处理按键启停:
func _input(event: InputEvent) -> void:
    # 按键按下时启动计时器,并立即射击第一发
    if (event.is_action_pressed("space") or event.is_action_pressed("leftclick")) and not reloading and ammo_in_mag > 0:
        if not firerate_timer.is_processing():
            firerate_timer.start()
            _shoot()
    # 按键抬起时停止计时器
    elif (event.is_action_released("space") or event.is_action_released("leftclick")):
        firerate_timer.stop()

# 封装射击逻辑
func _shoot() -> void:
    # 检查是否仍满足射击条件,不满足则停止计时器
    if ammo_in_mag <= 0 or reloading:
        firerate_timer.stop()
        return
    # 实例化子弹
    var bullet_instance = bullet.instantiate()
    add_child(bullet_instance)
    # 更新弹药计数和UI
    ammo_in_mag -= 1
    $CanvasLayer/Control/Label.text = "Ammo: " + str(ammo_in_mag)
  1. 修改超时回调函数调用射击逻辑:
func _on_shoot_timer_timeout():
    _shoot()

内容的提问来源于stack exchange,提问作者oliver james

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:37:08