Cave: Guía de Inicio
Cave: Guía para Empezar
Lesson 13 of 19 • 25 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 entendamos cómo funcionan los personajes y las animaciones en Cave. Un personaje no es solo un modelo 3D que se mueve por el nivel. En un juego real, usualmente combina física, lógica de movimiento, una malla visible, un esqueleto (armature), animaciones y código o Logic Bricks que deciden qué animación debe reproducirse.
Para hacerlo práctico, usaremos la plantilla predeterminada Player de los proyectos iniciales de Cave como referencia principal. Si creas un Third Person Game o Top Down Game, Cave genera un jugador que ya se mueve, tiene un personaje animado visible y reproduce animaciones básicas de locomoción.

Esta lección te mostrará cómo se organiza esa configuración y cómo puedes controlar las animaciones desde Python.
Aprenderás:
- Cómo está construida la plantilla inicial
Player. - Por qué la malla visual es una entidad hija en lugar de estar en la entidad raíz del jugador.
- Qué hace el Animation Component.
- Cómo obtener el animador desde Python (la lógica es similar para Logic Bricks).
- Cómo reproducir animaciones por nombre.
- Cómo funcionan el blending, las capas y los filtros de huesos.
- Cómo encajan las callbacks y sockets de animación en el sistema.
Estructura de la plantilla Player
En el proyecto inicial, el Player es una Entity Template. Esto significa que la configuración del jugador es reutilizable y puede colocarse en múltiples escenas.
La estructura es más o menos así:

Los hijos exactos pueden variar según las opciones del proyecto que hayas seleccionado, pero la idea importante es que la entidad raíz Player posee la configuración de juego, mientras que la entidad hija Mesh posee el personaje animado visible.
El enemigo inicial usa una idea muy similar. La entidad raíz del enemigo tiene la física y el comportamiento del personaje, y su entidad hija Mesh contiene la malla visible y el Animation Component.
La Entidad Raíz Player
La entidad raíz Player representa el personaje en el juego. Usualmente contiene:
- Un
Transform Component. - Un
Character Component. - Componentes Python para el movimiento del jugador, UI, auxiliares de animación y otra lógica del juego.
- Propiedades como la salud o configuraciones opcionales de comportamiento.
- Hijos usados para cámara, UI, malla visual y objetos auxiliares.
El Character Component es especialmente importante porque maneja la física estilo personaje: caminar, saltar, colisiones, pendientes y movimiento contra el mundo. Esto significa que la raíz Player es principalmente responsable del juego y la física.
La Entidad Hija Mesh
Dentro de la plantilla del jugador, hay una entidad hija llamada Mesh. Esta hija usualmente contiene:
- Un
Transform Component. - Uno o más
Mesh Components. - Un
Animation Component.
El Mesh Component da al personaje su modelo 3D visible y material. Si el personaje usa múltiples materiales, Cave puede representarlo con múltiples Mesh Components, siguiendo la misma regla de multimaterial explicada en la lección de importación.
El Animation Component es lo que evalúa el esqueleto y reproduce las animaciones.
Entonces, de forma simple:
| Entidad | Responsabilidad Principal |
|---|---|
Player |
Física, movimiento, lógica de juego, propiedades. |
Player -> Mesh |
Modelo visible, material, animación de esqueleto. |
Esta separación es intencional.
Por Qué la Malla Es una Entidad Hija
Podrías preguntarte por qué la malla no está colocada directamente en la entidad raíz Player.
La razón es que la física del personaje y el personaje animado visible a menudo necesitan transformaciones diferentes.
El transform de la raíz Player representa el cuerpo en el juego. Es lo que se mueve por el mundo, colisiona con paredes y lleva el Character Component. El transform hijo Mesh representa cómo se ve el personaje.
Esa separación es útil en muchas situaciones:
- La malla puede necesitar una escala diferente a la cápsula de física.
- La malla puede necesitar un pequeño offset para alinearse con la colisión del personaje.
- La malla puede necesitar rotar de forma independiente al cuerpo en movimiento.
- La malla puede necesitar mirar hacia la dirección del movimiento mientras la raíz mantiene una orientación específica para el juego.
- La malla puede necesitar mantenerse mirando hacia adelante mientras el jugador se mueve lateralmente.
Por ejemplo, imagina que el jugador se mueve hacia la izquierda. Si tienes una animación adecuada de "caminar a la izquierda", puedes querer que la malla del personaje siga mirando hacia adelante mientras la animación maneja el movimiento lateral. Pero si no tienes una animación lateral, puedes querer que la malla rote hacia la izquierda para que el personaje visualmente camine en esa dirección.
Ambos casos son válidos.
Requieren transformaciones separadas:
| Transform | Controla |
|---|---|
Transform raíz Player |
Posición física, cuerpo de juego, movimiento en el mundo. |
Transform hijo Mesh |
Orientación visual, escala, offsets, presentación de animación. |
Por eso el jugador inicial y el enemigo mantienen la malla animada como una entidad hija.
Qué Hace el Animation Component
El Animation Component es el componente principal usado para reproducir animaciones esqueléticas en una entidad.
Necesita:
- Un
Armature. - Una
Animaciónpor defecto. - Un Mesh Component válido en la misma entidad (o varios).
El armature define el esqueleto. La animación define cómo ese esqueleto se mueve a lo largo del tiempo. El Animation Component evalúa la pose animada final y la aplica al personaje visible.
En el jugador inicial por defecto, el hijo Mesh usa:
Proto MeshProto MatProto Armaturep-idlecomo animación por defecto (animación de reposo)
Esos assets iniciales están ahí para que puedas inspeccionar inmediatamente un personaje animado funcionando.
Armatures, Animaciones y Retargeting
- Un
Armaturees el esqueleto del personaje. Contiene los huesos a los que la malla sigue. - Una
Animaciónalmacena movimiento a lo largo del tiempo para los huesos en un armature.
El Animation Component conecta esas piezas:
| Pieza | Significado |
|---|---|
| Malla | El modelo visible del personaje. |
| Armature | El esqueleto dentro del personaje. |
| Animación | El movimiento, como idle, caminar, correr o caer. |
| Animation Component | El componente que reproduce la animación en la entidad. |
Cave también puede hacer retargeting de animaciones cuando es posible. Si la animación que se reproduce pertenece a un armature compatible diferente, el Animation Component puede usar retargeting para aplicar ese movimiento al armature actual.
El retargeting es útil cuando quieres reutilizar animaciones entre personajes compatibles, pero aún depende de la calidad y compatibilidad de los rigs importados. Si una animación se ve torcida, desplazada o extraña, revisa el rig fuente, el armature importado y la configuración de retargeting.
Obteniendo el Animator desde Python
Ahora empecemos a explorar cómo podemos animar personajes mediante lógica.
En proyectos Cave, es común mantener la lógica de juego del jugador en la entidad raíz Player, y luego acceder a la hija Mesh desde ese código. Los scripts iniciales por defecto siguen esta idea.
Aquí está el patrón básico:
import cave
class PlayerAnimationExample(cave.Component):
def start(self, scene: cave.Scene):
self.mesh : cave.Entity = self.entity.getChild("Mesh")
self.animator : cave.AnimationComponent = self.mesh.get("Animation")
def update(self):
# Ejemplo: reproduciendo una animación de reposo.
self.animator.playByName("p-idle", blend=0.2, loop=True)
En este ejemplo:
self.entityes la entidad raízPlayer.getChild("Mesh")encuentra la entidad hija visual.self.mesh.get("Animation")obtiene el Animation Component.- La variable se llama
animator, que es la práctica común de nomenclatura en scripts Cave. playByName(...)reproduce un asset de animación por nombre.
Esta es la conexión básica que necesitas antes de controlar animaciones mediante código.
Reproduciendo animaciones por nombre
El método más común que usarás es playByName.
Su uso básico es así:
self.animator.playByName("p-walk", blend=0.2, loop=True)
Los parámetros importantes son:
| Parámetro | Significado |
|---|---|
anim |
El nombre del asset de animación que se desea reproducir. |
blend |
Cuánto tiempo, en segundos, debe Cave mezclar para la nueva animación. |
loop |
Si la animación debe repetirse. |
layer |
Qué capa de animación debe reproducir la animación. |
Por ejemplo:
self.animator.playByName("p-idle", blend=0.2, loop=True)
self.animator.playByName("p-walk", blend=0.2, loop=True)
self.animator.playByName("p-run", blend=0.2, loop=True)
self.animator.playByName("p-fall", blend=0.2, loop=True)
Estas son las mismas llamadas que usan los scripts por defecto del jugador y del enemigo.
Un ejemplo simple de locomoción
Una configuración común de animación para el jugador es:
- Reproducir idle cuando el personaje está quieto.
- Reproducir walk cuando el personaje se mueve.
- Reproducir run cuando el personaje se mueve corriendo.
- Reproducir fall cuando el personaje no está en el suelo.
Aquí hay un ejemplo simplificado:
import cave
class SimplePlayerAnimator(cave.Component):
def start(self, scene: cave.Scene):
self.character : cave.CharacterComponent = self.entity.get("Character")
self.mesh : cave.Entity = self.entity.getChild("Mesh")
self.meshTransform : cave.TransformComponent = self.mesh.getTransform() if self.mesh else None
self.animator : cave.AnimationComponent = self.mesh.get("Animation") if self.mesh else None
def update(self):
if self.animator is None or self.character is None:
return
direction = self.character.getWalkDirection()
isMoving = direction.length() > 0
isRunning = False # Reemplaza esto con tu propia entrada o condición de juego.
if self.character.onGround():
if isMoving:
if isRunning:
self.animator.playByName("p-run", blend=0.2, loop=True)
else:
self.animator.playByName("p-walk", blend=0.2, loop=True)
else:
self.animator.playByName("p-idle", blend=0.2, loop=True)
else:
self.animator.playByName("p-fall", blend=0.2, loop=True)
Este ejemplo es intencionalmente simple. El controlador inicial real también maneja la entrada, la dirección del movimiento, saltos, comportamiento opcional de apuntar y hacer clic, y la rotación del mesh, pero la idea de la animación es la misma.
Rotar el Mesh hacia el movimiento
Debido a que la entidad visual Mesh tiene su propia transformación, puedes rotarla separadamente del Player raíz.
El jugador inicial hace esto cuando el personaje se mueve:
if direction.length() > 0 and self.meshTransform:
self.meshTransform.lookAtSmooth(
self.entity.getTransform().transformDirection(-direction),
6.0 * cave.getDeltaTime()
)
La idea importante no es la matemática exacta. La idea importante es que el cuerpo de juego y el mesh visual pueden ser controlados por separado.
Esto te permite escoger cómo debe orientarse el personaje:
- Mirar hacia la dirección del movimiento.
- Mantener la orientación hacia adelante mientras se mueve lateralmente.
- Rotar suavemente hacia la dirección deseada.
- Usar reglas de orientación visual diferentes para distintos modos de juego.
Esta es una de las razones principales por las que el personaje inicial tiene una entidad hija Mesh.
Mezcla de Animaciones
La mezcla de animaciones hace que las transiciones sean más suaves.
Sin mezcla, cambiar de una animación a otra puede ser instantáneo y brusco. Con mezcla, Cave puede transicionar suavemente entre animaciones en la misma capa.
Por ejemplo:
# De esto:
self.animator.playByName("p-idle", blend=0.2, loop=True)
# A esto:
self.animator.playByName("p-walk", blend=0.2, loop=True)
Aquí, blend=0.2 significa que Cave mezclará hacia la nueva animación durante 0.2 segundos.
Esto es especialmente importante para personajes. Un jugador puede notar cambios bruscos en la animación muy fácilmente, incluso en un prototipo.
Buenos valores iniciales para blend suelen ser pequeños:
0.1para transiciones muy rápidas.0.2para transiciones normales en locomoción.0.4o más para transiciones lentas o pesadas.
Deberías ajustar esto según la sensación que quieres.
Capas de Animación
Cave soporta múltiples capas de animación. Cada capa puede reproducir su propia animación, y capas superiores pueden superponerse a las inferiores. Puedes ejecutar animaciones en cualquier capa que desees.
La animación de locomoción predeterminada usualmente corre en la capa 0.
Por ejemplo:
self.animator.playByName("p-walk", blend=0.2, layer=0, loop=True)
Si tienes una animación de acción para la parte superior del cuerpo, como atacar, apuntar o recargar, puedes reproducirla en otra capa:
self.animator.playByName("Attack", blend=0.1, layer=1, loop=False)
La idea es:
| Capa | Propósito Común |
|---|---|
| Capa 0 | Locomoción de cuerpo completo, como idle, caminar, correr, saltar, caer. |
| Capa 1 | Acciones de la parte superior del cuerpo, como atacar, apuntar, recargar, sostener arma. |
Esto permite que el personaje siga caminando mientras otra capa añade una acción encima.
Pesos de Capa
Cada capa tiene un peso, que controla cuánto influye esa capa.
Puedes cambiarlo desde Python:
self.animator.setLayerWeight(1, 1.0)
También puedes leerlo:
weight = self.animator.getLayerWeight(1)
Un peso de 1.0 significa que la capa está completamente activa. Un peso de 0.0 significa que no tiene influencia visible.
Los pesos de capa son útiles cuando quieres desvanecer una capa de acción, como subir lentamente un arma, apuntar o mezclar en una postura especial.
Vale la pena mencionar que el parámetro blend solo mezcla animaciones dentro de la misma capa. No mezclamos animaciones que se reproducen en diferentes capas. Entonces, si tienes una animación en la capa 0 y luego de repente reproduces otra en la capa 1, sin importar el valor de blend, no habrá mezcla entre ellas. Solo se mezcla si ya había otra animación ejecutándose en la capa 1. Si quieres mezclar entre capas, necesitas crear una lógica personalizada que use el peso de la capa para hacerlo.
Filtros de Huesos
Los filtros de huesos controlan qué huesos son afectados por una capa y cuánto influye cada uno.
Esto es lo que hace posible la animación de la parte superior del cuerpo.
Por ejemplo, podrías querer:
- La capa 0 controle todo el cuerpo.
- La capa 1 controle solo la columna, brazos, manos y huesos del arma.
En Python, puedes crear un filtro para una capa y asignar influencia a un hueso y sus hijos:
def setupUpperBodyLayer(self):
armature = self.animator.armature.get()
spine = armature.getBone("mixamorig:Spine")
upperBody = self.animator.createLayerFilter(1)
upperBody.defaultBlend = 0.0
upperBody.setToBone(spine, 1.0, recursive=True)
En este ejemplo:
defaultBlend = 0.0significa que por defecto la capa no afecta huesos.setToBone(spine, 1.0, recursive=True)significa que la columna y sus hijos son afectados completamente.- La capa
1ahora puede usarse para animaciones de la parte superior del cuerpo.
Los nombres de tus huesos dependen del armature que importaste. Siempre inspecciona tu armature y usa los nombres correctos para tu personaje.
Ejemplo Práctico de Capas
Imagina un personaje en tercera persona que puede caminar y atacar al mismo tiempo.
Una configuración posible es:
| Capa | Lo que Maneja |
|---|---|
| Capa 0 | Idle, caminar, correr, caer. |
| Capa 1 | Ataque de la parte superior del cuerpo. |
El código podría verse así:
import cave
class CombatAnimator(cave.Component):
def start(self, scene: cave.Scene):
self.mesh = self.entity.getChild("Mesh")
self.animator : cave.AnimationComponent = self.mesh.get("Animation") if self.mesh else None
if self.animator:
armature = self.animator.armature.get()
spine = armature.getBone("mixamorig:Spine")
upperBody = self.animator.createLayerFilter(1)
upperBody.defaultBlend = 0.0
upperBody.setToBone(spine, 1.0, recursive=True)
self.animator.setLayerWeight(1, 1.0)
def playWalk(self):
self.animator.playByName("p-walk", blend=0.2, layer=0, loop=True)
def playAttack(self):
self.animator.playByName("Attack", blend=0.1, layer=1, loop=False)
Este ejemplo asume que tienes un asset de animación llamado Attack. Si tu proyecto usa un nombre diferente para la animación, usa ese nombre.
La idea importante es que la locomoción permanece en la capa 0, mientras que el ataque se reproduce en la capa 1 y afecta solo los huesos filtrados.
Callbacks de Animación
Las animaciones pueden ejecutar código Python en momentos específicos.
Cave soporta callbacks tales como:
- Al iniciar la animación.
- Al terminar la animación.
- En un cuadro específico de la animación.
Los callbacks son útiles cuando la animación debe disparar eventos de juego o efectos.
Ejemplos:
- Reproducir sonido de paso.
- Generar polvo al pisar.
- Aplicar daño en un cuadro de ataque.
- Iniciar el rastro de un arma.
- Activar un efecto de partículas.
- Notificar a la lógica que la animación terminó.
Las animaciones suelen conocer mejor el momento exacto que el código. Si una espada debe hacer daño solo cuando el golpe llega a la zona objetivo, un callback de animación puede colocar ese momento de juego en el cuadro correcto.
Ejemplo de Callback de Paso
Los proyectos iniciales pueden incluir callbacks de paso en animaciones de caminar y correr. Inspeccionarlos es una buena manera de ver un callback en acción.
La idea es simple:
- La animación sabe cuándo el pie toca el suelo.
- El callback se coloca en ese cuadro.
- El callback reproduce un sonido o genera un pequeño efecto.
Dentro de un callback de animación, Cave provee variables útiles como:
entity, la entidad dueña.animator, el Animation Component.handle, la capa/manejo de animación que se está reproduciendo.
Un callback muy pequeño para un paso podría verse así:
cave.playSound("Footstep Grass", volume=0.5)
Luego puedes ampliar esta idea para elegir diferentes sonidos dependiendo del material del suelo, velocidad del personaje o estado actual.
Callbacks de Animación Reutilizables
Los callbacks pertenecen al asset de animación.
Esto significa que si múltiples entidades reproducen la misma animación, el callback se ejecutará para cada entidad que la use.
Esto hace que los callbacks sean reutilizables. Por ejemplo, la misma animación de caminar puede disparar sonidos de pasos para todos los personajes que la reproduzcan, siempre que el código del callback use correctamente la entidad dueña.
La animación almacena el instante en que ocurre. La entidad proporciona el contexto.
Callbacks Avanzados de Pose
Cave también soporta callbacks post-evaluación a través de Python. Estos ocurren después de que el Animation Component evalúa la pose del armature.
Esta es una característica avanzada, pero puede usarse para:
- Cinemática inversa (IK).
- Apuntar con la cabeza.
- Apuntar con armas.
- Colocación de pies.
- Ajustes finales de la pose.
El Player Toolkit inicial incluye un ejemplo de Foot IK que usa este concepto. Obtiene el hijo Mesh, el componente Animation, y luego registra un método con:
self.animator.addPostEvaluationCallback(self.postEvaluation)
No necesitas escribir sistemas IK inmediatamente, pero es útil saber que Cave permite a Python ajustar la pose final después de la reproducción normal de animaciones.
Componente Animation Socket
El Animation Socket Component permite que una entidad hija siga un hueso de una entidad padre animada.
La entidad hija debe estar bajo un padre que tenga un Animation Component. Entonces el socket puede elegir un hueso y copiar posición, rotación y opcionalmente escala desde ese hueso, con desplazamientos si es necesario.
Los sockets son útiles para adjuntar cosas a personajes animados:
- Espada en una mano.
- Pistola en una mano.
- Escudo en un brazo.
- Casco en la cabeza.
- Mochila en un hueso de la columna vertebral.
- Objeto vinculado a una mano.
Por ejemplo, si un personaje sostiene una espada, esta puede ser una entidad hija con un Animation Socket Component que sigue el hueso de la mano. A medida que el personaje ataca, corre o está en reposo, la espada se mantiene adherida a la posición animada correcta.
Lo que debes recordar
- El jugador inicial es una plantilla con una entidad raíz
Playery una entidad hijaMesh. - La raíz
Playersuele manejar la física, el movimiento, las propiedades y la lógica del juego. - La entidad hija
Meshgeneralmente maneja el modelo visible, el material, la armadura y el Animation Component. - Esta separación da a la física y al personaje visual transformaciones separadas.
- El Animation Component reproduce animaciones esqueléticas usando un armature y recursos de animación.
- En Python, es común llamar al Animation Component
animator. playByNamereproduce un recurso de animación por nombre y soporta mezcla, bucle y capas.- Las capas permiten superponer múltiples animaciones.
- Los filtros de huesos permiten que una capa afecte solo una parte del esqueleto.
- Los callbacks de animación conectan el tiempo de la animación con eventos del juego.
- Los animation sockets adjuntan objetos a huesos animados.
Cuando inspecciones la plantilla inicial Player o Enemy, usa esta estructura como referencia: entidad raíz para la jugabilidad, entidad hija Mesh para los visuales y animación.