396 lines
22 KiB
GDScript
396 lines
22 KiB
GDScript
extends RefCounted
|
|
## Procedural low-poly animals, built from the same helpers as the trees and
|
|
## items (flat-shaded, vertex colours, no assets).
|
|
##
|
|
## Each kind gives a static "body" mesh (torso, head, ears, tail) facing -Z,
|
|
## one "leg" mesh hanging from the origin down -Y, and the four hip points
|
|
## the legs pivot on. creature.gd animates the legs.
|
|
|
|
const P = preload("res://scripts/world/proc_mesh.gd")
|
|
|
|
static var _cache := {}
|
|
|
|
static func build(kind: String) -> Dictionary:
|
|
if _cache.has(kind):
|
|
return _cache[kind]
|
|
var d: Dictionary
|
|
match kind:
|
|
"rabbit": d = _rabbit()
|
|
"deer": d = _deer()
|
|
"wolf": d = _wolf()
|
|
"alpha": d = _wolf(true)
|
|
"bear": d = _bear()
|
|
"fox": d = _scaled(_wolf_parts(Color(0.78, 0.4, 0.15), Color(0.92, 0.88, 0.8), 281), 0.6)
|
|
"crow": d = _crow()
|
|
"gull": d = _gull()
|
|
"crab": d = _crab()
|
|
"guard": d = _guard()
|
|
"drowned": d = _drowned()
|
|
"old_stag": d = _scaled(_stag(), 2.1)
|
|
"spirit_wolf": d = _wolf_parts(Color(0.62, 0.72, 0.78), Color(0.85, 0.92, 0.95), 351)
|
|
_: d = _boar()
|
|
_cache[kind] = d
|
|
return d
|
|
|
|
static func _rng(seed: int) -> RandomNumberGenerator:
|
|
var r := RandomNumberGenerator.new()
|
|
r.seed = seed
|
|
return r
|
|
|
|
static func _noise(seed: int, f: float = 1.6) -> FastNoiseLite:
|
|
var n := FastNoiseLite.new()
|
|
n.seed = seed
|
|
n.frequency = f
|
|
return n
|
|
|
|
static func _leg(len: float, r0: float, r1: float, col: Color, hoof: Color, seed: int) -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(seed)
|
|
P._cylinder(st, Vector3(0, 0, 0), Vector3(0, -len * 0.55, 0.02), r0, r0 * 0.75, 5, col, r, 0.0)
|
|
P._cylinder(st, Vector3(0, -len * 0.55, 0.02), Vector3(0, -len, 0), r0 * 0.75, r1, 5, col, r, 0.0, hoof)
|
|
return P._commit(st)
|
|
|
|
static func _rabbit() -> Dictionary:
|
|
var fur := Color(0.55, 0.46, 0.36)
|
|
var st := P._begin()
|
|
var r := _rng(201)
|
|
var n := _noise(201)
|
|
P._blob(st, Vector3(0, 0.2, 0.03), Vector3(0.13, 0.13, 0.2), n, 0.15, fur, r, 1)
|
|
P._blob(st, Vector3(0, 0.31, -0.17), Vector3(0.085, 0.085, 0.1), n, 0.12, fur, r, 1)
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.035, 0.38, -0.15), Vector3(s * 0.06, 0.56, -0.1), 0.025, 0.018, 4, P._mul(fur, 1.1), r, -1.0, Color(0.85, 0.65, 0.6))
|
|
P._blob(st, Vector3(s * 0.05, 0.33, -0.25), Vector3.ONE * 0.012, n, 0.0, Color(0.05, 0.04, 0.04), r, 0)
|
|
P._blob(st, Vector3(0, 0.25, 0.23), Vector3.ONE * 0.05, n, 0.2, Color(0.93, 0.92, 0.88), r, 0)
|
|
return {"body": P._commit(st), "leg": _leg(0.12, 0.03, 0.025, fur, P._mul(fur, 0.8), 202),
|
|
"hips": [Vector3(-0.07, 0.12, -0.1), Vector3(0.07, 0.12, -0.1), Vector3(-0.08, 0.14, 0.12), Vector3(0.08, 0.14, 0.12)],
|
|
"radius": 0.18, "height": 0.4}
|
|
|
|
static func _deer() -> Dictionary:
|
|
var coat := Color(0.62, 0.42, 0.25)
|
|
var belly := Color(0.85, 0.76, 0.62)
|
|
var dark := Color(0.2, 0.15, 0.12)
|
|
var st := P._begin()
|
|
var r := _rng(211)
|
|
var n := _noise(211, 1.2)
|
|
P._blob(st, Vector3(0, 1.0, 0), Vector3(0.26, 0.3, 0.62), n, 0.12, coat, r, 1)
|
|
P._blob(st, Vector3(0, 0.86, 0.05), Vector3(0.2, 0.14, 0.45), n, 0.1, belly, r, 1)
|
|
P._cylinder(st, Vector3(0, 1.1, -0.45), Vector3(0, 1.55, -0.68), 0.13, 0.09, 6, coat, r)
|
|
P._blob(st, Vector3(0, 1.6, -0.78), Vector3(0.11, 0.12, 0.2), n, 0.1, coat, r, 1)
|
|
P._blob(st, Vector3(0, 1.55, -0.96), Vector3(0.05, 0.05, 0.05), n, 0.0, dark, r, 0)
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.07, 1.7, -0.72), Vector3(s * 0.2, 1.82, -0.66), 0.04, 0.015, 4, coat, r)
|
|
P._blob(st, Vector3(s * 0.08, 1.65, -0.86), Vector3.ONE * 0.022, n, 0.0, dark, r, 0)
|
|
# Small antlers.
|
|
P._cylinder(st, Vector3(s * 0.04, 1.72, -0.76), Vector3(s * 0.12, 2.0, -0.7), 0.018, 0.01, 4, Color(0.8, 0.74, 0.6), r)
|
|
P._cylinder(st, Vector3(s * 0.09, 1.88, -0.72), Vector3(s * 0.08, 2.0, -0.86), 0.012, 0.006, 3, Color(0.8, 0.74, 0.6), r)
|
|
P._blob(st, Vector3(0, 1.12, 0.62), Vector3(0.06, 0.09, 0.05), n, 0.1, belly, r, 0)
|
|
return {"body": P._commit(st), "leg": _leg(0.88, 0.055, 0.035, coat, dark, 212),
|
|
"hips": [Vector3(-0.14, 0.9, -0.42), Vector3(0.14, 0.9, -0.42), Vector3(-0.14, 0.92, 0.42), Vector3(0.14, 0.92, 0.42)],
|
|
"radius": 0.4, "height": 1.7}
|
|
|
|
static func _boar() -> Dictionary:
|
|
var bristle := Color(0.33, 0.25, 0.2)
|
|
var snout := Color(0.55, 0.4, 0.36)
|
|
var tusk := Color(0.92, 0.9, 0.82)
|
|
var st := P._begin()
|
|
var r := _rng(221)
|
|
var n := _noise(221, 1.4)
|
|
P._blob(st, Vector3(0, 0.62, 0.02), Vector3(0.32, 0.34, 0.6), n, 0.18, bristle, r, 1)
|
|
P._blob(st, Vector3(0, 0.8, -0.2), Vector3(0.18, 0.15, 0.3), n, 0.3, P._mul(bristle, 0.75), r, 1) # mane
|
|
P._blob(st, Vector3(0, 0.6, -0.62), Vector3(0.2, 0.2, 0.26), n, 0.15, bristle, r, 1)
|
|
P._cylinder(st, Vector3(0, 0.55, -0.8), Vector3(0, 0.5, -0.98), 0.1, 0.08, 6, snout, r, -1.0, P._mul(snout, 0.8))
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.08, 0.48, -0.88), Vector3(s * 0.12, 0.62, -0.96), 0.022, 0.006, 4, tusk, r)
|
|
P._cylinder(st, Vector3(s * 0.1, 0.76, -0.62), Vector3(s * 0.17, 0.9, -0.55), 0.05, 0.015, 4, bristle, r)
|
|
P._blob(st, Vector3(s * 0.11, 0.68, -0.8), Vector3.ONE * 0.02, n, 0.0, Color(0.05, 0.03, 0.03), r, 0)
|
|
P._cylinder(st, Vector3(0, 0.7, 0.58), Vector3(0, 0.55, 0.72), 0.02, 0.012, 3, bristle, r)
|
|
return {"body": P._commit(st), "leg": _leg(0.36, 0.07, 0.05, bristle, Color(0.15, 0.12, 0.1), 222),
|
|
"hips": [Vector3(-0.17, 0.38, -0.36), Vector3(0.17, 0.38, -0.36), Vector3(-0.17, 0.4, 0.38), Vector3(0.17, 0.4, 0.38)],
|
|
"radius": 0.42, "height": 0.95}
|
|
|
|
## Grey wolf: lean body, long snout, pointed ears, bushy tail. "eyes" is a
|
|
## separate mesh so it can glow (creature.gd gives it an emissive material).
|
|
## `alpha`: a third bigger, near-black with a grizzled ruff and a scarred
|
|
## muzzle (wolf moon nights).
|
|
static func _wolf(alpha: bool = false) -> Dictionary:
|
|
if alpha:
|
|
return _scaled(_wolf_parts(Color(0.17, 0.16, 0.17), Color(0.5, 0.48, 0.45), 241), 1.32)
|
|
return _wolf_parts(Color(0.42, 0.42, 0.44), Color(0.72, 0.71, 0.68), 231)
|
|
|
|
## The same parts scaled up `k` times (body, eyes and leg meshes, hips, radius, height).
|
|
static func _scaled(d: Dictionary, k: float) -> Dictionary:
|
|
var out := d.duplicate()
|
|
for key in ["body", "eyes", "leg"]:
|
|
if d.has(key):
|
|
out[key] = _scale_mesh(d[key], k)
|
|
var hips: Array = []
|
|
for h: Vector3 in d.hips:
|
|
hips.append(h * k)
|
|
out.hips = hips
|
|
out.radius = float(d.radius) * k
|
|
out.height = float(d.height) * k
|
|
return out
|
|
|
|
static func _scale_mesh(m: ArrayMesh, k: float) -> ArrayMesh:
|
|
var arrays := m.surface_get_arrays(0)
|
|
var v: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
|
|
for i in range(v.size()):
|
|
v[i] *= k
|
|
arrays[Mesh.ARRAY_VERTEX] = v
|
|
var out := ArrayMesh.new()
|
|
out.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
|
return out
|
|
|
|
static func _wolf_parts(coat: Color, pale: Color, seed: int) -> Dictionary:
|
|
var dark := Color(0.16, 0.15, 0.15)
|
|
var st := P._begin()
|
|
var r := _rng(seed)
|
|
var n := _noise(seed, 1.5)
|
|
P._blob(st, Vector3(0, 0.7, 0.05), Vector3(0.22, 0.24, 0.55), n, 0.15, coat, r, 1)
|
|
P._blob(st, Vector3(0, 0.8, -0.32), Vector3(0.24, 0.26, 0.3), n, 0.25, P._mul(coat, 1.08), r, 1) # ruff
|
|
P._blob(st, Vector3(0, 0.6, -0.1), Vector3(0.16, 0.12, 0.35), n, 0.1, pale, r, 1) # belly
|
|
P._blob(st, Vector3(0, 0.92, -0.62), Vector3(0.15, 0.14, 0.17), n, 0.12, coat, r, 1) # head
|
|
P._cylinder(st, Vector3(0, 0.88, -0.72), Vector3(0, 0.83, -0.95), 0.09, 0.05, 6, pale, r, -1.0, dark) # snout
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.08, 1.02, -0.6), Vector3(s * 0.1, 1.2, -0.58), 0.05, 0.008, 4, P._mul(coat, 0.85), r)
|
|
# Bushy tail, hanging down and back.
|
|
P._cylinder(st, Vector3(0, 0.78, 0.55), Vector3(0, 0.5, 0.85), 0.07, 0.05, 5, coat, r)
|
|
P._blob(st, Vector3(0, 0.45, 0.9), Vector3(0.06, 0.08, 0.06), n, 0.2, pale, r, 0)
|
|
var est := P._begin()
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(est, Vector3(s * 0.065, 0.97, -0.75), Vector3.ONE * 0.022, n, 0.0, Color(1.0, 0.8, 0.3), r, 0)
|
|
return {"body": P._commit(st), "eyes": P._commit(est), "leg": _leg(0.52, 0.045, 0.03, coat, dark, seed + 1),
|
|
"hips": [Vector3(-0.11, 0.52, -0.38), Vector3(0.11, 0.52, -0.38), Vector3(-0.11, 0.54, 0.38), Vector3(0.11, 0.54, 0.38)],
|
|
"radius": 0.32, "height": 1.0}
|
|
|
|
## Brown bear: a heavy humped body, a broad head with a pale muzzle and
|
|
## round ears, thick short legs.
|
|
static func _bear() -> Dictionary:
|
|
var coat := Color(0.36, 0.24, 0.15)
|
|
var hump := Color(0.42, 0.29, 0.18)
|
|
var muzzle := Color(0.58, 0.45, 0.32)
|
|
var dark := Color(0.1, 0.08, 0.07)
|
|
var st := P._begin()
|
|
var r := _rng(261)
|
|
var n := _noise(261, 1.3)
|
|
P._blob(st, Vector3(0, 0.95, 0.15), Vector3(0.5, 0.5, 0.85), n, 0.14, coat, r, 1) # body
|
|
P._blob(st, Vector3(0, 1.22, -0.35), Vector3(0.44, 0.38, 0.42), n, 0.18, hump, r, 1) # shoulder hump
|
|
P._blob(st, Vector3(0, 1.05, -0.95), Vector3(0.3, 0.27, 0.3), n, 0.12, coat, r, 1) # head
|
|
P._cylinder(st, Vector3(0, 0.98, -1.12), Vector3(0, 0.92, -1.36), 0.15, 0.1, 6, muzzle, r, -1.0, dark)
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(st, Vector3(s * 0.2, 1.3, -0.9), Vector3(0.08, 0.08, 0.05), n, 0.1, P._mul(coat, 0.85), r, 0) # ears
|
|
P._blob(st, Vector3(0, 0.98, 0.98), Vector3(0.08, 0.08, 0.07), n, 0.2, coat, r, 0) # stub tail
|
|
var est := P._begin()
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(est, Vector3(s * 0.13, 1.12, -1.18), Vector3.ONE * 0.025, n, 0.0, Color(0.9, 0.6, 0.25), r, 0)
|
|
return {"body": P._commit(st), "eyes": P._commit(est), "leg": _leg(0.72, 0.13, 0.11, coat, dark, 262),
|
|
"hips": [Vector3(-0.28, 0.72, -0.5), Vector3(0.28, 0.72, -0.5), Vector3(-0.28, 0.74, 0.6), Vector3(0.28, 0.74, 0.6)],
|
|
"radius": 0.62, "height": 1.6}
|
|
|
|
## Crow: a small black bird facing -Z. The two "legs" are its wings
|
|
## (crow.gd swings them out sideways and flaps them).
|
|
static func _crow() -> Dictionary:
|
|
var black := Color(0.08, 0.08, 0.1)
|
|
var sheen := Color(0.14, 0.15, 0.2)
|
|
var beak := Color(0.2, 0.18, 0.15)
|
|
var st := P._begin()
|
|
var r := _rng(291)
|
|
var n := _noise(291, 2.0)
|
|
P._blob(st, Vector3(0, 0.16, 0), Vector3(0.07, 0.07, 0.14), n, 0.1, black, r, 1)
|
|
P._blob(st, Vector3(0, 0.22, -0.13), Vector3(0.05, 0.05, 0.055), n, 0.1, sheen, r, 1)
|
|
P._cylinder(st, Vector3(0, 0.215, -0.17), Vector3(0, 0.2, -0.24), 0.016, 0.002, 4, beak, r)
|
|
P._cylinder(st, Vector3(0, 0.17, 0.12), Vector3(0, 0.15, 0.26), 0.03, 0.05, 4, black, r)
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.025, 0.1, 0.0), Vector3(s * 0.03, 0.0, 0.02), 0.006, 0.005, 3, beak, r)
|
|
for s in [-1.0, 1.0]: # (dull eyes: no glowing "eyes" mesh for a crow)
|
|
P._blob(st, Vector3(s * 0.035, 0.235, -0.16), Vector3.ONE * 0.008, n, 0.0, Color(0.3, 0.25, 0.2), r, 0)
|
|
var wst := P._begin()
|
|
P._blob(wst, Vector3(0, -0.14, 0.02), Vector3(0.012, 0.15, 0.08), n, 0.05, sheen, r, 0)
|
|
return {"body": P._commit(st), "leg": P._commit(wst),
|
|
"hips": [Vector3(-0.06, 0.19, -0.01), Vector3(0.06, 0.19, -0.01)],
|
|
"radius": 0.12, "height": 0.3}
|
|
|
|
## Gull: a crow's build, bigger, white with grey wings and a yellow beak.
|
|
static func _gull() -> Dictionary:
|
|
var white := Color(0.93, 0.93, 0.9)
|
|
var grey := Color(0.6, 0.63, 0.67)
|
|
var tip := Color(0.12, 0.12, 0.13)
|
|
var beak := Color(0.95, 0.75, 0.2)
|
|
var st := P._begin()
|
|
var r := _rng(295)
|
|
var n := _noise(295, 2.0)
|
|
P._blob(st, Vector3(0, 0.2, 0), Vector3(0.09, 0.085, 0.18), n, 0.08, white, r, 1)
|
|
P._blob(st, Vector3(0, 0.25, 0.04), Vector3(0.075, 0.05, 0.14), n, 0.06, grey, r, 1)
|
|
P._blob(st, Vector3(0, 0.28, -0.16), Vector3(0.06, 0.06, 0.065), n, 0.08, white, r, 1)
|
|
P._cylinder(st, Vector3(0, 0.275, -0.21), Vector3(0, 0.255, -0.3), 0.017, 0.004, 4, beak, r)
|
|
P._cylinder(st, Vector3(0, 0.22, 0.15), Vector3(0, 0.2, 0.3), 0.035, 0.05, 4, tip, r)
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.03, 0.13, 0.0), Vector3(s * 0.035, 0.0, 0.02), 0.008, 0.007, 3, beak, r)
|
|
P._blob(st, Vector3(s * 0.04, 0.295, -0.19), Vector3.ONE * 0.009, n, 0.0, Color(0.1, 0.1, 0.1), r, 0)
|
|
var wst := P._begin()
|
|
P._blob(wst, Vector3(0, -0.2, 0.03), Vector3(0.014, 0.21, 0.09), n, 0.04, grey, r, 0)
|
|
P._blob(wst, Vector3(0, -0.38, 0.05), Vector3(0.012, 0.05, 0.06), n, 0.0, tip, r, 0)
|
|
return {"body": P._commit(st), "leg": P._commit(wst),
|
|
"hips": [Vector3(-0.08, 0.25, -0.01), Vector3(0.08, 0.25, -0.01)],
|
|
"radius": 0.15, "height": 0.38}
|
|
|
|
## Crab: a wide, flat red-brown shell facing -Z, two big claws in front and
|
|
## eyes on stalks; six thin legs splayed out to the sides (crab.gd turns the
|
|
## whole crab side-on to walk, and flickers the legs).
|
|
static func _crab() -> Dictionary:
|
|
var shell := Color(0.66, 0.22, 0.12)
|
|
var dark := Color(0.42, 0.13, 0.08)
|
|
var pale := Color(0.9, 0.72, 0.55)
|
|
var st := P._begin()
|
|
var r := _rng(297)
|
|
var n := _noise(297, 2.4)
|
|
P._blob(st, Vector3(0, 0.11, 0), Vector3(0.2, 0.06, 0.14), n, 0.1, shell, r, 1)
|
|
P._blob(st, Vector3(0, 0.08, 0.01), Vector3(0.17, 0.035, 0.12), n, 0.05, pale, r, 1)
|
|
for s in [-1.0, 1.0]:
|
|
# Arm, then the claw: a fat pincer and a thin finger.
|
|
P._cylinder(st, Vector3(s * 0.12, 0.1, -0.09), Vector3(s * 0.17, 0.13, -0.2), 0.025, 0.02, 4, shell, r)
|
|
P._blob(st, Vector3(s * 0.17, 0.14, -0.26), Vector3(0.05, 0.04, 0.07), n, 0.1, shell, r, 1)
|
|
P._cylinder(st, Vector3(s * 0.17, 0.15, -0.31), Vector3(s * 0.15, 0.16, -0.37), 0.02, 0.006, 4, dark, r)
|
|
P._cylinder(st, Vector3(s * 0.19, 0.12, -0.31), Vector3(s * 0.18, 0.12, -0.36), 0.014, 0.004, 4, dark, r)
|
|
# Eyes on stalks.
|
|
P._cylinder(st, Vector3(s * 0.04, 0.15, -0.11), Vector3(s * 0.05, 0.21, -0.13), 0.008, 0.006, 3, shell, r)
|
|
P._blob(st, Vector3(s * 0.05, 0.22, -0.13), Vector3.ONE * 0.014, n, 0.0, Color(0.05, 0.05, 0.05), r, 0)
|
|
var lst := P._begin()
|
|
P._cylinder(lst, Vector3(0, 0, 0), Vector3(0, -0.11, 0.0), 0.014, 0.01, 3, shell, r)
|
|
P._cylinder(lst, Vector3(0, -0.11, 0.0), Vector3(0, -0.2, 0.0), 0.01, 0.003, 3, dark, r)
|
|
var hips: Array = []
|
|
for s in [-1.0, 1.0]:
|
|
for z in [-0.05, 0.03, 0.1]:
|
|
hips.append(Vector3(s * 0.17, 0.1, z))
|
|
return {"body": P._commit(st), "leg": P._commit(lst), "hips": hips,
|
|
"radius": 0.2, "height": 0.25}
|
|
|
|
## Barrow guard: an upright skeleton facing -Z, in a rusted helm, an old
|
|
## sword in its right hand and a round shield on its left arm. Two legs
|
|
## (creature.gd walks them like a pair of a quadruped's).
|
|
static func _guard() -> Dictionary:
|
|
var bone := Color(0.82, 0.79, 0.68)
|
|
var old := Color(0.62, 0.58, 0.48)
|
|
var rust := Color(0.42, 0.24, 0.14)
|
|
var dark := Color(0.06, 0.06, 0.07)
|
|
var wood := Color(0.32, 0.22, 0.14)
|
|
var st := P._begin()
|
|
var r := _rng(301)
|
|
var n := _noise(301, 2.2)
|
|
P._blob(st, Vector3(0, 0.95, 0), Vector3(0.17, 0.07, 0.1), n, 0.2, old, r, 0) # pelvis
|
|
P._cylinder(st, Vector3(0, 0.97, 0.02), Vector3(0, 1.45, 0.0), 0.035, 0.03, 5, bone, r) # spine
|
|
for i in range(4): # ribs
|
|
var y := 1.18 + 0.075 * i
|
|
P._cylinder(st, Vector3(-0.15 + 0.01 * i, y, -0.02), Vector3(0.15 - 0.01 * i, y, -0.02), 0.018, 0.018, 4, bone, r)
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * (0.15 - 0.01 * i), y, -0.02), Vector3(s * 0.11, y - 0.02, 0.07), 0.015, 0.015, 3, old, r)
|
|
P._cylinder(st, Vector3(-0.22, 1.47, 0), Vector3(0.22, 1.47, 0), 0.025, 0.025, 4, bone, r) # shoulders
|
|
P._blob(st, Vector3(0, 1.66, -0.02), Vector3(0.11, 0.13, 0.12), n, 0.12, bone, r, 1) # skull
|
|
P._blob(st, Vector3(0, 1.56, -0.08), Vector3(0.07, 0.04, 0.06), n, 0.1, old, r, 0) # jaw
|
|
P._cylinder(st, Vector3(0, 1.69, -0.01), Vector3(0, 1.82, -0.01), 0.14, 0.06, 7, rust, r, -1.0, rust) # helm
|
|
P._cylinder(st, Vector3(0, 1.66, -0.12), Vector3(0, 1.5, -0.14), 0.018, 0.012, 4, rust, r) # nose guard
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(st, Vector3(s * 0.045, 1.67, -0.115), Vector3(0.03, 0.025, 0.012), n, 0.0, dark, r, 0) # sockets
|
|
# Right arm forward with the sword, left arm with the shield.
|
|
P._cylinder(st, Vector3(0.22, 1.47, 0), Vector3(0.28, 1.2, -0.12), 0.025, 0.022, 4, bone, r)
|
|
P._cylinder(st, Vector3(0.28, 1.2, -0.12), Vector3(0.27, 1.08, -0.38), 0.022, 0.02, 4, bone, r)
|
|
P._cylinder(st, Vector3(0.27, 1.08, -0.4), Vector3(0.29, 1.5, -0.95), 0.03, 0.006, 4, rust, r) # blade
|
|
P._cylinder(st, Vector3(0.2, 1.05, -0.38), Vector3(0.34, 1.1, -0.4), 0.02, 0.02, 4, rust, r) # crossguard
|
|
P._cylinder(st, Vector3(-0.22, 1.47, 0), Vector3(-0.3, 1.2, -0.05), 0.025, 0.022, 4, bone, r)
|
|
P._cylinder(st, Vector3(-0.3, 1.2, -0.05), Vector3(-0.28, 1.05, -0.25), 0.022, 0.02, 4, bone, r)
|
|
P._cylinder(st, Vector3(-0.33, 1.12, -0.3), Vector3(-0.31, 1.12, -0.36), 0.26, 0.26, 9, wood, r, -1.0, wood) # shield
|
|
P._cylinder(st, Vector3(-0.31, 1.12, -0.36), Vector3(-0.305, 1.12, -0.4), 0.06, 0.04, 6, rust, r, -1.0, rust) # boss
|
|
var est := P._begin()
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(est, Vector3(s * 0.045, 1.67, -0.125), Vector3.ONE * 0.012, n, 0.0, Color(0.5, 0.85, 1.0), r, 0)
|
|
var lst := P._begin()
|
|
P._cylinder(lst, Vector3(0, 0, 0), Vector3(0, -0.45, 0.02), 0.03, 0.025, 4, bone, r)
|
|
P._cylinder(lst, Vector3(0, -0.45, 0.02), Vector3(0, -0.9, 0), 0.025, 0.022, 4, bone, r)
|
|
P._blob(lst, Vector3(0, -0.9, -0.05), Vector3(0.04, 0.025, 0.08), n, 0.1, old, r, 0)
|
|
return {"body": P._commit(st), "eyes": P._commit(est), "leg": P._commit(lst),
|
|
"hips": [Vector3(-0.1, 0.93, 0), Vector3(0.1, 0.93, 0)],
|
|
"radius": 0.3, "height": 1.85}
|
|
|
|
## A drowned sailor (0.6.0): the barrow guard's bones, sea-greyed and hung
|
|
## with weed, a rag of a shirt, a bandana, and a cutlass; no shield or helm.
|
|
static func _drowned() -> Dictionary:
|
|
var bone := Color(0.62, 0.66, 0.58)
|
|
var old := Color(0.44, 0.5, 0.42)
|
|
var weed := Color(0.16, 0.32, 0.18)
|
|
var rag := Color(0.36, 0.33, 0.27)
|
|
var red := Color(0.45, 0.12, 0.1)
|
|
var steel := Color(0.5, 0.52, 0.55)
|
|
var dark := Color(0.05, 0.07, 0.06)
|
|
var st := P._begin()
|
|
var r := _rng(331)
|
|
var n := _noise(331, 2.2)
|
|
P._blob(st, Vector3(0, 0.95, 0), Vector3(0.17, 0.07, 0.1), n, 0.2, old, r, 0) # pelvis
|
|
P._cylinder(st, Vector3(0, 0.97, 0.02), Vector3(0, 1.45, 0.0), 0.035, 0.03, 5, bone, r) # spine
|
|
for i in range(4): # ribs
|
|
var y := 1.18 + 0.075 * i
|
|
P._cylinder(st, Vector3(-0.15 + 0.01 * i, y, -0.02), Vector3(0.15 - 0.01 * i, y, -0.02), 0.018, 0.018, 4, bone, r)
|
|
P._blob(st, Vector3(0.02, 1.3, 0.0), Vector3(0.19, 0.17, 0.12), n, 0.45, rag, r, 0) # shirt, in tatters
|
|
P._cylinder(st, Vector3(-0.22, 1.47, 0), Vector3(0.22, 1.47, 0), 0.025, 0.025, 4, bone, r) # shoulders
|
|
P._blob(st, Vector3(0, 1.66, -0.02), Vector3(0.11, 0.13, 0.12), n, 0.12, bone, r, 1) # skull
|
|
P._blob(st, Vector3(0, 1.56, -0.08), Vector3(0.07, 0.04, 0.06), n, 0.1, old, r, 0) # jaw
|
|
P._blob(st, Vector3(0, 1.75, 0.0), Vector3(0.12, 0.05, 0.13), n, 0.15, red, r, 0) # bandana
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(st, Vector3(s * 0.045, 1.67, -0.115), Vector3(0.03, 0.025, 0.012), n, 0.0, dark, r, 0) # sockets
|
|
for i in range(5): # weed hanging off
|
|
var x := -0.16 + i * 0.08
|
|
P._cylinder(st, Vector3(x, 1.45, -0.04), Vector3(x + 0.02, 1.05 - 0.05 * (i % 2), -0.06), 0.012, 0.004, 3, weed, r)
|
|
# Right arm forward with the cutlass, left hanging.
|
|
P._cylinder(st, Vector3(0.22, 1.47, 0), Vector3(0.28, 1.2, -0.12), 0.025, 0.022, 4, bone, r)
|
|
P._cylinder(st, Vector3(0.28, 1.2, -0.12), Vector3(0.27, 1.08, -0.38), 0.022, 0.02, 4, bone, r)
|
|
P._cylinder(st, Vector3(0.27, 1.08, -0.4), Vector3(0.33, 1.42, -0.85), 0.035, 0.008, 4, steel, r) # curved blade
|
|
P._cylinder(st, Vector3(0.21, 1.06, -0.38), Vector3(0.33, 1.1, -0.4), 0.02, 0.02, 4, steel, r) # guard
|
|
P._cylinder(st, Vector3(-0.22, 1.47, 0), Vector3(-0.27, 1.15, 0.02), 0.025, 0.022, 4, bone, r)
|
|
P._cylinder(st, Vector3(-0.27, 1.15, 0.02), Vector3(-0.26, 0.9, -0.02), 0.022, 0.02, 4, bone, r)
|
|
var est := P._begin()
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(est, Vector3(s * 0.045, 1.67, -0.125), Vector3.ONE * 0.012, n, 0.0, Color(0.5, 1.0, 0.6), r, 0)
|
|
var lst := P._begin()
|
|
P._cylinder(lst, Vector3(0, 0, 0), Vector3(0, -0.45, 0.02), 0.03, 0.025, 4, bone, r)
|
|
P._cylinder(lst, Vector3(0, -0.45, 0.02), Vector3(0, -0.9, 0), 0.025, 0.022, 4, bone, r)
|
|
P._blob(lst, Vector3(0, -0.2, 0), Vector3(0.07, 0.18, 0.07), n, 0.4, rag, r, 0) # breeches
|
|
P._blob(lst, Vector3(0, -0.9, -0.05), Vector3(0.04, 0.025, 0.08), n, 0.1, old, r, 0)
|
|
return {"body": P._commit(st), "eyes": P._commit(est), "leg": P._commit(lst),
|
|
"hips": [Vector3(-0.1, 0.93, 0), Vector3(0.1, 0.93, 0)],
|
|
"radius": 0.3, "height": 1.85}
|
|
|
|
## The Old Stag (before scaling up): a pale, moss-hung spirit deer with a
|
|
## huge crown of antlers.
|
|
static func _stag() -> Dictionary:
|
|
var coat := Color(0.72, 0.74, 0.7)
|
|
var moss := Color(0.32, 0.42, 0.24)
|
|
var bone := Color(0.9, 0.87, 0.76)
|
|
var dark := Color(0.15, 0.16, 0.18)
|
|
var st := P._begin()
|
|
var r := _rng(341)
|
|
var n := _noise(341, 1.2)
|
|
P._blob(st, Vector3(0, 1.0, 0), Vector3(0.3, 0.33, 0.66), n, 0.14, coat, r, 1)
|
|
P._blob(st, Vector3(0, 1.18, -0.3), Vector3(0.3, 0.28, 0.32), n, 0.3, moss, r, 1) # mossy mane
|
|
P._cylinder(st, Vector3(0, 1.15, -0.45), Vector3(0, 1.6, -0.68), 0.15, 0.1, 6, coat, r)
|
|
P._blob(st, Vector3(0, 1.66, -0.8), Vector3(0.12, 0.13, 0.22), n, 0.1, coat, r, 1)
|
|
P._blob(st, Vector3(0, 1.6, -1.0), Vector3(0.05, 0.05, 0.05), n, 0.0, dark, r, 0)
|
|
for s in [-1.0, 1.0]:
|
|
P._cylinder(st, Vector3(s * 0.07, 1.74, -0.74), Vector3(s * 0.2, 1.85, -0.7), 0.04, 0.015, 4, coat, r)
|
|
# Antlers: a beam with tines, wide and high.
|
|
var base := Vector3(s * 0.05, 1.78, -0.78)
|
|
var mid := Vector3(s * 0.32, 2.2, -0.7)
|
|
var top := Vector3(s * 0.52, 2.6, -0.55)
|
|
P._cylinder(st, base, mid, 0.035, 0.028, 5, bone, r)
|
|
P._cylinder(st, mid, top, 0.028, 0.012, 5, bone, r)
|
|
for t in [[mid, Vector3(s * 0.28, 2.45, -0.95)], [mid, Vector3(s * 0.55, 2.25, -0.85)],
|
|
[top, Vector3(s * 0.62, 2.85, -0.7)], [top, Vector3(s * 0.75, 2.6, -0.45)], [base.lerp(mid, 0.3), Vector3(s * 0.12, 2.05, -1.05)]]:
|
|
P._cylinder(st, t[0], t[1], 0.02, 0.006, 4, bone, r)
|
|
# Moss hanging from the antlers.
|
|
P._cylinder(st, mid, mid + Vector3(0, -0.25, 0), 0.03, 0.01, 4, moss, r)
|
|
P._blob(st, Vector3(0, 1.1, 0.64), Vector3(0.06, 0.09, 0.05), n, 0.1, coat, r, 0)
|
|
var est := P._begin()
|
|
for s in [-1.0, 1.0]:
|
|
P._blob(est, Vector3(s * 0.085, 1.7, -0.9), Vector3.ONE * 0.025, n, 0.0, Color(0.6, 0.95, 1.0), r, 0)
|
|
return {"body": P._commit(st), "eyes": P._commit(est), "leg": _leg(0.9, 0.06, 0.04, coat, dark, 342),
|
|
"hips": [Vector3(-0.15, 0.9, -0.44), Vector3(0.15, 0.9, -0.44), Vector3(-0.15, 0.92, 0.44), Vector3(0.15, 0.92, 0.44)],
|
|
"radius": 0.42, "height": 1.8}
|