How can you change the color of an object using GDScript

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By MZmuda

Hi!

I have a project that uses about 100 “characters.” I’ve already been able to get these characters to come into my scene by using:

onready var johnguy = preload(“res://JohnChar.tscn”)

and

for x in range(100):
var John = johnguy.instance()
add_child(John)

I’d like to change the color of each of these characters. How can I change the color of their meshes? (So that one “guy” is red, another is blueish, etc…)

Thanks -

  • Mike
:bust_in_silhouette: Reply From: kidscancode

Do your meshes have materials? If not, you can add a SpatialMaterial to each mesh. The material’s color is set via its albedo_color property. See https://docs.godotengine.org/en/latest/classes/class_spatialmaterial.html for details.

Hi!

Thanks for the response. (I love your website and YouTube videos by the way!)

My meshes do have a SpatialMaterial on them already, but I can’t seem to come up with any code that can isolate either the mesh or the material so that I can change the albedo_color on it. Could you give me a code snippet that might help? (The link that you mentioned explains a lot of fundamentals, but it doesn’t explain how to do things in GDScript.) (I should mention that my game is almost ENTIRELY script-based (the levels are all script generated, etc…))

Thanks again!

  • Mike

MZmuda | 2019-05-01 23:49

You get the material with MeshInstance.get_surface_material(), and now you’ll have a SpatialMaterial, which has an albedo_color property. So for example:

func _ready():
    var material = $MeshInstance.get_surface_material(0)
    material.albedo_color = Color(1, 0, 0)
    $MeshInstance.set_surface_material(0, material)

If you don’t already have a SpatialMaterial on your object you can make one with

var material = SpatialMaterial.new()

I don’t really understand what you mean by “isolate the mesh”. It’s a node, so you need to get it from wherever it is in relation to the node running the script.

edit:

If you have the material on the mesh itself rather than the MeshInstance, you get the material with

var material = $MeshInstance.mesh.surface_get_material(some_surface_index)

kidscancode | 2019-05-02 00:59

Thank You!

That definitely set me in the right direction. I’m now able to change the color of the spatial material. The problem is now that when I run the code, it changes ALL of the instances of the guys shirts to the last color issued.

(Example: I have 10 guys in the scene, and I run the code.

#################

for guy in range(10):
var Painted = (((((aThing as MeshInstance).mesh) as CubeMesh).material) as SpatialMaterial)
var somecolorR = (randi()%200)/200.0
var somecolorG = (randi()%200)/200.0
var somecolorB = (randi()%200)/200.0
Painted.albedo_color = Color(somecolorR,somecolorG,somecolorB)

#################

ALL of my guys now have the same color shirt. (Granted, before it was grey, and now they all have a color, but it’s all the same color.)

Any idea of what I’m doing wrong, or what I should do to make it so that all of my guys get different colors as they’re rendered?

Thanks again for the help - you really steered me down the right path!

  • Mike

MZmuda | 2019-05-02 05:29

All Resources (including Materials) are shared amongst instances. This saves lots of memory when you have lots of duplicated items. However, if you want them to have different materials, you need to make the resource unique to the node. This can be done in the Inspector, but since you’re doing this in code, you’ll want to do something like

material = material.duplicate() 

somewhere on your guy, to generate a copy of the material that you can then set the albedo on. Probably in _ready() makes the most sense.

kidscancode | 2019-05-02 05:41

But it haves an error, I tried to copy the code and it errors whenever I run it, how do I fix this error? its called "attempting to call function ‘get_surface_material’ in base ‘null instance’.

ICMationGodot | 2020-11-25 09:15

The function was renamed to get_surface_override_material()
Rename get_surface_material to get_surface_override_material by clayjohn · Pull Request #47878 · godotengine/godot · GitHub

s4300 | 2023-06-05 15:42