DungeonCrawler/camera_pivot.gd
Andre e4efb239f2 Enemy-System komplett überarbeitet, Kamera-Steuerung verbessert
- Enemy: Neues castle_guard_01 Modell mit Animationen (idle, walk, run, autoattack, death, turn)
- Enemy: Patrol-KI mit Turn-Animationen beim Richtungswechsel, 5s idle nach Spawn
- Enemy: Aggro durch Detection Range (15m) und Schadens-Aggro, Patrol→Chase Übergang
- Enemy: Respawn nach 5s am Spawnpunkt, XP-Vergabe beim Tod
- Kamera: LMB frei drehen (umschauen) auch mit markiertem Ziel
- Kamera: RMB Lock-On temporär aufheben zum Weglaufen
- Kamera: LMB-Klick auf freie Fläche visiert Ziel ab
- Kamera: Drag vs Klick Unterscheidung (< 5px Bewegung = Klick)
- Autoattack greift automatisch wieder an wenn Ziel zurück in Range
- Player zur Gruppe "player" hinzugefügt für Enemy-Detection
- Dokumentation vollständig aktualisiert

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 00:56:14 +01:00

79 lines
3.7 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):
# LMB: nur Kamera dreht sich, Spieler bleibt (auch mit Target → umschauen)
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):
# RMB: Spieler + Kamera drehen sich gemeinsam (auch mit Target → weglaufen)
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()
var rmb_held = Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
var lmb_held = Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)
if player.target != null and is_instance_valid(player.target) and not player.is_rolling and not rmb_held and not lmb_held:
# Soft Lock-On: Spieler dreht sich zum Ziel, Kamera folgt direkt dahinter
# (RMB gehalten → Lock-On pausiert, Spieler kann sich wegdrehen)
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