game/godot

Godot3 API - Using KinematicBody2D

C/H 2018. 11. 6. 08:30

Using KinematicBody2D

Introduction

Godot offers a number of collision objects to provide both collision detection and response. Trying to decide which one to use for your project can be confusing. You can avoid problems and simplify development if you understand how each of them works and what their pros and cons are. In this tutorial, we’ll look at the KinematicBody2D node and show some examples of how it can be used.
Godot은 충돌 탐지 및 응답을 제공하기 위해 여러 가지 충돌 객체를 제공합니다. 이것은 프로젝트 결정에 혼란을 줄 수 있습니다. 각각의 작동 방식과 장점 및 단점을 이해하면 문제를 피하고 개발을 단순화 할 수 있습니다. 이 튜토리얼에서는 KinematicBody2D 노드를 살펴보고이를 사용하는 방법에 대한 몇 가지 예를 보여줍니다.

Note

This document assumes you’re familiar with Godot’s various physics bodies. Please read Physics introduction first.
이 문서는 당신이 Godot의 다양한 물리 구조에 익숙하다고 가정합니다. 먼저 Physics introduction을 읽으십시오.

What is a kinematic body?

KinematicBody2D is for implementing bodies that are to be controlled via code. They detect collisions with other bodies when moving, but are not affected by engine physics properties like gravity or friction. While this means that you have to write some code to create their behavior, it also means you have more precise control over how they move and react.
KinematicBody2D는 코드를 통해 제어 될 body를 구현합니다. body가 움직일 때 다른 body와 충돌을 감지하지만 중력이나 마찰과 같은 엔진 물리 특성에 영향을받지 않습니다. 이는 동작을 위해서 코드를 작성해야한다는 것을 의미하지만, 이동 및 대응 방법을 보다 정확하게 제어 할 수 있음을 의미합니다.

Tip

A KinematicBody2D can be affected by gravity and other forces, but you must calculate the movement in code. The physics engine will not move a KinematicBody2D.
KinematicBody2D는 중력 및 다른 힘의 영향을받을 수 있지만 코드로 움직임을 계산해야합니다. 물리 엔진은 KinematicBody2D를 움직이지 않습니다.

Movement and Collision

When moving a KinematicBody2D, you should not set its position property directly. Instead, you use the move_and_collide() or move_and_slide() methods. These methods move the body along a given vector and will instantly stop if a collision is detected with another body. After a KinematicBody2D has collided, any collision response must be coded manually.
KinematicBody2D를 이동할 때 위치(position) 속성을 직접 설정하지 마십시오. 대신 move_and_collide() 또는 move_and_slide() 메서드를 사용합니다. 이러한 메서드는 주어진 벡터를 따라 본문을 이동하고 충돌이 다른 본문에서 감지되면 즉시 중지됩니다. KinematicBody2D가 충돌 한 후에는 충돌 응답을 직접 코딩해야합니다.

Warning

Kinematic body movement should only be done in the _physics_process() callback.
Kinematic body 이동은 _physics_process() 콜백에서만 수행해야합니다.

The two movement methods serve different purposes, and later in this tutorial you’ll see examples of how they work.
두 가지 이동 방법은 다른 용도로 사용되며, 나중에 이 자습서에서 어떻게 작동하는지 예제를 볼 수 있습니다.

move_and_collide

This method takes one parameter: a Vector2 indicating the body’s relative movement. Typically, this is your velocity vector multiplied by the frame timestep (delta). If the engine detects a collision anywhere along this vector, the body will immediately stop moving. If this happens, the method will return a KinematicCollision2D object.
이 메서드는 하나의 매개 변수, 즉 body의 상대(relative) 이동을 나타내는 Vector2를 사용합니다. 일반적으로 속도 벡터에 프레임 시간 단계(델타)를 곱한 값입니다. 엔진이 이 벡터를 따라 충돌을 감지하면 body는 즉시 움직이지 않습니다. 이 경우 메서드는 KinematicCollision2D 객체를 반환합니다.

KinematicCollision2D is an object containing data about the collision and the colliding object. Using this data you can calculate your collision response.
KinematicCollision2D는 충돌 및 충돌 객체에 대한 데이터가 포함 된 객체입니다. 이 데이터를 사용하여 충돌 응답을 계산할 수 있습니다.

move_and_slide

The move_and_slide() method is intended to simplify the collision response in the common case where you want one body to slide along the other. This is especially useful in platformers or top-down games, for example.
move_and_slide () 메서드는 하나의 body를 다른 body와 함께 슬라이드(겹치게?)하려는 일반적인 경우의 충돌 응답을 단순화하기위한 것입니다. 이것은 특히 플랫폼이나 하향식 게임에서 유용합니다.

Tip

move_and_slide() automatically calculates frame-based movement using delta. Do not multiply your velocity vector by delta before passing it to move_and_slide().
move_and_slide()는 델타를 사용하여 프레임 기반 이동을 자동으로 계산합니다. move_and_slide()에 전달하기 전에 속도 벡터에 델타를 곱하지 마십시오.

In addition to the velocity vector, move_and_slide() takes a number of other parameters allowing you to customize the slide behavior:
move_and_slide()는 속도 벡터 외에도 다음과 같은 여러 매개 변수를 사용하여 슬라이드 동작을 사용자 정의 할 수 있습니다:

  • floor_normal - default value: Vector2( 0, 0 )

    This parameter allows you to define what surfaces the engine should consider to be the floor. Setting this lets you use the is_on_floor(), is_on_wall(), and is_on_ceiling() methods to detect what type of surface the body is in contact with. The default value means that all surfaces are considered walls.
    이 매개 변수를 사용하면 엔진이 바닥이라고 생각할 표면을 정의 할 수 있습니다. 이를 설정하면 is_on_floor(), is_on_wall() 및 is_on_ceiling() 메서드를 사용하여 본문이 접촉하는 표면 유형을 감지 할 수 있습니다. 기본값은 모든 서피스가 벽으로 간주됨을 의미합니다.

  • slope_stop_min_velocity - default value: 5

    This is the minimum velocity when standing on a slope. This prevents a body from sliding down a slope when standing still.
    경사면에 서있을 때의 최소 속도입니다. 정지 상태에서 몸체가 경사면을 미끄러지는 것을 방지합니다.

  • max_bounces - default value: 4

    This is the maximum number of collisions before the body stops moving. Setting this too low may prevent movement entirely.
    body가 움직이기 전의 최대 충돌 횟수입니다. 너무 낮게 설정하면 움직임이 완전히 차단 될 수 있습니다.

  • floor_max_angle - default value: 0.785398 (in radians, equivalent to 45 degrees)

    This is the maximum angle before a surface is no longer considered a “floor”.
    표면이 더 이상 "바닥"으로 간주되지 않기 전의 최대 각도입니다.

Which movement method to use?

A common question from new Godot users is: “How do you decide which movement function to use?” Often the response is to use move_and_slide() because it’s “simpler”, but this is not necessarily the case. One way to think of it is that move_and_slide() is a special case, and move_and_collide() is more general. For example, the following two code snippets result in the same collision response:
새로운 Godot 사용자의 공통된 질문은 "어떤 운동 기능을 사용할지 결정하는 방법은 무엇입니까?" 종종 "반응이 간단하기"때문에 move_and_slide()를 사용하는 것이지만, 반드시 그런 것은 아닙니다. 그것을 생각하는 한 가지 방법은 move_and_slide()가 특별한 경우이고 move_and_collide()가 더 일반적인 경우입니다. 예를 들어 다음 두 코드 스 니펫은 동일한 충돌 응답을 발생시킵니다.

# using move_and_collide
var collision = move_and_collide(velocity * delta)
if collision:
    velocity = velocity.slide(collision.normal)

# using move_and_slide
velocity = move_and_slide(velocity)

Anything you do with move_and_slide() can also be done with move_and_collide(), but it might take a little more code. However, as we’ll see in the examples below, there are cases where move_and_slide() doesn’t provide the response you want.
move_and_slide()로 수행하는 작업은 move_and_collide()로 수행 할 수도 있지만 코드가 조금 더 필요할 수 있습니다. 그러나 아래 예제에서 볼 수 있듯이 move_and_slide()가 원하는 응답을 제공하지 않는 경우가 있습니다.

Examples

To see these examples in action, download the sample project: using_kinematic2d.zip.
이 예제가 실제로 작동하는지 보려면 샘플 프로젝트 : using_kinematic2d.zip을 다운로드하십시오.

Movement and walls

If you’ve downloaded the sample project, this example is in the “BasicMovement.tscn” scene.
샘플 프로젝트를 다운로드 한 경우이 예제는 "BasicMovement.tscn"장면에 있습니다.

For this example, Add a KinematicBody2D with two children: a Sprite and a CollisionShape2D. Use the Godot “icon.png” as the Sprite’s texture (drag it from the Filesystem dock to the Texture property of the Sprite). In the CollisionShape2D’s Shape property, select “New RectangleShape2D” and size the rectangle to fit over the sprite image.
이 예제에서는 Spin과 CollisionShape2D라는 두 개의 자식이있는 KinematicBody2D를 추가합니다. Godot "icon.png"를 스프라이트의 텍스처로 사용하십시오 (파일 시스템 도크에서 스프라이트의 텍스처 속성으로 드래그하십시오). CollisionShape2D의 Shape 속성에서 "New RectangleShape2D"를 선택하고 스프라이트 이미지 위에 맞도록 사각형 크기를 조정합니다.

Note

See 2D Movement Overview for examples of implementing 2D movement schemes.
2D 이동 체계 구현의 예는 2D 이동 개요를 참조하십시오.

Attach a script to the KinematicBody2D and add the following code:
KinematicBody2D에 스크립트를 첨부하고 다음 코드를 추가하십시오:

extends KinematicBody2D

var speed = 250
var velocity = Vector2()

func get_input():
    # Detect up/down/left/right keystate and only move when pressed
    velocity = Vector2()
    if Input.is_action_pressed('ui_right'):
        velocity.x += 1
    if Input.is_action_pressed('ui_left'):
        velocity.x -= 1
    if Input.is_action_pressed('ui_down'):
        velocity.y += 1
    if Input.is_action_pressed('ui_up'):
        velocity.y -= 1
    velocity = velocity.normalized() * speed

func _physics_process(delta):
    get_input()
	move_and_collide(velocity * delta)

Run this scene and you’ll see that move_and_collide() works as expected, moving the body along the velocity vector. Now let’s see what happens when you add some obstacles. Add a StaticBody2D with a rectangular collision shape. For visibility, you can use a sprite, a Polygon2D, or turn on “Visible Collision Shapes” from the “Debug” menu.
이 장면을 실행하면 move_and_collide()가 예상대로 작동하여 몸체를 속도 벡터를 따라 움직이는 것을 볼 수 있습니다. 이제 장애물을 추가 할 때 어떤 일이 발생하는지 봅시다. 직사각형 충돌 셰이프가있는 StaticBody2D를 추가하십시오. 가시성을 위해 Sprite, Polygon2D를 사용하거나 "Debug"메뉴에서 "Visible Collision Shapes"를 켤 수 있습니다.

Run the scene again and try moving into the obstacle. You’ll see that the KinematicBody2D can’t penetrate the obstacle. However, try moving into the obstacle at an angle and you’ll find that the obstacle acts like glue - it feels like the body gets stuck.
장면을 다시 실행하고 장애물로 이동하십시오. KinematicBody2D가 장애물을 통과 할 수 없음을 알 수 있습니다. 그러나 어떤 각도로 장애물로 움직여보십시오. 장애물이 접착제처럼 작용한다는 것을 알게 될 것입니다. 신체가 붙어있는 것처럼 느껴집니다.

This happens because there is no collision response. move_and_collide() stops the body’s movement when a collision occurs. We need to code whatever response we want from the collision.
이것은 충돌 응답이 없기 때문에 발생합니다. move_and_collide()는 충돌이 발생할 때 신체의 움직임을 멈춥니다. 우리는 충돌로부터 원하는 응답을 코드화해야합니다.

Try changing the function to move_and_slide(velocity) and running again. Note that we removed delta from the velocity calculation.
함수를 move_and_slide(velocity)로 변경하고 다시 실행 해보십시오. 우리는 속도 계산에서 델타를 제거했다.

move_and_slide() provides a default collision response of sliding the body along the collision object. This is useful for a great many game types, and may be all you need to get the behavior you want.
move_and_slide()는 충돌 객체를 따라 몸체를 움직이는 기본 충돌 응답을 제공합니다. 이는 많은 게임 유형에 유용하며 원하는 동작을 얻는 데 필요한 모든 것일 수 있습니다.

Bouncing/reflecting

What if you don’t want a sliding collision response? For this example (“BounceandCollide.tscn” in the sample project), we have a character shooting bullets and we want the bullets to bounce off the walls.
슬라이딩 충돌 전 응답을 원하지 않으면 어떻게해야합니까? 이 예제 (샘플 프로젝트의 "BounceandCollide.tscn")에는 총알을 쏘는 총알이 있으며 우리는 총알이 벽에서 튀어 나오길 원합니다.

This example uses three scenes. The main scene contains the Player and Walls. The Bullet and Wall are separate scenes so that they can be instanced.
이 예제에서는 3개의 장면을 사용합니다. 주요 장면은 플레이어와 벽을 포함합니다. 글 머리 기호와 장벽은 인스턴스화 할 수 있도록 별도의 장면입니다.

The Player is controlled by the w and s keys for forward and back. Aiming uses the mouse pointer. Here is the code for the Player, using move_and_slide():
플레이어는 앞과 뒤의 w 및 s 키로 제어됩니다. 조준은 마우스 포인터를 사용합니다. 다음은 move_and_slide ()를 사용하여 Player 코드입니다.

extends KinematicBody2D

var Bullet = preload("res://Bullet.tscn")
var speed = 200
var velocity = Vector2()

func get_input():
    # add these actions in Project Settings -> Input Map
    velocity = Vector2()
    if Input.is_action_pressed('backward'):
        velocity = Vector2(-speed/3, 0).rotated(rotation)
    if Input.is_action_pressed('forward'):
        velocity = Vector2(speed, 0).rotated(rotation)
    if Input.is_action_just_pressed('mouse_click'):
        shoot()

func shoot():
    # "Muzzle" is a Position2D placed at the barrel of the gun
    var b = Bullet.instance()
    b.start($Muzzle.global_position, rotation)
    get_parent().add_child(b)

func _physics_process(delta):
    get_input()
    var dir = get_global_mouse_position() - global_position
    # Don't move if too close to the mouse pointer
    if dir.length() > 5:
        rotation = dir.angle()
		velocity = move_and_slide(velocity)

And the code for the Bullet:
그리고 총알에 대한 코드 :

extends KinematicBody2D

var speed = 750
var velocity = Vector2()

func start(pos, dir):
    rotation = dir
    position = pos
    velocity = Vector2(speed, 0).rotated(rotation)

func _physics_process(delta):
    var collision = move_and_collide(velocity * delta)
    if collision:
        velocity = velocity.bounce(collision.normal)
        if collision.collider.has_method("hit"):
            collision.collider.hit()

func _on_VisibilityNotifier2D_screen_exited():
	queue_free()

The action happens in _physics_process(). After using move_and_collide() if a collision occurs, a KinematicCollision2D object is returned (otherwise, the return is Nil).
액션은 _physics_process ()에서 발생합니다. 충돌이 발생하면 move_and_slide ()를 사용한 후 Kinematic Collision 2D 객체가 반환됩니다(그렇지 않으면 반환 값은 Nil입니다).

If there is a returned collision, we use the normal of the collision to reflect the bullet’s velocity with the Vector2.bounce() method.
반환 된 충돌이있는 경우 충돌의 법선을 사용하여 총알의 속도를 Vector2.bounce() 메서드로 나타냅니다.

If the colliding object (collider) has a hit method, we also call it. In the example project, we’ve added a flashing color effect to the Wall to demonstrate this.
충돌 객체 (충돌 자)에 히트 메소드가있는 경우이를 호출합니다. 예제 프로젝트에서는 Wall에 깜박이는 색상 효과를 추가하여이를 보여줍니다.

Platformer movement

Let’s try one more popular example: the 2D platformer. move_and_slide() is ideal for quickly getting a functional character controller up and running. If you’ve downloaded the sample project, you can find this in “Platformer.tscn”.
보급형 예제인 2D 플랫폼을 사용해 보겠습니다: move_and_slide()는 funcional 캐릭터 컨트롤러를 신속하게 작동시키고 실행시키는 데 이상적입니다. 샘플 프로젝트를 다운로드 한 경우 "Platformer.tscn"에서 찾을 수 있습니다.

For this example, we’ll assume you have a level made of StaticBody2D objects. They can be any shape and size. In the sample project, we’re using Polygon2D to create the platform shapes.
이 예제에서는 StaticBody2D 객체로 구성된 레벨이 있다고 가정합니다. 그들은 어떤 형태와 크기가 될 수 있습니다. 샘플 프로젝트에서 우리는 Polygon2D를 사용하여 플랫폼 모양을 만듭니다.

Here’s the code for the player body:
플레이어 바디의 코드는 다음과 같습니다.

extends KinematicBody2D

export (int) var run_speed = 100
export (int) var jump_speed = -400
export (int) var gravity = 1200

var velocity = Vector2()
var jumping = false

func get_input():
    velocity.x = 0
    var right = Input.is_action_pressed('ui_right')
    var left = Input.is_action_pressed('ui_left')
    var jump = Input.is_action_just_pressed('ui_select')

    if jump and is_on_floor():
        jumping = true
        velocity.y = jump_speed
    if right:
        velocity.x += run_speed
    if left:
        velocity.x -= run_speed

func _physics_process(delta):
    get_input()
    velocity.y += gravity * delta
    if jumping and is_on_floor():
        jumping = false
    velocity = move_and_slide(velocity, Vector2(0, -1))

When using move_and_slide() the function returns a vector representing the movement that remained after the slide collision occurred. Setting that value back to the character’s velocity allows us to smoothly move up and down slopes. Try removing velocity = and see what happens if you don’t do this.
move_and_slide()를 사용할 때 함수는 슬라이드 충돌이 발생한 후에 남은 움직임을 나타내는 벡터를 반환합니다. 이 값을 다시 캐릭터의 속도로 설정하면 슬로프를 위아래로 부드럽게 움직일 수 있습니다. 속도 =를 제거하고 시도하지 않으면 어떻게되는지 보십시오.

Also note that we’ve added Vector2(0, -1) as the floor normal. This is a vector pointing straight upward. This means that if the character collides with an object that has this normal, it will be considered a floor.
또한 Vector2 (0, -1)를 바닥 법선으로 추가했습니다. 이것은 똑바로 위쪽을 가리키는 벡터입니다. 즉, 캐릭터가 이 법선을 가진 객체와 충돌하면 바닥으로 간주됩니다.

Using the floor normal allows us to make jumping work, using is_on_floor(). This function will only return true after a move_and_slide() collision where the colliding body’s normal is within 45 degrees of the given floor vector (this can be adjusted by setting floor_max_angle).
floor normal을 사용하면 is_on_floor ()를 사용하여 점프 작업을 할 수 있습니다. 이 함수는 충돌 본문의 법선이 주어진 바닥 벡터의 45도 이내 인 move_and_slide() 충돌 후 true를 반환합니다 (floor_max_angle를 설정하여 조정할 수 있음).

This also allows you to implement other features like wall jumps using is_on_wall(), for example.
이것은 또한 is_on_wall()을 사용하여 벽 점프와 같은 다른 기능을 구현할 수도 있습니다.

반응형

'game > godot' 카테고리의 다른 글

Godot3 API - Kinematic Character (2D)  (0) 2018.11.08
Godot3 API - Physics introduction  (0) 2018.11.07
Godot3 API - Ray-casting  (0) 2018.11.05
Godot3 API - InputDefault  (0) 2018.11.02
Godot3 API - Input  (0) 2018.11.02