Gestaltung der Mob-Szene

In diesem Teil werden Sie die Monster programmieren, welche wir Mobs nennen werden. In der nächsten Lektion werden wir sie zufällig im Spielbereich spawnen.

Lassen Sie uns die Monster in einer neuen Szene entwerfen. Die Node Struktur wird ähnlich wie die der Player-Szene.

Erstellen Sie eine weitere neue Szene mit einer KinematicBody Node als Wurzel. Benennen Sie ihn zu Mob um. Fügen sie ein Spatial Node als Unternode hinzu und nennen Sie es Pivot. Ziehen Sie die Datei mob.glb von dem Dateisystem-Panel auf den Pivot um das 3D-Modell des Monsters der Szene hinzuzufügen. Sie können das neu erstellte Node mob in Character umbenennen.

image0

Wir brauchen eine Kollisionsform damit unser Körper funktioniert. Klicken Sie mit der rechten Maustaste auf das Mob Node, die Wurzel der Szene, und klicken sie auf Node hier Anhängen.

image1

Füge eine CollisionShape hinzu.

image2

Weisen Sie im Inspektor der Shape Eigenschaft eine BoxShape zu.

image3

Wir sollten die Größe ändern damit die Form besser an das 3D-Modell passt. Sie können dies interaktiv tun, indem sie auf die orangen Punkte klicken und ziehen.

Die Box sollte den Boden berühren und ein wenig dünner als das Modell sein. Physik-Engines arbeiten so, dass eine Kollision stattfindet, wenn die Kugel des Spielers auch nur eine Ecke des Kastens berührt. Wenn die Kiste im vergleich zum 3D-Modell nur ein wenig zu groß ist, könnte man trotz sichtbarer entfernung von einem Monster sterben, was das Spiel auf die Spieler unfair wirken lässt.

image4

Beachten Sie dass meine Box höher ist als das Monster. Das ist in diesem Spiel in Ordnung, weil wir von oben auf die Szene herabschauen und eine feste Perspektive verwenden. Die Kollisionsformen müssen nicht genau mit dem Modell übereinstimmen. Ihre Form und Größe sollten davon abhängig sein wie sie sich beim testen des Spiels anfühlen.

Monster außerhalb des Bildschirms entfernen

Wir werden in regelmäßigen abständen Monster in dem Level erscheinen lassen. Wenn wir dabei nicht aufpassen, könnte ihre anzahl ins Unendliche steigen und das wollen wir nicht. Jede Mob-Instanz hat sowohl Speicher als auch Verarbeitungs Kosten und wir wollen nicht für sie zahlen wenn der Gegner außerhalb des Buildschirmbereichs ist.

Sobald ein Monster den Bildschirmbereich verlässt, brauchen wir es nicht mehr, also können wir es einfach löschen. Godot hat ein Node das erkennt wenn ein Objekt den Bildschirmbereich verlässt, namens VisibilityNotifier und wir werden es dafür benutzen um unsere Mobs zu zerstören.

Bemerkung

Wenn Sie ein bestimmtes Objekt in einem Spiel immer wieder instanzieren, gibt es eine Technik mit der wir die Kosten für das ständige Erstellen und Zerstören von Instanzen vermeiden können, die sich Pooling nennt. Sie besteht darin ein Array an Objekten vorab zu erstellen und diese dann immer wieder zu verwenden.

Wenn Sie mit GDScript arbeiten, müssen Sie sich darüber keine Gedanken machen. Der Hauptgrund für die verwendung von pools ist Standbilder bei Sprachen die Freispeichersammlung verwenden wie C# oder Lua zu vermeiden. GDScript nutzt eine andere Technik um den Speicher zu verwalten, nämlich das Referenzzählen, bei dem es diese Einschränkung nicht gibt. Sie können hier mehr darüber erfahren Speicher-Management.

Wählen sie das Mob Node aus und fügen sie einen VisibilityNotifier als Unternode hinzu. Eine weitere box, diesmal in pink, erscheint. Wenn diese Box den Bildschirmbereich komplett verlässt, wird das Node ein Signal senden.

image5

Ändern Sie die Größe der Box mithilfe der orangen Punkte, bis sie das gesamte 3D-Modell abdeckt.

|image6|

Die Bewegung des Gegners coden

Lassen Sie uns nun die Bewegung der Monster implementieren. Wir werden dies in zwei Schritten tun. Als erstes, werden wir ein Skript für den Mob schreiben, das eine Funktion zum Initialisieren des Monsters beinhaltet. Dann werden wir einen zufälligen Spawn-Mechanismus in der Szene Main erstellen und diese Funktion von dort aufrufen.

Hängen Sie ein Skript an den Mob an.

|image7|

Hier ist zu aller erst der Bewegungs Code. Wir definieren zwei Eigenschaften, min_speed und max_speed, um eine zufällige Geschwindigkeitsspanne zu definieren. Dann definieren und initialisieren wir die velocity.

extends KinematicBody

# Minimum speed of the mob in meters per second.
export var min_speed = 10
# Maximum speed of the mob in meters per second.
export var max_speed = 18

var velocity = Vector3.ZERO


func _physics_process(_delta):
    move_and_slide(velocity)

Ähnlich wie bei dem Spieler, bewegen wir den Mob jeden Frame indem wir die Methode des KinematicBodys move_and_slide() aufrufen. Dieses mal aktualisieren wir die velocity aber nicht jeden Frame: wir wollen dass das Monster sich mit einer konstanten Geschwindigkeit bewegt und den Bildschirm verlässt, selbst wenn es auf ein Hindernis trifft.

Möglicherweise wird in GDScript eine Warnung angezeigt, dass der Rückgabewert von move_and_slide() unbenutzt ist. Dies ist zu erwarten. Sie können die Warnung einfach ignorieren, oder wenn Sie sie ganz ausblenden wollen, können Sie den Kommentar #warning-ignore:return_value_discarded direkt über der Zeile move_and_slide(velocity) einfügen. Um mehr über das GDScript-Warnsystem zu erfahren, siehe GDScript Warnungs System.

Wir sollten eine weitere Funktion definieren um die Startgeschwindigkeit zu berechnen. Diese Funktion wird das Monster in die Richtung des Spielers drehen und sowohl den Bewegunswinkel als auch die Geschwindigkeit auf einen zufälligen Wert setzen.

Die Funktion nimmt eine start_position, also die Spawn-Position des Mobs und die player_position als Argumente.

Wir positionieren den Mob auf start_position und drehen ihn mit der Methode look_at_from_position() in die Richtung des Spielers, wobei wir ihn zusätzlich um einen zufälligen Betrag um die Y-Achse drehen. In dem unteren Code Abschnitt, wird rand_range() verwendet um einen zufälligen Wert zwischen -PI / 4 Radiant und PI / 4 Radiant zu erhalten.

# We will call this function from the Main scene.
func initialize(start_position, player_position):
    # We position the mob and turn it so that it looks at the player.
    look_at_from_position(start_position, player_position, Vector3.UP)
    # And rotate it randomly so it doesn't move exactly toward the player.
    rotate_y(rand_range(-PI / 4, PI / 4))

Wir berechnen dann eine zufällige Geschwindigkeit mit einer weiteren Verwendung von rand_range() und benutzen sie anschließend um den Bewegungs-Vektor zu berechnen.

Wir beginnen mit der Erstellung eines 3D-Vektors, der nach vorne zeigt, multiplizieren ihn mit unserem random_speed und drehen ihn schließlich mit der Methode rotated() aus der Klasse Vector3.

func initialize(start_position, player_position):
    # ...

    # We calculate a random speed.
    var random_speed = rand_range(min_speed, max_speed)
    # We calculate a forward velocity that represents the speed.
    velocity = Vector3.FORWARD * random_speed
    # We then rotate the vector based on the mob's Y rotation to move in the direction it's looking.
    velocity = velocity.rotated(Vector3.UP, rotation.y)

Verlassen des Bildschirms

Wir müssen noch die Mobs zerstören wenn sie den Bildschirmbereich verlassen. Um dies zu tun, verbinden wir das screen_exited Signal unserer VisibilityNotifier Node mit dem Mob.

Kehren Sie zum 3D-Ansichtsfenster zurück, indem sie auf die Beschriftung 3D am oberen Rand des Editors klicken. Sie können auch Ctrl + F2`(:kbd:`Alt + 2 auf macOS) drücken.

|image8|

Wählen Sie das VisibilityNotifier Node aus und navigieren sie auf der rechten Seite des Interface zu dem Node Panel. Doppelklicken Sie auf das Signal screen_exited().

|image9|

Verbinden Sie das Signal mit dem Gegner.

|image10|

Dies wird Sie zurück zu dem Script-Editor bringen und für Sie eine neue Funktion hinzufügen: _on_VisibilityNotifier_screen_exited(). Rufen sie von dort die Methode queue_free() auf. Dies wird die Mob-Instanz zerstören sobald die Box des VisibilityNotifier den Bildschirmbereich verlässt.

func _on_VisibilityNotifier_screen_exited():
    queue_free()

Unser Monster ist endlich bereit das Spiel zu betreten! I'm nächsten Teil werden Sie Monster im Spiellevel spawnen.

Hier ist das vollständige Mob.gd Skript als Referenz.

extends KinematicBody

# Minimum speed of the mob in meters per second.
export var min_speed = 10
# Maximum speed of the mob in meters per second.
export var max_speed = 18

var velocity = Vector3.ZERO


func _physics_process(_delta):
    move_and_slide(velocity)

func initialize(start_position, player_position):
    look_at_from_position(start_position, player_position, Vector3.UP)
    rotate_y(rand_range(-PI / 4, PI / 4))

    var random_speed = rand_range(min_speed, max_speed)
    velocity = Vector3.FORWARD * random_speed
    velocity = velocity.rotated(Vector3.UP, rotation.y)


func _on_VisibilityNotifier_screen_exited():
    queue_free()