Cave: Guia de Introdução
Cave: Guia de Início Rápido
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.
Agora que você viu como personagens e animação funcionam no Cave, vamos dar um passo atrás e entender o sistema de scripts que geralmente conecta tudo: Python.
Python é usado no Cave para escrever o comportamento do gameplay, ferramentas do editor, callbacks da interface, callbacks de animação, eventos da timeline e pequenos pedaços de lógica customizada que seriam específicos demais para existir como um componente embutido. Você não precisa se tornar um programador avançado em Python antes de usar o Cave, mas é muito útil entender a forma básica de um script Cave.
Nesta lição, você aprenderá:
- Para que o Python é usado no Cave.
- Como os assets Python Script e Componentes Python trabalham juntos.
- O que
start()eupdate()fazem. - Como acessar a entidade atual a partir de um script.
- Como obter componentes de uma entidade.
- Quando usar um Python Component ou um Python Code Component.
O objetivo não é ensinar toda a linguagem Python. O objetivo é fazer com que scripts Cave fiquem compreensíveis quando você os abrir.
Onde Aprender Python?
Se você não sabe programar em Python, o Uniday Studio na verdade oferece quests de aprendizado gratuitas sobre Python também. Vá para uniday.studio/learn para ver todas as opções ou comece aqui:
Para esta seção, vamos assumir que você já tem uma compreensão dos temas abordados nessas duas quests.
Para Que o Python é Usado no Cave
No Cave, Python é a camada de scripting que você usa quando um objeto do jogo precisa de comportamento.
Por exemplo, Python pode ser usado para:
- Mover um jogador ou inimigo.
- Abrir uma porta.
- Tocar uma animação.
- Acionar um som.
- Iniciar uma timeline.
- Trocar de cenas.
- Atualizar um elemento da UI.
- Criar ferramentas customizadas para o editor.
Basicamente, você pode escrever Python Scripts para criar toda a lógica do seu jogo.
Por isso o projeto inicial já contém scripts Python. O jogador padrão, por exemplo, não é só uma malha com animação. Ele também tem lógica de gameplay que lê entrada, move o personagem, rotaciona a malha e toca a animação correta.
Então, quando você escreve Python no Cave, geralmente não está escrevendo código isolado. Está escrevendo lógica que controla uma entity e conversa com os componentes ligados a essa entity.
Assets de Script e Componentes Python
O código Python geralmente fica dentro de um asset chamado Python Script.

Depois, para fazer esse script rodar numa cena, você adiciona um Python Component a uma entity e escolhe qual classe do script deve ser executada.
Pense assim:
| Parte | O Que Faz |
|---|---|
| Asset Python Script | Armazena o código. |
| Python Component | Roda uma classe daquele script numa entity. |
| Entity | O objeto controlado pelo script. |
Classe cave.Component |
O comportamento real que você escreveu. |
Por exemplo, você pode ter um asset script chamado Door Controller. Dentro dele, pode ter uma classe chamada DoorController que herda de cave.Component. Então você adiciona um Python Component à sua entity porta e seleciona essa classe.
Essa separação é importante porque o mesmo script pode ser reutilizado. Você pode colocar muitas portas na cena, cada uma usando o mesmo script controlador de portas, mas com propriedades diferentes ou objetos filhos diferentes.
Um Componente Cave Mínimo
Um componente Python básico no Cave fica assim:
import cave
class MyComponent(cave.Component):
def start(self, scene):
print("O componente iniciou!")
def update(self):
pass
Aqui alguns detalhes importantes:
import cavedá acesso ao seu script à API Python do Cave.class MyComponent(cave.Component)cria uma classe de componente que o Cave pode rodar.start(self, scene)roda quando o componente inicia.update(self)roda a cada frame enquanto o componente está ativo.
O nome MyComponent pode ser qualquer um, mas em projetos reais use nomes claros como DoorController, EnemyAI, Checkpoint ou PlayerHealth.
Métodos do Ciclo de Vida
O Cave chama alguns métodos automaticamente quando seu componente está rodando.
Os mais comuns são:
| Método | Quando Roda | Uso Comum |
|---|---|---|
start(self, scene) |
Quando o componente inicia. | Obter referências, ler propriedades, preparar variáveis. |
firstUpdate(self) |
Sempre após o start de todos os componentes da entidade, na primeira atualização. | Criar variáveis que dependem da inicialização de outros componentes. |
update(self) |
A cada frame, se a cena não estiver pausada. | Movimento, entrada, timers, checagens de estado. |
pausedUpdate(self) |
A cada frame, se a cena ESTIVER pausada. | Lógica em pausa. |
end(self, scene) |
Quando o componente termina. | Limpeza, se necessário. |
A maioria dos scripts para iniciantes usa start() e update(). Por exemplo, se você cria uma plataforma que se move, start() é um bom lugar para guardar a posição original e update() é onde você move a plataforma a cada frame.
Também existem os métodos editorUpdate e lateUpdate, mas não os exploraremos aqui por serem um pouco mais avançados.
Acessando a Entity Atual
Dentro de um componente Cave, self.entity é a entity que contém o Python Component.
Essa é uma das ideias mais importantes na scriptagem Cave. O script não fica solto na cena. Ele pertence a uma entity.
Aqui um exemplo simples:
import cave
class DoorController(cave.Component):
def start(self, scene):
self.transform = self.entity.getTransform()
self.isOpen = False
def update(self):
pass
Nesse script:
self.entityé a entity porta.self.entity.getTransform()pega o Component Transform da porta.self.isOpené uma variável usada pelo script para lembrar se a porta está aberta.
Você usará esse padrão sempre. Primeiro pega a entity, depois pega os componentes ou entidades filhas que precisa, e então usa na lógica.
Obtendo Outros Componentes
Para controlar uma entity, você geralmente precisa obter um ou mais componentes dela.
Por exemplo, um script de jogador pode obter:
- O componente
Transformpara mover ou rotacionar a entity. - O componente
Characterpara controle de movimento. - O componente
Animationde uma child entity mesh para tocar animações. - O componente
Audiopara tocar sons em loop.
Aqui um pequeno exemplo:
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)
Isso move a entity para frente a cada frame.
O importante é cave.getDeltaTime(). Como update() roda a cada frame, multiplicar o movimento pelo delta time mantém a velocidade constante mesmo se o frame rate variar.
Lendo Propriedades Customizadas
Valores fixos funcionam para um primeiro teste, mas propriedades editáveis geralmente são melhores para objetos reais do jogo.
Por exemplo, em vez de escrever:
self.speed = 2.0
Você pode ler o valor das propriedades da entity:
self.speed = self.entity.properties.get("speed", 2.0)
Isso significa:
- Se a entity tem uma propriedade
speed, use ela. - Se não, use o valor padrão
2.0.
Muito útil para scripts reutilizáveis. Você pode criar um script SimpleMover e usá-lo em várias entidades, cada uma com uma velocidade diferente.
Exemplo:
| Entity | Propriedade speed |
|---|---|
| Plataforma Lenta | 1.0 |
| Plataforma Rápida | 4.0 |
| Perigo em Movimento | 7.0 |
O script é o mesmo, mas o comportamento muda por entity.
Alternativamente, você pode criar variáveis modificáveis localmente para o próprio Component, em vez de depender das propriedades da Entity. Quando você cria uma variável assim:
import cave
class PlatformMover(cave.Component):
# Essa será local:
speed = 2.0
def start(self, scene: cave.Scene):
pass
def update(self):
events = cave.getEvents()
A variável speed será modificável localmente para cada instância do componente:

Obtendo Entities Filhas
Muitos objetos Cave são construídos como pequenas hierarquias.
O template player é bom exemplo. A entity raiz Player tem a física e lógica do personagem, enquanto a child entity Mesh tem a malha visual e o componente Animation.
Então, se um script na entity raiz quer tocar animações, ele primeiro obtém a entity filha 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)
Esse é o mesmo padrão usado pelo controlador player padrão:
- Pega a entity filha.
- Pega o componente daquela filha.
- Usa o componente quando necessário.
Quando você entender esse padrão, muitos scripts Cave ficam muito mais fáceis de ler.
O método getChild tem um parâmetro opcional "recursive", padrão para True. Se True, ele consulta todas as entities filhas, incluindo filhas de filhas, até encontrar a entity pelo nome.
Obtendo Entities da Cena (Consultas na Cena)
Ao criar um jogo, provavelmente você vai precisar obter outras entities na cena. Vamos explorar isso. O primeiro passo é obter a própria cena, e no Cave, você tem duas formas de fazer isso:
# Retorna a cena ativa:
scene = cave.getScene()
# Retorna a cena à qual a entidade pertence:
scene = self.entity.getScene()
Para conveniência, os métodos start e end do cave.Component também recebem a cena como parâmetro, já que é muito provável que você use isso nesses métodos. Para código local, como o Python Code Component, há também uma variável scene definida para você por padrão que pode ser "mágicamente usada" esperando que funcione.
Depois de obter a cena, você pode pegar uma Entidade específica pelo nome usando o seguinte código:
watchtower = scene.get("Watch Tower 01")
Cave oferece muitos outros métodos na classe scene para consultas diversas. Você pode fazer ray casts, sphere casts, checar uma caixa ou esfera de contato para consultas de colisão, ou até obter todas as entidades, todas as entidades raiz, todas as entidades com uma tag específica, todas as entidades com certas propriedades, ou com um nome específico, etc. Vale a pena consultar a API Python para mais detalhes.
Sempre lembre de verificar se sua consulta retornou algo válido. Por exemplo:
# Consultando uma Entidade inexistente:
ent = scene.get("This Entity Doesnt Exist")
if ent is None:
print("Entidade inválida!")
Obtendo Componentes da Entidade
Uma vez que você tenha uma entidade específica e tenha checado que ela existe, é uma boa ideia entender como obter componentes específicos dela.
A entidade possui um método chamado get onde você pode passar o nome do componente como string e ele automaticamente verifica se há um componente que corresponda à sua busca:
animator = self.entity.get("Animation Component")
Para facilitar sua vida, se um nome de componente termina com a palavra "Component", o que é muito comum, você pode omitir esse sufixo ao digitar o nome no método. Também pode escolher incluir ou não espaços em nomes compostos.
Por exemplo, para obter um Rigid Body Component de uma Entidade, embora o nome em Python seja RigidBodyComponent, todas as opções abaixo funcionarão:
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")
Como o Python não é fortemente tipado, é uma boa prática de programação no Cave fornecer uma dica de tipo para o tipo do componente, o que pode ser feito assim. Note que neste caso você precisa usar o nome completo do componente, pois é semântica do Python:
rb : cave.RigidBodyComponent = self.entity.get("Rigid Body")
Isso permite que o IntelliSense funcione em editores externos como Visual Studio Code, ou mesmo o autocomplete embutido que o Cave Engine oferece no editor de script embutido.
Para o Transform Component, já que é um dos tipos mais comuns e frequentemente consultado, a Entidade tem um método nativo para obter seu Transform principal:
transf = self.entity.getTransform()
Obter chamando self.entity.getTransform() fornece o mesmo resultado que self.entity.get("Transform"), mas a primeira opção é mais rápida e otimizada.
Se uma entidade tiver múltiplos componentes do mesmo tipo, o método get retornará a primeira correspondência, mas às vezes você pode querer obter todas as correspondências. Por exemplo, em uma malha com múltiplos materiais, representada no Cave por uma entidade com múltiplos componentes de malha, você pode querer obter todos eles. Para isso, use o método getAll:
meshCmps = self.entity.getAll("Mesh")
# Alterando todos os materiais para um que brilha:
for meshCmp in meshCmps:
meshCmp.material.setAsset("Glowing Material")
Obtendo Componentes Python da Entidade
Agora que sabemos como obter Componentes nativos do Cave, mas e se você quiser obter um componente personalizado escrito por você em Python?
Para isso, você precisa de um método especial chamado getPy, que funciona da mesma forma que o método get regular, mas que também retorna componentes Python:
myCmp = self.entity.getPy("MyCustomComponent")
Esse método especial é necessário por otimizações internas para garantir que o Cave rode o mais rápido possível.
Após obter seu Componente Python personalizado, você pode acessar livremente suas variáveis e métodos em Python:
myCmp = self.entity.getPy("MyCustomComponent")
# Alterando variáveis Python:
myCmp.customValue = 10
# Chamando métodos personalizados:
myCmp.doSomething()
myCmp.applyDamage(10)
Python Code Component
Além do Python Component regular, o Cave também tem o Python Code Component. Ele é útil para scripts rápidos escritos diretamente na entidade, sem criar primeiro um asset separado de Python Script.
Ele tem todos os outros métodos, mas a diferença é que no Python Code Component você escreve o script Python diretamente dentro do componente em si, não é modular nem reutilizável. Então, se você criar uma cópia da entidade, também criará uma cópia do script nela. Mas às vezes pode ser uma forma mais rápida de criar uma lógica simples, como a rotação de uma moeda.
É bom para:
- Testes rápidos.
- Pequenos callbacks.
- Comportamentos pontuais.
- Protótipos.
Não é a melhor opção para sistemas maiores de gameplay porque o código fica mais difícil de reutilizar e organizar, mas é ótimo para códigos pequenos.
Python Component vs Python Code Component
Use esta regra simples:
| Use Este | Quando |
|---|---|
| Python Component | O comportamento deve ser reutilizado, editado como asset ou crescer com o tempo. |
| Python Code Component | O comportamento é pequeno e local. |
Por exemplo, um EnemyAI reutilizável deve ser um asset Python Script usado pelo Python Component. Um código pequeno que imprime algo ou chama uma função quando um botão é pressionado pode ser um Python Code Component.
Um Bom Objetivo para o Primeiro Script
Um bom primeiro script no Cave é algo pequeno e visível.
Tente construir um destes:
- Uma plataforma que se move para frente.
- Uma porta que se abre quando a cena começa.
- Uma luz que liga e desliga a cada poucos segundos.
- Um item que toca um som e se desativa.
- Um botão que muda para outra cena.
Esses exemplos são pequenos, mas ensinam o fluxo de trabalho mais importante: pegar a entidade, pegar o componente, alterar algo, testar no Modo de Jogo, e ajustar.
O Que Você Deve Lembrar
Scripts Python no Cave geralmente ficam vinculados a entidades por meio dos Python Components.
O padrão mais importante para iniciantes é:
- Use
start()para obter referências e preparar valores. - Use
update()para executar o comportamento a cada frame. - Use
self.entitypara acessar a entidade que possui o script. - Use componentes para mover, animar, tocar som ou controlar o objeto.
Quando esse padrão parecer natural, programar no Cave deixa de ser um mistério. Você não está apenas escrevendo código. Você está ensinando entidades a se comportarem.