1 min read

Szene anhand vom Klassennamen erzeugen

Anhand der Klasse eine Instanz erzeugen dank einfachem Pattern!
Szene anhand vom Klassennamen erzeugen
Photo by Jakub Żerdzicki / Unsplash

Ich habe vor einer ganzen Weile ein spannendes Pattern im Godot Subreddit gefunden. Es ist best practice, dass eine Szene den selben Namen hat wie die dazugehörige Skript-Datei. Das kann man anschließend ausnutzen und darauf basierend sehr einfach eine Instanz dieser Szene erzeugen indem man den Klassennamen übergibt.

## Source: https://gist.github.com/gruebite/114a7d5c9d5878e5a996294d83649857
## Instantiates a scene based on [param class_name]. Scene must be located next
## to the associated class.
static func scene(class_name: GDScript) -> Node:
	var scene_path := scene_path(class_name)
	if scene_path.is_empty():
		return class_name.new()
	var scene: PackedScene = ResourceLoader.load(scene_path)
	var node: Node = scene.instantiate()
	node.name = class_name.to_string()
	return node


## Source: https://gist.github.com/gruebite/114a7d5c9d5878e5a996294d83649857
static func scene_path(class_name: GDScript) -> String:
	var class_path := class_name.resource_path
	assert(class_path.ends_with(".gd"), "missing script for class")
	var scene_path := class_path.get_basename() + ".tscn"
	return scene_path if ResourceLoader.exists(scene_path) else ""

Ich habe die Vorlage aus dem Gist etwas abgewandelt, weil es für meine Zwecke oftmals auch gut ist, wenn ich alternativ eine Instanz der Klasse zurück bekomme.

Der Code befindet sich üblicherweise in einer "Library Klasse". Ich nenne sowas bspw. ganz gerne UtilityLib o.ä.

Beispiel: Gegner

Jetzt ist es total einfach, zur Laufzeit neue Gegner zu spawnen. Du hast in deinem Projekt in etwa folgende Struktur:

Entities
  Enemy
    enemy.gd
    enemy.tscn
game.gd
game.tscn

Deine Main Szene ist game.tscn und du möchtest in deinem Spiel nun Gegner Spawnen. Das machen wir jetzt folgendermaßen:

# Game.gd
class_name Game
extends Node

...

# Hier muss man natürlich nicht Enemy zurückgeben, void wäre hier auch denkbar
# Je nach dem, ob man nach dem Spawnen noch etwas mit der Referenz machen möchte oder nicht
func spawn_enemy() -> Enemy:
  var enemy: Enemy = UtilityLib.scene(Enemy)
  add_child(enemy)
  return enemy

...

Und schon hat man einen neuen Gegner als Child Node unter der Game Node.

Ich finde das super praktisch und nutze es regelmäßig!