Cave: Guia de Introdução
Conceitos Básicos de Programação em Python
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ções funcionam no Cave, vamos dar um passo atrás e entender o sistema de script que normalmente conecta tudo: Python.
Python é usado no Cave para escrever comportamentos de jogabilidade, ferramentas de editor, callbacks de UI, callbacks de animação, eventos de linha do tempo e pequenos trechos de lógica personalizada que seriam muito específicos para existirem 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 do Cave.
Nesta lição, você aprenderá:
- Para que o Python é usado no Cave.
- Como os ativos de Script Python e os 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 Componente Python ou um Componente de Código Python.
O objetivo não é ensinar toda a linguagem Python. O objetivo é fazer os scripts do Cave parecerem compreensíveis quando você os abrir.
Onde Aprender Python?
Se você não sabe como programar em Python, Uniday Studio na verdade oferece maneiras de aprendizado gratuitas sobre Python também. Vá para uniday.studio/learn para ver todas as opções ou comece aqui:
- Fundamentos do Python: Seus Primeiros Passos na Programação
- Programação Orientada a Objetos (OOP) em Python
Para esta seção, vamos assumir que você já tem uma compreensão sobre os tópicos tratados nesses dois aprendizados.
Para Que o Python É Usado no Cave
No Cave, o Python é a camada de script que você usa quando um objeto de jogo precisa de comportamento.
Por exemplo, o Python pode ser usado para:
- Mover um jogador ou inimigo.
- Abrir uma porta.
- Tocar uma animação.
- Acionar um som.
- Iniciar uma linha do tempo.
- Mudar cenas.
- Atualizar um elemento da UI.
- Criar ferramentas de editor personalizadas.
Basicamente, você pode escrever Scripts Python para criar t toda a lógica do seu jogo.
É por isso que o projeto inicial já contém scripts Python. O jogador padrão, por exemplo, não é apenas uma malha com uma animação. Ele também possui lógica de jogabilidade que lê entradas, move o personagem, rotaciona a malha e toca a animação correta.
Portanto, quando você escreve Python no Cave, geralmente não está escrevendo código isolado. Você está escrevendo lógica que controla uma entidade e se comunica com os componentes anexados a essa entidade.
Ativos de Script e Componentes Python
O código Python geralmente vive dentro de um ativo de Script Python.

Então, para fazer esse script rodar em uma cena, você adiciona um Componente Python a uma entidade e escolhe qual classe do script deve ser executada.
Pense assim:
| Parte | O Que Faz |
|---|---|
| Ativo de Script Python | Armazena o código. |
| Componente Python | Executa uma classe desse script em uma entidade. |
| Entidade | O objeto controlado pelo script. |
Classe cave.Component |
O comportamento real que você escreveu. |
Por exemplo, você pode ter um ativo de script chamado Controlador de Porta. Dentro dele, você pode ter uma classe chamada DoorController. que herda de cave.Component. Então você adiciona um Componente Python à sua entidade 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 de controlador de porta, mas com propriedades diferentes ou diferentes objetos filhos.
Um Componente Python Mínimo
Um componente Python básico do Cave se parece com isto:
import cave
class MyComponent(cave.Component):
def start(self, scene):
print("O componente começou!")
def update(self):
pass
Existem alguns detalhes importantes aqui:
import cavedá ao seu script acesso à API Python do Cave.class MyComponent(cave.Component)cria uma classe de componente que o Cave pode executar.start(self, scene)é acionado quando o componente começa.update(self)é executado a cada quadro enquanto o componente está ativo.
O nome MyComponent pode ser qualquer coisa que você queira, mas em projetos reais você deve usar um nome claro como DoorController, EnemyAI, Checkpoint ou PlayerHealth.
Métodos de Ciclo de Vida
O Cave chama alguns métodos automaticamente quando seu componente está em execução.
Os mais comuns são:
| Método | Quando É Executado | Uso Comum |
|---|---|---|
start(self, scene) |
Quando o componente começa. | Obter referências, ler propriedades, preparar variáveis. |
firstUpdate(self) |
Sempre após o método start de cada Componente de Entidade, na primeira atualização. | Criar variáveis que dependem de outros componentes para terem sido inicializados. |
update(self) |
A cada quadro, se a cena não estiver pausada. | Movimento, entrada, temporizadores, verificações de estado. |
pausedUpdate(self) |
A cada quadro, se a Cena ESTIVER pausada. | Lógica pausada. |
end(self, scene) |
Quando o componente termina. | Limpar se necessário. |
A maioria dos scripts iniciantes usa start() e update(). Por exemplo, se você estiver criando uma plataforma móvel, start() é um bom lugar para armazenar a posição original, e update() é onde você move a plataforma a cada quadro.
Também temos os métodos editorUpdate e lateUpdate, mas não vamos explorá-los aqui, pois são um pouco mais avançados.
Acessando a Entidade Atual
Dentro de um componente do Cave, self.entity é a entidade que possui o Componente Python.
Esta é uma das ideias mais importantes na scriptagem do Cave. O script não flutua pela cena por conta própria. Ele pertence a uma entidade.
Aqui está 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
Neste script:
self.entityé a entidade da porta.self.entity.getTransform()obtém o Componente Transform da porta.self.isOpené uma variável usada pelo script para lembrar se a porta está aberta.
Você usará esse padrão o tempo todo. Primeiro você obtém a entidade, depois obtém os componentes ou entidades filhas de que precisa, e então você os utiliza em sua lógica.
Obtendo Outros Componentes
Para controlar uma entidade, você geralmente precisa obter um ou mais componentes dela.
Por exemplo, um script de jogador pode obter:
- O componente
Transformpara mover ou girar a entidade. - O componente
Characterpara lidar com o movimento do personagem. - O componente
Animationde uma entidade malha filha para tocar animações. - O componente
Audiopara tocar um som looping.
Aqui está 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 entidade para frente a cada quadro.
A parte importante é cave.getDeltaTime(). Como update() é executado a cada quadro, multiplicar o movimento pelo delta time mantém a velocidade de movimento consistente, mesmo que a taxa de quadros mude.
Lendo Propriedades Personalizadas
Codificar valores é bom para um primeiro teste, mas propriedades editáveis geralmente são melhores para objetos de jogo reais.
Por exemplo, em vez de escrever isto:
self.speed = 2.0
Você pode ler o valor das propriedades da entidade:
self.speed = self.entity.properties.get("speed", 2.0)
Isso significa:
- Se a entidade tem uma propriedade
speed, use-a. - Se não tiver, use
2.0como valor padrão.
Isso é muito útil para scripts reutilizáveis. Você pode criar um único script SimpleMover e usá-lo em várias entidades, cada uma com uma velocidade diferente.
Por exemplo:
| Entidade | Propriedade speed |
|---|---|
| Plataforma Lenta | 1.0 |
| Plataforma Rápida | 4.0 |
| Perigo Móvel | 7.0 |
O script permanece o mesmo, mas o comportamento muda por entidade.
Alternativamente, você pode criar variáveis localmente modificáveis para o Componente em si, em vez de depender das propriedades da Entidade. Quando você cria uma variável assim:
import cave
class PlatformMover(cave.Component):
# Isso 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 Entidades Filhas
Muitos objetos do Cave são construídos como pequenas hierarquias.
O template de jogador é um bom exemplo. A entidade raiz Player tem a física e lógica do personagem, enquanto a entidade filha Mesh tem a malha visual do personagem e o Componente de Animação.
Portanto, se um script na entidade raiz do jogador quiser tocar animações, primeiro ele obtém a entidade malha filha:
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 tipo de padrão usado pelo controlador padrão do jogador:
- Obter a entidade filha.
- Obter o componente dessa filha.
- Usar o componente quando necessário.
Uma vez que você entende esse padrão, muitos scripts do Cave se tornam muito mais fáceis de ler.
O método getChild tem um parâmetro opcional "recursivo", que é True por padrão. Se for True, ele consultará todas as crianças da Entidade, incluindo crianças de crianças, até encontrar a Entidade que você solicitou pelo nome.
Obtendo Entidades da Cena (Consultas de Cena)
Ao criar um jogo, é muito provável que você precise obter outras entidades na cena. Então, vamos explorar isso. O primeiro passo é obter a cena em si, e no Cave, você tem duas maneiras 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 de cave.Component também recebem a cena como um parâmetro, já que é muito provável que você os utilize nesses métodos. Para código local, como o Componente de Código Python, também há uma variável scene definida para você por padrão que você pode "simplesmente usar" e esperar que funcione.
Uma vez que você obtém a cena, pode obter uma Entidade específica pelo seu nome usando o seguinte código:
watchtower = scene.get("Watch Tower 01")
Cave oferece muitos outros métodos na classe de cena para você realizar outras consultas de cena. Você pode fazer ray casts, sphere casts, verificar uma caixa de contato ou esfera 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 propriedades específicas ou com um nome específico, etc. Portanto, vale a pena conferir a API Python para mais detalhes.
Sempre lembre-se de verificar se sua consulta retornou algo válido. Por exemplo:
# Consultando uma Entidade inexistente:
ent = scene.get("Esta Entidade Não Existe")
if ent is None:
print("Entidade Inválida!")
Obtendo Componentes de Entidade
Uma vez que você tenha uma entidade específica e verifique se ela é conhecida, é uma boa ideia entender como você pode obter componentes específicos dela.
A entidade possui um método específico chamado get, onde você pode passar o nome do componente como uma string e ele automaticamente irá verificar a entidade para ver se há um componente que corresponda à sua busca:
animator = self.entity.get("Animation Component")
Para facilitar sua vida, se um nome de componente terminar com a palavra "Component", o que é muito comum, você pode omitir completamente esse final ao digitar o nome do componente nesse método. Você também pode escolher se deseja incluir espaço em branco em nomes de componentes com várias palavras ou juntar tudo.
Por exemplo, se você quiser obter o Rigid Body Component de uma Entidade, mesmo que seu 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 Python não é fortemente tipado, é uma boa prática de programação no Cave que você forneça uma dica de tipo para o tipo de componente, o que pode ser feito da seguinte forma. Também observe que, nesse caso, você precisa incluir o nome completo do componente, pois é uma semântica Python:
rb : cave.RigidBodyComponent = self.entity.get("Rigid Body")
Isso permite que o IntelliSense funcione em editores externos, como Visual Studio Code, ou até mesmo a autocompletação embutida que o Cave Engine fornece para você em seu editor de script incorporado.
Para o Componente de Transformação, já que é um dos tipos de componentes mais comuns e você o consultará muito, a Entidade possui um método nativo para obter sua Transformação principal:
transf = self.entity.getTransform()
Obter chamando self.entity.getTransform() fornece o mesmo resultado que chamar self.entity.get("Transform"), mas a primeira opção é mais rápida e otimizada.
Se uma entidade tiver múltiplos componentes desse mesmo tipo, ela retornará a primeira correspondência, mas às vezes você pode querer ter todas as correspondências. Por exemplo, em uma malha de múltiplos materiais que no cave será representada por uma entidade com múltiplos componentes de malha, você pode querer obter todos os componentes de malha. E para isso, você pode usar o método getAll:
meshCmps = self.entity.getAll("Mesh")
# Mudando todos os materiais para um brilhante:
for meshCmp in meshCmps:
meshCmp.material.setAsset("Glowing Material")
Obtendo Componentes Python de Entidade
Agora sabemos como obter Componentes nativos do Cave, mas e se você quiser obter de uma Entidade um componente que foi escrito customizadamente por você usando Python?
Para isso, você precisa de um método especial chamado getPy, que funciona exatamente da mesma forma que o método get regular, exceto que este também retornará componentes Python:
myCmp = self.entity.getPy("MyCustomComponent")
Exige um método especial devido a otimizações internas para garantir que o Cave rode da maneira mais rápida possível.
Uma vez que você tenha seu Componente Python customizado, você pode acessar livremente suas variáveis e métodos feitos em Python:
myCmp = self.entity.getPy("MyCustomComponent")
# Mudando variáveis python:
myCmp.customValue = 10
# Chamando métodos customizados:
myCmp.doSomething()
myCmp.applyDamage(10)
Componente de Código Python
Além do Componente Python regular, o Cave também possui um Componente de Código Python. O Componente de Código Python é útil para scripts rápidos escritos diretamente na entidade, sem criar primeiramente um ativo de Script Python separado.
Ele tem todos os outros métodos, e a diferença é que no componente de código Python, você escreve o script Python diretamente dentro do componente em si, e não é modular e não reutilizável. Portanto, se você criar uma cópia da entidade, ela também criará uma cópia do script dentro dela. Mas às vezes, isso pode ser uma maneira mais rápida de criar uma lógica simples, como uma moeda girando.
Ele é bom para:
- Testes rápidos.
- Pequenos callbacks.
- Comportamento único.
- Protótipos.
Não é a melhor opção para sistemas de jogo maiores, pois o código é mais difícil de reutilizar e organizar, mas é ótimo para códigos pequenos.
Componente Python vs Componente de Código Python
Use esta regra simples:
| Use Isso | Quando |
|---|---|
| Componente Python | O comportamento deve ser reutilizado, editado como um ativo ou crescer ao longo do tempo. |
| Componente de Código Python | O comportamento é pequeno, local. |
Por exemplo, um EnemyAI reutilizável deve ser um ativo de Script Python usado por um Componente Python. Um pequeno código que imprime algo ou chama uma função quando um botão é pressionado pode ser um Componente de Código Python.
Um Bom Primeiro Objetivo de Script
Um bom primeiro script do Cave é algo pequeno e visível.
Tente construir um desses:
- 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: obter a entidade, obter o componente, mudar algo, testar em Modo de Jogo e ajustar.
O Que Você Deve Lembrar
Os scripts Python no Cave são geralmente anexados a entidades por meio de Componentes Python.
O padrão mais importante para iniciantes é:
- Use
start()para obter referências e preparar valores. - Use
update()para executar o comportamento a cada quadro. - Use
self.entitypara acessar a entidade que possui o script. - Use componentes para realmente mover, animar, tocar som ou controlar o objeto.
Uma vez que esse padrão se torne natural, a programação no Cave se torna muito menos misteriosa. Você não está apenas escrevendo código. Você está ensinando entidades como se comportar.