feat: implement modular character skinning system with procedural and imported model support
This commit is contained in:
@@ -5,6 +5,7 @@ var main_vbox: VBoxContainer
|
||||
var resume_btn: Button
|
||||
var respawn_btn: Button
|
||||
var loadouts_btn: Button
|
||||
var character_btn: Button
|
||||
var settings_btn: Button
|
||||
var return_btn: Button
|
||||
var exit_btn: Button
|
||||
@@ -51,6 +52,12 @@ var rebind_overlay: ColorRect
|
||||
var rebind_label: Label
|
||||
var waiting_for_input_action: String = ""
|
||||
|
||||
# Character Skin UI
|
||||
var character_editor: Control
|
||||
var character_back_btn: Button
|
||||
var skin_grid: GridContainer
|
||||
var skin_preview_label: Label
|
||||
|
||||
var quit_dialog: ConfirmationDialog
|
||||
var return_dialog: ConfirmationDialog
|
||||
|
||||
@@ -146,6 +153,11 @@ func _build_ui() -> void:
|
||||
loadouts_btn.custom_minimum_size = Vector2(200, 50)
|
||||
main_vbox.add_child(loadouts_btn)
|
||||
|
||||
character_btn = Button.new()
|
||||
character_btn.text = "Character"
|
||||
character_btn.custom_minimum_size = Vector2(200, 50)
|
||||
main_vbox.add_child(character_btn)
|
||||
|
||||
settings_btn = Button.new()
|
||||
settings_btn.text = "Settings"
|
||||
settings_btn.custom_minimum_size = Vector2(200, 50)
|
||||
@@ -667,6 +679,48 @@ func _build_ui() -> void:
|
||||
rebind_label.add_theme_font_size_override("font_size", 32)
|
||||
rebind_center.add_child(rebind_label)
|
||||
|
||||
# ── Character Editor Root ──
|
||||
character_editor = Control.new()
|
||||
character_editor.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
bg.add_child(character_editor)
|
||||
|
||||
var char_center = CenterContainer.new()
|
||||
char_center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
character_editor.add_child(char_center)
|
||||
|
||||
var char_vbox = VBoxContainer.new()
|
||||
char_vbox.custom_minimum_size = Vector2(600, 500)
|
||||
char_vbox.add_theme_constant_override("separation", 15)
|
||||
char_center.add_child(char_vbox)
|
||||
|
||||
var char_title = Label.new()
|
||||
char_title.text = "CHARACTER SKIN"
|
||||
char_title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
char_title.add_theme_font_size_override("font_size", 32)
|
||||
char_vbox.add_child(char_title)
|
||||
|
||||
skin_preview_label = Label.new()
|
||||
skin_preview_label.text = "Selected: Default Blue"
|
||||
skin_preview_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
skin_preview_label.add_theme_font_size_override("font_size", 18)
|
||||
char_vbox.add_child(skin_preview_label)
|
||||
|
||||
var skin_scroll = ScrollContainer.new()
|
||||
skin_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
char_vbox.add_child(skin_scroll)
|
||||
|
||||
skin_grid = GridContainer.new()
|
||||
skin_grid.columns = 4
|
||||
skin_grid.add_theme_constant_override("h_separation", 12)
|
||||
skin_grid.add_theme_constant_override("v_separation", 12)
|
||||
skin_grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
skin_scroll.add_child(skin_grid)
|
||||
|
||||
character_back_btn = Button.new()
|
||||
character_back_btn.text = "Back to Menu"
|
||||
character_back_btn.custom_minimum_size = Vector2(0, 40)
|
||||
char_vbox.add_child(character_back_btn)
|
||||
|
||||
|
||||
# ── Quit Dialog ──
|
||||
quit_dialog = ConfirmationDialog.new()
|
||||
@@ -734,6 +788,8 @@ func _connect_signals() -> void:
|
||||
save_loadout_btn.pressed.connect(_save_current_loadout)
|
||||
quit_dialog.confirmed.connect(_quit_game)
|
||||
return_dialog.confirmed.connect(_return_to_main_menu)
|
||||
character_btn.pressed.connect(_show_character)
|
||||
character_back_btn.pressed.connect(_show_main_menu)
|
||||
|
||||
func _show_return_dialog() -> void:
|
||||
return_dialog.popup_centered()
|
||||
@@ -753,14 +809,75 @@ func _show_main_menu() -> void:
|
||||
main_vbox.visible = true
|
||||
loadout_editor.visible = false
|
||||
settings_editor.visible = false
|
||||
character_editor.visible = false
|
||||
|
||||
func _show_loadouts() -> void:
|
||||
main_vbox.visible = false
|
||||
settings_editor.visible = false
|
||||
character_editor.visible = false
|
||||
loadout_editor.visible = true
|
||||
edit_panel.visible = false
|
||||
_populate_loadout_list()
|
||||
|
||||
func _show_character() -> void:
|
||||
main_vbox.visible = false
|
||||
settings_editor.visible = false
|
||||
loadout_editor.visible = false
|
||||
character_editor.visible = true
|
||||
_populate_skin_grid()
|
||||
|
||||
func _populate_skin_grid() -> void:
|
||||
for c in skin_grid.get_children():
|
||||
c.queue_free()
|
||||
|
||||
var skin_mgr = get_node_or_null("/root/SkinManager")
|
||||
if not skin_mgr: return
|
||||
|
||||
var current_id = skin_mgr.selected_skin_id
|
||||
var all_ids = skin_mgr.get_all_skin_ids()
|
||||
|
||||
for id in all_ids:
|
||||
var skin = skin_mgr.get_skin(id)
|
||||
|
||||
var panel = PanelContainer.new()
|
||||
var style = StyleBoxFlat.new()
|
||||
style.bg_color = skin.primary_color
|
||||
style.corner_radius_top_left = 8
|
||||
style.corner_radius_top_right = 8
|
||||
style.corner_radius_bottom_left = 8
|
||||
style.corner_radius_bottom_right = 8
|
||||
if id == current_id:
|
||||
style.border_width_left = 4
|
||||
style.border_width_right = 4
|
||||
style.border_width_top = 4
|
||||
style.border_width_bottom = 4
|
||||
style.border_color = Color.WHITE
|
||||
skin_preview_label.text = "Selected: " + skin.display_name
|
||||
panel.add_theme_stylebox_override("panel", style)
|
||||
panel.custom_minimum_size = Vector2(120, 120)
|
||||
|
||||
var btn = Button.new()
|
||||
btn.text = skin.display_name
|
||||
btn.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
var btn_style = StyleBoxEmpty.new()
|
||||
btn.add_theme_stylebox_override("normal", btn_style)
|
||||
btn.add_theme_stylebox_override("hover", btn_style)
|
||||
btn.add_theme_stylebox_override("pressed", btn_style)
|
||||
btn.add_theme_stylebox_override("focus", btn_style)
|
||||
|
||||
# Text shadow for readability
|
||||
btn.add_theme_color_override("font_color", Color.WHITE)
|
||||
btn.add_theme_color_override("font_outline_color", Color.BLACK)
|
||||
btn.add_theme_constant_override("outline_size", 4)
|
||||
|
||||
btn.pressed.connect(func():
|
||||
skin_mgr.set_player_skin(id)
|
||||
_populate_skin_grid() # Refresh borders
|
||||
)
|
||||
|
||||
panel.add_child(btn)
|
||||
skin_grid.add_child(panel)
|
||||
|
||||
func _populate_video_ui() -> void:
|
||||
if _display_mode_opt:
|
||||
for i in range(_display_mode_opt.item_count):
|
||||
|
||||
Reference in New Issue
Block a user