Zum Inhalt

Beispielarbeiten · Spiele & Interaktives

Godot: ein 2D-Ausweichspiel mit Punkten, Tempo und Neustart

Ein kleines 2D-Spiel in GDScript: Hindernisse fallen, der Spieler weicht aus, das Tempo steigt mit den Punkten, nach der Kollision geht es per Neustart weiter. Die Spiellogik ist automatisch durchgetestet.

Musterarbeit (Demo), kein Kundenauftrag. Gebaut als Probeaufgabe mit erfundenen Beispieldaten; die Prüfzahlen unten stammen aus dem automatischen Prüflauf und sind nicht geschönt.

Was gebaut wurde

  • Spielschleife mit Eingabe, Rand, Hindernissen, Punkten und steigendem Tempo
  • Zustände Läuft, Ende und Neustart, jeweils mit eigenen Prüfungen
  • Spieltests im Godot-Editor ohne Fenster, Gegenprobe mit absichtlich kaputten Fassungen
  • Das Bild stammt aus dem echten Spielfenster, nicht aus einem Entwurf

Bildschirmfoto aus dem Prüflauf: Godot: ein 2D-Ausweichspiel mit Punkten, Tempo und Neustart

spieltests.txt herunterladen godot-spiel-quellcode.zip herunterladen

Gezeichnete Formen ohne eigene Bilder, Töne oder Animationen; nur 2D, kein Mehrspieler, keine Shader. Die Tests prüfen die Logik, nicht das Spielgefühl. Exportiert wurden Windows und Web, die Windows-Datei ist unsigniert; Android, iOS und Store-Veröffentlichung sind nicht geprüft. Hier liegt der Quellcode, keine Exe.

Wie geprüft wurde

Automatischer Prüflauf vom 01.11.2026, aus dem Protokoll (Testdaten erfunden, Zahlen gemessen):

  • Import ok, Syntaxpruefung 3/3 Skripte fehlerfrei
  • Spieltests 25 Pruefungen gruen (Exit 0)
  • Export Windows .exe 109.3 MB, Web index.wasm 39.5 MB + html/js/pck ok
  • exportierte .exe startet ok
  • Gegenprobe 3/3 kaputte Fassungen erkannt
  • Bild mit Fenster gerendert: 480x640, Spielerpixel 1600, H

Grenzen

Was diese Probe nicht abdeckt, steht hier, damit niemand mehr erwartet:

  • Godot 4.7.2 Standard (GDScript), nicht die .NET/C#-Fassung; Godot 3.x-Projekte nicht geprueft
  • nur 2D-Spiellogik mit gezeichneten Formen (keine eigenen Bilder/Sounds/Animationen/Tilemaps); 3D, Netzwerk-Mehrspieler, Shader nicht geprueft
  • Export nur Windows x86_64 und Web (ohne Threads); Android/iOS/macOS/Linux brauchen SDK, Signatur bzw. Zielsystem und sind nicht geprueft; Windows-.exe unsigniert, ohne Icon/Versionsdaten (rcedit …
  • Spieltests pruefen die Logik (schritt), nicht das Spielgefuehl; Web-Export nicht im Browser gespielt (nur Dateien + Groesse), Steam/itch.io/Store-Veroeffentlichung nicht Teil der Probe
  • Bild wurde mit echtem Fenster der Grafikkarte gerendert; auf Rechnern ohne OpenGL 3.3 nicht moeglich

Das Spielskript

extends Node2D
## Ausweichen: Der Spieler (unten) weicht fallenden Hindernissen aus.
## Pro ausgewichenem Hindernis +1 Punkt. Beruehrung = Game Over, Leertaste = Neustart.
## Die Spiellogik steckt in schritt(delta) und ist ohne Fenster testbar.

signal punkte_geaendert(neu: int)
signal spiel_beendet(punkte: int)

const BREITE := 480.0
const HOEHE := 640.0
const SPIELER_GROESSE := Vector2(40, 40)
const HINDERNIS_GROESSE := Vector2(48, 48)
const SPIELER_TEMPO := 320.0
const SPAWN_ABSTAND := 0.9

var zustand: String = "laeuft"   # "laeuft" oder "ende"
var punkte: int = 0
var spieler_pos: Vector2 = Vector2.ZERO
var hindernisse: Array = []        # Eintraege: Vector2 (obere linke Ecke)
var fall_tempo: float = 160.0
var spawn_zeit: float = 0.0
var zufall := RandomNumberGenerator.new()


func _init() -> void:
	zufall.seed = 12345


func _ready() -> void:
	neustart()


func neustart() -> void:
	zustand = "laeuft"
	punkte = 0
	hindernisse.clear()
	fall_tempo = 160.0
	spawn_zeit = 0.0
	spieler_pos = Vector2((BREITE - SPIELER_GROESSE.x) / 2.0, HOEHE - SPIELER_GROESSE.y - 20.0)
	punkte_geaendert.emit(punkte)
	queue_redraw()


func hindernis_setzen(x: float, y: float) -> void:
	hindernisse.append(Vector2(x, y))


func _kollidiert(h: Vector2) -> bool:
	var a := Rect2(spieler_pos, SPIELER_GROESSE)
	var b := Rect2(h, HINDERNIS_GROESSE)
	return a.intersects(b)


func schritt(delta: float) -> void:
	if zustand == "ende":
		if Input.is_action_just_pressed("neustart"):
			neustart()
		return
	# Bewegung
	var achse := Input.get_axis("links", "rechts")
	spieler_pos.x = clampf(spieler_pos.x + achse * SPIELER_TEMPO * delta, 0.0, BREITE - SPIELER_GROESSE.x)
	# Hindernisse erzeugen
	spawn_zeit += delta
	if spawn_zeit >= SPAWN_ABSTAND:
		spawn_zeit -= SPAWN_ABSTAND
		hindernis_setzen(zufall.randf_range(0.0, BREITE - HINDERNIS_GROESSE.x), -HINDERNIS_GROESSE.y)
	# Hindernisse bewegen, zaehlen, pruefen
	var rest: Array = []
	for alt in hindernisse:
		var h: Vector2 = Vector2(alt.x, alt.y + fall_tempo * delta)
		if _kollidiert(h):
			zustand = "ende"
			spiel_beendet.emit(punkte)
		if h.y > HOEHE:
			punkte += 1
			punkte_geaendert.emit(punkte)
			fall_tempo += 8.0
		else:
			rest.append(h)
	hindernisse = rest
	queue_redraw()


func _physics_process(delta: float) -> void:
	schritt(delta)


func _draw() -> void:
	draw_rect(Rect2(0, 0, BREITE, HOEHE), Color(0.08, 0.1, 0.16))
	draw_rect(Rect2(spieler_pos, SPIELER_GROESSE), Color(0.2, 0.8, 0.4))
	for h in hindernisse:
		draw_rect(Rect2(h, HINDERNIS_GROESSE), Color(0.9, 0.25, 0.25))
	var schrift := ThemeDB.fallback_font
	draw_string(schrift, Vector2(12, 28), "Punkte: %d" % punkte, HORIZONTAL_ALIGNMENT_LEFT, -1, 22, Color.WHITE)
	if zustand == "ende":
		draw_string(schrift, Vector2(0, HOEHE / 2.0), "GAME OVER - Leertaste", HORIZONTAL_ALIGNMENT_CENTER, BREITE, 28, Color(1, 0.9, 0.3))

So etwas für deinen Betrieb?

Beschreib kurz, was du brauchst. Du bekommst einen Festpreis, bevor ich anfange; ohne dein Ja passiert nichts.

Zur Werkstatt