Unity DOTS/Unity.Physics

unity.physics - CastRay 레이케스트

개양반 2022. 12. 4.
728x90

1. 개요

UNITY DOTS는 unity.physics로 물리를 구현한다. unity.physics에서 Ray를 사용하는 방법에 대해 알아보자.

이해를 돕기 위해 테스트 환경을 만드는 과정까지 세세히 설명했다. RayCast 코드를 보고 싶으신 분은

3. RayCast 구현으로 넘어가면 된다.

 

2. 환경 만들기

2-1 서브 씬 만들기

Hirarchy뷰에 마우스 우클릭 -> New Sub Scene를 눌러 Entity를 생성할 SubScene을 만든다.

 

2-2 테스트할 게임오브젝트 제작

2-2-1 Cube 생성하기

위에서 만든 Sub Scene에 Cube 두개를 생성하고 Transform.Position.z 값을 적당히 설정하여 떨어트린다. 정면의 대상을 탐색할 예정이다.

 

2-2-2 Physics Shape

위에서 만든 Cube 두 개에 Physics Shape를 Component로 추가한다.

 

2-2-3 PhysicsCategoryNames

Collision Filter의 Belongs To의 드롭다운 창을 클릭한다. 맨 아래에 Edit Physics Category Names를 클릭한다.

 

Physics Category Names에 Player와 Enemy를 추가한다.

 

Physics Shape의 Belongs To에 0: Player 또는 1: Enemy를 각각의 Cube에 설정한다. 

Belongs To : 본인이 속할 그룹, Colliders With: 충돌할 대상의 그룹

 

2-2-4 스크립트 작업

PlayerData.cs 를 만들고 아래의 코드를 작성한다.

using Unity.Entities;
using UnityEngine;

public struct PlayerData : IComponentData
{
    public int Health;
}

 

PlayerAuthoring.cs를 만들고 아래의 코드를 작성한다.

using Unity.Entities;
using UnityEngine;

public class PlayerAuthoring : MonoBehaviour
{
    public int health;

    class Baker : Baker<PlayerAuthoring>
    {
        public override void Bake(PlayerAuthoring authoring)
        {
            AddComponent(new PlayerData { Health = authoring.health });
        }
    }

 

PlayerAuthoring.cs을 Hirarchy View에서 위에서 만든 두개의 Cube에 추가한다.

 

3. RayCast 구현하기

3-1 스크립트 작성

TestPhysicsRayCastSystem.cs를 만들고 아래의 코드를 작성한다.

using Unity.Entities;
using Unity.Physics;
using Unity.Transforms;
using UnityEngine;

public partial struct TestPhysicsRayCastSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        
    }

    public void OnDestroy(ref SystemState state)
    {
    }

    public void OnUpdate(ref SystemState state)
    {
        // 레이캐스트를 사용하기 위해 PysicsWorldSingleton이 필요하다.
        PhysicsWorldSingleton physicsWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>();

        foreach (var (player, tranform) in SystemAPI.Query<RefRO<PlayerData>, TransformAspect>())
        {
            var ray = new RaycastInput()
            {
                Start = tranform.Position,
                End = tranform.Forward * 10,
                Filter = new CollisionFilter
                {
                    GroupIndex = 0,

                    // 1u << 0는 Physics Category Names에서 0번째의 레이어마스크이다.
                    // 1u << 1는 Physics Category Names에서 1번째의 레이어마스크이다.
                    BelongsTo = 1u << 0,
                    CollidesWith = 1u << 1
                }
               
            };

            // 레이캐스트 발사 후 hit가 존재하면 if 실행
            if (physicsWorld.CastRay(ray, out var hit))
            {
                Debug.Log($"{hit.Position}");
                Debug.Log($"{hit.ToString()}");
                Debug.Log($"{hit.Entity.Index}");
            }
        }
       
        state.Enabled = false;
    }
}

 

3-2 결과

유니티로 돌아와서 재생 버튼을 눌러 확인한다.

맨 윗 두줄은 Authoring을 위해 만들었던 Cube의 정보이고 그 다음 아랫줄부터는 Cube가 Entity로 전환된 뒤의 로그이다.

 

4. 번외 CollisionFilter Authoring

PhysicsCategoryTags를 Authoring의 맴버 변수로 만들 수 있다.

using Unity.Entities;
using UnityEngine;
using Unity.Physics.Authoring;
using Unity.Physics;

public class PlayerAuthoring : MonoBehaviour
{
    public int health;
    public PhysicsCategoryTags BelongsTo;
    public PhysicsCategoryTags CollidesWith;

    class Baker : Baker<PlayerAuthoring>
    {
        public override void Bake(PlayerAuthoring authoring)
        {
            CollisionFilter filter = CollisionFilter.Default;
            filter.CollidesWith =authoring.CollidesWith.Value;
            filter.BelongsTo = authoring.BelongsTo.Value;

            AddComponent(new PlayerData
            {
                Health = authoring.health,
                Filter = filter
            });
        }
    }
}

 

 그럼, Inspector View에서 Filter를 설정할 수 있다.

댓글

💲 추천 글