game/godot

Godot3 API - Ray-casting

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

Ray-casting

Introduction

One of the most common tasks in game development is casting a ray (or custom shaped object) and checking what it hits. This enables complex behaviors, AI, etc. to take place. This tutorial will explain how to do this in 2D and 3D.
게임 개발에서 가장 공통적 인 작업 중 하나는 광선(또는 사용자 정의 모양의 대상)을(레이를) 캐스팅하고 그것이 무엇을 치는지(hit) 확인하는 것입니다. 이것은 복잡한 행동과 AI 등을 가능하게합니다. 이 자습서에서는 2D 및 3D에서이 작업을 수행하는 방법을 설명합니다.

Godot stores all the low level game information in servers, while the scene is just a frontend. As such, ray casting is generally a lower-level task. For simple raycasts, node such as RayCast and RayCast2D will work, as they will return every frame what the result of a raycast is.
Godot은 모든 저수준 게임 정보를 서버에 저장하지만 장면은 프론트 엔드에 불과합니다. 이와 같이 레이 캐스팅은 일반적으로 하위 수준 작업입니다. 단순한 레이 캐스트의 경우 RayCast 및 RayCast2D와 같은 노드가 작동합니다. 레이캐스트의 결과가 모든 프레임을 반환하기 때문입니다.

Many times, though, ray-casting needs to be a more interactive process so a way to do this by code must exist.
하지만 레이 캐스팅 (Ray-casting)은 인터랙티브 한 프로세스가되어야하므로 코드로 이런 작업을 수행 할 수 있어야합니다.

Space

In the physics world, Godot stores all the low level collision and physics information in a space. The current 2d space (for 2D Physics) can be obtained by accessing CanvasItem.get_world_2d().space. For 3D, it’s Spatial.get_world().space.
물리 세계에서 Godot은 모든 저레벨 충돌 및 물리 정보를 공간(Space)에 저장합니다. 현재 2D공간 (2D Physics 용)은 CanvasItem.get_world_2d ().space에 액세스하여 얻을 수 있습니다. 3D의 경우 Spatial.get_world().space입니다.

The resulting space RID can be used in PhysicsServer and Physics2DServer respectively for 3D and 2D.
결과 공간 RID는 3D 및 2D 각각 PhysicsServer 및 Physics2DServer에서 사용할 수 있습니다.
(스페이스 RID는 3D, 2D 각각 PhysicsServer, Physics2DServer를 사용해서 결과를 얻을 수 있습니다.)

Accessing space

Godot physics runs by default in the same thread as game logic, but may be set to run on a separate thread to work more efficiently. Due to this, the only time accessing space is safe is during the Node._physics_process() callback. Accessing it from outside this function may result in an error due to space being locked.
Godot 물리학은 기본적으로 게임 로직과 동일한 스레드에서 실행되지만보다 효율적으로 작업하려면 별도의 스레드에서 실행되도록 설정할 수 있습니다. 이 때문에 공간정보(Space Information)에 액세스하는 유일한 때(방법?)은 Node._physics_process() 콜백입니다. 이 함수 밖에서 액세스하면 공간이 잠겨 오류가 발생할 수 있습니다.

To perform queries into physics space, the Physics2DDirectSpaceState and PhysicsDirectSpaceState must be used.
물리 공간으로 쿼리를 수행하려면 Physics2DDirectSpaceState 및 PhysicsDirectSpaceState를 사용해야합니다.

Use the following code in 2D:
2D에서 다음 코드를 사용합니다:

func _physics_process(delta):
    var space_rid = get_world_2d().space
    var space_state = Physics2DServer.space_get_direct_state(space_rid)

Or more directly:
또는 직접적으로:

func _physics_process(delta):
    var space_state = get_world_2d().direct_space_state

And in 3D:
그리고 3D에서 :

func _physics_process(delta):
    var space_state = get_world().direct_space_state

Raycast query

For performing a 2D raycast query, the method Physics2DDirectSpaceState.intersect_ray() may be used. For example:
2D 레이캐스트 쿼리를 수행하려면 Physics2DDirectSpaceState.intersect_ray() 메서드를 사용할 수 있습니다. 예 :

func _physics_process(delta):
    var space_state = get_world_2d().direct_space_state
    # use global coordinates, not local to node
    var result = space_state.intersect_ray(Vector2(0, 0), Vector2(50, 100))

The result is a dictionary. If the ray didn’t hit anything, the dictionary will be empty. If it did hit something it will contain collision information:
결과는 딕셔너리 사전입니다. 레이가 아무 것도 치지(hit) 않으면 사전이 비어있게됩니다. 충돌 한 경우 충돌 정보가 포함됩니다.

if result:
	print("Hit at point: ", result.position)

The result dictionary when a collision occurs contains the following data:
충돌이 발생할 때 결과 사전에 다음 데이터가 포함됩니다.

{
   position: Vector2 # point in world space for collision
   normal: Vector2 # normal in world space for collision
   collider: Object # Object collided or null (if unassociated)
   collider_id: ObjectID # Object it collided against
   rid: RID # RID it collided against
   shape: int # shape index of collider
   metadata: Variant() # metadata of collider
}

The data is similar in 3D space, using Vector3 coordinates.
데이터는 3D 공간정보(3D Space Information)도 유사하며 Vector3 좌표를 사용합니다.

Collision exceptions

A common use case for ray casting is to enable a character to gather data about the world around it. One problem with this is that the same character has a collider, so the ray will only detect its parent’s collider, as shown in the following image:
레이 캐스팅의 일반적인 사용 사례는 캐릭터가 주변 세계에 대한 데이터를 수집 할 수있게하는 것입니다. 이 문제의 한 가지 문제점은 동일한 캐릭터에 충돌자가 있기 때문에 다음 그림과 같이 광선이 부모의 충돌 자만 탐지한다는 것입니다.

To avoid self-intersection, the intersect_ray() function can take an optional third parameter which is an array of exceptions. This is an example of how to use it from a KinematicBody2D or any other collision object node:
자체 교집합을 피하기 위해 intersect_ray() 함수는 선택적 배열 인 선택적 세번째 매개 변수를 사용할 수 있습니다. 다음은 KinematicBody2D 또는 다른 충돌 객체 노드에서 사용하는 방법의 예입니다.

extends KinematicBody2D

func _physics_process(delta):
    var space_state = get_world_2d().direct_space_state
    var result = space_state.intersect_ray(global_position, enemy_position, [self])

The exceptions array can contain objects or RIDs.
예외 배열에는 객체 또는 RID가 포함될 수 있습니다.

Collision Mask

While the exceptions method works fine for excluding the parent body, it becomes very inconvenient if you need a large and/or dynamic list of exceptions. In this case, it is much more efficient to use the collision layer/mask system.
exceptions 메소드는 상위 본문을 제외시키는 데는 효과가 있지만 대용량/동적 예외 목록이 필요한 경우 매우 불편합니다. 이 경우 충돌 레이어/마스크 시스템을 사용하는 것이 훨씬 더 효율적입니다.

The optional fourth argument for intersect_ray() is a collision mask. For example, to use same mask as the parent body, use the collision_mask member variable:
intersect_ray()의 선택적 네 번째 인수는 충돌 마스크입니다. 예를 들어 모체와 동일한 마스크를 사용하려면 collision_mask 멤버 변수를 사용합니다.

extends KinematicBody2D

func _physics_process(delta):
    var space_state = get_world().direct_space_state
    var result = space_state.intersect_ray(global_position, enemy_position,
                            [self], collision_mask)

3D ray casting from screen

Casting a ray from screen to 3D physics space is useful for object picking. There is not much of a need to do this because CollisionObject has an “input_event” signal that will let you know when it was clicked, but in case there is any desire to do it manually, here’s how.
화면에서 3D 물리 공간(Space)으로 레이 캐스팅하는 것은 객체를 선택하는데 유용합니다. CollisionObject에는 클릭 한 시점을 알려주는 "input_event"신호가 있기 때문에이 작업을 수행 할 필요는별로 없지만 수동으로 수행하려는 경우가 있습니다.

To cast a ray from the screen, you need a Camera node. A Camera can be in two projection modes: perspective and orthogonal. Because of this, both the ray origin and direction must be obtained. This is because origin changes in orthogonal mode, while normal changes in perspective mode:
화면에서 레이를 투영하려면 Camera 노드가 필요합니다. 카메라는 원근법과 직각의 두 가지 투영 모드를 가질 수 있습니다. 이 때문에 광선의 원점과 방향을 모두 얻어야합니다. 직교(Orthogonal) 모드에서 원점이 변경되고 원근감(Perspective) 모드에서 정상적으로 변경되기 때문입니다.

To obtain it using a camera, the following code can be used:
카메라를 사용하여이 코드를 얻으려면 다음 코드를 사용할 수 있습니다.

const ray_length = 1000

func _input(event):
    if event is InputEventMouseButton and event.pressed and event.button_index == 1:
          var camera = $Camera
          var from = camera.project_ray_origin(event.position)
          var to = from + camera.project_ray_normal(event.position) * ray_length

Remember that during _input(), the space may be locked, so in practice this query should be run in _physics_process().
_input() 중에 공간이 잠길 수 있으므로 실제로이 쿼리는 _physics_process()에서 실행되어야합니다.

반응형

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

Godot3 API - Physics introduction  (0) 2018.11.07
Godot3 API - Using KinematicBody2D  (0) 2018.11.06
Godot3 API - InputDefault  (0) 2018.11.02
Godot3 API - Input  (0) 2018.11.02
Godot3 API - Customizing mouse cursor  (0) 2018.11.01