Bagutreko
Bagutreko

Reputation: 11

Invalid get index 'size' (on base: 'RigidBody3D (asteroid_shape_generator.gd)')

I have been trying to create an asteroid spawner for my game in Godot 4.2.

I've already managed to make my code work on the main scene when running the game, however I'd like to have the same script be able to run as a @tool on my spawner scene, so I can test everything without having to run the game.

In my asteroid scene, the root node contains a script where asteroids shapes are defined inside _ready() and require the parameters size, noise_scale and noise_adjustment. Here is the relevant piece code:

extends RigidBody3D

var fnl = FastNoiseLite.new()
var mdt = MeshDataTool.new()
var surface_tool := SurfaceTool.new()

@onready var collision_shape_3d = $CollisionShape3D
@onready var mesh_instance_3d = $CollisionShape3D/MeshInstance3D

var size: float = 5
var noise_scale: float = 1
var noise_adjustment: float = 0

func _ready():
    
    surface_tool.create_from(mesh_instance_3d.mesh,0)
    mesh_instance_3d.mesh = surface_tool.commit()
...
...

I created a spawner scene, with a single node containing a script where my asteroid scene is instantiated multiple times, and size, noise_scale and noise_adjustment are all set based on parameters given to the spawner.

@tool
extends Node3D

@export var asteroid_scene: PackedScene
@export var num_asteroids: int = 10
@export_range(0, 1500) var spawn_range: float = 500
@export_range(0, 500) var velocity_range: float = 200

@export_range(1, 500) var min_size: float = 5
@export_range(1, 500) var max_size: float = 200
@export_range(0, 10) var noise_scale: float = 1
@export_range(0, 10) var noise_adjustment: float = 0

# Called when the node enters the scene tree for the first time.
func _ready():
    
    if max_size < min_size:
        max_size = min_size
    if min_size > max_size:
        min_size = max_size
    
    for i in range(num_asteroids):
        
        var asteroid = asteroid_scene.instantiate()
        
        var size = randf_range(min_size, max_size)
        asteroid.size = size
        asteroid.noise_scale = noise_scale
        asteroid.noise_adjustment = noise_adjustment
...
...

        add_child(asteroid)

When reloading the spawner scene I get the error message res://Scripts/asteroid_spawner.gd:27 - Invalid set index 'size' (on base: 'RigidBody3D (asteroid_shape_generator.gd)') with value of type 'float'.

I've already tested simply running asteroid.size without assigning a value, but then I get another error: Invalid get index 'size' (on base: 'RigidBody3D (asteroid_shape_generator.gd)')

I've also tried moving the contents of the _ready() function into another function and then calling this function inside _process, which also didn't solve my issue.

I expected to simply have the asteroids spawn inside my spawner scene, just like they do in game (DEBUG)

Upvotes: 1

Views: 46

Answers (2)

Bagutreko
Bagutreko

Reputation: 11

I've found out that since my asteroid spawner script is a @tool, then my instantiated asteroids script must also be a @tool. Simply adding this annotation to the header of my script solved the problem

Upvotes: 0

HumanWrites
HumanWrites

Reputation: 945

This is happening because it can not find a property called size that belongs to the asteroid object you have instantiated.

When you instantiate your asteroid_scene with var asteroid = asteroid_scene.instantiate(), it is being instantiated as a Rigidbody3D. If you check the documentation, you will see that a Rigidbody3D does not have a size property:[https://docs.godotengine.org/en/stable/classes/class_rigidbody3d.html] (https://docs.godotengine.org/en/stable/classes/class_rigidbody3d.html)

If you want to assign to the size property that you declared in the script attached to your asteroid scene you need to let the spawner script know that you are instantiating an asteroid specifically. You can do this by giving your asteroid script a class_name and then spawning the asteroid as an instance of that class.

E.g.

In the asteroid script:

class_name Asteroid
extends RigidBody3D
...

var size: float = 5
...

In the spawner script:

func _ready():
    ...
    
    for i in range(num_asteroids):
        var asteroid = asteroid_scene.instantiate() as Asteroid
        asteroid.size = size

Upvotes: 1

Related Questions