diff --git a/enemy.gd b/enemy.gd index 614d535..72f9a5c 100644 --- a/enemy.gd +++ b/enemy.gd @@ -52,7 +52,9 @@ const ANIMATION_FILES = { "walk": "res://assets/animations/Walking.fbx", "autoattack": "res://assets/animations/Autoattack.fbx", "die": "res://assets/animations/Dying Backwards.fbx", + "idle": "res://assets/animations/Idle.fbx", } +const LOOP_ANIMATIONS = ["walk", "idle"] var anim_player: AnimationPlayer = null var current_anim: String = "" @@ -69,13 +71,8 @@ func _ready(): # Animationen laden func _setup_animations(): - # Debug: Alle Kinder ausgeben um den Modell-Node zu finden - print("Enemy Kinder: ") - for child in get_children(): - print(" - ", child.name, " (", child.get_class(), ")") var model = get_node_or_null("EnemyModel") if model == null: - print("Enemy: EnemyModel nicht gefunden!") return anim_player = _find_node_by_class(model, "AnimationPlayer") if anim_player == null: @@ -91,7 +88,6 @@ func _setup_animations(): for anim_id in ANIMATION_FILES: var scene = load(ANIMATION_FILES[anim_id]) as PackedScene if scene == null: - print("Enemy: Animation nicht gefunden: ", ANIMATION_FILES[anim_id]) continue var instance = scene.instantiate() var source_ap = _find_node_by_class(instance, "AnimationPlayer") @@ -99,21 +95,12 @@ func _setup_animations(): var names = source_ap.get_animation_list() if names.size() > 0: var anim = source_ap.get_animation(names[0]) + if anim_id in ["walk", "idle"]: + anim.loop_mode = Animation.LOOP_LINEAR if lib.has_animation(anim_id): lib.remove_animation(anim_id) lib.add_animation(anim_id, anim) - print("Enemy: Animation geladen: ", anim_id) - else: - print("Enemy: Kein AnimationPlayer in ", ANIMATION_FILES[anim_id]) instance.queue_free() - print("Enemy: Verfügbare Animationen: ", anim_player.get_animation_list()) - # Debug: Modell-Hierarchie ausgeben - _print_tree(model, 0) - -func _print_tree(node: Node, depth: int): - print(" ".repeat(depth), node.name, " (", node.get_class(), ")") - for child in node.get_children(): - _print_tree(child, depth + 1) func _find_node_by_class(node: Node, class_name_str: String) -> Node: for child in node.get_children(): @@ -126,21 +113,14 @@ func _find_node_by_class(node: Node, class_name_str: String) -> Node: func _play_anim(anim_name: String): if anim_player == null: - print("Enemy: anim_player ist null!") return + # Wenn Animation ausgelaufen ist, zurücksetzen + if not anim_player.is_playing(): + current_anim = "" if anim_name != current_anim: current_anim = anim_name - if anim_name != "" and anim_player.has_animation(anim_name): + if anim_player.has_animation(anim_name): anim_player.play(anim_name) - print("Enemy: Spiele Animation: ", anim_name) - # Debug: Track-Pfade und root_node ausgeben - var anim = anim_player.get_animation(anim_name) - print(" AnimPlayer root_node: ", anim_player.root_node) - print(" AnimPlayer absoluter Pfad: ", anim_player.get_path()) - for t in range(mini(3, anim.get_track_count())): - print(" Track ", t, ": ", anim.track_get_path(t)) - elif anim_name != "": - print("Enemy: Animation nicht gefunden: ", anim_name, " | Verfügbar: ", anim_player.get_animation_list()) else: anim_player.stop() @@ -273,7 +253,7 @@ func _physics_process(delta): else: velocity.x = 0 velocity.z = 0 - _play_anim("") # Idle beim Angriff + _play_anim("idle") # Idle beim Angriff if can_attack: _attack() @@ -296,7 +276,7 @@ func _do_patrol(): # Am Ziel angekommen, warten und neues Ziel wählen velocity.x = 0 velocity.z = 0 - _play_anim("") + _play_anim("idle") _wait_at_patrol_point() else: # Zum Patrol-Ziel laufen diff --git a/player.gd b/player.gd index e0a200b..ed457bf 100644 --- a/player.gd +++ b/player.gd @@ -96,7 +96,9 @@ var cast_spell_id = "" # Welcher Zauber gecastet wird # Animation System const ANIMATION_FILES = { + "start_walk": "res://assets/animations/Start Walking.fbx", "walk": "res://assets/animations/Walking.fbx", + "stop_walk": "res://assets/animations/Stop Walking.fbx", "walk_back": "res://assets/animations/Walking Backwards.fbx", "strafe_left": "res://assets/animations/Left Strafe Walking.fbx", "strafe_right": "res://assets/animations/Right Strafe Walking.fbx", @@ -104,7 +106,10 @@ const ANIMATION_FILES = { "autoattack": "res://assets/animations/Autoattack.fbx", "heavy_strike": "res://assets/animations/Heavy Strike.fbx", "die": "res://assets/animations/Dying Backwards.fbx", + "idle": "res://assets/animations/Idle.fbx", } +# Animations-State für Walk-Kette +var walk_state: String = "" # "", "start", "walking", "stop" var anim_player: AnimationPlayer = null var current_anim: String = "" @@ -154,22 +159,16 @@ func _ready(): # Animationen aus FBX-Dateien laden und in AnimationPlayer einbinden func _setup_animations(): - print("Player Kinder: ") - for child in get_children(): - print(" - ", child.name, " (", child.get_class(), ")") var model = get_node_or_null("PlayerModel") if model == null: - print("PlayerModel nicht gefunden!") return # AnimationPlayer im Modell finden anim_player = _find_node_by_class(model, "AnimationPlayer") if anim_player == null: - # Neuen AnimationPlayer erstellen und ans Modell hängen anim_player = AnimationPlayer.new() anim_player.name = "AnimationPlayer" model.add_child(anim_player) - print("Neuer AnimationPlayer erstellt") # AnimationLibrary holen oder erstellen var lib: AnimationLibrary @@ -183,24 +182,36 @@ func _setup_animations(): for anim_id in ANIMATION_FILES: var scene = load(ANIMATION_FILES[anim_id]) as PackedScene if scene == null: - print("Animation nicht gefunden: ", ANIMATION_FILES[anim_id]) continue - var instance = scene.instantiate() var source_ap = _find_node_by_class(instance, "AnimationPlayer") - if source_ap: var names = source_ap.get_animation_list() if names.size() > 0: var anim = source_ap.get_animation(names[0]) + # Endlos-Animationen loopen + if anim_id in ["walk", "walk_back", "strafe_left", "strafe_right", "idle"]: + anim.loop_mode = Animation.LOOP_LINEAR if lib.has_animation(anim_id): lib.remove_animation(anim_id) lib.add_animation(anim_id, anim) - print("Animation geladen: ", anim_id) - instance.queue_free() - print("Verfügbare Animationen: ", anim_player.get_animation_list()) + # Signal für Walk-Kette: Start Walking → Walking + anim_player.animation_finished.connect(_on_animation_finished) + +# Callback wenn eine Animation fertig ist +func _on_animation_finished(anim_name: StringName): + if anim_name == "start_walk" and walk_state == "start": + # Start Walking fertig → Walking (loop) starten + walk_state = "walking" + current_anim = "walk" + anim_player.play("walk") + elif anim_name == "stop_walk" and walk_state == "stop": + # Stop Walking fertig → Idle + walk_state = "" + current_anim = "idle" + anim_player.play("idle") # Rekursiv nach einem Node einer bestimmten Klasse suchen func _find_node_by_class(node: Node, class_name_str: String) -> Node: @@ -217,15 +228,56 @@ func _update_animation(input_dir: Vector2): if anim_player == null: return - var new_anim = "" + # Angriffs-/Death-Animation nicht unterbrechen + if anim_player.is_playing() and current_anim in ["autoattack", "heavy_strike", "die"]: + return + var is_walking_forward = input_dir.y < -0.1 or (input_dir.length() > 0 and abs(input_dir.y) <= 0.1 and abs(input_dir.x) <= 0.1) + var is_moving = input_dir.length() > 0 + + # Vorwärts-Laufen: Start Walking → Walking → Stop Walking + if is_walking_forward: + if walk_state == "": + # Loslaufen: Start Walking abspielen + walk_state = "start" + current_anim = "start_walk" + anim_player.play("start_walk") + elif walk_state == "start" and not anim_player.is_playing(): + # Start Walking fertig → Walking (loop) + walk_state = "walking" + current_anim = "walk" + anim_player.play("walk") + elif walk_state == "stop": + # War gerade am Anhalten, wieder loslaufen + walk_state = "start" + current_anim = "start_walk" + anim_player.play("start_walk") + # walking state: walk loopt automatisch + return + + # Nicht mehr vorwärts → Stop Walking wenn nötig + if walk_state == "start" or walk_state == "walking": + if not is_moving: + walk_state = "stop" + current_anim = "stop_walk" + anim_player.play("stop_walk") + return + else: + # Wechsel zu anderer Bewegung (rückwärts, strafe) + walk_state = "" + + # Stop Walking läuft noch + if walk_state == "stop": + if anim_player.is_playing(): + return # Warten bis Stop Walking fertig + walk_state = "" + + # Andere Animationen + var new_anim = "" if not is_on_floor(): new_anim = "jump" - elif input_dir.length() > 0: - # Vorwärts/Rückwärts hat Priorität - if input_dir.y < -0.1: - new_anim = "walk" - elif input_dir.y > 0.1: + elif is_moving: + if input_dir.y > 0.1: new_anim = "walk_back" elif input_dir.x < -0.1: new_anim = "strafe_left" @@ -234,15 +286,15 @@ func _update_animation(input_dir: Vector2): else: new_anim = "walk" else: - new_anim = "" # Idle — keine Animation (oder Idle wenn vorhanden) + new_anim = "idle" - # Angriffs-/Death-Animation nicht unterbrechen - if anim_player.is_playing() and current_anim in ["autoattack", "heavy_strike", "die"]: - return + # Wenn Animation ausgelaufen ist, zurücksetzen + if not anim_player.is_playing(): + current_anim = "" if new_anim != current_anim: current_anim = new_anim - if new_anim != "" and anim_player.has_animation(new_anim): + if anim_player.has_animation(new_anim): anim_player.play(new_anim) else: anim_player.stop() @@ -253,6 +305,7 @@ func _play_attack_anim(anim_name: String): return if anim_player.has_animation(anim_name): current_anim = anim_name + walk_state = "" # Walk-Kette unterbrechen anim_player.stop() anim_player.play(anim_name)