Impact Particles
LineTrace로 적중한 위치에 Particle을 소환하는것을 코드로 구현한다.
ShooterCharacter.h
// Particles spawned upon bullet impact
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Combat, meta = (AllowPrivateAccess = "true"))
UParticleSystem *impactParticles; // 전방선언은 전에 MuzzleFlash에서 해주어서 생략 가능
ShooterCharacter.cpp
void AShooterCharacter::FireWeapon(const FInputActionValue &Value)
{
...
if (BarrelSocket)
{
...
FHitResult FireHit;
...
if (FireHit.bBlockingHit)
{
...
if (impactParticles)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), impactParticles, FireHit.Location);
}
}
}
...
}
컴파일 이후 P_BelicaHitWorld 파티클을 BP_ShooterCharacter의 Impact Particles 변수에 적용합니다.
( 경로 : All > Content > ParagonLtBelica > FX > Particles > Belica > Abilities > Primary > FX > P_BelicaHitWorld )
이후 ABP_ShooterCharacter > AnimGraph > Ground Locomotion 에서 Idle 상태를 Idle_Zero_Pose로 바꿔서 BarrelSocket이 흔들리지 않게 설정해 줍니다.
Beam Paritcles
FX 폴더 안에 SmokeBeam 폴더를 만들어 줍니다. 이후에 다운로드를 통해서 채워줍니다.
Meterial(M_Beam, M_Beam_Faded)를 켜보면 둘다 error! 가 발생해 있는데 이를 고쳐줍시다.
그 다음 Particle(P_SmokeTrail, P_SmokeTrail_Faded)을 수정해 줍니다.
Required를 클릭해주고, Detail에서 각자에게 맞는 Material을 선택해 줍니다. (Faded는 Faded끼리)
ShooterCharacter 코드를 수정하여 궤적을 나타내는 BeamParticles를 생성하고 적용해줍니다.
ShooterCharacter.h
// Smoke trail for bullets
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Combat, meta = (AllowPrivateAccess = "true"))
UParticleSystem *BeamParticles;
ShooterCharacter.cpp
#include "Particles/ParticleSystemComponent.h"
void AShooterCharacter::FireWeapon(const FInputActionValue &Value)
{
...
if (BarrelSocket)
{
...
const FVector End{Start + RotationAxis * 50'000.f};
FVector BeamEndPoint{End};
...
if (BeamParticles)
{
UParticleSystemComponent *Beam = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), BeamParticles, SocketTransform);
if (Beam)
{
Beam->SetVectorParameter(FName("Target"), BeamEndPoint);
}
}
}
}
- ParticleSystemComponent *Beam = UGameplayStatics::SpawnEmitterAtLocation(...) : UGameplayStatics의 SpawnEmitterAtLocation 함수를 사용하여 지정된 위치에 파티클 이펙트를 생성합니다.
- SetVectorParameter : UParticleSystemComponent 클래스의 멤버 함수로, 파티클 시스템 내에서 벡터 타입의 파라미터 값을 설정하는 데 사용됩니다.
- "Target" 파라미터의 역할 :
- 파티클 시스템의 목표점 설정: "Target" 파라미터는 일반적으로 파티클 시스템에서 어떤 특정 지점을 가리키는 용도로 사용됩니다. 예를 들어, 레이저 빔이나 광선 등을 표현하는 파티클 시스템에서는 "Target"이 빔의 끝점을 나타낼 수 있습니다.
- 파티클의 동작 조절: 파티클 시스템이 "Target" 파라미터를 기반으로 파티클의 동작을 결정합니다. 예를 들어, 빔 파티클이 시작점(Beam의 위치)에서 끝점(BeamEndPoint)까지 그려질 수 있습니다.
이후 BP_ ShooterCharacter에서 BeamParticles에 P_SmokeTrail_Faded를 설정해 줍니다.
Socket Offset
지금까지 우리는 움직이는 방향을 BP_ShooterCharacter가 가리키게 하였는데 이를 해제하고, 크로스 헤어를 중앙에 놓기 위해 Camera의 위치를 조정해 줄것입니다.
아래는 ShooterCharacter.cpp의 코드이며 작성한 부분만 수정해줍니다.
ShooterCharacter.cpp
AShooterCharacter::AShooterCharacter() : BaseTrunRate(45.f), BaseLookUpRate(45.f)
{
...
// 새로 작성
CameraBoom->SocketOffset = FVector{0, 50.f, 50.f};
...
// 수정
bUseControllerRotationYaw = true;
...
// 수정
GetCharacterMovement()->bOrientRotationToMovement = false;
...
}
- CameraBoom->SocketOffset = FVector{0, 50.f, 50.f} : Spring Arm Component의 소켓 위치를 조절하는 데 사용됩니다. X축으로 0, Y축으로 50, Z축으로 50의 오프셋을 설정합니다.
- bUseControllerRotationYaw : 캐릭터가 컨트롤러(예: 게임패드, 마우스)의 Yaw 회전(좌우 회전)을 따라 회전할지 여부를 결정합니다.
- bOrientRotationToMovement : 캐릭터가 이동하는 방향으로 자동으로 회전할지 여부를 결정합니다.
컴파일을 완료한 후 BP_ShooterCharacter에 잘 적용되었는지 확인해줍니다.
HUD Class and Crosshairs
아래 사진과 같이 HUD와 Crosshairs를 위한 폴더를 총 3
이후 Crosshairs 폴더에 다운받은 Textures\Textures\Icons\Crosshairs 파일들을 import 해줍니다.
모든 Cross 텍스쳐 파일을 열어서 Compression Settings를 UserInterface2D로 변경해 줍니다.
이후 HUD 폴더에 HUD를 상속하는 블루프린트를 만들어 줍니다.
이후 BP_ShooterGameModeBase로 가서 HUD Class를 방금 생성한 BP_ShooterHUD로 바꿔줍니다.
이후 BP_ShooterHUD에서 Event Receive Draw HUD노드를 생성합니다.
Event Receive Draw HUD 노드는 스크린의 사이즈를 제공합니다.
Event Receive Draw HUD
HUD (Head-Up Display) 클래스의 이벤트 중 하나로, 화면에 HUD 요소를 그리기 위해 사용됩니다. 이 이벤트는 게임의 시각적 인터페이스 요소, 예를 들어 점수, 건강 바, 미니맵, 탄약 수량 등을 그리는 데 쓰입니다.
이후 스크린의 중앙 위치를 저장할 ScreenCenter(Vector 2D) 변수를 생성하고 초기화 해줍니다.
이후 Draw Texture 노드를 사용하여 Cross_Q_9을 중앙에 그려줍니다. 설명은 사진 아래에 남기겠습니다.
- Target: 이 액션을 실행할 HUD 객체를 참조합니다. "self"는 이 노드가 포함된 현재의 HUD 인스턴스를 가리킵니다.
- Texture: 화면에 그릴 텍스처를 지정합니다. (Cross_Q_9)
- Screen X: 텍스처가 화면에 나타날 X 위치를 픽셀 단위로 지정합니다.
- Screen Y: 텍스처가 화면에 나타날 Y 위치를 픽셀 단위로 지정합니다.
- Screen W: 텍스처의 너비를 픽셀 단위로 지정합니다.
- Screen H: 텍스처의 높이를 픽셀 단위로 지정합니다.
- Texture U (U Start): 텍스처의 U 좌표를 나타냅니다. 이것은 텍스처의 어떤 부분을 HUD에 그릴지 결정하는 시작점입니다.
- Texture V (V Start): 텍스처의 V 좌표를 나타냅니다. 이것은 U 좌표와 함께 텍스처의 특정 부분을 그리기 위한 시작점을 정의합니다.
- Texture UWidth (U Size): 텍스처의 U 방향의 크기를 정의합니다. 이 값은 텍스처의 가로 부분이 얼마나 그려질지 결정합니다.
- Texture VHeight (V Size): 텍스처의 V 방향의 크기를 정의합니다. 이 값은 텍스처의 세로 부분이 얼마나 그려질지 결정합니다.
이후 컴파일 하고 실행하면 아래와 같이 오른쪽아래로 치우친 크로스 헤어가 보이는데, 이는 좌상단을 기준으로 크로스헤어를 그렸기 때문이다. 따라서 이를 보완하기 위해서 크로스헤어의 크기의 반만큼 이동시키는 작업이 필요하다.
BP_ShooterHud에서 CrosshairHarfWidth(float) 변수를 만들고 기본 값을 32로 설정해 준다. (64의 절반)
이후 아래와 같이 설정해서 크로스헤어가 가운데 가도록 수정해 줍니다.
강의에선 크로스헤어가 낮다고 변수를 하나더 만들어서 사용하는데, 저는 안하겠습니다.
마지막으로 주석(단축키 C)을 생성해 줍니다.
Directing Rifle Shots
크로스헤어로 총을 쏘기 위해서 ShooterCharacter.cpp를 바꿔 줄것입니다. 우선 아래의 코드를 주석처리 해줍니다.
ShooterCharacter.cpp
/*
FHitResult FireHit;
const FVector Start{SocketTransform.GetLocation()};
const FQuat Rotation{SocketTransform.GetRotation()};
const FVector RotationAxis{Rotation.GetAxisX()};
const FVector End{Start + RotationAxis * 50'000.f};
FVector BeamEndPoint{End};
GetWorld()->LineTraceSingleByChannel(FireHit, Start, End, ECollisionChannel::ECC_Visibility);
if (FireHit.bBlockingHit)
{
// DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 2.f);
// DrawDebugPoint(GetWorld(), FireHit.Location, 2.f, FColor::Red, false, 2.f);
BeamEndPoint = FireHit.Location;
if (impactParticles)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), impactParticles, FireHit.Location);
}
}
if (BeamParticles)
{
UParticleSystemComponent *Beam = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), BeamParticles, SocketTransform);
if (Beam)
{
Beam->SetVectorParameter(FName("Target"), BeamEndPoint);
}
}
*/
주석으로 처리한 부분을 아래와 같이 수정해 줍니다.
// 현재 뷰포트의 크기 가져오기
FVector2D ViewportSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
// 크로스헤어의 화면 공간 위치 가져오기
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
// 크로스헤어의 월드 위치 및 방향 가져오기
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(this, 0),
CrosshairLocation,
CrosshairWorldPosition,
CrosshairWorldDirection);
if (bScreenToWorld) // 투영이 성공했는지 확인
{
FHitResult ScreenTraceHit;
const FVector Start{CrosshairWorldPosition};
const FVector End{CrosshairWorldPosition + CrosshairWorldDirection * 50'000.f};
// 빔의 끝점을 라인 트레이스의 끝점으로 설정
FVector BeamEndPoint{End};
// 크로스헤어의 월드 위치에서 외부로 추적
GetWorld()->LineTraceSingleByChannel(ScreenTraceHit, Start, End, ECollisionChannel::ECC_Visibility);
if (ScreenTraceHit.bBlockingHit) // 트레이스 히트가 있는지 확인
{
// 빔의 끝점을 트레이스 히트 위치로 설정
BeamEndPoint = ScreenTraceHit.Location;
if (impactParticles)
{
// 이펙트 파티클 생성
UGameplayStatics::SpawnEmitterAtLocation(
GetWorld(),
impactParticles,
ScreenTraceHit.Location);
}
if (BeamParticles)
{
// 빔 파티클 생성
UParticleSystemComponent *Beam = UGameplayStatics::SpawnEmitterAtLocation(
GetWorld(),
BeamParticles,
SocketTransform);
if (Beam)
{
Beam->SetVectorParameter(FName("Target"), BeamEndPoint);
}
}
}
}
'Unreal 공부 > Unreal Engine 4 C++ The Ultimate Shooter' 카테고리의 다른 글
Animation - 5 (1) | 2023.12.31 |
---|---|
Animation - 4 (1) | 2023.12.31 |
Animation - 2 (1) | 2023.12.28 |
Animation (0) | 2023.12.27 |
[UE] C++에서 SpringArm과 Camera 구현하기 (1) | 2023.12.22 |