{"id":576,"date":"2025-06-04T09:00:11","date_gmt":"2025-06-04T07:00:11","guid":{"rendered":"https:\/\/staratnight.de\/blog\/?p=576"},"modified":"2025-06-01T16:31:37","modified_gmt":"2025-06-01T14:31:37","slug":"spieleraktionen-in-godot-steuern","status":"publish","type":"post","link":"https:\/\/staratnight.de\/blog\/spieleraktionen-in-godot-steuern\/","title":{"rendered":"Spieleraktionen in Godot steuern"},"content":{"rendered":"\n<p>Nachdem wir unseren Sprite mit einem Script zum Rotieren gebracht haben, ist es an der Zeit, ihm Interaktion mit der Spieler:in zu erm\u00f6glichen. Input ist ein zentraler Bestandteil der meisten Spiele. Wie reagiert unser Spiel auf die Eingaben der Spieler:in (Tastatur, Maus, Gamepad)? Godot hat daf\u00fcr ein sehr flexibles System, die <strong>Input Map<\/strong>. Anstatt direkt auf Tasten wie &#8222;W&#8220; oder &#8222;Up Arrow&#8220; zu pr\u00fcfen, definieren wir <strong>Input Actions<\/strong>. Eine Action ist ein abstrakter Befehl, wie z.B. &#8222;move_up&#8220;, &#8222;attack&#8220; oder &#8222;move_right&#8220;. Diesen Actions k\u00f6nnen wir dann eine oder mehrere Tasten\/Mausbuttons\/Gamepad-Buttons zuweisen. Das hat den Vorteil, dass wir die Steuerung sp\u00e4ter leicht \u00e4ndern k\u00f6nnen, ohne den Script-Code anpassen zu m\u00fcssen.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Schritt 1: Input Actions definieren<\/h3>\n\n\n\n<p>Wir beginnen damit, unsere Bewegungs-Actions in den Project Settings zu definieren:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Gehe im Men\u00fc oben auf <strong>Project<\/strong> -> <strong>Project Settings&#8230;<\/strong>.<\/li>\n\n\n\n<li>W\u00e4hle oben den Tab <strong>Input Map<\/strong>.<\/li>\n\n\n\n<li>Oben siehst du ein Feld <strong>&#8222;Add New Action&#8220;<\/strong>. Gib hier den Namen unserer ersten Action ein, z.B. <code>move_right<\/code>.<\/li>\n\n\n\n<li>Klicke auf den Button <strong>&#8222;+ Add&#8220;<\/strong> daneben. Die Action <code>move_right<\/code> erscheint in der Liste.<\/li>\n\n\n\n<li>Klicke neben der Action <code>move_right<\/code> auf das <strong>&#8222;+&#8220;<\/strong> Symbol.\u00a0<\/li>\n\n\n\n<li>Ein Fenster \u00f6ffnet sich, das dich auffordert, eine Taste auszuw\u00e4hlen. Dr\u00fccke die <strong>Rechte Pfeiltaste<\/strong>. Es erscheint &#8222;Right or Right (physical) or Right (Unicode) im Eingabefeld \u00fcber der Liste und in der Liste wird der Eintrag &#8222;Right&#8220; ausgwe\u00e4hlt. Klicke auf <strong>&#8222;OK&#8220;<\/strong>.<\/li>\n\n\n\n<li>(Optional) Klicke erneut auf das <strong>&#8222;+&#8220;<\/strong> neben <code>move_right<\/code> und dr\u00fccke die Taste <strong>&#8222;D&#8220;<\/strong>, um &#8222;D&#8220; ebenfalls f\u00fcr die Bewegung nach rechts zu konfigurieren.<\/li>\n\n\n\n<li>Wiederhole die Schritte 3-6\/7 f\u00fcr die anderen drei Bewegungsrichtungen:\n<ul class=\"wp-block-list\">\n<li><code>move_left<\/code> (z.B. Linke Pfeiltaste und &#8222;A&#8220;)<\/li>\n\n\n\n<li><code>move_up<\/code> (z.B. Obere Pfeiltaste und &#8222;W&#8220;)<\/li>\n\n\n\n<li><code>move_down<\/code> (z.B. Untere Pfeiltaste und &#8222;S&#8220;)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Wenn du alle vier Actions definiert und die gew\u00fcnschten Tasten zugewiesen hast, schlie\u00dfe das Fenster <strong>Project Settings<\/strong>. Die \u00c4nderungen werden automatisch gespeichert.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Schritt 2: Input Actions im Script abfragen<\/h3>\n\n\n\n<p>Jetzt kehren wir zu unserem <code>Player.gd<\/code> Script zur\u00fcck. Wir erweitern die <code>_process<\/code>-Funktion, um auf diese Input Actions zu reagieren und den Sprite zu bewegen.<\/p>\n\n\n\n<p>\u00d6ffne dein Script (klicke im Filesystem Dock doppelt auf <code>Player.gd<\/code>, falls es nicht mehr ge\u00f6ffnet ist).<\/p>\n\n\n\n<p>Wir f\u00fcgen eine Variable f\u00fcr die Geschwindigkeit hinzu und \u00e4ndern dann die <code>_process<\/code>-Funktion:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" >class_name Player extends Sprite2D\nvar speed = 200 # Einheit: Pixel pro Sekunde\n# Called when the node enters the scene tree for the first time.\nfunc _ready():\n    pass\n# Called every frame. 'delta' is the elapsed time since the previous frame.\nfunc _process(delta):\n    # Rotation (behalten wir erstmal)\n    rotation_degrees += 45 * delta\n    # Bewegung Input verarbeiten\n    var direction = Vector2.ZERO\n    if Input.is_action_pressed(\"move_right\"):\n        direction.x += 1 # Bewegung nach rechts addiert 1 zur X-Koordinate\n    if Input.is_action_pressed(\"move_left\"):\n        direction.x -= 1 # Bewegung nach links subtrahiert 1 von der X-Koordinate\n    if Input.is_action_pressed(\"move_down\"):\n        direction.y += 1 # Bewegung nach unten addiert 1 zur Y-Koordinate\n    if Input.is_action_pressed(\"move_up\"):\n        direction.y -= 1 # Bewegung nach oben subtrahiert 1 von der Y-Koordinate\n    # Normalisieren bei diagonaler Bewegung\n    if direction.length() &gt; 0: # Pr\u00fcfen, ob \u00fcberhaupt eine Richtung aktiv ist\n        direction = direction.normalized() # Normalisieren auf Vektor der L\u00e4nge 1\n    # Bewegung anwenden: Aktuelle Position + (Richtung * Geschwindigkeit * Zeit seit letztem Frame)\n    position += direction * speed * delta<\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Erkl\u00e4rung des neuen Codes:<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>var speed = 200<\/code>: Eine neue Variable <code>speed<\/code> wird deklariert und initialisiert. <code>var<\/code> ist das Schl\u00fcsselwort f\u00fcr Variablen. Sie speichert, wie viele Pixel pro Sekunde sich der Sprite bewegen soll.<\/li>\n\n\n\n<li><code>var direction = Vector2.ZERO<\/code>: <code>Vector2<\/code> ist ein eingebauter Godot-Datentyp, der ein Paar von 2D-Koordinaten (<code>x<\/code>, <code>y<\/code>) darstellt. Perfekt f\u00fcr Positionen, Richtungen oder Geschwindigkeiten in 2D. <code>Vector2.ZERO<\/code> ist eine Abk\u00fcrzung f\u00fcr <code>Vector2(0, 0)<\/code>. Wir initialisieren hiermit einen Vektor, der die aktuelle Bewegungsrichtung speichern wird.<\/li>\n\n\n\n<li><code>Input.is_action_pressed(\"...\")<\/code>: Dies ist die Funktion, um abzufragen, ob die Taste(n) f\u00fcr die genannte Input Action gerade gedr\u00fcckt werden. Sie gibt <code>true<\/code> oder <code>false<\/code> zur\u00fcck.<\/li>\n\n\n\n<li><code>direction.x += 1<\/code>, etc.: Abh\u00e4ngig davon, welche Bewegungstasten gedr\u00fcckt sind, addieren oder subtrahieren wir 1 zu den X- oder Y-Komponenten unseres <code>direction<\/code>-Vektors. Zum Beispiel, wenn nur &#8222;move_right&#8220; gedr\u00fcckt wird, ist <code>direction<\/code> am Ende <code>Vector2(1, 0)<\/code>. Wenn &#8222;move_right&#8220; und &#8222;move_down&#8220; gleichzeitig gedr\u00fcckt werden, wird <code>direction<\/code> <code>Vector2(1, 1)<\/code>.<br><em>Hinweis:<\/em> in Godot 2D geht Y nach unten.<\/li>\n\n\n\n<li><code>if direction.length() > 0: direction = direction.normalized()<\/code>: Wenn wir diagonal laufen (z.B. rechts und runter, <code>Vector2(1, 1)<\/code>), ist die L\u00e4nge des Richtungsvektors gr\u00f6\u00dfer als 1 (genau: Wurzel von <span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"mord sqrt\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist\"><span class=\"svg-align\"><span class=\"mord\">2<\/span><\/span><\/span><span class=\"vlist-s\">\u200b<\/span><\/span><\/span><\/span><\/span><\/span><\/span>). Um zu verhindern, dass die diagonale Bewegung schneller ist als die horizontale oder vertikale, normalisieren wir den Vektor. <code>normalized()<\/code> gibt einen neuen Vektor mit derselben Richtung, aber der L\u00e4nge 1 zur\u00fcck. So hat die Richtung immer die L\u00e4nge 0 (kein Input) oder 1 (Input in eine beliebige Richtung). Wir pr\u00fcfen <code>length() > 0<\/code>, damit wir nicht versuchen, einen Nullvektor zu normalisieren, was einen Fehler geben w\u00fcrde.<\/li>\n\n\n\n<li><code>position += direction * speed * delta<\/code>: Dies ist die Zeile, die die Position des Sprites tats\u00e4chlich aktualisiert. <code>position<\/code> ist eine eingebaute Eigenschaft, die die aktuelle Position des Nodes speichert (ein <code>Vector2<\/code>). Wir addieren zu der aktuellen Position den Bewegungsvektor. Dieser Bewegungsvektor wird berechnet, indem wir die normierte <code>direction<\/code> (L\u00e4nge 0 oder 1) mit unserer <code>speed<\/code> (Pixel pro Sekunde) und <code>delta<\/code> (Zeit seit letztem Frame in Sekunden) multiplizieren. Das Ergebnis ist die Strecke, die der Sprite in diesem einen Frame zur\u00fccklegen soll. Das <code>+=<\/code> addiert diese Strecke zur aktuellen <code>position<\/code>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Schritt 3: Script speichern und Scene ausf\u00fchren<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Speichere dein Script (Strg + S).<\/li>\n\n\n\n<li>F\u00fchre die Scene aus (F6 oder F5).<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Ergebnis:<\/h4>\n\n\n\n<p>Du siehst nun das rotierende Godot-Logo, das du mit den von dir konfigurierten Tasten (Pfeiltasten oder WASD) bewegen kannst!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Dein n\u00e4chster Schritt<\/h3>\n\n\n\n<p>Du hast gelernt, wie man <strong>Input Actions<\/strong> in Godot definiert und diese dann in GDScript nutzt, um unseren Sprite mit der Tastatur zu bewegen. Du verstehst jetzt die grundlegende Struktur f\u00fcr Spieler-Input und die Bedeutung von <code>Vector2<\/code> sowie <code>delta<\/code> f\u00fcr eine fl\u00fcssige, bildratenunabh\u00e4ngige Bewegung.<\/p>\n\n\n\n<p>Als N\u00e4chstes tauchen wir in das Thema Kollisionen ein \u2013 wie unser Sprite mit anderen Objekten in der Welt interagieren kann.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nachdem wir unseren Sprite mit einem Script zum Rotieren gebracht haben, ist es an der Zeit, ihm Interaktion mit der Spieler:in zu erm\u00f6glichen.&hellip;<\/p>\n","protected":false},"author":2,"featured_media":629,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[33],"tags":[35,34,38],"class_list":["post-576","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-godot","tag-2d-game","tag-godot","tag-input-management"],"_links":{"self":[{"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/posts\/576","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/comments?post=576"}],"version-history":[{"count":5,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions"}],"predecessor-version":[{"id":613,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions\/613"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/media\/629"}],"wp:attachment":[{"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/media?parent=576"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/categories?post=576"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/staratnight.de\/blog\/wp-json\/wp\/v2\/tags?post=576"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}