언리얼5

[UE5 Multiplayer Shooting-14] Reload, Match State, Scatter 알고리즘 구현 및 무기 추가

TIN9 2023. 8. 21.
반응형

구현 내용

  • Reloading 구현(Effect, Sound 등)
  • Updating Ammo
  • Match State
    WarmingUpState - 게임 입장 후 대기시간
    CooldownState - 게임 끝나고 대기시간
  • Rocket 구현
  • 히트스캔 무기 구현
    권총, SMG, 샷건
  • Scatter 알고리즘 구현
    랜덤하게 총알을 흩뿌리는 알고리즘(랜덤하게 총알이 발사됨)

중요한 부분

게임 모드와 게임 모드 베이스의 차이

게임 모드 (Game Mode): 게임 모드는 게임의 규칙과 로직을 관리하는 클래스입니다. 말 그대로 게임의 '모드'를 설정하며, 플레이어들이 어떻게 상호작용하고 승패를 결정할지를 결정한다고 합니다. 예를 들어 만들고자 하는 게임이 팀 전투를 다룬다면, 여기서 각 팀의 승패 조건을 정할 수 있습니다. 게임 모드는 게임 시작, 종료, 플레이어 생성 및 스폰 등을 다루며, 이러한 기능을 확장하거나 변경할 수 있고 MatchState라는 namespace를 활용하여 매치의 상태에 따른 구성을 할 수 있습니다.

게임 모드 베이스 (Game Mode Base) : 게임 모드 베이스는 여러 게임 모드에서 공통된 기능을 정의하는 클래스입니다. 여러 게임 모드 사이에서 반복되는 로직이나 기능을 한 번에 정의하고, 개별 게임 모드에서는 이를 상속받아 자신만의 독특한 특징을 추가할 수 있습니다. 게임 모드 베이스는 기본적인 게임 진행 로직을 제공하며, 이를 수정하거나 확장하여 각각의 게임 모드에 맞게 커스터마이징 할 수 있습니다.


namespace MatchState 설명

  • EnteringMap (맵 진입 중): 이 상태는 플레이어가 게임 맵에 처음 진입할 때의 상태를 나타냅니다. 게임 모드가 아직 초기화되고, 플레이어의 캐릭터들이 스폰되기 전의 단계
  • WaitingToStart (시작 대기 중): 게임이 아직 시작되지 않았고, 플레이어 캐릭터가 아직 스폰되지 않았을 때의 상태입니다.
  • InProgress (진행 중): 게임이 실제로 실행되고 있는 상태입니다. 모든 플레이어 캐릭터가 생성되어 플레이어들은 캐릭터를 제어할 수 있는 단계
  • WaitingPostMatch (게임 종료 후 대기 중): 게임이 종료되고 나서도 맵을 떠나기 전에 플레이어들이 잠시 머물러 있는 상태
  • LeavingMap (맵 종료 중): 실제로 맵을 떠나는 상태입니다. 플레이어들이 현재 맵에서 벗어나는 절차가 이루어진다.
  • Aborted (중단 상태): 게임이 강제로 종료되거나 중단된 상태입니다. 예상치 못한 상황이나 오류가 발생했을 때 사용된다.

My MatchState 추가

이처럼 게임모드에는 위와같은 MatchState가 있습니다

하지만 필요에 따라서 MatchState를 아래와 같이 추가하여 관리할 수도 있습니다.

MyGameMode

.h
namespace MatchState
{
	extern BLASTER_API const FName Cooldown;	// 경기 시간에 도달 승자를 표시하고 쿨다운 타이머를 시작
}

UCLASS()
class BLASTER_API ABlasterGameMode : public AGameMode
{
	GENERATED_BODY()
    
protected:
	virtual void OnMatchStateSet() override;


.cpp
namespace MatchState
{
	const FName Cooldown = FName("Cooldown");
}
void ABlasterGameMode::OnMatchStateSet()
{
	Super::OnMatchStateSet();
	
    // 모든 플레이어 컨트롤러한테 매치 상태를 전달
	for (FConstPlayerControllerIterator iter = GetWorld()->GetPlayerControllerIterator(); iter; ++iter)
	{
		ABlasterPlayerController* BlasterPlayer = Cast<ABlasterPlayerController>(*iter);
		if (BlasterPlayer)
		{
			BlasterPlayer->OnMatchStateSet(MatchState);
		}
	}
}

MyPlayerController

.h

UCLASS()
class BLASTER_API ABlasterPlayerController : public APlayerController
{
	GENERATED_BODY()
    
public:
	void OnMatchStateSet(FName State);
}

.cpp
void ABlasterPlayerController::OnMatchStateSet(FName State)
{
	MatchState = State;

	// 매치 상태가 InProgress(인게임 진행)이 되었다면 그때 오버레이를 생성한다.
    // 매치 상태에 따른 코드 실행
	if (MatchState == MatchState::InProgress)
	{
		HandleMatchHasStarted();
	}
	else if (MatchState == MatchState::Cooldown)
	{
		HandleCooldown();
	}
}

Scatter 알고리즘

FVector AHitScanWeapon::TraceEndWithScatter(const FVector& TraceStart, const FVector& HitTarget)
{
	FVector ToTargetNormalized = (HitTarget - TraceStart).GetSafeNormal();
	FVector SphereCenter = TraceStart + ToTargetNormalized * DistanceToSphere;
	FVector RandVec = UKismetMathLibrary::RandomUnitVector() * FMath::RandRange(0.f, SphereRadius);
	FVector EndLoc = SphereCenter + RandVec;
	FVector ToEndLoc = EndLoc - TraceStart;
	
    // 눈으로 확인하기 위함
	DrawDebugSphere(GetWorld(), SphereCenter, SphereRadius, 12, FColor::Red, true);
	DrawDebugSphere(GetWorld(), EndLoc, 4.f, 12, FColor::Orange, true);
	DrawDebugLine(GetWorld(), TraceStart, FVector(TraceStart + ToEndLoc * TRACE_LENGTH / ToEndLoc.Size()),
		FColor::Cyan, true);

	// ToEndLoc.size()로 나누는 이유는 TRACE_LENGTH가 8만이여서 곱했을때 범위 벗어나는거 방지를 위함
	return FVector(TraceStart + ToEndLoc * TRACE_LENGTH / ToEndLoc.Size());
}

 

 

영상

https://youtu.be/XPwgJNPiSV0

 

 

반응형

댓글