캐스팅(Casting)

 

작성 기준 버전 :: 4.21 - 4.26

 

프로그래밍 작업을 할 때 캐스팅, 즉 형 변환은 상당히 중요하다. 특히 여러 클래스가 상속으로 엮여있는 상황이라면 더더욱 중요해진다. 언리얼 엔진에서는 대부분의 클래스가 AActor 클래스를 상속받고 있고, 개발자가 만들어내는 클래스 역시 상당수는 AActor를 상속받게 된다.

 

C++

 

그렇기 때문에 몇몇 함수들은 이렇게 메인이 되는 부모 클래스를 매개변수로 받거나 돌려준다. 간단한 예를 들자면 다음 함수가 있다.

 

void AActor::NotifyActorBeginOverlap(AActor* OtherActor)
{

}

 

NotifyActorBeginOverlap() 함수는 액터의 콜리전에 콜리전을 가진 다른 액터가 들어오기 시작했을 때 호출되는 함수로, 매개변수를 통해서 자신의 콜리전과 접촉한 액터를 알려준다. 언리얼 엔진에서는 레벨에 배치되는 모든 오브젝트는 AActor 클래스를 상속받기 때문에, 콜리전과 접촉한 액터가 어떤 클래스던지 상관없이 무조건 AActor 클래스로 보내주는 것이다.

 

만약 콜리전 체크를 하는 액터가 겹침 이벤트가 발생할때마다 데미지를 입는 클래스인데 데미지를 입힐 수 있는 클래스가 AProjectile 클래스라고 가정했을 때, 위의 예시 코드처럼 별도의 검사를 하지 않는다면, 액터가 아무 물체에나 스칠 때마다 데미지를 입어버릴 것이다.

 

그래서 필요한 것이 바로 캐스팅이다. 언리얼 엔진에서는 Cast<T>() 라는 함수로 기본적인 캐스팅을 제공한다.

 

void AActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
    AProjectile* Projectile = Cast<AProjectile>(OtherActor);
    if (Projectile)
    {
        // Damage Process
    }
}

 

바로 위의 예시 코드처럼 캐스팅을 진행하면 된다. 만약 콜리전에 검출된 액터가 AProjectile 클래스가 아니라면 캐스팅에 실패할 것이고 Projectile 변수의 값을 nullptr이 되기 때문에 if문 안으로 진행하지 못해서 Damage Process가 진행되지 않는다.

 

블루프린트

 

블루프린트 작업에서도 캐스팅이 가능하다.

 

 

 

블루프린트 컨텍스트 메뉴에서 "형변환"이나, 캐스팅하고자 하는 타입의 클래스 명을 검색하면 해당 클래스로 형변환할 수 있는 노드를 추가할 수 있다.

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

BoxCast, SphereCast, CapsuleCast 제대로 사용하기

 

지난 Physics 섹션에서는 매 프레임 콜라이더 충돌을 검출하지 않고 원하는 순간에만 콜라이더를 검출해낼 수 있는 Cast 계열의 함수들에 대해서 알아보았다. 이번 섹션에서는 그 중에서도 BoxCast, SphereCast, CapsuleCast를 제대로 사용하는 방법에 대해서 알아보자.

 

지난 섹션에서 설명했듯이 Cast 계열의 함수는 오브젝트에서 콜라이더 컴포넌트를 가질 필요도 없고, OnCollision이나 OnTrigger같은 이벤트를 통해 매 프레임 동작하는 낭비를 줄일 수 있다. 하지만 이러한 Cast 계열의 함수에는 작은 단점이 하나 존재한다.

 

게임 오브젝트가 콜라이더 컴포넌트를 가지고, 이벤트를 통해 작동하는 경우에는 Scene 뷰에서 콜라이더의 위치나 크기, 방향 등을 확인할 수 있지만, 이 Cast 계열의 함수의 경우에는 위치, 방향, 크기 등을 직관적으로 확인할 수 없다는 것이다. 즉, 이 Cast 계열 함수에 익숙하지 않은 사람이라면 이 Cast의 위치, 방향, 크기가 자신이 의도한대로 작동되고 있는지 확인하기가 쉽지가 않다는 의미이다. 당연하게도 이것은 확인하기 어려운 문제를 발생시킬 것이다.

 

그리고 이 Cast의 범위를 확인하기 어려운 문제는 함수의 매개변수의 이름이 불분명한 것과 함수의 매개변수 중 지정하지 않은 값의 기본값이 얼마라고 명시되어 있지 않은 점과 맞물려 전혀 예측하지 못한 형태로 작동하게 만들어 버린다.

 

 

 

 

문제

 

캐릭터 주변의 반지름 내의 범위에 존재하는 모든 적들을 찾아서 데미지를 입히는 스킬을 구현한다고 가정해보자. 이 스킬을 구현하기 위해서는 우선 SphereCastAll 함수를 사용해야 할 것이다. 우선 SphereCastAll 함수의 제일 간단한 형태를 보자면 다음과 같다.

 

RayCastHit[] Physics.SphereCastAll(Vector3 origin, float radius, Vector3 direction);

 

그림 1 : 파란색 화살표는 forward를 의미한다.

 

origin과 radius는 간단하게 이해할 수 있지만, 일반적으로 SphereCast가 위의 그림처럼 캐릭터 중심으로 구형으로 작동할 것이라고 받아들이기 쉽기 때문에 SphereCast에 익숙하지 않거나 처음 사용하는 사람의 경우에는 'Sphere가 방향이 바뀌면 뭐가 달라지지?'하는 생각에 direction에서 당황하게 될 것이다. 그리고 일반적으로 아래의 예시 코드와 같이 RayCast를 사용하듯이 direction에 character의 정면에 해당하는 transform.forward를 넣게 될 확률이 높다.

 

var hits = Physics.SphereCastAll(transform.position, radius, transform.forward);

 

 

이렇게 코드를 작성하면 잘 모르는 사용자는 위의 이미지처럼 캐릭터를 중심으로 구형의 범위 내에서만 캐스팅을 할 것이라고 생각하겠지만, 이것은 놀랍게도 전혀 다른 결과를 가져온다.

 

 

그림 2

 

첫번째 이미지처럼 동작할 것이라고 생각한 코드는 사실은 바로 위의 두번째 이미지처럼 구가 캐릭터의 전방으로 무한히 늘어선 형태로 캐스팅을 해버린다. 마치 드래곤볼의 손오공이 에너지파를 전방으로 쏘아낸 것처럼 말이다.

 

왜 이런 결과가 나왔는지에 대해서 알아보자면 다음의 좀 더 복잡한 매개변수를 가지는 SphereCastAll의 오버로드를 살펴보아야 한다.

 

RayCastHit[] Physics.SphereCastAll(Vector3 origin, float radius, Vector3 direction, float maxDistance, int layerMask);

 

위 코드를 살펴보면 제일 처음 보았던 매개변수에 maxDistance라는 매개변수가 추가된 것이 보인다. 이것은 원점인 origin으로부터 direction 방향으로 얼마나 되는 거리까지 캐스팅할 것인지를 의미한다. 그리고 이 값의 기본값은 Infinity, 즉 무한대이다. 그렇기 때문에 그림 2처럼 캐릭터의 정면을 향해서 무한히 확장되는 형태로 캐스팅이 되는 것이다.

 

이것들이 의미하는 바를 살펴보자면 BoxCast, SphereCast, CapsuleCast 등은 사실 가장 기본적인 RayCast와 똑같이 동작하며, 그 범위만 하나의 점에서 육면체, 구, 캡슐 모양으로 확장된 형태로 동작한다는 것이다.

 

그렇다면, Cast대신에 다시 콜라이더를 사용해야 하는가? 아니다. 몇가지 방법을 이용하면 충분히 캐릭터 주변의 반지름 내에서 적들을 찾아낼 수 있다.

 

 

 

 

1. direction을 Vector3.up으로

 

var hits = Physics.SphereCastAll(transform.position, radius, Vector3.up)

 

첫번째 방법은 매개변수 중에 direction 값을 Vector3.up으로 주는 것이다.

이렇게 하면 캐스팅이 위쪽으로 확장되면서 캐릭터의 주변에 있는 적들만 검출해낼 수 있게 된다. 다만, 이 방법을 썼을 때는 캐릭터의 위쪽에 있으면서 반지름 내의 범위에 있는 적도 검출되기 때문에, 캐릭터를 중심으로 완전히 구형 내에서만 적을 찾고자 한다면 다음의 방법을 쓰는게 좋다. 그리고 성능적인 면에서도 다음 방법이 훨씬 좋다.

 

 

 

 

2. maxDistance 값을 0으로

 

var hits = Physics.SphereCastAll(transform.position, radius, Vector3.up, 0f)

 

캐스팅의 범위를 캐릭터의 주변으로 제한하는 방법 중 가장 확실하고 좋은 방법은 maxDistance 값을 0으로 설정하는 것이다. 이렇게 하면 SphereCast나 BoxCast, CapsuleCast의 범위가 direction 방향으로 확장되지 않고 아래의 그림처럼 설정된 크기 내에서만 캐스팅이 이루어지게 된다.

 

 

이번 섹션에서 이야기한 문제는 예시를 보인 SphereCast뿐만 아니라 BoxCast, CapsuleCast에서도 똑같이 작용한다. 다만 SphereCast가 훨씬 간단하게 사용하고 예시를 보여줄 수 있기 때문에 SphereCast로만 예시를 보였다.

 

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

+ Recent posts