How to get modulate property of another node?

Godot Version

4.3

Question

I’m trying to make this simple color matching game to learn Godot and C# and while i was able to find solutions to the problems i had, this one just bamboozled me. Color of character and the obstacles are set from Main.cs, obstacles are created via ObstacleSpawner, i tried to signal the color of character from Main.cs but couldn’t get it to work, so i thought why not just get the character node inside the obstacle.cs and then just use its modulate but to no avail. I kind of have to get the color of character at the moment of contact with the obstacle (character color shifts as it moves). I’m thinking one of these approaches has to work but i might be missing something. It is giving me error saying that in process() for _characterCOLOR = character.Modulate “Object reference not set to an instance of an object”, i tried to change it (using variations of the existing path but it didn’t work.). After that i tried to change it so that when obstacle collides with character it EmitSignal of its color to Main and then in Main i could do the calculation but it doesn’t trigger that way also.

Code

public partial class obstacle : Area2D
{
	public float speed = 100.0f;
	public Color color = default;
	public Color _characterCOLOR;
	Character character;
	Main _main;

	public float ColorDifferencesHSV(Color color1, Color color2)
	{
		float h1, s1, v1;
		float h2, s2, v2;
		
		color1.ToHsv(out h1, out s1, out v1);
		color2.ToHsv(out h2, out s2, out v2);

		const float H_WEIGHT = 0.5f; // Adjust this value experimentally to balance hue impact


		float hDiff = Mathf.Min(Mathf.Abs(h1 - h2), 1.0f - Mathf.Abs(h1 - h2)) * H_WEIGHT;
		float sDiff = Mathf.Abs(s1 - s2);
		float vDiff = Mathf.Abs(v1 - v2);

    	float ColorDistance = Mathf.Sqrt(hDiff * hDiff + sDiff * sDiff + vDiff * vDiff);

		return ColorDistance / 1.5f;
	}



    public override void _Ready()
    {
		_main = GetParent<Main>();
		character = GetNode<Character>("/root/Main/character");

    }

    
	private void On_Body_Entered(Node area)
	{
		GD.Print("body detected 1");
		if (area is CharacterBody2D)
		{
			GD.Print("body detected");
			Color obstacleColor = this.Modulate;
                        //just tried to send this part to Main.cs but didn't work
			GD.Print("obstacle color is " + obstacleColor);
			Color characterColor = _characterCOLOR;
			GD.Print("character color is " + characterColor);

			float differenceOfColors = ColorDifferencesHSV(obstacleColor, characterColor);
			GD.Print("Color difference is " + differenceOfColors);

			if (differenceOfColors <=  0.10f)
			{
				GD.Print("Yay!");
			}
			else 
			{
				GD.Print("Nay...");
			}
		}
	}
	public override void _Process(double delta)
	{
		// Update movement.
		Translate(new Godot.Vector2(0, speed*(float)delta));
		_characterCOLOR = character.Modulate;
		GD.Print(_characterCOLOR);
	}
}

Getting Object reference not set to an instance of an object, when you call a function on character, means that character does not reference anything (i.e., it is null).
My guess is, that your path to the node is wrong:

character = GetNode<Character>("/root/Main/character");

If so, the first error you get is a Node not found. I would not use an absolute path to get a node. You are getting the main node anyways so you can just use it:

_main.GetNode<Character>("character")

Else I don’t know why your character is null, if you don’t set it anywhere else.

In any case, I would suggest a different approach.
Since you are getting the ‘character’ in the collision, you can use it right there:

if (area is CharacterBody2D collisionCharacter) {
  // collisionCharacter is accessible here, it is automatically cast to CharacterBody2D
  // e.g. collisionCharacter.Modulate
}

As an aside, I suggest you look at a C# style-guide to make you code more readable :wink: (here is e.g., the one from Godot: C# style guide — Godot Engine (stable) documentation in English)

2 Likes
	private void On_Body_Entered(Node area)
	{
		GD.Print("body detected 1");
		if (area is CharacterBody2D)
		{

When you confirmed area is a character just use that area modulate etc. You don’t needed hardcode reference.

Thanks for the suggestions. I didn’t know i could do that… I guess i’ll study C# some more.

1 Like