I’m making a small game about picking carots when they are ripe. Each Carot scene has a Timer on it related to its growth. When a Carot is instanced a function is called to set a random value to the Timer.wait_time, so that each Carot grows at a different pace. The Sprite2D animation is based on Timer.time_left.
So far so good. But when the game is initiated, I need the Carots not to all start with their full time_left. The game has to start with some Carots already ripe, some almost ripe, etc. But if I set a smaller wait_time, the animation looks like the Carot is not already ripe but instead grows faster. Therefore I would need to set the Timer.time_left property manually, but I can’t because it’s read-only.
So my questions are:
Why is Timer.time_left read-only ? It seems unnecessary
What would be the normal way in Godot to address my need ?
Here is my current code:
extends Area2D
@export var minWaitTime = 5.0
@export var maxWaitTime = 10.0
# images of the different stages of the carot
const texture1 = preload("res://assets/carot/stage-1.png")
const texture2 = preload("res://assets/carot/stage-2.png")
const texture3 = preload("res://assets/carot/stage-3.png")
# between 1 and 0, time LEFT when the carot changes state
const grow2 = 0.4
const grow3 = 0.0
# carot state
var state = 1
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
reset( true )
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
# check if the timer is passed the time when the carot changes state, and if so changes state
if ( $GrowTimer.time_left / $GrowTimer.wait_time <= grow3 ):
state = 3
$Sprite2D.texture = texture3
elif ( $GrowTimer.time_left / $GrowTimer.wait_time <= grow2 ):
state = 2
$Sprite2D.texture = texture2
func reset( random_progress: bool = false ):
var waitTime = minWaitTime + ( ( maxWaitTime - minWaitTime ) * randf_range( 0, 1 ) )
print( waitTime )
$GrowTimer.wait_time = waitTime
$GrowTimer.start()
$Sprite2D.texture = texture1
# if random_progress is true is means that we want to set the timer to a random progress value.
if ( random_progress ):
pass
# this is where I would like to set $GrowTimer.time_left
func _on_area_entered(area: Area2D) -> void:
reset()
Thank you for your reply, that’s what I did initially, but it messes with the Carot animation.
Basically the animation checks in the loop at what percent the Carot’s Timer is (
time_left / wait_time ). If it’s above 30% it set a given texture, if it’s above 50% it sets the next texture, etc.
If I just set a smaller wait_time, the animation will start from the beginning, whereas what I want is the start the animation from the state of the timer (if it’s 50%, it’s going to be the right texture).
I worked around it by setting state and restarting the Timer every time a new state is reached, but it seems unnecessarily complex. Please let me know if there is a better way.
extends Area2D
signal picked
@export var minWaitTime = 5.0
@export var maxWaitTime = 10.0
# images of the different stages of the carot
const textures = [
null,
preload("res://assets/carot/stage-1.png"),
preload("res://assets/carot/stage-2.png"),
preload("res://assets/carot/stage-3.png")
]
# carot state
var state
# percents of the Timer value to wait to reach each new state
const grow1 = 0.2
const grow2 = 0.4
const grow3 = 0.4
func _ready() -> void:
reset( true )
func _process( delta: float ) -> void:
# check if the timer is passed the time when the carot changes state, and if so changes state
if ( state == 0 && $GrowTimer.time_left / $GrowTimer.wait_time <= 1.0 - grow1 ):
setState( 1 )
if ( state == 1 && $GrowTimer.time_left / $GrowTimer.wait_time <= 1.0 - grow2 ):
setState( 2 )
if ( state == 2 && $GrowTimer.time_left / $GrowTimer.wait_time <= 1.0 - grow3 ):
setState( 3 )
func reset( random_progress: bool = false ):
# reset the timer with a new wait_time value, so that this Carot grows at a different pace.
var waitTime = minWaitTime + ( ( maxWaitTime - minWaitTime ) * randf_range( 0, 1 ) )
$GrowTimer.wait_time = waitTime
$GrowTimer.start()
if ( random_progress ):
setState( randi_range( 0, 3 ) )
else:
setState( 0 )
func setState( newState ):
state = newState
$Sprite2D.texture = textures[ newState ]
$GrowTimer.stop()
$GrowTimer.start()
func _on_area_entered(area: Area2D) -> void:
if ( state == 3 ):
picked.emit()
reset()
I am not sure what you mean by this
What I mean is you can’t manually set the property:
extends Area2D
signal picked
@export var minWaitTime = 5.0
@export var maxWaitTime = 10.0
# images of the different stages of the carot
const textures = [
null,
preload("res://assets/carot/stage-1.png"),
preload("res://assets/carot/stage-2.png"),
preload("res://assets/carot/stage-3.png")
]
# carot state
var state
# percents of the Timer value to wait to reach each new state
const grow1 = 0.2
const grow2 = 0.4
const grow3 = 0.4
var timer_wait_time = 0
func _ready() -> void:
reset( true )
func _process( delta: float ) -> void:
# check if the timer is passed the time when the carot changes state, and if so changes state
if ( state == 0 && $GrowTimer.time_left / timer_wait_time <= 1.0 - grow1 ):
setState( 1 )
if ( state == 1 && $GrowTimer.time_left / timer_wait_time <= 1.0 - grow2 ):
setState( 2 )
if ( state == 2 && $GrowTimer.time_left / timer_wait_time <= 1.0 - grow3 ):
setState( 3 )
func reset( random_progress: bool = false ):
# reset the timer with a new wait_time value, so that this Carot grows at a different pace.
var waitTime = minWaitTime + ( ( maxWaitTime - minWaitTime ) * randf_range( 0, 1 ))
timer_wait_time = waitTime
$GrowTimer.wait_time = 2.2 #time_left (change it)
$GrowTimer.start()
if ( random_progress ):
setState( randi_range( 0, 3 ) )
else:
setState( 0 )
func setState( newState ):
state = newState
$Sprite2D.texture = textures[ newState ]
$GrowTimer.stop()
$GrowTimer.start()
func _on_area_entered(area: Area2D) -> void:
if ( state == 3 ):
picked.emit()
reset()
Actually I am in mobile, as I am out of home. So my brain is not working properly but the codes should work. Let me know what happened?