The script isn’t working as it should—what am I doing wrong?

Godot Version

v 4.4.1 (Steam)

Question

“There is code that drains the flashlight. The thing is, when the scene (game) starts, the flashlight drains in 2-3 seconds, regardless of the drain_rate values—whether it’s 0.001 or 5. I can’t figure out what the problem might be.”

extends Node3D

@onready var flashlight_model = $flashlightwithhand
@onready var spot_light = $flashlightwithhand/SpotLight3D
@onready var flashlight_sound = $FlashlightSound
@onready var flicker_sound = $FlickerSound
@onready var label = $“../../../HUD/BatteryLabel”
@onready var charge_label = $“../../../HUD/LabelPercent”

@export var camera_3d: Camera3D
@export var smooth_factor : float = 0.025
@export var flashlight_intensity = 1.5
@export var drain_rate = 0.001
@export var intense_boost_duration = 2.0
var log_timer := 0.0

var flashlight_battery := 100
var boosted = false
var boost_timer = 0.0
var flicker_timer = 0.0
var flicker_active = false
var is_near_battery = false
var last_printed_battery = -1

func _ready():
label.text = “E”
label.visible = false
randomize()

func _process(delta):
# :fuel_pump: Разрядка фонаря
if spot_light.visible and flashlight_battery > 0 and not boosted:
var effective_drain: float = max(drain_rate, 0.01) # даже при 0 будет медленно садиться
flashlight_battery -= effective_drain * delta
flashlight_battery = clamp(flashlight_battery, 0, 100)

# 🚀 Обработка буста
if boosted:
	boost_timer = max(boost_timer - delta, 0.0)
	var t = 1.0 - (boost_timer / intense_boost_duration)
	spot_light.light_energy = lerp(3.0, flashlight_intensity, t)
	if boost_timer <= 0.0:
		boosted = false
		spot_light.light_energy = flashlight_intensity

# 🔘On/off flashlight
if Input.is_action_just_pressed("flashlight") and flashlight_battery > 0:
	if flashlight_battery < 15:
		start_flicker_sequence(true)
	else:
		spot_light.visible = !spot_light.visible
	flashlight_sound.play()

# 🪫 Auto off
if flashlight_battery <= 0.0 and spot_light.visible:
	spot_light.visible = false
	spot_light.light_energy = 0.0

# 🔋 E (take)
label.visible = is_near_battery
if is_near_battery:
	label.text = "%d%%\n[Нажмите E]" % int(flashlight_battery)
	if Input.is_action_just_pressed("interact"):
		charge_flashlight()

# 🧪 Отображение процентов (дебаг)
_update_battery_label()

# 🎮 Anim
var sway_amount = Vector3.ZERO
var start_position = Vector3(-0.368, -0.02, -19.127)
flashlight_model.position = flashlight_model.position.lerp(start_position + sway_amount, smooth_factor)

# 🌩️ Flicker
call_deferred("handle_flicker", delta)

# ⏱️ Лог состояния
log_timer += delta
if log_timer >= 0.5:
	log_timer = 0.0
	var time_sec := Time.get_ticks_msec() / 1000.0
	print("⏱ Time: %.1fs | 🔋 Battery: %d%% | ⚡ Drain rate: %.2f" % [time_sec, flashlight_battery, drain_rate])

# 🚀 Log boost
if boosted:
	print("BOOST: ", "%.2f" % (intense_boost_duration - boost_timer), " сек | ЭНЕРГИЯ:", "%.2f" % spot_light.light_energy)

func charge_flashlight():
flashlight_battery = 100
boosted = true
boost_timer = intense_boost_duration
spot_light.visible = true
spot_light.light_energy = 3.0
flashlight_sound.play()
is_near_battery = false
label.visible = false
_update_battery_label()

func _update_battery_label():
var current = int(flashlight_battery)
if current != last_printed_battery and charge_label:
charge_label.text = str(current) + “%”
last_printed_battery = current

func handle_flicker(delta: float) → void:
if flashlight_battery >= 70 or flicker_active:
return

# Постоянное мерцание при <10%
if flashlight_battery < 10:
	flicker_timer -= delta
	if flicker_timer <= 0:
		spot_light.light_energy = randf_range(0.1, 1.0)
		spot_light.visible = !spot_light.visible
		flicker_timer = randf_range(0.05, 0.2)
		if flicker_sound:
			flicker_sound.play()
	if flashlight_battery <= 0:
		spot_light.visible = false
		spot_light.light_energy = 0.0
	return

# Разовые мигания
var should_flicker = false
match int(flashlight_battery):
	70, 50, 30, 25, 20, 15:
		should_flicker = true

if should_flicker:
	start_flicker_sequence(flashlight_battery <= 30)

func start_flicker_sequence(with_intensity := false) → void:
if flicker_active:
return
flicker_active = true
var blinks = randi_range(1, 3)
flicker_sequence(blinks, with_intensity)

func flicker_sequence(blinks: int, with_intensity := false) → void:
for i in range(blinks):
var delay = randf_range(0.05, 0.15)
spot_light.visible = false
await get_tree().create_timer(delay).timeout

	if with_intensity and randi_range(0, 2) == 1:
		spot_light.light_energy = randf_range(0.2, 2.5)
	else:
		spot_light.light_energy = flashlight_intensity

	spot_light.visible = true
	if flicker_sound:
		flicker_sound.play()
	await get_tree().create_timer(delay).timeout
flicker_active = false

Sorry. The forum somehow split my post, but it goes from top to bottom correctly

About formatting code:

Put “gd” behind the beginning set of ticks (```gd) for GDScript code. It is also generally helpful to translate any comments to English so we don’t have to do it ourselves to understand the code properly.

flashlight_battery is an integer so whether you subtract 0.01 * delta or 5 * delta doesn’t matter if they’re both below 1:

f_1 = int(100 - 0.01 * 0.016) = int(99.99984) = 99
f_2 = int(100 - 5.0 * 0.016) = int(99.92) = 99

If you change var flashlight_battery := 100 to var flashlight_battery: float = 100 or var flashlight_battery := 100.0 it should work.

I would suggest explicitly specifying the types of all class members (variables and functions).

1 Like