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``와 자식 노드로 ``Sprite``와 ``CollisionShape2D``로 시작합니다. 당신은 스프라이트 텍스쳐로 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``로 설정하고 원하는 속도를 곱합니다.

참고

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

회전 + 이동

이러한 이동의 유형은 때때로 "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);
    }
}

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

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

클릭과 이동

This last example uses only the mouse to control the character. Clicking on the screen will cause the player to move to the target location.

../../_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);
        }
    }
}

Note the length() check we make prior to movement. Without this test, the body would "jitter" upon reaching the target position, as it moves slightly past the position and tries to move back, only to move too far and repeat.

Uncommenting the rotation line will also turn the body to point in its direction of motion if you prefer.

참고

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.

요약

You may find these code samples useful as starting points for your own projects. Feel free to use them and experiment with them to see what you can make.

You can download this sample project here: 2D_movement_demo.zip