Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
Personagem cinemático (2D)¶
Introdução¶
Sim, o nome soa estranho. "Personagem cinemático". O que é aquilo? A razão para o nome é que, quando os motores de física surgiram, eles eram chamados de motores "Dinâmicos" (porque lidavam principalmente com respostas de colisão). Muitas tentativas foram feitas para criar um controlador de personagem usando os motores de dinâmica, mas não foi tão fácil quanto parecia. Godot tem uma das melhores implementações de controlador de personagem dinâmico que você pode encontrar (como pode ser visto na demo 2d/platformer), mas usá-lo requer um nível considerável de habilidade e compreensão dos motores de física (ou muita paciência com testes e erro).
Alguns motores de física, como o Havok, parecem defender os controladores de personagens dinâmicos como a melhor opção, enquanto outros (PhysX) preferem promover o cinemático.
Então, qual é a diferença?:
Um controlador dinâmico de personagem usa um corpo rígido com um tensor de inércia infinito. É um corpo rígido que não pode girar. Os motores de física sempre permitem que os objetos se movam e colidam, então resolvem suas colisões todas juntas. Isso torna os controladores de personagem dinâmicos capazes de interagir perfeitamente com outros objetos físicos, como visto na demonstração do jogo de plataforma. No entanto, essas interações nem sempre são previsíveis. As colisões podem levar mais de um quadro para serem resolvidas, então algumas colisões podem parecer deslocar um pouquinho. Esses problemas podem ser corrigidos, mas requerem uma certa habilidade.
Presume-se que um controlador de caractere cinemático comece sempre em um estado sem colisão e sempre se moverá para um estado sem colisão. Se começar em estado de colisão, tentará se libertar como fazem os corpos rígidos, mas esta é a exceção, não a regra. Isso torna seu controle e movimento muito mais previsível e fácil de programar. No entanto, como desvantagem, eles não podem interagir diretamente com outros objetos físicos, a menos que sejam feitos à mão em código.
This short tutorial focuses on the kinematic character controller. It uses the old-school way of handling collisions, which is not necessarily simpler under the hood, but well hidden and presented as an API.
Processo físico¶
Para gerenciar a lógica de um corpo ou personagem cinemático, é sempre aconselhável usar o processo de física, pois é chamado antes da simulação de física e sua execução está em sincronia com o servidor de física, também é chamado a mesma quantidade de vezes por segundo, sempre. Isso faz com que a física e o cálculo de movimento funcionem de maneira mais previsível do que usando o processo regular, que pode ter picos ou perder a precisão se a taxa de quadros for muito alta ou muito baixa.
extends CharacterBody2D
func _physics_process(delta):
pass
using Godot;
public partial class MyCharacterBody2D : CharacterBody2D
{
public override void _PhysicsProcess(double delta)
{
}
}
Configuração da cena¶
To have something to test, here's the scene (from the tilemap tutorial): kinematic_character_2d_starter.zip. We'll be creating a new scene for the character. Use the robot sprite and create a scene like this:
Você notará que há um ícone de aviso próximo ao nosso nó CollisionShape2D; isso porque não definimos uma forma para ele. Crie um novo CircleShape2D na propriedade de forma de CollisionShape2D. Clique em <CircleShape2D> para acessar as opções e defina o raio como 30:
Observação: como mencionado anteriormente no tutorial de física, o engine de física não pode lidar com a escala na maioria dos tipos de formas (somente polígonos de colisão, planos e segmentos funcionam), portanto, sempre altere os parâmetros (como o raio) da forma em vez de dimensioná-la. O mesmo também é verdade para os próprios corpos cinemáticos/rígidos/estáticos, pois sua escala afeta a escala da forma.
Agora, crie um script para o personagem, o usado como exemplo acima deve servir de base.
Por fim, crie uma instância dessa cena de personagem no tilemap e torne a cena do mapa a principal, para que seja executada ao pressionar o play.
Movendo o personagem cinemático¶
Go back to the character scene, and open the script, the magic begins
now! Kinematic body will do nothing by default, but it has a
useful function called CharacterBody2D.move_and_collide()
.
This function takes a Vector2 as
an argument, and tries to apply that motion to the kinematic body. If a
collision happens, it stops right at the moment of the collision.
Então, vamos mover nosso sprite para baixo até atingir o chão:
extends CharacterBody2D
func _physics_process(delta):
move_and_collide(Vector2(0, 1)) # Move down 1 pixel per physics frame
using Godot;
public partial class MyCharacterBody2D : CharacterBody2D
{
public override void _PhysicsProcess(double delta)
{
// Move down 1 pixel per physics frame
MoveAndCollide(new Vector2(0, 1));
}
}
O resultado é que o personagem vai se mover, mas parar ao bater no chão. Bem legal, né?
O próximo passo será adicionar gravidade à mistura, de forma que ela se comporte um pouco mais como um personagem normal do jogo:
extends CharacterBody2D
const GRAVITY = 200.0
func _physics_process(delta):
velocity.y += delta * GRAVITY
var motion = velocity * delta
move_and_collide(motion)
using Godot;
public partial class MyCharacterBody2D : CharacterBody2D
{
private const float Gravity = 200.0f;
public override void _PhysicsProcess(double delta)
{
var velocity = Velocity;
velocity.Y += (float)delta * Gravity;
Velocity = velocity;
var motion = velocity * (float)delta;
MoveAndCollide(motion);
}
}
Agora o personagem cai sem problemas. Vamos fazê-lo andar para os lados, esquerda e direita ao tocar nas teclas direcionais. Lembre-se de que os valores usados (pelo menos para velocidade) são pixels/segundo.
This adds basic support for walking when pressing left and right:
extends CharacterBody2D
const GRAVITY = 200.0
const WALK_SPEED = 200
func _physics_process(delta):
velocity.y += delta * GRAVITY
if Input.is_action_pressed("ui_left"):
velocity.x = -WALK_SPEED
elif Input.is_action_pressed("ui_right"):
velocity.x = WALK_SPEED
else:
velocity.x = 0
# "move_and_slide" already takes delta time into account.
move_and_slide()
using Godot;
public partial class MyCharacterBody2D : CharacterBody2D
{
private const float Gravity = 200.0f;
private const int WalkSpeed = 200;
public override void _PhysicsProcess(double delta)
{
var velocity = Velocity;
velocity.Y += (float)delta * Gravity;
if (Input.IsActionPressed("ui_left"))
{
velocity.X = -WalkSpeed;
}
else if (Input.IsActionPressed("ui_right"))
{
velocity.X = WalkSpeed;
}
else
{
velocity.X = 0;
}
Velocity = velocity;
// "MoveAndSlide" already takes delta time into account.
MoveAndSlide();
}
}
E experimente.
Este é um bom ponto de partida para um jogo de plataforma. Uma demonstração mais completa pode ser encontrada no zip de demonstração distribuído com o mecanismo ou no https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character.