mob.scale not visually updating in scene despite value being set

Godot Version

4.4.1.stable

Question

Hi! I’m just getting started with Godot and following the official documentation tutorial.

After implementing the spawn logic and modifying mob.linear_velocity and mob.scale, I decided to try changing the scale of each mob to a random value within a specified range. I used print(mob.scale) to confirm the scale is being set correctly in code, and it shows different values as expected.

However, when I run the scene, the mobs still appear at their original size — the scale change doesn’t seem to have any visual effect.

Am I missing something? Why isn’t the visual size of the mobs changing, even though mob.scale is being set?

Thanks in advance!

func _on_mob_timer_timeout():
	# Create a new instance of the Mob scene.
	var mob = mob_scene.instantiate()

	# Choose a random location on Path2D.
	var mob_spawn_location = $MobPath/MobSpawnLocation
	mob_spawn_location.progress_ratio = randf()

	# Set the mob's position to the random location.
	mob.position = mob_spawn_location.position

	# Set the mob's direction perpendicular to the path direction.
	var direction = mob_spawn_location.rotation + PI / 2

	# Add some randomness to the direction.
	direction += randf_range(-PI / 4, PI / 4)
	mob.rotation = direction

	# Choose the velocity for the mob.
	var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
	mob.linear_velocity = velocity.rotated(direction)
	
	var rand_scale_factor := randf_range(0.3, 1)
	mob.scale = Vector2(rand_scale_factor,rand_scale_factor)
	
	# Spawn the mob by adding it to the Main scene.
	add_child(mob)

Try changing the scale after you add it to the scene tree.

	# Spawn the mob by adding it to the Main scene.
	add_child(mob)
	mob.scale = Vector2(rand_scale_factor,rand_scale_factor)
1 Like

Even after changing the order, the scale remains fixed at (1,1).

What type of object is mob?

1 Like

RigidBody2D

Ok, so the AnimatedSprite2D and the CollisionShape2D are affected (or should be) but the Mob itself has no size, so it only passes its scaling down to those two nodes. If they are added after the scaling happens, then they will not be affected. However, if you were to change the scale back to 1.0 after later, they would get bigger.

My guess is you’re experiencing a race condition. When you call mob_scene.instantiate(), what happens is the mob variable in your code has a Rigidbody2D created and assigned to it. While it’s still in its _ready() function, the three child nodes are created. When their _ready() functions are completed and returned, then the Rigidbody2D’s completes.

However, while that construction is going on, you can still run code on the Rigidbody2D part of the mob. So what’s likely happening is that the scale of your parent Rigidbody2D is being set to a random value before the nodes you want to change are affected by it.

There’s a few possible solutions.

The first is to defer the call to scale. This should give enough time for the construction to catch up.

var rand_scale_factor := randf_range(0.3, 1)
mob.set_deferred("scale", Vector2(rand_scale_factor,rand_scale_factor))

The second is to bypass the parent and set the value on the child nodes. There are a few ways to do this. The safest is to add this code to mob:

@onready var animated_sprite_2d: Animatedsprite2D = $AnimatedSprite2D
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D

func set_scale(scale_factor: float) -> void:
	var scale_vector := Vector2(scale_factor, scale_factor)
	animated_sprite_2d.scale = scale_vector
	collision_shape_2d.scale = scale_vector

Then add this code to your timeout:

var rand_scale_factor := randf_range(0.3, 1)
mob.set_scale(rand_scale_factor)
1 Like

I tried option one, using mob.set_deferred, but it still had no effect—the behavior was exactly the same.

Option two gives me the following error:

Invalid assignment of property or key 'scale' with value of type 'Vector2' on a base object of type 'Nil'.

on line 8 of the script mob.gd, which is attached to the root scene Mob. This is strange, as it reports as if the AnimatedSprite2D and CollisionShape2D don’t exist at the moment set_body_scale is called by main.gd.

As you can see in the screenshot, I’m in the mob.gd script, which is the script attached to the root scene “Mob”.

P.S.: I renamed set_scale to set_body_scale because set_scale is already an existing internal method, which I actually tried to use before all of this, but it didn’t work either.

This is good info. They don’t exist yet. Try:

mob.set_body_scale.call_deferred(rand_scale_factor)