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:
commit
5addad0b8c
25 changed files with 803 additions and 0 deletions
4
.editorconfig
Normal file
4
.editorconfig
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
||||||
9
basic_attack.tres
Normal file
9
basic_attack.tres
Normal 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
32
camera_pivot.gd
Normal 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
1
camera_pivot.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bwtwon54po4w3
|
||||||
79
enemy.gd
Normal file
79
enemy.gd
Normal 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
1
enemy.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bg5qs3pcfp7p7
|
||||||
34
enemy.tscn
Normal file
34
enemy.tscn
Normal 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
33
hud.gd
Normal 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
1
hud.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c1vae5t5fabmf
|
||||||
161
hud.tscn
Normal file
161
hud.tscn
Normal 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
1
icon.svg
Normal 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
43
icon.svg.import
Normal 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
168
player.gd
Normal 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
1
player.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b6n25e5fh82ra
|
||||||
29
player.tscn
Normal file
29
player.tscn
Normal 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
107
project.godot
Normal 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
28
resources/attack.gd
Normal 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
1
resources/attack.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cpa1p4k6xtiga
|
||||||
14
resources/weapon.gd
Normal file
14
resources/weapon.gd
Normal 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
1
resources/weapon.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c0jenjw4stba2
|
||||||
11
world.gd
Normal file
11
world.gd
Normal 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
1
world.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cx56h588mfsk0
|
||||||
38
world.tscn
Normal file
38
world.tscn
Normal 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")
|
||||||
Loading…
Add table
Reference in a new issue