Cave: Guía de Inicio
Cave: Guía de inicio
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.
Ahora que has visto cómo funcionan los personajes y la animación en Cave, vamos a dar un paso atrás y entender el sistema de scripting que suele conectar todo: Python.
Python se usa en Cave para escribir el comportamiento del juego, herramientas del editor, callbacks de la interfaz de usuario, callbacks de animación, eventos de timeline y pequeños fragmentos de lógica personalizada que serían demasiado específicos para existir como un componente incorporado. No necesitas ser un programador avanzado de Python antes de usar Cave, pero es muy útil entender la forma básica de un script en Cave.
En esta lección, aprenderás:
- Para qué se usa Python en Cave.
- Cómo funcionan juntos los assets Python Script y los Python Components.
- Qué hacen
start()yupdate(). - Cómo acceder a la entidad actual desde un script.
- Cómo obtener componentes de una entidad.
- Cuándo usar un Python Component o un Python Code Component.
El objetivo no es enseñar todo el lenguaje Python. El objetivo es que los scripts de Cave te resulten comprensibles cuando los abras.
¿Dónde Aprender Python?
Si no sabes programar en Python, Uniday Studio ofrece quests gratuitas para aprender Python. Ve a uniday.studio/learn para ver todas las opciones o empieza por aquí:
Para esta sección, asumiremos que ya tienes un conocimiento básico de los temas tratados en esas dos quests.
Para Qué Se Usa Python en Cave
En Cave, Python es la capa de scripting que usas cuando un objeto del juego necesita comportamiento.
Por ejemplo, Python puede usarse para:
- Mover un jugador o enemigo.
- Abrir una puerta.
- Reproducir una animación.
- Activar un sonido.
- Iniciar un timeline.
- Cambiar escenas.
- Actualizar un elemento de UI.
- Crear herramientas personalizadas para el editor.
Básicamente, puedes escribir Python Scripts para crear toda la lógica de tu juego.
Por eso el proyecto de inicio ya contiene scripts Python. El jugador por defecto, por ejemplo, no es solo una malla con animación. También tiene lógica de juego que lee la entrada, mueve el personaje, rota la malla y reproduce la animación correcta.
Así que, cuando escribes Python en Cave, normalmente no escribes código aislado. Estás escribiendo lógica que controla una entidad y se comunica con los componentes adjuntos a esa entidad.
Assets de Script y Python Components
El código Python normalmente vive dentro de un asset Python Script.

Luego, para hacer que ese script se ejecute en una escena, agregas un Python Component a una entidad y eliges qué clase del script debe ejecutarse.
Piénsalo así:
| Parte | Qué Hace |
|---|---|
| Asset Python Script | Almacena el código. |
| Python Component | Ejecuta una clase de ese script en una entidad. |
| Entidad | El objeto que controla el script. |
Clase cave.Component |
El comportamiento real que escribiste. |
Por ejemplo, puedes tener un asset script llamado Door Controller. Dentro, puedes tener una clase llamada DoorController que hereda de cave.Component. Luego agregas un Python Component a tu entidad puerta y seleccionas esa clase.
Esta separación es importante porque el mismo script puede reutilizarse. Puedes colocar muchas puertas en la escena, cada una usando el mismo script controlador de puertas pero con propiedades diferentes o hijos distintos.
Un Componente Cave Mínimo
Un componente Python básico en Cave se ve así:
import cave
class MyComponent(cave.Component):
def start(self, scene):
print("¡El componente empezó!")
def update(self):
pass
Hay algunos detalles importantes aquí:
import caveda acceso al API Python de Cave.class MyComponent(cave.Component)crea una clase de componente que Cave puede ejecutar.start(self, scene)se ejecuta cuando el componente inicia.update(self)se ejecuta cada frame mientras el componente está activo.
El nombre MyComponent puede ser cualquiera, pero en proyectos reales debes usar un nombre claro como DoorController, EnemyAI, Checkpoint o PlayerHealth.
Métodos de Ciclo de Vida
Cave llama algunos métodos automáticamente cuando tu componente está corriendo.
Los más comunes son:
| Método | Cuándo Se Ejecuta | Uso Común |
|---|---|---|
start(self, scene) |
Al iniciar el componente. | Obtener referencias, leer propiedades, preparar variables. |
firstUpdate(self) |
Siempre después del start de cada Entity Component, en la primera actualización. |
Crear variables que dependen de otros componentes ya inicializados. |
update(self) |
Cada frame, si la escena no está en pausa. | Movimiento, entrada, temporizadores, chequeo de estados. |
pausedUpdate(self) |
Cada frame, si la escena está en pausa. | Lógica mientras está en pausa. |
end(self, scene) |
Al terminar el componente. | Limpieza si es necesario. |
La mayoría de scripts para principiantes usan start() y update(). Por ejemplo, si creas una plataforma que se mueve, start() es un buen lugar para guardar la posición original, y update() es donde mueves la plataforma cada frame.
También existen los métodos editorUpdate y lateUpdate, pero no los exploraremos aquí porque son un poco más avanzados.
Accediendo a la Entidad Actual
Dentro de un componente Cave, self.entity es la entidad que posee el Python Component.
Esta es una de las ideas más importantes en el scripting de Cave. El script no está flotando por la escena solo. Pertenece a una entidad.
Aquí un ejemplo sencillo:
import cave
class DoorController(cave.Component):
def start(self, scene):
self.transform = self.entity.getTransform()
self.isOpen = False
def update(self):
pass
En este script:
self.entityes la entidad puerta.self.entity.getTransform()obtiene el Componente Transform de la puerta.self.isOpenes una variable usada por el script para recordar si la puerta está abierta.
Usarás este patrón todo el tiempo. Primero obtienes la entidad, luego los componentes o entidades hijas que necesitas, y después los usas en tu lógica.
Obteniendo Otros Componentes
Para controlar una entidad, normalmente necesitas obtener uno o más componentes de ella.
Por ejemplo, un script para jugador puede obtener:
- El componente
Transformpara mover o rotar la entidad. - El componente
Characterpara manejar el movimiento del personaje. - El componente
Animationde una entidad hija malla para reproducir animaciones. - El componente
Audiopara reproducir un sonido en loop.
Aquí un ejemplo pequeño:
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)
Esto mueve la entidad hacia adelante cada frame.
Lo importante es cave.getDeltaTime(). Como update() se ejecuta cada frame, multiplicar el movimiento por delta time mantiene la velocidad constante aunque cambie la tasa de frames.
Leyendo Propiedades Personalizadas
Hardcodear valores está bien para una primera prueba, pero las propiedades editables suelen ser mejores para objetos reales del juego.
Por ejemplo, en lugar de escribir:
self.speed = 2.0
Puedes leer el valor desde las propiedades de la entidad:
self.speed = self.entity.properties.get("speed", 2.0)
Esto significa:
- Si la entidad tiene una propiedad
speed, úsala. - Si no, usa
2.0como valor por defecto.
Esto es muy útil para scripts reutilizables. Puedes crear un script SimpleMover y usarlo en varias entidades, cada una con diferente velocidad.
Por ejemplo:
| Entidad | Propiedad speed |
|---|---|
| Plataforma Lenta | 1.0 |
| Plataforma Rápida | 4.0 |
| Peligro en Movimiento | 7.0 |
El script es el mismo, pero el comportamiento cambia según la entidad.
Alternativamente, puedes crear variables modificables localmente para el propio Component en lugar de depender de las propiedades de la Entidad. Cuando creas una variable así:
import cave
class PlatformMover(cave.Component):
# Esto será local:
speed = 2.0
def start(self, scene: cave.Scene):
pass
def update(self):
events = cave.getEvents()
La variable speed será modificable localmente en cada instancia del componente:

Obteniendo Entidades Hijas
Muchos objetos en Cave están construidos como pequeñas jerarquías.
La plantilla de jugador es un buen ejemplo. La entidad raíz Player contiene la física y lógica de personaje, mientras que la entidad hija Mesh tiene la malla visual del personaje y el Componente Animation.
Así que, si un script en la entidad raíz del jugador quiere reproducir animaciones, primero obtiene la entidad hija mesh:
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)
Este es el mismo patrón usado por el controlador de jugador por defecto:
- Obtén la entidad hija.
- Obtén el componente de esa hija.
- Usa el componente cuando sea necesario.
Una vez entiendas ese patrón, muchos scripts de Cave son mucho más fáciles de leer.
El método getChild tiene un parámetro opcional "recursive" que por defecto es True. Si es True, buscará en todos los hijos de la entidad, incluyendo hijos de hijos, hasta encontrar la entidad que solicitaste por nombre.
Obteniendo Entidades de la Escena (Consultas de Escena)
Al crear un juego, es muy probable que necesites obtener otras entidades dentro de la escena. Así que exploremos eso. El primer paso es obtener la escena misma, y en Cave, tienes dos formas de hacerlo:
# Devuelve la escena activa:
scene = cave.getScene()
# Devuelve la escena a la que pertenece la entidad:
scene = self.entity.getScene()
Para mayor comodidad, los métodos start y end de cave.Component también reciben la escena como parámetro, ya que es muy probable que los uses en esos métodos. Para código local, como el Python Code Component, también hay una variable scene definida por defecto que puedes "usar mágicamente" y esperar que funcione.
Una vez que tengas la escena, puedes obtener una Entidad específica por su nombre usando el siguiente código:
watchtower = scene.get("Watch Tower 01")
Cave proporciona muchos otros métodos en la clase escena para que hagas otras consultas sobre la escena. Puedes hacer ray casts, sphere casts, comprobar una caja o esfera de contacto para consultas de colisión básicas, o incluso obtener todas las entidades, todas las entidades raíz, todas las entidades con una etiqueta específica, todas las entidades con propiedades específicas, o con un nombre específico, etc. Así que vale la pena revisar la API de Python para más detalles.
Recuerda siempre verificar si tu consulta devolvió algo válido. Por ejemplo:
# Consultando una Entidad inexistente:
ent = scene.get("This Entity Doesnt Exist")
if ent is None:
print("Entidad inválida!")
Obtener Componentes de una Entidad
Una vez que tienes una entidad específica y verificas que no es nula, es buena idea entender cómo obtener componentes específicos de ella.
La entidad tiene un método específico llamado get al que le puedes pasar el nombre del componente como cadena, y automáticamente busca en la entidad si hay un componente que coincida con tu búsqueda:
animator = self.entity.get("Animation Component")
Para facilitarte la vida, si el nombre de un componente termina con la palabra "Component", lo cual es muy común, puedes omitir completamente esta terminación al escribir el nombre del componente en este método. También puedes elegir si quieres incluir espacios en nombres compuestos o juntarlo todo.
Por ejemplo, si quieres obtener el Rigid Body Component de una Entidad, aunque su nombre en Python sea RigidBodyComponent, todas las opciones siguientes funcionarán:
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")
Dado que Python no es fuertemente tipado, es buena práctica en Cave proporcionar una pista de tipo para el componente, lo que puede hacerse de la siguiente manera. Nota que en este caso debes incluir el nombre completo del componente, porque es una semántica de Python:
rb : cave.RigidBodyComponent = self.entity.get("Rigid Body")
Esto permite que IntelliSense funcione en editores externos como Visual Studio Code o incluso el autocompletado incorporado que Cave Engine ofrece en su editor de scripts integrado.
Para el Transform Component, al ser uno de los tipos de componentes más comunes y que consultarás frecuentemente, la Entidad tiene un método nativo para obtener su Transform principal:
transf = self.entity.getTransform()
Obtenerlo llamando self.entity.getTransform() da el mismo resultado que llamando self.entity.get("Transform"), pero la primera opción es más rápida y optimizada.
Si una entidad tiene múltiples componentes del mismo tipo, retornará la primera coincidencia, pero a veces puedes querer obtener todas las coincidencias. Por ejemplo, en una malla con múltiples materiales que en Cave se representa por una entidad con varios componentes mesh, puede que quieras obtener todos los componentes mesh. Para eso puedes usar el método getAll:
meshCmps = self.entity.getAll("Mesh")
# Cambiando todos los materiales a uno brillante:
for meshCmp in meshCmps:
meshCmp.material.setAsset("Glowing Material")
Obtener Componentes Python de una Entidad
Ahora sabemos cómo obtener componentes nativos de Cave, pero ¿qué pasa si quieres obtener de una Entidad un componente que fue escrito por ti usando Python?
Para eso necesitas un método especial llamado getPy, que funciona igual que el método normal get, salvo que este también devuelve componentes Python:
myCmp = self.entity.getPy("MyCustomComponent")
Se requiere un método especial debido a optimizaciones internas para asegurar que Cave funcione lo más rápido posible.
Una vez que tienes tu Componente Python personalizado, puedes acceder libremente a sus variables y métodos hechos en Python:
myCmp = self.entity.getPy("MyCustomComponent")
# Modificando variables Python:
myCmp.customValue = 10
# Llamando métodos personalizados:
myCmp.doSomething()
myCmp.applyDamage(10)
Python Code Component
Además del componente Python regular, Cave también tiene un Python Code Component. Este componente es útil para scripts rápidos escritos directamente en la entidad, sin crear un asset de Python Script por separado.
Tiene todos los demás métodos, y la diferencia es que en el Python Code Component escribes el script Python directamente dentro del componente, no es modular ni reusable. Así que si creas una copia de la entidad, también se crea una copia del script. Pero a veces esto puede ser una forma más rápida de crear una lógica simple, como una moneda que gira.
Es bueno para:
- Pruebas rápidas.
- Callbacks pequeños.
- Comportamientos puntuales.
- Prototipos.
No es la mejor opción para sistemas de juego más grandes porque el código es más difícil de reutilizar y organizar, pero es óptimo para códigos pequeños.
Python Component vs Python Code Component
Usa esta regla simple:
| Usa esto | Cuando |
|---|---|
| Python Component | El comportamiento debe ser reutilizado, editado como un asset o crecer con el tiempo. |
| Python Code Component | El comportamiento es pequeño y local. |
Por ejemplo, un EnemyAI reutilizable debería ser un asset Python Script usado por un Python Component. Un código pequeño que imprime algo o llama una función cuando un botón es presionado puede ser un Python Code Component.
Un buen primer objetivo para un script
Un buen primer script en Cave es algo pequeño y visible.
Intenta construir uno de estos:
- Una plataforma que se mueve hacia adelante.
- Una puerta que se abre cuando inicia la escena.
- Una luz que se enciende y apaga cada pocos segundos.
- Un objeto para recoger que reproduce un sonido y se desactiva.
- Un botón que cambia a otra escena.
Estos ejemplos son pequeños, pero enseñan la flujo de trabajo más importante: obtener la entidad, obtener el componente, cambiar algo, probar en modo Play y ajustar.
Lo que debes recordar
Los scripts Python en Cave normalmente se adjuntan a entidades a través de Python Components.
El patrón más importante para principiantes es:
- Usa
start()para obtener referencias y preparar valores. - Usa
update()para ejecutar comportamiento en cada frame. - Usa
self.entitypara acceder a la entidad que posee el script. - Usa componentes para mover, animar, reproducir sonidos o controlar el objeto.
Una vez que este patrón te resulte natural, programar en Cave será mucho menos misterioso. No solo escribes código, enseñas a las entidades cómo comportarse.