Avatar customization: skin colour = swatches + shade slider
checkpoint / checkpoint (push) Successful in 1m45s
checkpoint / checkpoint (push) Successful in 1m45s
The single tone slider could never get back to the default yellow. Replaced it with a row of preset colour swatches (yellow first, then skin tones and a few fun colours) plus a "Shade" slider that darkens/lightens the picked swatch (0.5 = as-is). Picking yellow at mid shade reproduces the baked default exactly. Verified: avatar smoke 14/14, fresh-clone, and drove the swatches + shade in rendered screenshots (green skin, back to yellow, dark tan). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
This commit is contained in:
@@ -76,6 +76,23 @@ var _preview_root: Node3D = null
|
|||||||
## Currently selected slot id.
|
## Currently selected slot id.
|
||||||
var _selected_slot: String = ""
|
var _selected_slot: String = ""
|
||||||
|
|
||||||
|
## Skin: a base colour picked from a swatch, plus a shade multiplier from the
|
||||||
|
## slider (0.5 = the swatch as-is, lower = darker, higher = lighter). The
|
||||||
|
## first swatch is the placeholder default yellow.
|
||||||
|
const SKIN_SWATCHES: Array[Color] = [
|
||||||
|
Color(0.96, 0.80, 0.19), # yellow (default)
|
||||||
|
Color(0.95, 0.78, 0.66), # pale
|
||||||
|
Color(0.83, 0.62, 0.46), # tan
|
||||||
|
Color(0.55, 0.38, 0.27), # brown
|
||||||
|
Color(0.33, 0.21, 0.15), # deep brown
|
||||||
|
Color(0.62, 0.62, 0.64), # grey
|
||||||
|
Color(0.78, 0.24, 0.24), # red
|
||||||
|
Color(0.30, 0.62, 0.34), # green
|
||||||
|
Color(0.26, 0.46, 0.76), # blue
|
||||||
|
Color(0.62, 0.36, 0.72), # purple
|
||||||
|
]
|
||||||
|
var _skin_base: Color = SKIN_SWATCHES[0]
|
||||||
|
|
||||||
## Turntable: the preview avatar's Y rotation (radians), whether the player is
|
## Turntable: the preview avatar's Y rotation (radians), whether the player is
|
||||||
## currently dragging it, and how long since they last touched it (drives the
|
## currently dragging it, and how long since they last touched it (drives the
|
||||||
## slow idle auto-spin). Starts facing the camera.
|
## slow idle auto-spin). Starts facing the camera.
|
||||||
@@ -289,14 +306,28 @@ func _build_ui() -> void:
|
|||||||
_item_list.add_theme_constant_override("separation", 4)
|
_item_list.add_theme_constant_override("separation", 4)
|
||||||
item_scroll.add_child(_item_list)
|
item_scroll.add_child(_item_list)
|
||||||
|
|
||||||
# Skin tone control.
|
# Skin colour: a row of preset swatches + a shade slider that darkens or
|
||||||
|
# lightens the picked colour. The first swatch is the default yellow.
|
||||||
var skin_header := Label.new()
|
var skin_header := Label.new()
|
||||||
skin_header.text = "Skin Tone"
|
skin_header.text = "Skin Colour"
|
||||||
skin_header.add_theme_font_size_override("font_size", 16)
|
skin_header.add_theme_font_size_override("font_size", 16)
|
||||||
controls_vbox.add_child(skin_header)
|
controls_vbox.add_child(skin_header)
|
||||||
|
|
||||||
|
var swatch_grid := GridContainer.new()
|
||||||
|
swatch_grid.columns = 5
|
||||||
|
swatch_grid.add_theme_constant_override("h_separation", 4)
|
||||||
|
swatch_grid.add_theme_constant_override("v_separation", 4)
|
||||||
|
controls_vbox.add_child(swatch_grid)
|
||||||
|
for c in SKIN_SWATCHES:
|
||||||
|
swatch_grid.add_child(_make_swatch(c))
|
||||||
|
|
||||||
|
var shade_label := Label.new()
|
||||||
|
shade_label.text = "Shade"
|
||||||
|
shade_label.add_theme_font_size_override("font_size", 13)
|
||||||
|
controls_vbox.add_child(shade_label)
|
||||||
|
|
||||||
_skin_tone_slider = HSlider.new()
|
_skin_tone_slider = HSlider.new()
|
||||||
_skin_tone_slider.name = "SkinToneSlider"
|
_skin_tone_slider.name = "ShadeSlider"
|
||||||
_skin_tone_slider.min_value = 0.0
|
_skin_tone_slider.min_value = 0.0
|
||||||
_skin_tone_slider.max_value = 1.0
|
_skin_tone_slider.max_value = 1.0
|
||||||
_skin_tone_slider.step = 0.01
|
_skin_tone_slider.step = 0.01
|
||||||
@@ -486,17 +517,44 @@ func _refresh_preview() -> void:
|
|||||||
# Skin tone
|
# Skin tone
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func _on_skin_tone_changed(value: float) -> void:
|
## Build one clickable colour swatch.
|
||||||
|
func _make_swatch(color: Color) -> Button:
|
||||||
|
var b := Button.new()
|
||||||
|
b.custom_minimum_size = Vector2(40, 30)
|
||||||
|
b.tooltip_text = "#" + color.to_html(false)
|
||||||
|
for state in ["normal", "hover", "pressed", "focus", "disabled"]:
|
||||||
|
var sb := StyleBoxFlat.new()
|
||||||
|
sb.bg_color = color
|
||||||
|
sb.set_corner_radius_all(3)
|
||||||
|
if state == "hover" or state == "pressed" or state == "focus":
|
||||||
|
sb.set_border_width_all(2)
|
||||||
|
sb.border_color = Color.WHITE
|
||||||
|
b.add_theme_stylebox_override(state, sb)
|
||||||
|
b.pressed.connect(_on_skin_swatch_pressed.bind(color))
|
||||||
|
return b
|
||||||
|
|
||||||
|
|
||||||
|
func _on_skin_swatch_pressed(color: Color) -> void:
|
||||||
|
_skin_base = color
|
||||||
|
_apply_skin_colour()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_skin_tone_changed(_value: float) -> void:
|
||||||
|
_apply_skin_colour()
|
||||||
|
|
||||||
|
|
||||||
|
## Combine the picked swatch with the shade slider and push it to the loadout.
|
||||||
|
func _apply_skin_colour() -> void:
|
||||||
if loadout == null:
|
if loadout == null:
|
||||||
return
|
return
|
||||||
# Map slider 0..1 across a deep-to-pale skin range.
|
var shade: float = _skin_tone_slider.value if _skin_tone_slider != null else 0.5
|
||||||
var t := value
|
var col := _skin_base
|
||||||
loadout.skin_tone = Color(
|
if shade < 0.5:
|
||||||
0.35 + 0.60 * t, # R
|
col = _skin_base.lerp(Color.BLACK, (0.5 - shade) * 1.7)
|
||||||
0.22 + 0.55 * t, # G
|
elif shade > 0.5:
|
||||||
0.16 + 0.50 * t, # B
|
col = _skin_base.lerp(Color.WHITE, (shade - 0.5) * 1.3)
|
||||||
1.0,
|
col.a = 1.0
|
||||||
)
|
loadout.skin_tone = col
|
||||||
_refresh_preview()
|
_refresh_preview()
|
||||||
loadout_changed.emit(loadout)
|
loadout_changed.emit(loadout)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user