Combining two colors into a new third color

Godot Version

4.2

Question

I have an area2D with a ColorRect, and my player character contains a CanvasModulate. When my player enters the area2D, it changes to the color of the ColorRect. The code looks like this:

That works fine. I have a separate area2D with another ColorRect and what I want is for when the player enters the area2D on this ColorRect, the player changes color to the color he already is, combined with the color of the ColorRect. So, for example, if the player is red, and the ColorRect is green, the player should turn yellow. But I can’t figure out how to make this happen. I’ve tried color.blend() and I’ve tried just adding the colors together, and I’ve tried multiplying them, and nothing works. The player simply turns to the color of the ColorRect. The code for this looks like this:

How can I achieve what I’m trying to achieve; combining two colors into a new third color?

CanvasModulate is used for coloring the whole canvas. If your goal is to change the color of a playable character, you don’t need the CanvasModulate node.

Colors can be mixed with linear interpolation, so maybe code like this would work.

func _on_area_2d_body_entered(player):
    if player is CharacterBody2D:
        player.modulate = player.modulate.lerp(color, 0.5)

This works, but the problem is that it doesn’t seem to create the expected color. Let me explain. In my game, there are colored gates and to get through them the player has to be the same color as the gate. This works fine for primary colors like red or blue, but when combining red and blue to make purple, it becomes a different shade of purple than the gate, whose color I set manually by just maxing out the R and B values and putting G at zero. This means the player cannot pass the purple gate by combining blue with red which is the behavior I want. Do I need to somehow define the specific color I want to get from combining two others?

If you want to blend the colors, I suggest mixing hue values instead of colors.

I assume you want the colors mixed using the shorter path on a color circle, but what would be the desired effect for mixing opposite colors? If the player is blue and the color change thing is yellow, what color should the player become?

You could also make the objects add or subtract colors. Then the code could be something like this.

@export var addition = true

func _on_area_2d_body_entered(player):
    if player is CharacterBody2D:
        if addition:
            player.modulate = (player.modulate + color).clamp()
        else:
            player.modulate = (player.modulate - color).clamp()
            player.modulate.a = 1.0

And then of course there would need to be some kind of indicator, which tells the player wheter the object is going to add or subtract its color from the player.

Also, when you check if the player can pass through a gate, it’s good idea to avoid floating point precision errors by having some tolerance in the check.

# Gate script
const TOLERANCE = 0.01

func _on_area_2d_body_entered(player):
    if player is CharacterBody2D:
        if absf(player.modulate.h - color.h) < TOLERANCE:
            the_player_can_pass_through()
        else:
            access_denied()

I wound up going with the add/subtract method, like this:
image_2024-03-31_055850355

That seems to do what I want, although it does give me certain colors I had not previously accounted for, like cyan. I think I’m going to have to read up on some color theory to figure out potential combinations I need to account for. Thanks for your help!