如何在Godot中实现稳定无异常的高速自动射击计时器系统?
解决Godot自动步枪射速不稳定(漏射/乱射)问题
问题根源
当前实现的核心问题在于用_input()处理持续射击逻辑,_input()是响应离散输入事件的(如按键按下、抬起),而按住按键时,系统的事件触发频率不稳定,尤其是射速较快(0.2秒/发)时,容易出现事件触发不及时导致漏射;同时one_shot计时器在快速重复启动时可能出现计时重置,进一步加剧射击不稳定。
方案一:用时间戳+_process()实现稳定射速
这种方式直接跟踪射击时间差,每一帧检查是否达到射击间隔,逻辑简单且可靠,适合自动射击场景。
- 定义变量记录上次射击时间:
var last_shoot_time: float = 0.0
- 替换原
_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
- 移除原有的
firerate_timer和can_shoot相关代码(包括_ready()里的计时器创建和_on_shoot_timer_timeout()函数)。
方案二:用循环计时器+输入事件控制启停
如果想保留计时器逻辑,可改为循环计时器,通过按键按下/抬起事件控制计时器启停,确保每次超时触发一次射击。
- 修改
_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)
- 重构
_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)
- 修改超时回调函数调用射击逻辑:
func _on_shoot_timer_timeout(): _shoot()
内容的提问来源于stack exchange,提问作者oliver james
相关产品推荐
相关产品推荐

