commit 5addad0b8c132500aaaeac895fdac3cb5bfb767b Author: Andre Date: Sat Mar 14 15:35:13 2026 +0100 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 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0af181c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/basic_attack.tres b/basic_attack.tres new file mode 100644 index 0000000..e1a34be --- /dev/null +++ b/basic_attack.tres @@ -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" diff --git a/camera_pivot.gd b/camera_pivot.gd new file mode 100644 index 0000000..344e374 --- /dev/null +++ b/camera_pivot.gd @@ -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) diff --git a/camera_pivot.gd.uid b/camera_pivot.gd.uid new file mode 100644 index 0000000..0ae3d0f --- /dev/null +++ b/camera_pivot.gd.uid @@ -0,0 +1 @@ +uid://bwtwon54po4w3 diff --git a/enemy.gd b/enemy.gd new file mode 100644 index 0000000..7a60e6b --- /dev/null +++ b/enemy.gd @@ -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 diff --git a/enemy.gd.uid b/enemy.gd.uid new file mode 100644 index 0000000..963bf6f --- /dev/null +++ b/enemy.gd.uid @@ -0,0 +1 @@ +uid://bg5qs3pcfp7p7 diff --git a/enemy.tscn b/enemy.tscn new file mode 100644 index 0000000..823a15e --- /dev/null +++ b/enemy.tscn @@ -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 diff --git a/hud.gd b/hud.gd new file mode 100644 index 0000000..32798cb --- /dev/null +++ b/hud.gd @@ -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) diff --git a/hud.gd.uid b/hud.gd.uid new file mode 100644 index 0000000..944cf9a --- /dev/null +++ b/hud.gd.uid @@ -0,0 +1 @@ +uid://c1vae5t5fabmf diff --git a/hud.tscn b/hud.tscn new file mode 100644 index 0000000..36d80ed --- /dev/null +++ b/hud.tscn @@ -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" diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..176d369 --- /dev/null +++ b/icon.svg.import @@ -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 diff --git a/player.gd b/player.gd new file mode 100644 index 0000000..4ae3bed --- /dev/null +++ b/player.gd @@ -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() diff --git a/player.gd.uid b/player.gd.uid new file mode 100644 index 0000000..2b4ce41 --- /dev/null +++ b/player.gd.uid @@ -0,0 +1 @@ +uid://b6n25e5fh82ra diff --git a/player.tscn b/player.tscn new file mode 100644 index 0000000..14906d5 --- /dev/null +++ b/player.tscn @@ -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")] diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..b0f0c19 --- /dev/null +++ b/project.godot @@ -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" diff --git a/resources/attack.gd b/resources/attack.gd new file mode 100644 index 0000000..14ad0fb --- /dev/null +++ b/resources/attack.gd @@ -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 diff --git a/resources/attack.gd.uid b/resources/attack.gd.uid new file mode 100644 index 0000000..3d0513c --- /dev/null +++ b/resources/attack.gd.uid @@ -0,0 +1 @@ +uid://cpa1p4k6xtiga diff --git a/resources/weapon.gd b/resources/weapon.gd new file mode 100644 index 0000000..e44c404 --- /dev/null +++ b/resources/weapon.gd @@ -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 diff --git a/resources/weapon.gd.uid b/resources/weapon.gd.uid new file mode 100644 index 0000000..9b9713f --- /dev/null +++ b/resources/weapon.gd.uid @@ -0,0 +1 @@ +uid://c0jenjw4stba2 diff --git a/world.gd b/world.gd new file mode 100644 index 0000000..3ee514d --- /dev/null +++ b/world.gd @@ -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!") diff --git a/world.gd.uid b/world.gd.uid new file mode 100644 index 0000000..aa7fd4f --- /dev/null +++ b/world.gd.uid @@ -0,0 +1 @@ +uid://cx56h588mfsk0 diff --git a/world.tscn b/world.tscn new file mode 100644 index 0000000..6f1de4f --- /dev/null +++ b/world.tscn @@ -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")