[업데이트 예정]Unity 토이프로젝트 찍먹 - 물리

Changhoony·2022년 11월 18일
0

Unity_Toy_Project

목록 보기
4/4
post-thumbnail

목표

Trigger와 Collision을 자유 자재로 다룰 수 있다.

방법

1. UnityEngine의 Collider와 Collision에 대해 컴포넌트 기본 구성을 이해한다.
2. ECS DOTS 1.0 기반의 물리 충돌은 ITriggerEventJob 혹은 ICollisionEventJob을 활용한다.

순서

1. UnityEngine의 물리관련 컴포넌트 정리 [Collider , RigidBody]
2. 자주 쓰거나 중요한 팁과 관련된 정보 정리
3. ECS와 기존 컴포넌트 구성과 비교
4. ECS 스크립트 예제


UnityEngine


1. RigidBody


  • useGravity
    0이면 중력의 영향을 받지 않는다. 그 외에는 영향을 받는다.
  • IsKinematic
    충돌 효과를 없앨 수 있다. Trigger 는 가능.
  • Interpolate
    캐릭터의 움직임을 상황에 맞게 보간하는 기능
    -interpolate : 이전 프레임을 근거로 다음 프레임을 보간.
    -exterpolate : 다음 프레임을 근거로 이전 프레임을 보간.
    ex. 콜라이더 벽을 뚫는 현상을 완화 하기 위해서는 exterpolate가 더 낫다.
  • CollisionDetection
    -Discrete : 기본값, 모든 충돌 감지
    -Continuous : 배경 감지 / ContinuousDynamic : 동적 감지 ( 일반과 배경감지를 번갈아 탐지 , 정밀함)
  • Contraint
    위치나 회전 값을 고정시킬 수 있는 기능.

2. Collider


  • IsTrigger
    트리거 감지 기능 스위치 : OnTriggerEvent
  • 복잡한 콜라이더
    PolygonCollider 사용.

  1. Joint

  • Fixed Joint
    특정 힘 이상을 가하면 부러지는 효과를 표현할때 사용.
  • Spring Joint
    스프링 효과, 감속 비율, 최대 최소 거리, 브레이크 포스 등을 설정할 수 있음.
  • Hinge Joint
    축을 기준으로 원 운동을 하는 효과 (경첩, 모터 등)
  • Character Joint
    Ragdoll , 캐릭터 관절 효과를 표현할 수 있음.
  • Configurable Joint
    커스텀 조인트, 모든 기능 내포, 상세 설정 가능.

3. Tip


  • 충돌이 아니라 트리거면, 키네마틱 설정은 꼭 하고 넘어가자.
  • FixedUpdate에서 함수 호출.
  • 콜라이더 태그 사용 꼭 하기.
    ProjectSetting => Physics / Physics2D => 콜라이더 관계 체크
  • 스크립팅
    Trigger 나 Collision의 Stay이벤트에서는 IEnumerator를 사용할 수 있다. - 제어가능
    ex.
    private IEnumerator OnTriggerStay(Collide col) { ... }

4. ECS와 비교.


PhysicsBody (Rigidbody 대응)

  • motionType
    동적, 키네마틱, 정적 타입.
  • smoothing
    기존 리지드 바디의 'CollisionDetection'과 대응
  • ~Damping
    감속을 나타내는 프로퍼티, friction과 대응
PhysicsShape (Collider 대응)

  • shapeType
    3D를 타깃으로 만들어져 있다고 하지만, 2D에서 사용해도 괜찮음. 기존의 박스콜라이더, 서클콜라이더 모양 고르는 부분
  • BevelRadius
    둥근 모서리 너비, 각진 모서리를 둥글게 처리해 박스콜라이더와 스피어콜라이더를 둘다 타협해서 활용할 수 있음.
  • Material Template
    Create => DOTS => Physics 에 템플릿을 만들 수 있으니 참고.
  • Collision Response
    Trigger 이벤트와 Collision 이벤트를 분리할 수 있음. 개별처리 쌍방처리 모두 가능.
  • Collision Filter
    충돌 태그 카테고리, 아래 Advanced는 MaterialTemplate과 연관이 있다.
    BelongsTo : 현재 속한 태그 ( 내 태그 )
    CollideWith : 반응 대상 태그 ( 상대방 태그 )
  • Advanced
    CustomTags : 머터리얼 관련 태그

5. ECS 예제


5.1 이전 포스팅 기준으로 이어서 만들었다.

5.2 총알을 발사하고, 아이템을 만들어 생성된 오브젝트를 파괴하여 점수를 획득하는 로직을 구현하였다.

5.3 추가한 스크립트는 '충돌처리 이벤트 스크립트'와 '점수 스크립트' 둘이다.
5.4 ISystem이나 SystemBase나 둘다 가능하지만 이번에는 SystemBase로 만들었다.


ex. 충돌 이벤트 시스템

[UpdateInGroup(typeof(PhysicsSystemGroup))]
[UpdateAfter(typeof(EndSimulationEntityCommandBufferSystem))]
[BurstComplie]
public partial struct BulletColliderSystem : SystemBase
{
	[BurstCompile]
    protected override void OnUpdate()
    {
    	  // 이벤트 주체와 이벤트 대상을 찾는다.
    	  var enemies =  SystemAPI.QueryBuilder().WithAll<BallTag>().Build().ToEntityArray(Allocator.Persistent);
          var weapons =  SystemAPI.QueryBuilder().WithAll<BulletTag>().Build().ToEntityArray(Allocator.Persistent);
          
          var ecb = SystemAPI.GetSingleton<EndFixedStepSimulationEntityCommandBufferSystem.Singleton>()
            .CreateCommandBuffer(World.Unmanaged);
          
          // 점수 스크립트
          var pointEntity = SystemAPI.GetSingletonEntity<PointComponent>();
          var pointComponent = SystemAPI.GetSingleton<PointComponent>();
          
          // 충돌 처리를 잡 시스템에 위임
           var bulletColliderEventJob= new BulletColliderEventJob
           {
              Enemies = enemies,
              Weapons = weapons,
              Ecb = ecb,
              PointComponent = pointComponent,
              Point = pointEntity
            
           }.Schedule(SystemAPI.GetSingleton<SimulationSingleton>(), Dependency);
        
        Debug.Log($"point : {pointComponent.Point}");
        
        bulletColliderEventJob.Complete();
        
        // 점수를 UI에 보낸다.
        GameManager.Instance.UpdatePoint(pointComponent.Point);
    }
}
 [BurstCompile]
 public partial struct WeaponColliderEventJob : ITriggerEventsJob
 {
        // 충돌 주체와 , 충돌 대상 배열
 	    [ReadOnly] public NativeArray<Entity> Enemies;
        [ReadOnly] public NativeArray<Entity> Weapons;
        
        // 파괴 처리 버퍼
        public EntityCommandBuffer Ecb;
        
        // 점수
        public PointComponent PointComponent;
        public Entity Point;
        
        public void Execute(TriggerEvent collisionEvent)
        {
              // 자기들 끼리 충돌이면 무시하고
        	  if (InTheSameGroups(collisionEvent.EntityA, collisionEvent.EntityB))
                return;
        
              // 상대를 충돌하면 파괴하고 점수 올린 뒤, 점수 스크립트에 값을 할당한다.
              if (Enemies.Contains(collisionEvent.EntityA) && Weapons.Contains(collisionEvent.EntityB))
              {
                  Ecb.DestroyEntity(collisionEvent.EntityA);
             
                  PointComponent.Point++;
                  Ecb.SetComponent(Point,PointComponent);
                  Debug.Log($"[Collide] : entityA - ball - [{collisionEvent.EntityA} | entityB - bullet - [{collisionEvent.EntityB}]");
              }
        
              if (Weapons.Contains(collisionEvent.EntityA) && Enemies.Contains(collisionEvent.EntityB))
              {
                  Ecb.DestroyEntity(collisionEvent.EntityB);
                
                  PointComponent.Point++;
                  Ecb.SetComponent(Point,PointComponent);
                  Debug.Log($"[Collide] : entityA - bullet - [{collisionEvent.EntityA} | entityB - ball - [{collisionEvent.EntityB}]");
              }
        }
        
        // 자기들 끼리 충돌 되는 것을 방지하는 부분.
        private bool InTheSameGroups(Entity entityA, Entity entityB)
        {
            return InTheSameGroup(Enemies, entityA, entityB) || InTheSameGroup(Weapons, entityA, entityB);
        }
        
        private bool InTheSameGroup(in NativeArray<Entity> group, Entity entityA, Entity entityB)
        {
            return group.Contains(entityA) && group.Contains(entityB);
        }
 }

결과 ▼

  • 탕탕 특공대 슈리켄을 클론 해보았다. (이전에 만든 회전 참고)
  • UI 연동은, 아직 베타버전이어서 그런지 플레이모드를 재시동걸면 잘 작동하지 않는데, 이럴 때는 에디터 컴파일을 갱신해주고 다시 시작해보면 잘 작동한다.
  • 이 점수를 체력 컴포넌트에 대입하면 체력이 될 것이고, 점수를 더하고 빼는 기능을 활용하면 Buff시스템도 만들 수 있다.
  • CollisionEvent는 ICollisionEvent를 job에 연결하면된다.

profile
Unity 개발

0개의 댓글