feat(skin): add skin system + Miku character skin
Skin System: - PlayerSkin resource class (model_path, color_tint, etc.) - SkinManager with default skins: Default, Red Team, Forest, Miku - HumanoidModel.apply_skin() supports both GLB model replacement and procedural color tinting - Procedural meshes auto-hide when GLB model is loaded Miku Skin: - 43-part procedural model generated in Blender (headless) - Twin tails, headphones, thigh-high socks, idol outfit - Teal/cyan color scheme with red accents - Exported to assets/characters/skins/miku.glb - Applied to player 1 in test level builder Pipeline: - Blender 5.0.1 + MCP addon installed - Bridge script for socket-based Blender control - docs/3D_ASSET_PIPELINE.md documents full workflow
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
extends Node
|
||||
class_name SkinManager
|
||||
|
||||
## Manages all available player skins.
|
||||
## Add new skins here or load from a config file.
|
||||
|
||||
var skins: Dictionary = {}
|
||||
var active_skin_id: String = "default"
|
||||
|
||||
func _ready() -> void:
|
||||
_register_default_skins()
|
||||
|
||||
func _register_default_skins() -> void:
|
||||
# Default blue soldier
|
||||
var default_skin = PlayerSkin.new()
|
||||
default_skin.skin_name = "Default"
|
||||
default_skin.description = "Standard issue"
|
||||
default_skin.color_tint = Color(0.2, 0.4, 0.8)
|
||||
default_skin.is_unlocked = true
|
||||
skins["default"] = default_skin
|
||||
|
||||
# Red team
|
||||
var red_skin = PlayerSkin.new()
|
||||
red_skin.skin_name = "Red Team"
|
||||
red_skin.description = "Red team colors"
|
||||
red_skin.color_tint = Color(0.8, 0.2, 0.2)
|
||||
red_skin.is_unlocked = true
|
||||
skins["red_team"] = red_skin
|
||||
|
||||
# Green soldier
|
||||
var green_skin = PlayerSkin.new()
|
||||
green_skin.skin_name = "Forest"
|
||||
green_skin.description = "Forest camouflage"
|
||||
green_skin.color_tint = Color(0.2, 0.6, 0.2)
|
||||
green_skin.is_unlocked = true
|
||||
skins["forest"] = green_skin
|
||||
|
||||
# Hatsune Miku
|
||||
var miku_skin = PlayerSkin.new()
|
||||
miku_skin.skin_name = "Miku"
|
||||
miku_skin.description = "Hatsune Miku — Virtual Idol"
|
||||
miku_skin.model_path = "res://assets/characters/skins/miku.glb"
|
||||
miku_skin.color_tint = Color(0.0, 0.75, 0.75)
|
||||
miku_skin.is_unlocked = true
|
||||
skins["miku"] = miku_skin
|
||||
|
||||
print("SkinManager: registered %d skins" % skins.size())
|
||||
for id in skins:
|
||||
print(" - %s: %s" % [id, skins[id].skin_name])
|
||||
|
||||
func get_skin(skin_id: String) -> PlayerSkin:
|
||||
if skins.has(skin_id):
|
||||
return skins[skin_id]
|
||||
return skins["default"]
|
||||
|
||||
func get_active_skin() -> PlayerSkin:
|
||||
return get_skin(active_skin_id)
|
||||
|
||||
func set_active_skin(skin_id: String) -> void:
|
||||
if skins.has(skin_id) and skins[skin_id].is_unlocked:
|
||||
active_skin_id = skin_id
|
||||
print("SkinManager: active skin set to '%s'" % skins[skin_id].skin_name)
|
||||
Reference in New Issue
Block a user