- Third-Person Spieler mit WASD-Bewegung und Kamerasteuerung (RMB + Mausrad-Zoom) - HP-System mit Healthbar und Aktionsleiste (Slots 1-9) - Autoattack-System: Linksklick markiert Ziel, Rechtsklick markiert + greift an - Waffensystem-Basis: Schaden basiert auf ausgerüsteter Waffe (unbewaffnet = 1) - Gegner-KI: läuft auf Spieler zu, greift bei Reichweite an, zeigt HP-Label bei Markierung - Ressourcen-Klassen: Attack und Weapon Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
168 lines
5 KiB
GDScript
168 lines
5 KiB
GDScript
# Player.gd
|
|
# Steuert den Spielercharakter: Bewegung, Kamera, HP, Angriff, Zielauswahl
|
|
extends CharacterBody3D
|
|
|
|
const SPEED = 5.0
|
|
const JUMP_VELOCITY = 4.5
|
|
const GRAVITY = 9.8
|
|
|
|
var max_hp = 100
|
|
var current_hp = 100
|
|
var can_attack = true
|
|
var target = null # Aktuell markierter Gegner
|
|
var equipped_weapon = null # Ausgerüstete Waffe (null = unbewaffnet, Schaden = 1)
|
|
|
|
@onready var camera_pivot = $CameraPivot
|
|
@onready var camera = $CameraPivot/Camera3D
|
|
@onready var hud = $HUD
|
|
|
|
func _ready():
|
|
hud.update_health(current_hp, max_hp)
|
|
hud.set_active_slot(0)
|
|
|
|
# Schaden am Spieler abziehen und HP-Leiste aktualisieren
|
|
func take_damage(amount):
|
|
current_hp = clamp(current_hp - amount, 0, max_hp)
|
|
hud.update_health(current_hp, max_hp)
|
|
if current_hp <= 0:
|
|
die()
|
|
|
|
# HP heilen und HP-Leiste aktualisieren
|
|
func heal(amount):
|
|
current_hp = clamp(current_hp + amount, 0, max_hp)
|
|
hud.update_health(current_hp, max_hp)
|
|
|
|
func die():
|
|
print("Spieler gestorben!")
|
|
|
|
# Schaden basierend auf ausgerüsteter Waffe (unbewaffnet = 1)
|
|
func get_attack_damage() -> int:
|
|
if equipped_weapon == null:
|
|
return 1
|
|
return randi_range(equipped_weapon.min_damage, equipped_weapon.max_damage)
|
|
|
|
# Reichweite basierend auf ausgerüsteter Waffe (unbewaffnet = 1.5)
|
|
func get_attack_range() -> float:
|
|
if equipped_weapon == null:
|
|
return 1.5
|
|
return equipped_weapon.range
|
|
|
|
# Angriffsgeschwindigkeit basierend auf ausgerüsteter Waffe (unbewaffnet = 1.5s)
|
|
func get_attack_cooldown() -> float:
|
|
if equipped_weapon == null:
|
|
return 1.5
|
|
return equipped_weapon.attack_speed
|
|
|
|
# Ziel markieren — start_attack=true startet sofort die Autoattack
|
|
func set_target(new_target, start_attack: bool = false):
|
|
if target != null and is_instance_valid(target):
|
|
target.hide_health()
|
|
target = new_target
|
|
target.show_health()
|
|
print("Ziel markiert: ", target.name)
|
|
if start_attack and can_attack:
|
|
autoattack()
|
|
|
|
# Autoattack: greift wiederholt an solange Ziel gültig ist
|
|
func autoattack():
|
|
if target == null or not is_instance_valid(target):
|
|
target = null
|
|
return
|
|
if not can_attack:
|
|
return
|
|
|
|
var distance = global_position.distance_to(target.global_position)
|
|
if distance <= get_attack_range():
|
|
can_attack = false
|
|
var dmg = get_attack_damage()
|
|
target.take_damage(dmg)
|
|
print("Autoattack: ", dmg, " Schaden")
|
|
await get_tree().create_timer(get_attack_cooldown()).timeout
|
|
can_attack = true
|
|
autoattack()
|
|
else:
|
|
await get_tree().create_timer(0.5).timeout
|
|
autoattack()
|
|
|
|
# Raycast von der Kamera auf Mausposition — trifft Gegner mit take_damage()
|
|
func _try_select_target(start_attack: bool = false):
|
|
var space_state = get_world_3d().direct_space_state
|
|
var viewport = get_viewport()
|
|
var mouse_pos = viewport.get_mouse_position()
|
|
var ray_origin = camera.project_ray_origin(mouse_pos)
|
|
var ray_end = ray_origin + camera.project_ray_normal(mouse_pos) * 100.0
|
|
var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_end)
|
|
query.exclude = [self]
|
|
var result = space_state.intersect_ray(query)
|
|
if result and result.collider.has_method("take_damage"):
|
|
set_target(result.collider, start_attack)
|
|
|
|
func _physics_process(delta):
|
|
# Schwerkraft
|
|
if not is_on_floor():
|
|
velocity.y -= GRAVITY * delta
|
|
|
|
# Springen
|
|
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
|
velocity.y = JUMP_VELOCITY
|
|
|
|
# Linksklick: nur markieren
|
|
if Input.is_action_just_pressed("select_target"):
|
|
_try_select_target(false)
|
|
|
|
# Rechtsklick: markieren + angreifen
|
|
if Input.is_action_just_pressed("ui_right_mouse"):
|
|
_try_select_target(true)
|
|
|
|
# Aktionsleiste 1-9
|
|
if Input.is_action_just_pressed("action_1"):
|
|
hud.set_active_slot(0)
|
|
if target != null:
|
|
autoattack()
|
|
if Input.is_action_just_pressed("action_2"):
|
|
hud.set_active_slot(1)
|
|
if Input.is_action_just_pressed("action_3"):
|
|
hud.set_active_slot(2)
|
|
if Input.is_action_just_pressed("action_4"):
|
|
hud.set_active_slot(3)
|
|
if Input.is_action_just_pressed("action_5"):
|
|
hud.set_active_slot(4)
|
|
if Input.is_action_just_pressed("action_6"):
|
|
hud.set_active_slot(5)
|
|
if Input.is_action_just_pressed("action_7"):
|
|
hud.set_active_slot(6)
|
|
if Input.is_action_just_pressed("action_8"):
|
|
hud.set_active_slot(7)
|
|
if Input.is_action_just_pressed("action_9"):
|
|
hud.set_active_slot(8)
|
|
|
|
# TEST: T drücken = 10 Schaden
|
|
if Input.is_action_just_pressed("test_damage"):
|
|
take_damage(10)
|
|
|
|
# Eingabe
|
|
var input_dir = Vector2.ZERO
|
|
if Input.is_action_pressed("move_forward"):
|
|
input_dir.y -= 1
|
|
if Input.is_action_pressed("move_back"):
|
|
input_dir.y += 1
|
|
if Input.is_action_pressed("move_left"):
|
|
input_dir.x -= 1
|
|
if Input.is_action_pressed("move_right"):
|
|
input_dir.x += 1
|
|
|
|
# Bewegung relativ zur Kamera
|
|
var world_yaw = rotation.y + camera_pivot.rotation.y
|
|
var forward = Vector3(-sin(world_yaw), 0, -cos(world_yaw)).normalized()
|
|
var right = Vector3(cos(world_yaw), 0, -sin(world_yaw)).normalized()
|
|
var direction = (forward * -input_dir.y + right * input_dir.x)
|
|
|
|
velocity.x = direction.x * SPEED
|
|
velocity.z = direction.z * SPEED
|
|
|
|
# RMB gehalten: Spieler schaut in Kamerarichtung
|
|
if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
|
|
rotation.y = world_yaw
|
|
camera_pivot.rotation.y = 0
|
|
|
|
move_and_slide()
|