Visão geral de movimento 2D¶
Introdução¶
Todo iniciante está lá: "Como faço para mover meu personagem?" Dependendo do estilo de jogo que você está fazendo, você pode ter requisitos especiais, mas em geral o movimento na maioria dos jogos 2D é baseado em um pequeno número de designs.
Usaremos KinematicBody2D para esses exemplos, mas os princípios também serão aplicados a outros tipos de nó (Area2D, RigidBody2D).
Configurar¶
Cada exemplo abaixo usa a mesma configuração de cena. Comece com um KinematicBody2D
com dois filhos: Sprite
e CollisionShape2D
. Você pode usar o ícone do Godot ("icon.png") para a textura do Sprite ou usar qualquer imagem 2D que você tiver.
Abra Projeto -> Configurações do Projeto
e selecione a guia "Mapa de Entrada". Adicione as seguintes ações de entrada (consulte InputEvent para obter detalhes):
Movimento em 8 direções¶
Neste cenário, você quer que o usuário pressione as quatro teclas direcionais (para cima/esquerda/baixo/direita ou W/A/S/D) e se mova na direção selecionada. O nome "movimento em 8 direções" vem do fato de que o jogador pode se mover diagonalmente pressionando duas teclas ao mesmo tempo.
Adicione um script ao corpo cinemático e adicione o seguinte código:
extends KinematicBody2D
export (int) var speed = 200
var velocity = Vector2()
func get_input():
velocity = Vector2()
if Input.is_action_pressed("right"):
velocity.x += 1
if Input.is_action_pressed("left"):
velocity.x -= 1
if Input.is_action_pressed("down"):
velocity.y += 1
if Input.is_action_pressed("up"):
velocity.y -= 1
velocity = velocity.normalized() * speed
func _physics_process(delta):
get_input()
velocity = move_and_slide(velocity)
using Godot;
using System;
public class Movement : KinematicBody2D
{
[Export] public int speed = 200;
public Vector2 velocity = new Vector2();
public void GetInput()
{
velocity = new Vector2();
if (Input.IsActionPressed("right"))
velocity.x += 1;
if (Input.IsActionPressed("left"))
velocity.x -= 1;
if (Input.IsActionPressed("down"))
velocity.y += 1;
if (Input.IsActionPressed("up"))
velocity.y -= 1;
velocity = velocity.Normalized() * speed;
}
public override void _PhysicsProcess(float delta)
{
GetInput();
velocity = MoveAndSlide(velocity);
}
}
Na função get_input()
, verificamos os quatro eventos principais e os somamos para obter o vetor de velocidade. Isso tem a vantagem de fazer com que duas chaves opostas se anulem, mas também resultará em um movimento diagonal mais rápido devido à soma das duas direções.
Podemos evitar isso se normalizarmos a velocidade, o que significa que definimos seu comprimento como 1
, e multiplicamos pela velocidade desejada.
Dica
Se você nunca usou matemática vetorial antes, ou precisa de uma atualização, você pode ver uma explicação sobre o uso de vetores no Godot em Matemática vetorial.
Nota
Se o código acima não faz nada quando você pressiona as teclas, verifique se você configurou as ações de entrada corretamente conforme descrito na parte Configurar deste tutorial.
Rotação + movimento¶
Esse tipo de movimento às vezes é chamado de "estilo Asteroids" porque se assemelha a como o clássico jogo de arcade que funcionava assim. Pressionar a esquerda/direita gira o caractere, enquanto para cima/para baixo o move para frente ou para trás em qualquer direção que esteja voltado.
extends KinematicBody2D
export (int) var speed = 200
export (float) var rotation_speed = 1.5
var velocity = Vector2()
var rotation_dir = 0
func get_input():
rotation_dir = 0
velocity = Vector2()
if Input.is_action_pressed("right"):
rotation_dir += 1
if Input.is_action_pressed("left"):
rotation_dir -= 1
if Input.is_action_pressed("down"):
velocity = Vector2(-speed, 0).rotated(rotation)
if Input.is_action_pressed("up"):
velocity = Vector2(speed, 0).rotated(rotation)
func _physics_process(delta):
get_input()
rotation += rotation_dir * rotation_speed * delta
velocity = move_and_slide(velocity)
using Godot;
using System;
public class Movement : KinematicBody2D
{
[Export] public int speed = 200;
[Export] public float rotationSpeed = 1.5f;
public Vector2 velocity = new Vector2();
public int rotationDir = 0;
public void GetInput()
{
rotationDir = 0;
velocity = new Vector2();
if (Input.IsActionPressed("right"))
rotationDir += 1;
if (Input.IsActionPressed("left"))
rotationDir -= 1;
if (Input.IsActionPressed("down"))
velocity = new Vector2(-speed, 0).Rotated(Rotation);
if (Input.IsActionPressed("up"))
velocity = new Vector2(speed, 0).Rotated(Rotation);
velocity = velocity.Normalized() * speed;
}
public override void _PhysicsProcess(float delta)
{
GetInput();
Rotation += rotationDir * rotationSpeed * delta;
velocity = MoveAndSlide(velocity);
}
}
Aqui adicionamos duas novas variáveis para rastrear nossa direção e velocidade de rotação. Novamente, pressionar ambas as teclas ao mesmo tempo cancelará e resultará em nenhuma rotação. A rotação é aplicada diretamente na propriedade rotation
do corpo.
Para definir a velocidade, usamos o método Vector2.rotated()
, de forma que ela aponte na mesma direção do corpo. rotated()
é uma função vetorial útil que você pode usar em muitas circunstâncias onde você precisaria aplicar funções trigonométricas.
Rotação + movimento (mouse)¶
Este estilo de movimento é uma variação do anterior. Desta vez, a direção é definida pela posição do mouse em vez do teclado. O personagem sempre "olhará" para o ponteiro do mouse. No entanto, as entradas para a frente/para trás permanecem as mesmas.
extends KinematicBody2D
export (int) var speed = 200
var velocity = Vector2()
func get_input():
look_at(get_global_mouse_position())
velocity = Vector2()
if Input.is_action_pressed("down"):
velocity = Vector2(-speed, 0).rotated(rotation)
if Input.is_action_pressed("up"):
velocity = Vector2(speed, 0).rotated(rotation)
func _physics_process(delta):
get_input()
velocity = move_and_slide(velocity)
using Godot;
using System;
public class Movement : KinematicBody2D
{
[Export] public int speed = 200;
public Vector2 velocity = new Vector2();
public void GetInput()
{
LookAt(GetGlobalMousePosition());
velocity = new Vector2();
if (Input.IsActionPressed("down"))
velocity = new Vector2(-speed, 0).Rotated(Rotation);
if (Input.IsActionPressed("up"))
velocity = new Vector2(speed, 0).Rotated(Rotation);
velocity = velocity.Normalized() * speed;
}
public override void _PhysicsProcess(float delta)
{
GetInput();
velocity = MoveAndSlide(velocity);
}
}
Aqui estamos usando o método Node2D look_at()
para apontar o jogador para uma determinada posição. Sem esta função, você poderia obter o mesmo efeito definindo o ângulo assim:
rotation = get_global_mouse_position().angle_to_point(position)
var rotation = GetGlobalMousePosition().AngleToPoint(Position);
Clique e mova¶
Este último exemplo usa apenas o mouse para controlar o personagem. Clicar na tela fará com que o jogador se mova para o local de destino.
extends KinematicBody2D
export (int) var speed = 200
onready var target = position
var velocity = Vector2()
func _input(event):
if event.is_action_pressed("click"):
target = get_global_mouse_position()
func _physics_process(delta):
velocity = position.direction_to(target) * speed
# look_at(target)
if position.distance_to(target) > 5:
velocity = move_and_slide(velocity)
using Godot;
using System;
public class Movement : KinematicBody2D
{
[Export] public int speed = 200;
public Vector2 target;
public Vector2 velocity = new Vector2();
public override void _Ready()
{
target = Position;
}
public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed("click"))
{
target = GetGlobalMousePosition();
}
}
public override void _PhysicsProcess(float delta)
{
velocity = Position.DirectionTo(target) * speed;
// LookAt(target);
if (Position.DistanceTo(target) > 5)
{
velocity = MoveAndSlide(velocity);
}
}
}
Observe a verificação distance_to()
que fazemos antes do movimento. Sem esse teste, o corpo "tremeria" ao atingir a posição-alvo, pois se moveria um pouco além da posição e tentaria voltar, apenas para se afastar demais e repetir.
Descomentar a linha look_at()
também irá virar o corpo para apontar em sua direção de movimento, se você preferir.
Dica
Essa técnica também pode ser usada como base para um personagem "seguidor". A posição target
pode ser a de qualquer objeto para o qual você deseja mover.
Resumo¶
Você pode achar esses exemplos de código úteis como pontos de partida para seus próprios projetos. Sinta-se livre para usá-los e experimentá-los para ver o que você pode fazer.
Você pode baixar este projeto de amostra aqui: 2D_movement_demo.zip