본문 바로가기

[언리얼5] 블루프린트를 이용하여 간단한 슈팅방 만들기 - 2

Kwonriver 2023. 1. 3.
728x90

 

[개요]

언리얼 5.1과 블루프린트를 이용하여 간단하게 물리 슈팅 게임을 만들어본다.

2장에서는 간단한 투사체를 만들고 키보드를 눌러 투사체를 발사한다.

 

블루프린트를 이용하여 간단한 슈팅방 만들기 - 1

블루프린트를 이용하여 간단한 슈팅방 만들기 - 3


 

[투사체 만들기]

언리얼 좌측에 있는 [액터 배치] - [셰이프]를 선택하면 큐브, 스피어, 실린더 등의 도형을 배치할 수 있는 창이 나타난다. 해당 창에서 스피어를 선택하여 드래그 앤 드랍으로 뷰포트에 배치한다.

 

 

이 스피어의 크기를 조절하여 약간 긴 투사체로 만들어준다. 액터를 선택한 채로 R 키를 눌러 스케일을 조절할 수 있는 상태로 변경하고 적절하게 크기를 조절한다. 디테일 패널의 트랜스폼에서 스케일을 조절해도 무방하다. (1.25, 0.25, 0.25로 조절했다.)

 

 

투사체가 하얀 것이 좀 이상하다. 머티리얼을 변경하여 색상을 바꿔본다. 해당 액터를 선택한 채로 디테일 패널에 [머티리얼] 을 보면 얼리먼트 0으로 하얀색의 BasicSphereMaterial이 설정되어 있는 것을 볼 수 있다. 이름을 선택하여 원하는 머티리얼로 변경하자. 총알 느낌을 내기 위해 M_Metal_Chrome을 사용하였다.

 

 

이제 이 액터를 상속받는 블루프린트 클래스를 만든다. 해당 액터를 선택한 채로 디테일 패널을 보면 [+추가] 옆에 뻗어나가는 모양의 버튼을 볼 수 있다. 해당 버튼을 클릭하면 해당 액터를 사용한 블루프린트 클래스를 생성할 수 있다. 

 

 

액터의 이름은 BP_Projectile로 설정하고 [새 서브클래스]로 생성한다. 접두어로 BP_를 붙여 이 클래스가 블루프린트 클래스라는 것을 알게한다. 선택 버튼을 클릭하면 아래 사진과 같은 블루프린트 클래스 편집창이 나타난다. 

 

 

앞서 뷰포트에서 만들었던 모양 그대로의 스태틱 메시를 포함한 블루프린트 클래스가 생성되었다. 이 액터도 시뮬레이션을 진행해야하므로 디테일 패널에서 [피직스] - [Simulate Physics]를 활성화해준다. 콘텐츠 브라우저에서 이 블루프린트 클래스를 확인할 수 있다.

 

 


[투사체 생성하기]

레벨 블루프린트를 이용하여 이 투사체를 발사한다. 에디터 좌측 상단에 있는 블루프린트 생성 모양 버튼을 클릭하면 레벨 블루프린트를 열 수 있는 창이 나타난다. 레벨 블루프린트를 열면 아까 보았던 BP_Projectile과 유사한 블루프린트 편집창이 나타난다. 단, 레벨 블루프린트는 컴포넌트를 추가할 수 없어 이벤트 그래프만 존재한다.

 

 

이벤트 그래프에서 우클릭을 하면 다양한 기능을 선택할 수 있는 리스트가 나타나는데 검색에 [스페이스 바]를 입력하고 선택하여 새로운 이벤트 노드를 추가한다.

 

 

이처럼 이름 부분에 빨간색으로 처리된 노드는 이벤트 노드이다. 특정 이벤트가 발생하면 실행하게 되는데 [스페이스 바]의 경우 키보드 스페이스 바를 누르면 Pressed 노드가, 키에서 손을 떼면 Released 노드가 실행된다. 스페이스바를 눌렀을 때 총알이 발사되게 할 것이므로 Pressed 노드만 신경쓴다.

 

투사체를 생성하기 위해 SpawnActor 함수를 사용한다. 이벤트 그래프를 우클릭하여 SpawnActor from class를 검색하여 선택한다. 클래스에는 위에서 만들었던 BP_Projectile을 선택하고 Pressed 노드를 연결한다.

 

 

Tranform에는 Location, Rotation, Scale이 존재한다. 다만 여기서는 Location과 Rotation만 사용하는데 플레이어의 위치에서 플레이어가 바라보고 있는 방향으로 투사체를 발사할 것이므로 Scale의 조정은 따로 필요하지 않다. 이를 위해서 함수 노드의 핀을 분리해준다.

 

 

Spawn Transform 핀을 우클릭하고 구조체 핀 분할을 누르면 Location, Rotation, Scale로 분리된다. 다시 재결합도 가능하니 걱정하지 않아도 된다. 각각은 액터가 스폰될 위치, 액터 회전 정도, 액터의 크기를 나타낸다.

 

플레이어의 위치에서 발사할 것이기 때문에 플레이어의 정보를 가져와야한다. 빈 공간에서 우클릭을 한 뒤 Get Player Pawn 함수를 가져온다. Player Index는 플레이어의 넘버를 의미하지만 로컬 게임에서는 0이 현재 플레이어를 의미한다.

더보기

Player Index는 플레이어 컨트롤러의 인덱스로 네트워크 게임이 아니라면 대부분 0이다. 로컬 게임에서 시작 시 게임모드에 의해 플레이어 컨트롤러가 생성되는데 이 때 기본적으로 0에 바인딩 된다.

 

해당 함수의 리턴 핀(Return Value)를 클릭하고 끌어내면 해당 밸류와 연관되어 있는 함수들이 리스트로 나온다. 

 

 

액터의 위치를 가져오는 Get Actor Location 함수와 컨트롤러의 방향(시야 방향)을 가져오는 Get Control Rotation 함수를 호출하고 해당 함수들의 리턴 밸류를 SpawnActor 함수의 Spawn Transform Location, Spawn Transform Rotation에 연결한다.

더보기

GetActorRotation 함수도 있는데 이는 컨트롤러가 아닌 Pawn의 회전 정보를 가져오는 함수이다. 현재는 Pawn의 메시를 세팅하지 않았기 때문에 눈에 보이지 않지만 현재 상태에서 마우스 회전 시 회전하는 것은 Pawn이 아닌 Player Controller이다. 따라서 실제 회전하고 있는 Player Controller의 회전 정보인 Get Control Rotation 함수를 이용하여 회전을 설정한다.

 

 

에디터 뷰포트에 돌아와서 실행한 뒤 스페이스 바를 누르면 앞에서 만든 BP_Projectile이 마구 생성되는것을 볼 수 있다.

 

 


[투사체 날리기]

위에서 만들어진 투사체는 날아가지 않고 바로 바닥으로 떨어진다. 이 액터에 힘을 가해 앞으로 날아가도록 한다. 우선 멤버 함수가 필요하다. 레벨 블루프린트에서 Spawn Actor 함수를 통해 만들어진 액터는 BP_Projectile이다. 이 블루프린트 클래스의 멤버 함수를 호출하여 앞으로 날아가도록 한다. 

 

BP_Projectile 블루프린트 클래스로 돌아와서 왼쪽에 [내 블루프린트]에서 [함수] 옆에 있는 [+]버튼을 누르면 새로운 함수를 만들 수 있다. 

 

생성된 함수는 입력노드를 하나 가지고 있게 된다. 이 액터를 움직이게 하기 위해 물리적인 힘을 가할 것인데 그 때 사용하는 함수는 Add Impulse 함수이다. 이벤트 그래프를 우클릭하여 Add Impulse를 검색하면 Add Impulse(StaticMeshComponent)가 있다. 이는 타겟이 StaticMeshComponent라는 의미로 이 함수를 추가한다.

 

BP_Projectile은 플레이어가 발사한 투사체이기 때문에 앞으로 나아간다. 이 때 앞은 전방 벡터(Forward Vector)로 표현되는데 이 또한 언리얼에서 기본적으로 제공한다. Get Actor Forward Vector 함수가 이 액터의 전방 벡터를 반환하는 함수이므로 이를 사용한다. 이 때 반환되는 전방 벡터는 Normalize된 벡터이므로 크기가 매우 작다. 따라서 적절한 스칼라 값을 곱해 Add Impulse 함수에 연결한다. 여기에 사용된 스칼라 값이 사실상 힘이다.

 

 

이제 레벨 블루프린트로 돌아와 해당 함수(Fired)를 호출해준다.

 

 

이제 뷰포트 에디터에서 실행하고 스페이스 바를 누르면 앞으로 날아가는 투사체를 볼 수 있다. 그런데 생각보다 앞으로 많이 안날아가는데 이는 Vel Change 를 사용하여 변경할 수 있다. Add Impulse 함수에는 Vel Change라는 입력 핀이 있었는데 이 것을 True 로 넘기면 impulse의 힘을 속도 변화로 변경해서 받아들여 매우 빠르게 날아가는 모습을 볼 수 있다.

 

 

이렇게 날아가는 투사체는 얇은 벽이나 사물을 그대로 통과해버리기도 한다. 이를 방지하기 위해 CCD 라는 기능이 존재한다. BP_Projectile이 생성될 때 SetUseCCD 함수를 호출하여 CCD를 사용하도록 한다.

 

다만 이 때는 BeginPlay가 아닌 Construction Script에서 호출하였다. BeginPlay는 게임이 시작될 때 발생하는 이벤트이며 Contruction Script는 해당 액터가 생성될 때 호출되는 스크립트이다.

더보기

이 예제에서는 SetUseCCD를 어디에서 호출하든 동일한 효과를 발생시키지만 Construction Scirpt가 Begin Play보다 먼저 호출된다는 점을 기억하자. Construction Scirpt는 게임이 시작하기 전에, Begin Play는 게임이 시작한 후에 호출된다.

 

 

Actor Lifecycle

What actually happens when an Actor is loaded or spawned, and eventually dies.

docs.unrealengine.com

 

 

SetUseCCD를 True로 변경하고 난 뒤 특정 위치에서 발사할 때 이상하게 날아가는 것을 볼 수 있다. 이는 플레이어의 콜리전에 투사체가 충돌되면서 발생한 이슈이다. 따라서 플레이어가 바라보고 있는 방향보다 조금 앞에서 발사되도록 수정한다.

 

레벨 블루프린트로 돌아와 Spawn Actor 함수에서 Set Transform Location 하는 부분이 있다. 플레이어 컨트롤러의 전방 벡터를 가져와 스칼라를 곱한 뒤 위치를 세팅한다. GetControlRotation 했을 때와 동일한 이유이다. 다만 GetControlForwardVector 같은 함수가 없으므로 GetController를 호출한 뒤 ForwardVector를 가져온다.

 

 

이렇게 하면 투사체가 Player Pawn에 부딪치지 않고 앞으로 발사된다.

 


[투사체 파괴하기]

현재는 투사체를 무한하게 만들어낼 수 있다. 다만 계속해서 만들어내다보면 연산량이 증가해 프레임이 지속적으로 떨어지게 된다. 이를 방지하기 위해 일정 시간이 지난 투사체는 삭제되도록 한다. 

 

BP_Projectile의 이벤트 그래프에서 BeginPlay 이벤트 발생 시에 타이머를 생성하도록 한다. 이때 Set Timer by Function Name 함수를 사용하여 타이머를 생성하는데 이 함수는 일정 시간이 지난 뒤 Function Name이 자동적으로 실행되도록 한다. 생성된 타이머 핸들러는 변수로 승격하여 액터가 파괴될 때 함께 제거되도록 한다.

 

 

이제 Function Name을 채워준다. 위에서 만들었던 멤버 함수 기능을 이용하여 새로운 함수를 추가한다. DestroySelf 라는 이름의 함수를 만든 다음 Function Name에 입력해준다. 오탈자가 발생할 경우 실행되지 않기 때문에 오타가 나지 않도록 잘 입력한다.

 

이제 DestroySelf 함수에서 스스로를 파괴시키는 부분을 작성한다. 타이머 핸들러를 먼저 Clear 하고 스스로를 파괴시킨다.

이렇게 블루프린트를 작성한 뒤 실행하면 발사된 투사체는 일정 시간이 지난 뒤 파괴된다. 게임 시작 후 디테일 패널에서 BP_Projectile이 생성되었다가 사라진다. 회색으로 표시되는 것은 제거중인 상태를 의미한다.

 

 

 

728x90