Modifying instanced resourced

Godot Version

v4.2.1.stable.mono.official [b09f793f5]

Question

I’m attemting to change a child object’s collisionShape3D’s size to the size of the parent’s collisionShape3D (both are boxShapes) whith this script:

 public override void _Ready()
  {
    collisionShape = GetNode<CollisionShape3D>("CollisionShape3D");
    BodyEntered += OnBodyEntered;
    
    var parentShape =  GetParent().GetNode<CollisionShape3D>("CollisionShape3D");
    if (IsInstanceValid(parentShape)) size = ((BoxShape3D)parentShape.Shape).Size * 1.01f;
    GD.Print(size);
    ChangeSize(size);
  }

This works when the scene is local, like this:
Immagine 2024-04-27 094225
(Obstacle is the object with the script in question, the obstaclle scene has a collisionShape3D as a child)
But not when it’s instanced like this
Immagine 2024-04-27 094248
(Floor, Block, and Block1 are all Block scenes)

All resources are local to scene, and the block script has this tool script attached (I never uses tool scripts before, so I the mistake may be there, even though I don’t see how)

[Tool]
public partial class FloorTool : Node
{
    [Export] public Vector3 size;
    CollisionShape3D shape3D;
    MeshInstance3D mesh3D;
    ShaderMaterial mat;

    BoxShape3D shape;
    BoxMesh mesh;

    [Export]Color color;

    public override void _Ready()
    {
        shape3D = GetNode<CollisionShape3D>("CollisionShape3D");
        mesh3D = GetNode<MeshInstance3D>("MeshInstance3D");
        
        shape = (BoxShape3D)shape3D.Shape;
        mesh = (BoxMesh)mesh3D.Mesh;
         
        mat = (ShaderMaterial)mesh.Material;

    }

    public override void _PhysicsProcess(double delta)
    {   
        shape.Size = size;
        mesh.Size = size;
        mat.SetShaderParameter("color", color);
    }

}

I really don’t understand what I’m doing wrong, can anyone help?

I understand that you said you are trying to change the collision shape. But collision shapes are invisible. I assume you also want to change the visual mesh as well? What is the end result of your code?

What is this function doing?

Ah sorry, I forgot to add that function to the post, here it is

public void ChangeSize(Vector3 s)
  {
    var shape = (BoxShape3D)GetNode<CollisionShape3D>("CollisionShape3D").Shape;
    shape.Size = s;
  }

It just gets the boxshape and changes its size.

I understand that you said you are trying to change the collision shape. But collision shapes are invisible. I assume you also want to change the visual mesh as well

In this case, no. This script is attached to a “obstacle” object that kills the player when it touches it. I want to be able to attach it to anything, and automatically set the size to its parent collisionShape size to make it easier to use. It doesn’t need to have a visual component, because it’s supposed to always be attached to something else.

In the first scene I posted, the collisionShape changes size correctly, and prints that size.

In the second scene however the obstacle size alway results (1,01, 1,01, 1,01) regarldless of the size of the block.

1 Like

Well at least from your tools perspective you set the mesh and size of the floor/block in its ready function. Which by order of the tree readiness is last. And will not be called again if modified.

I would instance the object, modify it, and then add it to the scene where the ready functions will be triggered.

I’m not sure if the hierarchy is the problem here, since in the first scene hierarchy the script works, and the order should be the same. It also works if I make the blocks local in the second scene. Is there a difference in the order ready functions are called between local and instanced scenes?

It shouldn’t, but ready function calls starts at the lowest and deepest children and work up.

But in regards to a tool with a pre built scene things probably work differently, I have had my issues with tools in this regard and I haven’t taken the time to really look into their nature.

I think in some sense once a tool has loaded it will only call ready once, until it is closed and reopen.

I tried printing the size of the block in the ready function, and indeed it seems that when I run the program, the size prints as the “default” size (the size set in the block scene) and only later does it change to the size I set in the editor.

I tried adding a signal on the root node that is emitted in the root’s ready function

[Signal] public delegate void SceneLoadedEventHandler();
public override void _Ready()
{
    EmitSignal(SignalName.SceneLoaded);
}

And then connecting the signal to the obstacle

  public override void _Ready()
  {
    GetTree().Root.GetChild<root>(0).SceneLoaded += LateReady;
  }

  public void LateReady()
  {
    collisionShape = GetNode<CollisionShape3D>("CollisionShape3D");
    BodyEntered += OnBodyEntered;
    
    var parentShape =  GetParent().GetNode<CollisionShape3D>("CollisionShape3D");
    if (IsInstanceValid(parentShape)) size = ((BoxShape3D)parentShape.Shape).Size * 1.01f;
    GD.Print(size);
    ChangeSize(size);
  }

This way the size is changed AFTER the block’s ready function. Then I modified the tool script to change the size once in the ready function, as well as the physicsprocess, this way by the time the LateReady function is called, the block already has the correct size. Now it works correctly, thanks for the help.

1 Like