Cave: Erste Schritte Anleitung
Cave: Erste Schritte Leitfaden
Lesson 15 of 19 • 50 XP
Keep your place in this quest
Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.
Jetzt, da du gesehen hast, wie Charaktere und Animationen in Cave funktionieren, machen wir einen Schritt zurück und verstehen das Skriptsystem, das normalerweise alles miteinander verbindet: Python.
Python wird in Cave verwendet, um Gameplay-Verhalten, Editor-Tools, UI-Callbacks, Animations-Callbacks, Timeline-Ereignisse und kleine Stücke von benutzerdefinierter Logik zu schreiben, die zu spezifisch sind, um als eingebautes Component zu existieren. Du musst kein fortgeschrittener Python-Programmierer sein, bevor du Cave benutzt, aber es ist sehr nützlich, die Grundstruktur eines Cave-Skripts zu verstehen.
In dieser Lektion lernst du:
- Wofür Python in Cave verwendet wird.
- Wie Python Script Assets und Python Components zusammenarbeiten.
- Was
start()undupdate()machen. - Wie du auf die aktuelle Entity aus einem Skript zugreifst.
- Wie du Components von einer Entity erhältst.
- Wann du einen Python Component oder einen Python Code Component verwenden solltest.
Das Ziel ist nicht, die gesamte Python-Sprache zu lehren. Das Ziel ist, dass Cave-Skripte verständlich sind, wenn du sie öffnest.
Wo lernt man Python?
Wenn du noch nicht weißt, wie man in Python programmiert, stellt Uniday Studio tatsächlich auch kostenlose Learn Quests zu Python bereit. Gehe zu uniday.studio/learn, um alle Optionen zu sehen, oder starte hier:
Für diesen Abschnitt setzen wir voraus, dass du die Themen aus diesen beiden Learn Quests bereits kennst.
Wofür Python in Cave verwendet wird
In Cave ist Python die Skripting-Schicht, die du verwendest, wenn ein Spielobjekt Verhalten benötigt.
Zum Beispiel kann Python verwendet werden, um:
- Einen Spieler oder Gegner zu bewegen.
- Eine Tür zu öffnen.
- Eine Animation abzuspielen.
- Einen Sound auszulösen.
- Eine Timeline zu starten.
- Szenen zu wechseln.
- Ein UI-Element zu aktualisieren.
- Benutzerdefinierte Editor-Tools zu erstellen.
Grundsätzlich kannst du mit Python Scripts die gesamte Logik deines Spiels erstellen.
Deshalb enthält das Startprojekt bereits Python-Skripte. Der Standardspieler ist zum Beispiel nicht nur ein Mesh mit einer Animation. Er hat auch Gameplay-Logik, die Eingaben liest, den Charakter bewegt, das Mesh dreht und die richtige Animation abspielt.
Wenn du also in Cave Python schreibst, schreibst du normalerweise keinen isolierten Code. Du schreibst Logik, die eine Entity steuert und mit den an diese Entity angehängten Components kommuniziert.
Script Assets und Python Components
Python-Code lebt meistens in einem Python Script Asset.

Um dieses Skript in einer Szene auszuführen, fügst du einer Entity einen Python Component hinzu und wählst aus, welche Klasse aus dem Skript ausgeführt werden soll.
Denk daran so:
| Teil | Was es macht |
|---|---|
| Python Script Asset | Speichert den Code. |
| Python Component | Führt eine Klasse aus diesem Skript an einer Entity aus. |
| Entity | Das Objekt, das vom Skript gesteuert wird. |
cave.Component Klasse |
Das tatsächliche Verhalten, das du geschrieben hast. |
Zum Beispiel hast du vielleicht ein Skript-Asset namens Door Controller. Darin ist eine Klasse DoorController, die von cave.Component erbt. Dann fügst du dem Tür-Entity einen Python Component hinzu und wählst diese Klasse aus.
Diese Trennung ist wichtig, weil dasselbe Skript wiederverwendet werden kann. Du kannst viele Türen in der Szene platzieren, jede mit demselben Tür-Controller-Skript, aber mit unterschiedlichen Eigenschaften oder Kindobjekten.
Ein Minimaler Cave Component
Ein einfaches Cave Python Component sieht so aus:
import cave
class MyComponent(cave.Component):
def start(self, scene):
print("The component started!")
def update(self):
pass
Ein paar wichtige Details:
import cavegibt deinem Skript Zugriff auf die Python-API von Cave.class MyComponent(cave.Component)erstellt eine Component-Klasse, die Cave ausführen kann.start(self, scene)wird ausgeführt, wenn die Komponente startet.update(self)wird in jedem Frame ausgeführt, während die Komponente aktiv ist.
Der Name MyComponent kann alles sein, aber in echten Projekten solltest du einen klaren Namen wie DoorController, EnemyAI, Checkpoint oder PlayerHealth verwenden.
Lebenszyklus-Methoden
Cave ruft einige Methoden automatisch auf, wenn deine Komponente läuft.
Die gebräuchlichsten sind:
| Methode | Wann sie läuft | Übliche Verwendung |
|---|---|---|
start(self, scene) |
Wenn die Komponente startet. | Referenzen holen, Eigenschaften lesen, Variablen vorbereiten. |
firstUpdate(self) |
Immer direkt nach der start Methode aller Entity Components, im ersten Update. |
Variablen erstellen, die von anderen Components initialisiert sein müssen. |
update(self) |
Jeder Frame, wenn die Szene nicht pausiert ist. | Bewegung, Eingaben, Timer, Statusprüfungen. |
pausedUpdate(self) |
Jeder Frame, wenn die Szene P A U S I E R T ist. | Logik für Pausen. |
end(self, scene) |
Wenn die Komponente endet. | Aufräumen wenn nötig. |
Die meisten Anfänger-Skripte verwenden start() und update(). Zum Beispiel ist für eine bewegte Plattform start() ein guter Ort, um die Ausgangsposition zu speichern, und update() ist dann der Ort, an dem die Plattform in jedem Frame bewegt wird.
Es gibt auch noch editorUpdate und lateUpdate Methoden, die sind aber etwas fortgeschrittener und werden hier nicht behandelt.
Zugriff auf die aktuelle Entity
Innerhalb einer Cave-Komponente ist self.entity die Entity, die den Python Component besitzt.
Das ist eine der wichtigsten Ideen in der Cave-Skripterstellung. Das Skript schwebt nicht einfach frei in der Szene. Es gehört zu einer Entity.
Hier ein einfaches Beispiel:
import cave
class DoorController(cave.Component):
def start(self, scene):
self.transform = self.entity.getTransform()
self.isOpen = False
def update(self):
pass
In diesem Skript:
self.entityist die Tür-Entity.self.entity.getTransform()holt die Transform-Komponente der Tür.self.isOpenist eine Variable, die das Skript verwendet, um zu merken, ob die Tür offen ist.
Dieses Muster wirst du sehr oft verwenden. Zuerst holst du dir die Entity, dann die benötigten Komponenten oder Kind-Entities und benutzt sie in deiner Logik.
Andere Komponenten abrufen
Um eine Entity zu steuern, brauchst du normalerweise eine oder mehrere Komponenten davon.
Zum Beispiel holt ein Spieler-Skript:
- Die
TransformKomponente, um die Entity zu bewegen oder zu drehen. - Die
CharacterKomponente, um die Charakter-Bewegung zu handhaben. - Die
AnimationKomponente von einer Kind-Mesh-Entity, um Animationen abzuspielen. - Die
AudioKomponente, um einen Loop-Sound abzuspielen.
Hier ein kleines Beispiel:
import cave
class SimpleMover(cave.Component):
def start(self, scene):
self.transform = self.entity.getTransform()
self.speed = 2.0
def update(self):
self.transform.move(0, 0, self.speed * cave.getDeltaTime(), local=True)
Dadurch bewegt sich die Entity in jedem Frame nach vorne.
Wichtig ist cave.getDeltaTime(). Da update() in jedem Frame ausgeführt wird, sorgt die Multiplikation mit Delta-Time dafür, dass die Bewegungsgeschwindigkeit konstant bleibt, auch wenn sich die Framerate ändert.
Eigene Eigenschaften lesen
Fest eingebaute Werte sind für erste Tests in Ordnung, aber editierbare Eigenschaften sind meistens besser für echte Spielobjekte.
Zum Beispiel statt so:
self.speed = 2.0
liest du den Wert aus den Eigenschaften der Entity:
self.speed = self.entity.properties.get("speed", 2.0)
Das bedeutet:
- Wenn die Entity eine Eigenschaft
speedhat, wird sie verwendet. - Wenn nicht, wird
2.0als Standardwert genommen.
Das ist sehr nützlich für wiederverwendbare Skripte. Du kannst ein SimpleMover Skript erstellen und auf mehreren Entities verwenden, jede mit unterschiedlicher Geschwindigkeit.
Zum Beispiel:
| Entity | speed Eigenschaft |
|---|---|
| Langsame Plattform | 1.0 |
| Schnelle Plattform | 4.0 |
| Bewegliche Gefahr | 7.0 |
Das Skript bleibt gleich, aber das Verhalten ändert sich je Entity.
Alternativ kannst du auch lokal veränderbare Variablen für die Komponente selbst erstellen, anstatt auf die Eigenschaften der Entity angewiesen zu sein. Wenn du eine Variable so definierst:
import cave
class PlatformMover(cave.Component):
# Dies wird lokal sein:
speed = 2.0
def start(self, scene: cave.Scene):
pass
def update(self):
events = cave.getEvents()
Die Variable speed ist für jede Component-Instanz lokal veränderbar:

Kind-Entities abrufen
Viele Cave-Objekte sind als kleine Hierarchien aufgebaut.
Das Spieler-Template ist ein gutes Beispiel. Die Root-Player-Entity hat die Charakterphysik und Logik, während die Kind-Mesh-Entity das visuelle Charakter-Mesh und die Animation-Komponente enthält.
Wenn ein Skript an der Root-Player-Entity Animationen abspielen möchte, holt es zuerst die Kind-Mesh-Entity:
import cave
class PlayerAnimationExample(cave.Component):
def start(self, scene):
self.mesh = self.entity.getChild("Mesh")
self.animator = self.mesh.get("Animation")
def update(self):
self.animator.playByName("p-idle", blend=0.2, loop=True)
Dieses Muster verwendet auch der Standard-Player-Controller:
- Hole die Kind-Entity.
- Hole die Komponente von der Kind-Entity.
- Benutze die Komponente wenn nötig.
Wenn du das Muster verstehst, werden viele Cave-Skripte viel leichter lesbar.
Die Methode getChild hat einen optionalen Parameter "recursive", der standardmäßig auf True gesetzt ist. Wenn True, sucht sie alle Kind-Entities, auch Kinder von Kindern, bis die gewünschte Entity nach Namen gefunden wird.
Scene Entities abfragen (Szenen-Abfragen)
Wenn du ein Spiel erstellst, wirst du sehr wahrscheinlich andere Entities in der Szene abrufen müssen. Schauen wir uns das an. Der erste Schritt ist die Szene selbst zu bekommen, und in Cave hast du zwei Möglichkeiten, das zu tun:
# Returns the active scene:
scene = cave.getScene()
# Returns the scene the entity belongs to:
scene = self.entity.getScene()
Aus Bequemlichkeit erhalten die cave.Component-Methoden start und end ebenfalls die Szene als Parameter, da es sehr wahrscheinlich ist, dass Sie sie in diesen Methoden verwenden. Für lokalen Code wie die Python Code Component wird außerdem standardmäßig eine scene-Variable für Sie definiert, die Sie auf magische Weise „einfach so verwenden“ können und erwarten können, dass sie funktioniert.
Sobald Sie die Szene erhalten haben, können Sie eine bestimmte Entity anhand ihres Namens mit folgendem Code abrufen:
watchtower = scene.get("Watch Tower 01")
Cave stellt viele weitere Methoden in der Scene-Klasse zur Verfügung, mit denen Sie andere Abfragen zur Szene durchführen können. Sie können Raycasts, Spherecasts durchführen, eine Kontaktbox oder eine Kugel für grundsätzliche Kollisionsabfragen prüfen oder sogar alle Entities, alle Root-Entities, alle Entities mit einem bestimmten Tag, alle Entities mit bestimmten Eigenschaften oder mit einem bestimmten Namen abrufen, usw. Es lohnt sich also, die Python-API für weitere Details zu prüfen.
Denken Sie immer daran, zu prüfen, ob Ihre Abfrage etwas Gültiges zurückgegeben hat. Zum Beispiel:
# Abfrage einer nicht vorhandenen Entity:
ent = scene.get("This Entity Doesnt Exist")
if ent is None:
print("Ungültige Entity!")
Abrufen von Entity Components
Sobald Sie eine bestimmte Entity haben und geprüft haben, ob sie bekannt ist, ist es sinnvoll zu verstehen, wie Sie bestimmte Komponenten davon erhalten können.
Die Entity hat eine spezielle Methode namens get, der Sie den Namen der Komponente als String übergeben können, und sie durchsucht die Entity automatisch, ob es eine Komponente gibt, die Ihrer Suche entspricht:
animator = self.entity.get("Animation Component")
Um Ihnen das Leben zu erleichtern: Wenn ein Komponentenname mit dem Wort „Component“ endet, was sehr häufig vorkommt, können Sie dieses Ende beim Tippen des Komponenten-Namens in dieser Methode komplett weglassen. Sie können auch entscheiden, ob Sie Leerzeichen in mehrwortigen Komponentennamen verwenden oder alles zusammen schreiben.
Zum Beispiel, wenn Sie die Rigid Body Component von einer Entity erhalten wollen, obwohl der Python-Name RigidBodyComponent lautet, funktionieren alle untenstehenden Optionen:
rb = self.entity.get("Rigid Body")
rb = self.entity.get("RigidBody")
rb = self.entity.get("Rigid Body Component")
rb = self.entity.get("RigidBodyComponent")
rb = self.entity.get("RigidBody Component")
Da Python nicht stark typisiert ist, ist es eine gute Programmierpraxis in Cave, für den Komponententyp einen Typ-Hinweis zu geben, was wie unten geschehen kann. Beachten Sie auch, dass Sie in diesem Fall den vollständigen Komponentennamen angeben müssen, da dies eine Python-Semantik ist:
rb : cave.RigidBodyComponent = self.entity.get("Rigid Body")
Dies ermöglicht IntelliSense in externen Editoren wie Visual Studio Code oder sogar die integrierte Autovervollständigung, die Cave Engine im eingebetteten Skript-Editor bietet.
Für die Transform Component, da sie eine der häufigsten Komponententypen ist und Sie sie oft abfragen werden, hat die Entity eine native Methode, um ihre Haupt-Transform zu erhalten:
transf = self.entity.getTransform()
Das Abrufen durch self.entity.getTransform() liefert dasselbe Ergebnis wie self.entity.get("Transform"), aber die erste Option ist schneller und optimierter.
Hat eine Entity mehrere Komponenten gleichen Typs, wird die erste Übereinstimmung zurückgegeben, aber manchmal möchten Sie alle Treffer erhalten. Zum Beispiel bei einem Mesh mit mehreren Materialien, das in Cave durch eine Entity mit mehreren Mesh-Komponenten dargestellt wird, möchten Sie vielleicht alle Mesh-Komponenten erhalten. Dafür gibt es die Methode getAll:
meshCmps = self.entity.getAll("Mesh")
# Ändern aller Materialien zu einem leuchtenden:
for meshCmp in meshCmps:
meshCmp.material.setAsset("Glowing Material")
Abrufen von Python Entity Components
Nun wissen wir, wie man native Cave-Komponenten bekommt, aber was ist, wenn Sie eine Komponente möchten, die von Ihnen in Python selbst geschrieben wurde?
Dafür benötigen Sie eine spezielle Methode namens getPy, die genauso funktioniert wie die reguläre get-Methode, nur dass diese auch Python-Komponenten zurückgibt:
myCmp = self.entity.getPy("MyCustomComponent")
Eine spezielle Methode ist wegen interner Optimierungen erforderlich, um sicherzustellen, dass Cave so schnell wie möglich läuft.
Mit Ihrer benutzerdefinierten Python-Komponente können Sie frei auf deren Python-Variablen und Methoden zugreifen:
myCmp = self.entity.getPy("MyCustomComponent")
# Ändern von Python-Variablen:
myCmp.customValue = 10
# Aufrufen von benutzerdefinierten Methoden:
myCmp.doSomething()
myCmp.applyDamage(10)
Python Code Component
Neben der regulären Python Component gibt es in Cave auch die Python Code Component. Die Python Code Component ist nützlich für schnelle Skripte, die direkt an der Entity geschrieben werden, ohne vorher ein separates Python Script Asset zu erstellen.
Sie hat alle anderen Methoden, und der Unterschied ist, dass Sie in der Python Code Component das Python-Skript direkt in der Komponente selbst schreiben. Es ist nicht modular und nicht wiederverwendbar. Wenn Sie also eine Kopie der Entity erstellen, wird auch eine Kopie dieses Skripts mit erstellt. Manchmal kann dies jedoch ein schneller Weg sein, eine einfache Logik wie sich drehende Münzen zu erstellen.
Sie eignet sich gut für:
- Schnelle Tests.
- Kleine Callbacks.
- Einmaliges Verhalten.
- Prototypen.
Für größere Gameplay-Systeme ist es nicht die beste Option, weil der Code schwerer wiederverwendbar und organisierbar ist, aber für kleine Codes ist sie optimal.
Python Component vs. Python Code Component
Verwenden Sie diese einfache Regel:
| Verwenden Sie | Wenn |
|---|---|
| Python Component | Verhalten wiederverwendet, als Asset editiert oder im Laufe der Zeit erweitert werden soll. |
| Python Code Component | Verhalten klein und lokal ist. |
Zum Beispiel sollte eine wiederverwendbare EnemyAI ein Python Script Asset sein, das von einer Python Component verwendet wird. Ein kleiner Code, der etwas ausgibt oder eine Funktion bei Tastendruck aufruft, kann eine Python Code Component sein.
Ein gutes erstes Skriptziel
Ein gutes erstes Cave-Skript ist etwas Kleines und Sichtbares.
Versuchen Sie, eines der Folgenden zu erstellen:
- Eine Plattform, die sich vorwärts bewegt.
- Eine Tür, die sich beim Start der Szene öffnet.
- Ein Licht, das alle paar Sekunden an- und ausgeht.
- Ein Pickup, der einen Sound abspielt und sich deaktiviert.
- Einen Knopf, der zu einer anderen Szene wechselt.
Diese Beispiele sind klein, lehren aber den wichtigsten Workflow: Entity bekommen, Komponente erhalten, etwas ändern, im Play-Modus testen und anpassen.
Was Sie sich merken sollten
Python-Skripte in Cave sind üblicherweise über Python Components an Entities gebunden.
Das wichtigste Anfänger-Muster ist:
- Verwenden Sie
start(), um Referenzen zu erhalten und Werte vorzubereiten. - Verwenden Sie
update(), um Verhalten jeden Frame auszuführen. - Verwenden Sie
self.entity, um auf die Entity zuzugreifen, die das Skript besitzt. - Verwenden Sie Komponenten, um tatsächlich zu bewegen, animieren, Sound abzuspielen oder das Objekt zu steuern.
Wenn Ihnen dieses Muster vertraut ist, wird das Scripting in Cave viel weniger mysteriös. Sie schreiben nicht nur Code. Sie bringen Entities bei, wie sie sich verhalten sollen.