update
This commit is contained in:
@@ -9,22 +9,43 @@ const SPEED_TRAUM := 8.0
|
||||
const SPEED_GEIST := 11.0
|
||||
const GRAVITY := 24.0
|
||||
const JUMP := 9.0
|
||||
const MAUS := 0.0026
|
||||
const FOLGE_ABSTAND := 3.0
|
||||
const FOLGE_ABSTAND := 2.2
|
||||
const FOLGE_SPIEL := 1.5
|
||||
const PITCH := -0.96 # 55° von oben, fest wie in Diablo
|
||||
const CAM_YAW := PI * 0.25 # Blick diagonal über den Bezirk
|
||||
const ZOOM := [26.0, 40.0] # zwei Stufen, Mausrad
|
||||
const FOV := 35.0
|
||||
const DREHSCHRITT := PI * 0.5
|
||||
|
||||
var mode: int = Mode.TRAUM
|
||||
var yaw := 0.0
|
||||
var pitch := -0.25
|
||||
var look_enabled := true
|
||||
var yaw := CAM_YAW # Kamera- und damit Steuerrichtung
|
||||
var look_enabled := true # Steuerung an (aus, solange ein Panel offen ist)
|
||||
var folgt: Node3D = null # Mensch, an den sich der Geist gehängt hat
|
||||
|
||||
var pivot: Node3D
|
||||
var arm: SpringArm3D
|
||||
var arm: Node3D
|
||||
var cam: Camera3D
|
||||
var _dreh_rest := 0.0 # noch zu drehender Winkel (Q)
|
||||
var _zoom_stufe := 0
|
||||
var _schwebe_ziel := -1.0 # Etage, zu der der Geist gerade gleitet
|
||||
var body: Node3D
|
||||
var _schleier: MeshInstance3D
|
||||
var _kern: MeshInstance3D
|
||||
var _ringe: Array = []
|
||||
var _kopf: MeshInstance3D
|
||||
var _augen: Array = []
|
||||
var _funken: Array = [] # kreisende Lichter, eins je gelernter Technik
|
||||
var _schleppe: Array = [] # Lichtschweif hinter dem Geist
|
||||
var _schleppe_pos: Array = []
|
||||
var _farbe := Color(0.55, 0.85, 1.0)
|
||||
var _schleier_mat: StandardMaterial3D
|
||||
var _kern_mat: StandardMaterial3D
|
||||
var _kopf_mat: StandardMaterial3D
|
||||
var _kreis := 0.0
|
||||
|
||||
const FARBE_TRAUM := Color(0.55, 0.85, 1.0)
|
||||
const FARBE_GEIST := Color(0.50, 0.92, 0.90) # kühl: beobachten
|
||||
const FARBE_FOLGE := Color(1.0, 0.72, 0.38) # warm: verfolgen
|
||||
const FUNKEN_MAX := 6
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -38,32 +59,47 @@ func _ready() -> void:
|
||||
|
||||
body = Node3D.new()
|
||||
add_child(body)
|
||||
_kern = Prims.capsule(body, Vector3(0, 1.0, 0), 0.42, 1.6, Color(0.55, 0.85, 1.0))
|
||||
_kern.material_override = Prims.mat(Color(0.55, 0.85, 1.0), 0.9)
|
||||
var kopf := Prims.sphere(body, Vector3(0, 2.0, 0), 0.28, Color(0.80, 0.92, 1.0), 0.6)
|
||||
kopf.name = "Kopf"
|
||||
for i in range(2):
|
||||
var r := Prims.cyl(body, Vector3(0, 0.5 + i * 0.9, 0), 0.75 + i * 0.15, 0.06,
|
||||
Color(0.6, 0.9, 1.0), false, 1.6)
|
||||
r.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
_ringe.append(r)
|
||||
# kleiner Blick nach vorn, damit man die Laufrichtung sieht
|
||||
Prims.box(body, Vector3(0, 1.55, -0.36), Vector3(0.5, 0.12, 0.12), Color(1, 1, 1), false, 2.0)
|
||||
# Schleier: oben schmal, unten weit, halb durchsichtig
|
||||
_schleier = Prims.cyl(body, Vector3(0, 1.05, 0), 0.6, 1.7, _farbe, false)
|
||||
(_schleier.mesh as CylinderMesh).top_radius = 0.24
|
||||
_schleier_mat = Prims.mat(Color(_farbe, 0.55), 0.35)
|
||||
_schleier.material_override = _schleier_mat
|
||||
_schleier.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
# Lichtkern im Schleier
|
||||
_kern = Prims.sphere(body, Vector3(0, 1.15, 0), 0.26, _farbe, 2.2)
|
||||
_kern_mat = _kern.material_override as StandardMaterial3D
|
||||
_kern.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
_kopf = Prims.sphere(body, Vector3(0, 2.0, 0), 0.3, _farbe.lightened(0.4), 0.6)
|
||||
_kopf.name = "Kopf"
|
||||
_kopf_mat = _kopf.material_override as StandardMaterial3D
|
||||
for sx: float in [-1.0, 1.0]:
|
||||
var auge := Prims.box(body, Vector3(sx * 0.11, 2.04, -0.27), Vector3(0.07, 0.11, 0.05),
|
||||
Color(1, 1, 1), false, 3.0)
|
||||
auge.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
_augen.append(auge)
|
||||
for i in range(FUNKEN_MAX):
|
||||
var f := Prims.sphere(body, Vector3.ZERO, 0.08, _farbe.lightened(0.3), 2.6)
|
||||
f.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
f.visible = false
|
||||
_funken.append(f)
|
||||
for i in range(3):
|
||||
var k := Prims.sphere(self, Vector3.ZERO, 0.16 - i * 0.04, _farbe, 1.8)
|
||||
k.top_level = true
|
||||
k.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
k.visible = false
|
||||
_schleppe.append(k)
|
||||
_schleppe_pos.append(global_position)
|
||||
|
||||
pivot = Node3D.new()
|
||||
pivot.position.y = 1.5
|
||||
pivot.position.y = 1.0
|
||||
add_child(pivot)
|
||||
arm = SpringArm3D.new()
|
||||
arm.spring_length = 6.5
|
||||
arm.margin = 0.2
|
||||
var arm_form := SphereShape3D.new()
|
||||
arm_form.radius = 0.45 # Kugel statt Strahl: die Kamera klemmt nicht in Wänden
|
||||
arm.shape = arm_form
|
||||
arm = Node3D.new()
|
||||
arm.rotation.x = PITCH
|
||||
pivot.add_child(arm)
|
||||
arm.add_excluded_object(get_rid())
|
||||
cam = Camera3D.new()
|
||||
cam.position.x = 0.7 # Blick über die Schulter, am Ende des Arms
|
||||
cam.fov = 74.0
|
||||
cam.position.z = ZOOM[0]
|
||||
cam.fov = FOV
|
||||
cam.near = 0.5
|
||||
arm.add_child(cam)
|
||||
set_mode(Mode.TRAUM)
|
||||
|
||||
@@ -74,44 +110,37 @@ func set_mode(m: int) -> void:
|
||||
if m == Mode.GEIST:
|
||||
collision_layer = 0
|
||||
collision_mask = 0
|
||||
arm.collision_mask = 0
|
||||
arm.spring_length = 5.0
|
||||
pivot.position.y = 2.1
|
||||
body.scale = Vector3.ONE * 0.72
|
||||
_kern.material_override = Prims.mat(Color(0.65, 0.9, 1.0, 0.26), 0.5)
|
||||
for r in _ringe:
|
||||
r.material_override = Prims.mat(Color(0.7, 0.95, 1.0, 0.20), 0.8)
|
||||
r.scale = Vector3(0.55, 1.0, 0.55)
|
||||
body.scale = Vector3.ONE * 0.6
|
||||
_schleier_mat.albedo_color.a = 0.3
|
||||
else:
|
||||
collision_layer = 1
|
||||
collision_mask = 1
|
||||
arm.collision_mask = 1
|
||||
arm.spring_length = 6.5
|
||||
pivot.position.y = 1.5
|
||||
body.scale = Vector3.ONE
|
||||
_kern.material_override = Prims.mat(Color(0.55, 0.85, 1.0), 0.9)
|
||||
for r in _ringe:
|
||||
r.material_override = Prims.mat(Color(0.6, 0.9, 1.0), 1.6)
|
||||
r.scale = Vector3.ONE
|
||||
body.scale = Vector3.ONE * 0.8
|
||||
_schleier_mat.albedo_color.a = 0.55
|
||||
velocity = Vector3.ZERO
|
||||
_schwebe_ziel = -1.0
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not look_enabled:
|
||||
return
|
||||
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
||||
yaw -= event.relative.x * MAUS
|
||||
pitch = clampf(pitch - event.relative.y * MAUS, -1.3, 0.6)
|
||||
if event.is_action_pressed("drehen"):
|
||||
_dreh_rest += DREHSCHRITT
|
||||
elif event is InputEventMouseButton and event.pressed:
|
||||
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
||||
_zoom_stufe = 0
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||
_zoom_stufe = 1
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
var dreh := minf(_dreh_rest, delta * 4.0)
|
||||
yaw += dreh
|
||||
_dreh_rest -= dreh
|
||||
pivot.rotation.y = yaw
|
||||
arm.rotation.x = pitch
|
||||
cam.position.z = lerpf(cam.position.z, float(ZOOM[_zoom_stufe]), 1.0 - pow(0.01, delta))
|
||||
|
||||
for i in range(_ringe.size()):
|
||||
var r: MeshInstance3D = _ringe[i]
|
||||
r.rotation.y += delta * (0.8 + 0.5 * i)
|
||||
r.position.y = 0.5 + i * 0.9 + sin(Time.get_ticks_msec() * 0.001 * (1.2 + i * 0.4)) * 0.12
|
||||
_beleben(delta)
|
||||
|
||||
var input := Vector2.ZERO
|
||||
if look_enabled:
|
||||
@@ -128,8 +157,9 @@ func _physics_process(delta: float) -> void:
|
||||
elif dir.length() > 0.01:
|
||||
folgt = null # eigene Bewegung löst die Verfolgung
|
||||
else:
|
||||
var schulter := folgt.global_position + Vector3(0, 1.6, 0) \
|
||||
- blickrichtung() * FOLGE_ABSTAND
|
||||
var rechts := Basis(Vector3.UP, yaw) * Vector3(1, 0, 0)
|
||||
var schulter := folgt.global_position + Vector3(0, 1.4, 0) \
|
||||
+ rechts * FOLGE_ABSTAND - blickrichtung() * 0.8
|
||||
global_position = global_position.lerp(schulter, 1.0 - pow(0.004, delta))
|
||||
# weich nachziehen, aber an der Leine: sonst reißt der Faden beim Gehen
|
||||
var ab := global_position - schulter
|
||||
@@ -141,12 +171,24 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
if mode == Mode.GEIST:
|
||||
var v := dir * SPEED_GEIST
|
||||
velocity.x = lerpf(velocity.x, v.x, 1.0 - pow(0.001, delta))
|
||||
velocity.z = lerpf(velocity.z, v.z, 1.0 - pow(0.001, delta))
|
||||
# Steigen und Sinken wechseln die Etage: der Geist gleitet ein Stockwerk
|
||||
if look_enabled:
|
||||
if Input.is_action_pressed("steigen"):
|
||||
v.y += SPEED_GEIST * 0.75
|
||||
if Input.is_action_pressed("sinken"):
|
||||
v.y -= SPEED_GEIST * 0.75
|
||||
velocity = velocity.lerp(v, 1.0 - pow(0.001, delta))
|
||||
var von: float = _schwebe_ziel if _schwebe_ziel >= 0.0 else global_position.y
|
||||
if Input.is_action_just_pressed("steigen"):
|
||||
_schwebe_ziel = clampf(von + Orte.ETAGE, 0.4, 45.0)
|
||||
if Input.is_action_just_pressed("sinken"):
|
||||
_schwebe_ziel = clampf(von - Orte.ETAGE, 0.4, 45.0)
|
||||
if _schwebe_ziel >= 0.0:
|
||||
var dy := _schwebe_ziel - global_position.y
|
||||
velocity.y = clampf(dy * 6.0, -SPEED_GEIST, SPEED_GEIST)
|
||||
if absf(dy) < 0.05:
|
||||
global_position.y = _schwebe_ziel
|
||||
velocity.y = 0.0
|
||||
_schwebe_ziel = -1.0
|
||||
else:
|
||||
velocity.y = 0.0
|
||||
move_and_slide()
|
||||
if global_position.y < 0.4:
|
||||
global_position.y = 0.4
|
||||
@@ -173,3 +215,47 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
func blickrichtung() -> Vector3:
|
||||
return -Vector3(sin(yaw), 0, cos(yaw))
|
||||
|
||||
|
||||
## Schweben, Funken, Schweif und Modusfarbe -- der Zustand ist am Geist ablesbar.
|
||||
func _beleben(delta: float) -> void:
|
||||
var t := Time.get_ticks_msec() * 0.001
|
||||
var ziel := FARBE_TRAUM
|
||||
if mode == Mode.GEIST:
|
||||
ziel = FARBE_FOLGE if folgt != null else FARBE_GEIST
|
||||
if not Game.situation.is_empty() and fmod(t, 0.5) < 0.12:
|
||||
ziel = ziel.lightened(0.6)
|
||||
_farbe = _farbe.lerp(ziel, 1.0 - pow(0.02, delta))
|
||||
_schleier_mat.albedo_color = Color(_farbe, _schleier_mat.albedo_color.a)
|
||||
_schleier_mat.emission = _farbe
|
||||
_kern_mat.albedo_color = _farbe
|
||||
_kern_mat.emission = _farbe
|
||||
_kopf_mat.albedo_color = _farbe.lightened(0.4)
|
||||
_kopf_mat.emission = _farbe.lightened(0.4)
|
||||
|
||||
body.position.y = sin(t * 1.6) * 0.08
|
||||
_kern.scale = Vector3.ONE * (1.0 + sin(t * 3.1) * 0.12)
|
||||
var tempo_flach := Vector2(velocity.x, velocity.z).length()
|
||||
var neigung := -0.16 * clampf(tempo_flach / SPEED_TRAUM, 0.0, 1.0)
|
||||
body.rotation.x = lerpf(body.rotation.x, neigung, 1.0 - pow(0.01, delta))
|
||||
|
||||
var anzahl := clampi(Game.known.size(), 1, FUNKEN_MAX)
|
||||
_kreis += delta * (0.9 + 0.7 * float(Game.tempo - 1))
|
||||
for i in range(FUNKEN_MAX):
|
||||
var f: MeshInstance3D = _funken[i]
|
||||
f.visible = i < anzahl
|
||||
if not f.visible:
|
||||
continue
|
||||
var w := _kreis + float(i) * TAU / float(anzahl)
|
||||
f.position = Vector3(cos(w) * 0.85, 1.2 + sin(w * 2.0 + float(i)) * 0.3, sin(w) * 0.85)
|
||||
f.scale = Vector3.ONE * (0.8 + 0.3 * sin(t * 4.0 + float(i)))
|
||||
|
||||
var kopf_welt := body.to_global(Vector3(0, 1.1, 0))
|
||||
var sichtbar := tempo_flach > 1.0
|
||||
for i in range(_schleppe.size()):
|
||||
var k: MeshInstance3D = _schleppe[i]
|
||||
var vorher: Vector3 = kopf_welt if i == 0 else _schleppe_pos[i - 1]
|
||||
_schleppe_pos[i] = (_schleppe_pos[i] as Vector3).lerp(vorher, 1.0 - pow(0.0002 * (i + 1), delta))
|
||||
k.global_position = _schleppe_pos[i]
|
||||
k.visible = sichtbar
|
||||
k.material_override = _kern_mat
|
||||
|
||||
Reference in New Issue
Block a user