DungeonCrawler/camera_pivot.gd
Andre 394b3a89b8 Souls/RPG-Hybrid Bewegungssystem, Kamera, Animationen & Dokumentation
Bewegung:
- Souls-Modus (kein Ziel): Charakter dreht sich zur Laufrichtung relativ zu
  camera_pivot.world_yaw; bei RMB gehalten → Strafe statt Drehung
- Walk-Toggle (NumLock): RPG-Strafe-Modus mit langsamerer Geschwindigkeit
- Lock-On (Ziel markiert): Spieler dreht sich smooth zum Gegner, WASD = Strafe
- Ausweichrolle (Shift): rollt in Eingaberichtung (world_yaw-relativ im Souls-Modus)
- Sofort-180°-Snap statt animierter Drehung bei >150° Winkelunterschied

Kamera (camera_pivot.gd):
- world_yaw: absolute Weltausrichtung, unabhängig von Spielerrotation (kein Feedback-Loop)
- LMB gehalten: Kamera orbitet, Spieler dreht sich nicht
- RMB gehalten: Spieler + Kamera drehen sich gemeinsam
- Soft Lock-On: camera_pivot dreht Spieler smooth zum Ziel

Animationen:
- Neue FBX-Animationen: Quick Roll, Running Jump, Walking Jump,
  Running Strafe L/R, Running Turn 180
- Animationen im Souls-Modus: immer "run" vorwärts; S = walk_back
- Root-Motion-Strip: XZ-Bewegung auf Knochen-Tracks wird genullt

Welt:
- Boden-Shader: Schachbrettmuster in World-Space (INV_VIEW_MATRIX)
- ProceduralSkyMaterial + WorldEnvironment per Code
- Alte assets/animations und assets/models durch Warrior+Animation ersetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 22:26:10 +01:00

76 lines
3.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CameraPivot.gd
# ─────────────────────────────────────────────────────────────────────────────
# Third-Person Kamerasystem Kind-Node des Spielers
#
# Kamera-Modi:
# • Kein Ziel, LMB gehalten → Kamera orbitet um den Spieler (world_yaw ändert sich,
# Spielerrotation bleibt)
# • Kein Ziel, RMB gehalten → Spieler + Kamera drehen sich gemeinsam
# • Ziel markiert → Soft Lock-On: Spieler dreht sich smooth zum Ziel,
# Kamera bleibt direkt dahinter
# • Mausrad → Zoom (min_zoom … max_zoom)
#
# world_yaw: absolute Weltausrichtung der Kamera in Grad (Y-Achse).
# Unabhängig von player.rotation.y → verhindert Feedback-Loop bei Souls-Rotation.
# camera_pivot.rotation.y wird in _process() immer als (world_yaw - player.rotation.y)
# gesetzt, sodass die Kamera in World-Space stabil bleibt.
# ─────────────────────────────────────────────────────────────────────────────
extends Node3D
@export var sensitivity = 0.3
@export var min_pitch = -40.0
@export var max_pitch = 20.0
@export var min_zoom = 5.0
@export var max_zoom = 20.0
@export var zoom_speed = 1.0
@export var lock_on_speed = 5.0
var pitch: float = 0.0
var world_yaw: float = 0.0 # Absolute Weltausrichtung der Kamera (unabhängig von Spielerrotation)
@onready var camera = $Camera3D
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
world_yaw = get_parent().rotation.y
func _input(event):
var player = get_parent()
var has_target = player.target != null and is_instance_valid(player.target)
if event is InputEventMouseMotion:
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and not has_target:
# LMB: nur Kamera dreht sich, Spieler bleibt
world_yaw -= deg_to_rad(event.relative.x * sensitivity)
pitch -= event.relative.y * sensitivity
pitch = clamp(pitch, min_pitch, max_pitch)
rotation_degrees.x = pitch
elif Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) and not has_target:
# RMB: Spieler + Kamera drehen sich gemeinsam
var delta_yaw = deg_to_rad(-event.relative.x * sensitivity)
world_yaw += delta_yaw
player.rotation.y += delta_yaw
pitch -= event.relative.y * sensitivity
pitch = clamp(pitch, min_pitch, max_pitch)
rotation_degrees.x = pitch
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
camera.position.z = clamp(camera.position.z + zoom_speed, min_zoom, max_zoom)
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
camera.position.z = clamp(camera.position.z - zoom_speed, min_zoom, max_zoom)
func _process(delta):
var player = get_parent()
if player.target != null and is_instance_valid(player.target) and not player.is_rolling:
# Soft Lock-On: Spieler dreht sich zum Ziel, Kamera folgt direkt dahinter
var to_target = player.target.global_position - player.global_position
to_target.y = 0
if to_target.length() > 0.1:
var target_angle = atan2(-to_target.x, -to_target.z)
player.rotation.y = lerp_angle(player.rotation.y, target_angle, delta * lock_on_speed)
world_yaw = player.rotation.y
# Lokale Rotation so setzen dass Kamera immer auf world_yaw zeigt
rotation.y = world_yaw - player.rotation.y