I am making an avatar customizer, and I’m wondering what the best route for sake of ease and user friendliness I should take without disrupting my current script too much. Currently I’m working on the hairstyle section, and wondering how we should handle changing the color of the material on the hairstyles. Currently the hairstyles are instanced into the scene on a button press and can be removed by pressing another button. The instance button makes the hairstyle a child of a Node3d to make sure the hair sits on top of the head just right.
I guess I’m confused on how to change the material of an instanced node in general, but also wondering what would be easiest for me to make while keeping it easy for the player to use as well. Three options come to mind for the color input–A colorpicker node, an array of colors that the player can flip through, or a color pallet that players click the color they want. On top of this players can have more than one hairstyle present at a time…Really stumped.
TL;DR How do I change the color of an instanced node and what’s the best option for creating a UI for this?
Node SetUp (Each hairstyle option has a Node3D that it’s instance will be parented to with its matching name) :
Hairstyle Instance Script Example :
#YORK-----------------BEGIN------------------------------------------------------------------------------------------- #INST FUNCTIONS
func yorkhair_inst():
var YorkHairScene = preload(“res://Meshes/Angels/Hair/york_hair.tscn”)
var YHinst = YorkHairScene.instantiate()
var YorkHPos = $“…/…/…/…/Base_Angel/Armature/Skeleton3D/NeckBone/YorkHPos”
YorkHPos.add_child(YHinst) #Checking for Instance
if is_instance_valid(YHinst): #Toggles QF button to Visible
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairQF.visible = true #Disables the Hair Inst Button
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairBTN.disabled = true
func _on_york_hair_btn_pressed(): #Runs the York Hair Instance func
yorkhair_inst() #Playing Animation
AP.play(“Posing001”)
#QUEUE FREE FUNCTION
func _on_york_hair_qf_pressed():
var YorkHpos = $“…/…/…/…/Base_Angel/Armature/Skeleton3D/NeckBone/YorkHPos”
var childNode = YorkHpos.get_child(0)
if childNode:
childNode.queue_free() #Toggles Visibility of QF button to False (default)
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairQF.visible = false #Re-enables the Hair Inst Button
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairBTN.disabled = false
If every hairstyle is a simple MeshInstance3D (with a StandardMaterial3D) then you can get the material with dot notation, and change the color with the albedo_color property
Every time I click the black hair color button, I just get the “Nothing to change!” message we set up. I’m not sure if there’s a better way to do this or if I’m missing something. I tried setting the instance as well to make sure it’s a meshinstance3D, as before it was a Node3D parented to the MeshInstance3D itself. So, I changed the instance to a scene of just the meshinstance3D by itself.
Here’s the updated script with a section for the black hair color :
func yorkhair_inst():
var YorkHairScene = preload("res://Meshes/Angels/Hair/GLB/YorkHair.glb")
var YHinst = YorkHairScene.instantiate()
var YorkHPos = $"../../../../Base_Angel/Armature/Skeleton3D/NeckBone/YorkHPos"
YorkHPos.add_child(YHinst)
#Checking for Instance
if is_instance_valid(YHinst):
#Toggles QF button to Visible
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairQF.visible = true
#Disables the Hair Inst Button
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairBTN.disabled = true
func _on_black_hair_pressed():
var YorkHpos = $"../../../../Base_Angel/Armature/Skeleton3D/NeckBone/YorkHPos"
var childNode = YorkHpos.get_child(0)
if childNode is MeshInstance3D:
childNode.material.albedo_color = Color(0,0,0)
else :
print("Nothing to change!")
func _on_york_hair_btn_pressed():
#Runs the York Hair Instance func
yorkhair_inst()
#Playing Animation
AP.play("Posing001")
#QUEUE FREE FUNCTION
func _on_york_hair_qf_pressed():
var YorkHpos = $"../../../../Base_Angel/Armature/Skeleton3D/NeckBone/YorkHPos"
var childNode = YorkHpos.get_child(0)
if childNode:
childNode.queue_free()
#Toggles Visibility of QF button to False (default)
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairQF.visible = false
#Re-enables the Hair Inst Button
$TabContainer/Hair/HairOptions/YorkHairPVW/YorkHairBTN.disabled = false
Apologies if I’m mistaking this but, after setting up the remote debug I’m afraid my phone won’t run it. Ironically enough I was helping another dev playtest their mobile game a couple days ago, but my phone wouldn’t run it because my phone doesn’t have very much ram. My phone spat out the same error for both the dev’s beta test and my remote debug. Something about not being optimized, it even gave me an option to clear my cache for better performance, but it doesn’t seem to be working.
It was a 3D game too, so I’m wondering if that’s why. I’m a little stumped.
Is there another way to see what the node tree is doing while testing? Any other suggestions?
Sorry, this is getting a little complicated and thanks for the copy and paste script tip, I’ve been wondering how to do that for ages.
When you hit play (F5) to debug locally this tab appears, click on “remote”. This will show you the in-game scene tree, I want you to look for your YorkHPos children.
Material Override worked perfectly, just made the blackHair it’s own material that gets loaded in.
Working Script :
func _on_black_hair_pressed():
var blackHair = "res://Meshes/Angels/HairColors/BlackHair.tres"
var YorkHpos = $"../../../../Base_Angel/Armature/Skeleton3D/NeckBone/YorkHPos"
var childNode = YorkHpos.get_child(0)
if childNode is MeshInstance3D:
childNode.material_override = load(blackHair)
else :
print("Nothing to change!")
Thanks for all your help again, I learned a lot from this whole thread!