Initial commit: DungeonCrawler Grundgerüst

- 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>
This commit is contained in:
Andre 2026-03-14 15:35:13 +01:00
commit 5addad0b8c
25 changed files with 803 additions and 0 deletions

4
.editorconfig Normal file
View file

@ -0,0 +1,4 @@
root = true
[*]
charset = utf-8

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Godot 4+ specific ignores
.godot/
/android/

9
basic_attack.tres Normal file
View file

@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="Attack" format=3 uid="uid://d02bao1dwygan"]
[ext_resource type="Script" uid="uid://cpa1p4k6xtiga" path="res://resources/attack.gd" id="1_4028k"]
[resource]
script = ExtResource("1_4028k")
name = "Autoattack"
cooldown = 1.5
metadata/_custom_type_script = "uid://cpa1p4k6xtiga"

32
camera_pivot.gd Normal file
View file

@ -0,0 +1,32 @@
# CameraPivot.gd
# Steuert die Third-Person-Kamera: Maussteuerung (RMB), Zoom per Mausrad
extends Node3D
@export var sensitivity = 0.3 # Mausempfindlichkeit
@export var min_pitch = -40.0 # Maximale Neigung nach unten
@export var max_pitch = 20.0 # Maximale Neigung nach oben
@export var min_zoom = 5.0 # Minimale Kameraentfernung
@export var max_zoom = 20.0 # Maximale Kameraentfernung
@export var zoom_speed = 1.0 # Zoom-Geschwindigkeit pro Mausrad-Schritt
var pitch = 0.0
@onready var camera = $Camera3D
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
func _input(event):
# RMB gehalten: Kamera drehen
if event is InputEventMouseMotion and Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
get_parent().rotate_y(deg_to_rad(-event.relative.x * sensitivity))
pitch -= event.relative.y * sensitivity
pitch = clamp(pitch, min_pitch, max_pitch)
rotation_degrees.x = pitch
# Mausrad: Zoom
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)

1
camera_pivot.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bwtwon54po4w3

79
enemy.gd Normal file
View file

@ -0,0 +1,79 @@
# Enemy.gd
# Steuert den Gegner: KI-Bewegung zum Spieler, Angriff, HP, Zielanzeige
extends CharacterBody3D
const SPEED = 3.0
const GRAVITY = 9.8
const ATTACK_DAMAGE = 5
const ATTACK_RANGE = 1.5
const ATTACK_COOLDOWN = 2.0
var max_hp = 50
var current_hp = 50
var target = null # Ziel des Gegners (normalerweise der Spieler)
var can_attack = true
@onready var health_label = $HealthLabel
func _ready():
health_label.visible = false
_update_label()
# HP-Label Text aktualisieren
func _update_label():
health_label.text = str(current_hp) + " / " + str(max_hp)
# HP-Label anzeigen (wenn Gegner markiert wird)
func show_health():
health_label.visible = true
# HP-Label verstecken (wenn Markierung aufgehoben wird)
func hide_health():
health_label.visible = false
# Schaden nehmen und Label aktualisieren
func take_damage(amount):
current_hp -= amount
_update_label()
if current_hp <= 0:
die()
# Gegner aus der Szene entfernen
func die():
print("Gegner besiegt!")
queue_free()
func _physics_process(delta):
if not is_on_floor():
velocity.y -= GRAVITY * delta
if target == null:
move_and_slide()
return
var distance = global_position.distance_to(target.global_position)
if distance <= ATTACK_RANGE:
# In Reichweite: angreifen
velocity.x = 0
velocity.z = 0
if can_attack:
_attack()
else:
# Direkt auf Ziel zubewegen
var direction = (target.global_position - global_position)
direction.y = 0
direction = direction.normalized()
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
look_at(Vector3(target.global_position.x, global_position.y, target.global_position.z))
move_and_slide()
# Angriff mit Cooldown
func _attack():
can_attack = false
target.take_damage(ATTACK_DAMAGE)
print("Gegner greift an!")
await get_tree().create_timer(ATTACK_COOLDOWN).timeout
can_attack = true

1
enemy.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bg5qs3pcfp7p7

34
enemy.tscn Normal file
View file

@ -0,0 +1,34 @@
[gd_scene format=3 uid="uid://cvojaeanxugfj"]
[ext_resource type="PackedScene" uid="uid://tosl2au4emxt" path="res://assets/kenney_blocky-characters_20/Models/GLB format/character-d.glb" id="1_7k104"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_4gyqm"]
radius = 0.6
height = 3.0
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_7k104"]
radius = 0.6
height = 3.0
[node name="Enemy" type="CharacterBody3D" unique_id=332011146]
[node name="character-d2" parent="." unique_id=846574684 instance=ExtResource("1_7k104")]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1323028920]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
shape = SubResource("CapsuleShape3D_4gyqm")
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="." unique_id=457987844]
[node name="Area3D" type="Area3D" parent="." unique_id=1689838821]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D" unique_id=116643275]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
shape = SubResource("CapsuleShape3D_7k104")
[node name="HealthLabel" type="Label3D" parent="." unique_id=1251847350]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 3.5, 0)
visible = false
text = "50 / 50"
outline_size = 8

33
hud.gd Normal file
View file

@ -0,0 +1,33 @@
# HUD.gd
# Verwaltet die Spieler-UI: HP-Leiste, Aktionsleiste (Slots 1-9)
extends CanvasLayer
@onready var health_bar = $Control/HealthBar
@onready var health_label = $Control/HealthBar/HealthLabel
@onready var action_slots = [
$Control/ActionBar/A1,
$Control/ActionBar/A2,
$Control/ActionBar/A3,
$Control/ActionBar/A4,
$Control/ActionBar/A5,
$Control/ActionBar/A6,
$Control/ActionBar/A7,
$Control/ActionBar/A8,
$Control/ActionBar/A9
]
var active_slot = 0
# HP-Leiste und Text aktualisieren
func update_health(current_hp, max_hp):
health_bar.max_value = max_hp
health_bar.value = current_hp
health_label.text = str(current_hp) + " / " + str(max_hp)
# Aktions-Slot kurz golden hervorheben (0.1s)
func set_active_slot(index):
action_slots[active_slot].self_modulate = Color(1, 1, 1)
active_slot = index
action_slots[active_slot].self_modulate = Color(1, 0.8, 0)
await get_tree().create_timer(0.1).timeout
action_slots[active_slot].self_modulate = Color(1, 1, 1)

1
hud.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://c1vae5t5fabmf

161
hud.tscn Normal file
View file

@ -0,0 +1,161 @@
[gd_scene format=3 uid="uid://bej3excyoxrdh"]
[ext_resource type="Script" uid="uid://c1vae5t5fabmf" path="res://hud.gd" id="1_37p78"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_37p78"]
bg_color = Color(0.82191056, 2.623126e-06, 7.70092e-07, 1)
[node name="HUD" type="CanvasLayer" unique_id=1901284390]
script = ExtResource("1_37p78")
[node name="Control" type="Control" parent="." unique_id=1898217661]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="HealthBar" type="ProgressBar" parent="Control" unique_id=1012082084]
layout_mode = 0
offset_left = 20.0
offset_top = 20.0
offset_right = 220.0
offset_bottom = 47.0
theme_override_styles/fill = SubResource("StyleBoxFlat_37p78")
value = 100.0
show_percentage = false
[node name="HealthLabel" type="Label" parent="Control/HealthBar" unique_id=347950412]
layout_mode = 0
offset_right = 200.0
offset_bottom = 27.0
horizontal_alignment = 1
vertical_alignment = 1
[node name="ActionBar" type="HBoxContainer" parent="Control" unique_id=1015761408]
layout_mode = 1
anchors_preset = -1
anchor_left = 14.875001
anchor_top = 15.125001
anchor_right = 14.875001
anchor_bottom = 15.125001
offset_left = -225.00006
offset_top = -25.000061
offset_right = 224.99994
offset_bottom = 24.999939
[node name="A1" type="Panel" parent="Control/ActionBar" unique_id=712323959]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A1" unique_id=2101503869]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "1"
[node name="A2" type="Panel" parent="Control/ActionBar" unique_id=1606850166]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A2" unique_id=908151683]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "2"
[node name="A3" type="Panel" parent="Control/ActionBar" unique_id=1199740879]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A3" unique_id=2139034524]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "3"
[node name="A4" type="Panel" parent="Control/ActionBar" unique_id=268936083]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A4" unique_id=1504208330]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "4"
[node name="A5" type="Panel" parent="Control/ActionBar" unique_id=1768061775]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A5" unique_id=1852586315]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "5"
[node name="A6" type="Panel" parent="Control/ActionBar" unique_id=514136908]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A6" unique_id=129205342]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "6"
[node name="A7" type="Panel" parent="Control/ActionBar" unique_id=930419077]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A7" unique_id=1594316102]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "7"
[node name="A8" type="Panel" parent="Control/ActionBar" unique_id=1826123904]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A8" unique_id=682267067]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "8"
[node name="A9" type="Panel" parent="Control/ActionBar" unique_id=1708070042]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
[node name="Label" type="Label" parent="Control/ActionBar/A9" unique_id=989106090]
custom_minimum_size = Vector2(46, 50)
layout_mode = 0
offset_left = 2.0
offset_right = 48.0
offset_bottom = 50.0
theme_override_font_sizes/font_size = 12
text = "9"

1
icon.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 995 B

43
icon.svg.import Normal file
View file

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cghqrs3ts1t2y"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

168
player.gd Normal file
View file

@ -0,0 +1,168 @@
# 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()

1
player.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://b6n25e5fh82ra

29
player.tscn Normal file
View file

@ -0,0 +1,29 @@
[gd_scene format=3 uid="uid://dniyuebl8yhtv"]
[ext_resource type="Script" uid="uid://b6n25e5fh82ra" path="res://player.gd" id="1_4flbx"]
[ext_resource type="PackedScene" uid="uid://01rrtitc6yh1" path="res://assets/kenney_blocky-characters_20/Models/GLB format/character-b.glb" id="2_hqtel"]
[ext_resource type="Script" uid="uid://bwtwon54po4w3" path="res://camera_pivot.gd" id="2_onrkg"]
[ext_resource type="PackedScene" uid="uid://bej3excyoxrdh" path="res://hud.tscn" id="4_hqtel"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_4flbx"]
radius = 0.6
height = 3.0
[node name="CharacterBody3D" type="CharacterBody3D" unique_id=937297102]
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0)
script = ExtResource("1_4flbx")
[node name="character-b2" parent="." unique_id=926968795 instance=ExtResource("2_hqtel")]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1359412306]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
shape = SubResource("CapsuleShape3D_4flbx")
[node name="CameraPivot" type="Node3D" parent="." unique_id=638440275]
script = ExtResource("2_onrkg")
[node name="Camera3D" type="Camera3D" parent="CameraPivot" unique_id=1625345908]
transform = Transform3D(2, 0, 0, 0, 1.8126155, 0.84523654, 0, -0.84523654, 1.8126155, 0, 5, 5)
[node name="HUD" parent="." unique_id=1901284390 instance=ExtResource("4_hqtel")]

107
project.godot Normal file
View file

@ -0,0 +1,107 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="DungeonCrawler"
run/main_scene="uid://bp0g1glxo816h"
config/features=PackedStringArray("4.6", "Forward Plus")
config/icon="res://icon.svg"
[input]
move_forward={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
]
}
move_back={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
]
}
move_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
]
}
move_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
]
}
test_damage={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":116,"location":0,"echo":false,"script":null)
]
}
action_1={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":49,"key_label":0,"unicode":49,"location":0,"echo":false,"script":null)
]
}
action_2={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":50,"key_label":0,"unicode":50,"location":0,"echo":false,"script":null)
]
}
action_3={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":51,"key_label":0,"unicode":51,"location":0,"echo":false,"script":null)
]
}
action_4={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":52,"key_label":0,"unicode":52,"location":0,"echo":false,"script":null)
]
}
action_5={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":53,"key_label":0,"unicode":53,"location":0,"echo":false,"script":null)
]
}
action_6={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":54,"key_label":0,"unicode":54,"location":0,"echo":false,"script":null)
]
}
action_7={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":55,"key_label":0,"unicode":55,"location":0,"echo":false,"script":null)
]
}
action_8={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":56,"key_label":0,"unicode":56,"location":0,"echo":false,"script":null)
]
}
action_9={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":57,"key_label":0,"unicode":57,"location":0,"echo":false,"script":null)
]
}
select_target={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(250, 17),"global_position":Vector2(259, 65),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
}
ui_right_mouse={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":2,"position":Vector2(411, 19),"global_position":Vector2(420, 67),"factor":1.0,"button_index":2,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
}
[physics]
3d/physics_engine="Jolt Physics"
[rendering]
rendering_device/driver.windows="d3d12"

28
resources/attack.gd Normal file
View file

@ -0,0 +1,28 @@
# Attack.gd
# Ressource für Angriffe — Schaden, Reichweite und Cooldown kommen von der ausgerüsteten Waffe
extends Resource
class_name Attack
enum DamageType { PHYSICAL, FIRE, ICE, LIGHTNING, POISON }
@export var name: String = "Unbenannt"
@export var damage_type: DamageType = DamageType.PHYSICAL
@export var icon: Texture2D = null
# Schaden berechnen — ohne Waffe = 1
func get_damage(weapon: Weapon) -> int:
if weapon == null or weapon.weapon_type == Weapon.WeaponType.UNARMED:
return 1
return randi_range(weapon.min_damage, weapon.max_damage)
# Reichweite — ohne Waffe = 1.5
func get_range(weapon: Weapon) -> float:
if weapon == null or weapon.weapon_type == Weapon.WeaponType.UNARMED:
return 1.5
return weapon.range
# Cooldown — ohne Waffe = 1.5s
func get_cooldown(weapon: Weapon) -> float:
if weapon == null or weapon.weapon_type == Weapon.WeaponType.UNARMED:
return 1.5
return weapon.attack_speed

1
resources/attack.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://cpa1p4k6xtiga

14
resources/weapon.gd Normal file
View file

@ -0,0 +1,14 @@
# Weapon.gd
# Ressource für Waffen — definiert Schadensbereich, Angriffsgeschwindigkeit und Reichweite
extends Resource
class_name Weapon
enum WeaponType { UNARMED, SWORD, AXE, MACE, DAGGER, STAFF, BOW }
@export var name: String = "Unbewaffnet"
@export var weapon_type: WeaponType = WeaponType.UNARMED
@export var min_damage: int = 1
@export var max_damage: int = 1
@export var attack_speed: float = 1.5 # Cooldown in Sekunden
@export var range: float = 2.0
@export var icon: Texture2D = null

1
resources/weapon.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://c0jenjw4stba2

11
world.gd Normal file
View file

@ -0,0 +1,11 @@
# World.gd
# Initialisiert die Spielwelt: weist dem Gegner den Spieler als Ziel zu
extends Node3D
func _ready():
var player = get_node("Player")
var enemy = get_node("Enemy")
if enemy and player:
enemy.target = player
else:
print("Fehler: Player oder Enemy nicht gefunden!")

1
world.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://cx56h588mfsk0

38
world.tscn Normal file
View file

@ -0,0 +1,38 @@
[gd_scene format=3 uid="uid://bp0g1glxo816h"]
[ext_resource type="PackedScene" uid="uid://dniyuebl8yhtv" path="res://player.tscn" id="1_f3sb7"]
[ext_resource type="Script" uid="uid://cx56h588mfsk0" path="res://world.gd" id="1_tlwt5"]
[ext_resource type="PackedScene" uid="uid://cvojaeanxugfj" path="res://enemy.tscn" id="2_fj7yv"]
[ext_resource type="Script" uid="uid://bg5qs3pcfp7p7" path="res://enemy.gd" id="4_aqk2v"]
[sub_resource type="BoxShape3D" id="BoxShape3D_fj7yv"]
size = Vector3(200, 0.5, 200)
[sub_resource type="BoxMesh" id="BoxMesh_tlwt5"]
size = Vector3(200, 0.5, 200)
[sub_resource type="NavigationMesh" id="NavigationMesh_fj7yv"]
[node name="World" type="Node3D" unique_id=2007838514]
script = ExtResource("1_tlwt5")
[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=2101916269]
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=1873339390]
shape = SubResource("BoxShape3D_fj7yv")
[node name="MeshInstance3D" type="MeshInstance3D" parent="StaticBody3D" unique_id=1214783061]
mesh = SubResource("BoxMesh_tlwt5")
[node name="Player" parent="." unique_id=937297102 instance=ExtResource("1_f3sb7")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3, 0)
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1394887598]
transform = Transform3D(-45, 0, 0, 0, -45, 0, 0, 0, -45, 0, 0, 0)
[node name="Enemy" parent="." unique_id=332011146 instance=ExtResource("2_fj7yv")]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0.3, -7.038)
script = ExtResource("4_aqk2v")
[node name="NavigationRegion3D" type="NavigationRegion3D" parent="." unique_id=827244005]
navigation_mesh = SubResource("NavigationMesh_fj7yv")