2D 이동 개요

소개

Every beginner has been there: "How do I move my character?" Depending on the style of game you're making, you may have special requirements, but in general the movement in most 2D games is based on a small number of designs.

우리는 이번 예제에 KinematicBody2D 를 사용할 겁니다. 하지만 원리는 다른 노드 유형(Area2D, RiqidBody2D)에도 적용할 수 있습니다.

Setup

아래의 각 예제는 동일한 씬 설정을 사용합니다. KinematicBody2D 와 자식 노드로 SpriteCollisionShape2D 로 시작합니다. 당신은 스프라이트 텍스쳐로 Godot 아이콘("icon.png")을 사용하거나 가지고 있는 다른 2D 이미지를 사용할 수 있습니다.

프로젝트 -> 프로젝트 설정 을 열고 "입력 설정" 탭을 선택합니다. 다음의 입력 액션들을 추가하세요 (see InputEvent for details):

../../_images/movement_inputs.png

8 방향 이동

이 시나리오에서는 사용자가 4 방향의 키들(위/왼쪽/아래/오른쪽 또는 W/A/S/D)을 누르고 선택된 방향으로 움직였으면 합니다. "8 방향 이동" 명칭은 동시에 두 키를 눌러서 플레이어가 대각선으로 움직이게 되는 것에서 유래합니다.

../../_images/movement_8way.gif

kinematic body에 스크립트를 추가하고 다음과 같은 코드를 추가합니다:

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;

    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);
    }
}

get_input() 함수에서 4키 이벤트를 확인하고 이를 합산해서 속도 벡터를 얻습니다. 두 반대편 키를 서로 상쇄하는 장점이 있지만 두 개의 방향을 함께 추가하기 때문에 대각선 이동이 더 빨라지게 된다.

우리는 속도를 *정상화*해서 방지할 수 있습니다. *길이*를 ``1``로 설정하고 원하는 속도를 곱합니다.

참고

벡터 수학을 사용해 본 적이 없거나 재교육이 필요한 경우 벡터 에서 Godot 내 벡터 사용에 대한 설명을 볼 수 있습니다.

회전 + 이동

이러한 이동의 유형은 때때로 "Asteroids-style"이라 불립니다. 왜냐하면 고전 아케이드 게임 Asteroids 작동 방식과 닮았기 때문입니다. 왼쪽 또는 오른쪽을 누르면 캐릭터가 회전합니다. 반면에 위 또는 아래를 누르면 보고 있는 방향에 대햐여 전진 하거나 후진합니다.

../../_images/movement_rotate1.gif
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;

    Vector2 velocity = new Vector2();
    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);
    }
}

여기에 회전 방향과 속도를 추적하기 위한 새로운 변수 두 개를 추가했습니다. 다시 두 키를 동시에 누르면 취소되고 회전하지 않습니다. 이 회전은 바디의 rotation 속성에 직접 적용됩니다.

속도를 설정하기 위해 우리는 Vector2.rotated() 메서드를 사용해 바디와 같은 방향을 가리키도록 합니다. ``rotated``는 삼각함수를 적용해야 하는 여러 가지 상황에서 사용할 수 있는 유용한 벡터 함수입니다.

회전 + 이동 (마우스)

이번 동작 방식은 이전 동작의 변형입니다. 이번에는 키보드 대신 마우스 위치에 의해 방향이 정해집니다. 캐릭터는 항상 마우스 포인터를 봅니다("look at"). 그러나 전방/후진 입력은 동일하게 유지됩니다.

../../_images/movement_rotate2.gif
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;

    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);
    }
}

여기서 우리는 플레이어를 주어진 포지션으로 향하도록 하기 위해 Node2Dlook_at() 메서드를 사용하고 있습니다. 이 함수가 없으면 각도를 다음과 같이 설정하여 동일한 효과를 얻을 수 있습니다:

rotation = get_global_mouse_position().angle_to_point(position)
var rotation = GetGlobalMousePosition().AngleToPoint(Position);

클릭과 이동

이번 마지막 예제는 마우스만 사용하여 캐릭터를 제어합니다. 화면을 클릭하면 플레이어는 지정 위치로 움직입니다.

../../_images/movement_click.gif
extends KinematicBody2D

export (int) var speed = 200

var target = Vector2()
var velocity = Vector2()

func _input(event):
    if event.is_action_pressed('click'):
        target = get_global_mouse_position()

func _physics_process(delta):
    velocity = (target - position).normalized() * speed
    # rotation = velocity.angle()
    if (target - position).length() > 5:
        velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int Speed = 200;

    Vector2 target = new Vector2();
    Vector2 velocity = new Vector2();

    public override void _Input(InputEvent @event)
    {
        if (@event.IsActionPressed("click"))
        {
            target = GetGlobalMousePosition();
        }
    }

    public override void _PhysicsProcess(float delta)
    {
        velocity = (target - Position).Normalized() * Speed;
        // Rotation = velocity.Angle();
        if ((target - Position).Length() > 5)
        {
            velocity = MoveAndSlide(velocity);
        }
    }
}

이동 하기 전에 length() 로 확인하는 것을 유의하세요. 이 테스트가 없으면 위치를 약간 지나쳐서 되돌아가려 할 때 지정 위치에 도달하고 "덜덜 떨 것입니다", only to move too far and repeat.

원한다면 rotation 줄의 주석 처리를 제거해서 움직이는 방향으로 몸을 돌리게 할 수 있습니다.

참고

This technique can also be used as the basis of a "following" character. The target position can be that of any object you want to move to.

요약

당신은 이 코드 샘플들이 자신의 프로젝트 시작점으로서 유용하다는 것을 알게 될 것입니다. 자유롭게 그것들을 사용해서 무엇을 만들 수 있을 지 실험해보세요.

여기에서 이 샘플 프로젝트를 다운할 수 있습닌다: 2D_movement_demo.zip