extends RefCounted ## Procedural low-poly player character, coloured by the player's appearance ## (identity.gd: tunic, hair, beard). Feet at the origin, facing -Z, 1.8 m ## tall to match the player capsule. ## ## build() returns: ## body: torso, belt, head, hair and beard (static) ## arm / leg: one limb each, hanging from its pivot down -Y ## shoulders / hips: the pivot points (left, right) ## hand: where a held item goes, in arm space const P = preload("res://scripts/world/proc_mesh.gd") const IM = preload("res://scripts/items/item_meshes.gd") const Identity = preload("res://scripts/net/identity.gd") const SKIN := Color(0.86, 0.68, 0.55) const TROUSERS := Color(0.30, 0.25, 0.20) const BOOTS := Color(0.20, 0.14, 0.10) const BELT := Color(0.35, 0.22, 0.12) const EYES := Color(0.08, 0.07, 0.06) static var _cache := {} static func build(appearance: Dictionary) -> Dictionary: var a := Identity.sanitize_appearance(appearance) var key := "%d_%d_%s" % [a.tunic, a.hair, a.beard] if _cache.has(key): return _cache[key] var tunic: Color = Identity.TUNICS[a.tunic] var hair: Color = Identity.HAIR[a.hair] var r := RandomNumberGenerator.new() r.seed = 7 var n := FastNoiseLite.new() n.seed = 7 n.frequency = 1.5 var st := P._begin() IM._box(st, Vector3(0, 1.2, 0), Vector3(0.42, 0.56, 0.24), tunic) # tunic IM._box(st, Vector3(0, 0.93, 0), Vector3(0.44, 0.1, 0.26), P._mul(tunic, 0.85)) # skirt hem IM._box(st, Vector3(0, 1.0, 0), Vector3(0.45, 0.06, 0.27), BELT) IM._box(st, Vector3(0, 1.0, -0.135), Vector3(0.07, 0.05, 0.02), Color(0.6, 0.55, 0.4)) # buckle IM._box(st, Vector3(0, 1.5, 0), Vector3(0.12, 0.06, 0.12), SKIN) # neck P._blob(st, Vector3(0, 1.65, 0), Vector3(0.13, 0.15, 0.14), n, 0.05, SKIN, r, 1) # head for s in [-1.0, 1.0]: IM._box(st, Vector3(s * 0.05, 1.67, -0.13), Vector3(0.03, 0.025, 0.02), EYES) IM._box(st, Vector3(0, 1.62, -0.145), Vector3(0.035, 0.05, 0.03), P._mul(SKIN, 0.92)) # nose P._blob(st, Vector3(0, 1.72, 0.02), Vector3(0.145, 0.1, 0.15), n, 0.15, hair, r, 1) # hair IM._box(st, Vector3(0, 1.66, 0.11), Vector3(0.24, 0.14, 0.06), hair) # back of the head if a.beard: IM._box(st, Vector3(0, 1.54, -0.115), Vector3(0.2, 0.13, 0.07), hair) IM._box(st, Vector3(0, 1.47, -0.1), Vector3(0.12, 0.06, 0.05), hair) var body := P._commit(st) st = P._begin() IM._box(st, Vector3(0, -0.2, 0), Vector3(0.12, 0.42, 0.13), tunic) IM._box(st, Vector3(0, -0.47, 0), Vector3(0.09, 0.12, 0.1), SKIN) var arm := P._commit(st) st = P._begin() IM._box(st, Vector3(0, -0.4, 0), Vector3(0.14, 0.78, 0.15), TROUSERS) IM._box(st, Vector3(0, -0.85, -0.03), Vector3(0.15, 0.14, 0.22), BOOTS) var leg := P._commit(st) var out := {"body": body, "arm": arm, "leg": leg, "shoulders": [Vector3(-0.27, 1.43, 0), Vector3(0.27, 1.43, 0)], "hips": [Vector3(-0.1, 0.92, 0), Vector3(0.1, 0.92, 0)], "hand": Vector3(0, -0.5, -0.02)} _cache[key] = out return out