Replicated

[FPSScoring] 재장전 구현 본문

언리얼 엔진/Mini Projects [Unreal]

[FPSScoring] 재장전 구현

라구넹 2025. 3. 11. 18:54

 

25-3-11~12일 단국대학교 Aegis의 동아리 알림제가 진행되고 있다.

그런데 어제 탄환 재장전을 넣어달라는 요구사항이 들어와서 어제 저녁에 급하게 재장전 작업이 진행되었다.

 

 

탄환 30개를 다 쓰거나 R을 누르면 리로드가 진행된다

 

void AFSCharacterPlayer::Shoot()
{
	if (bIsShooted) return;
	bIsShooted = true;

	UFSObjectPoolSubsystem* ObjectPool = GetGameInstance()->GetSubsystem<UFSObjectPoolSubsystem>();
	if ( ObjectPool )
	{
		if ( BulletCount > 0 )
		{
			FVector SpawnLocation = GetActorLocation() + GetActorForwardVector() * 100.0f + FVector(0.0f, 0.0f, 50.0f);
			FRotator SpawnRotation = GetControlRotation();

			AFSBullet* Bullet = Cast<AFSBullet>(ObjectPool->GetPooledObject(AFSBullet::StaticClass(), SpawnLocation, SpawnRotation));
			Bullet->Reset();

			--BulletCount;

			if ( BulletCount == 0 )
			{
				// Reload
				int32 ReloadTime = 3;
				GetWorld()->GetTimerManager().SetTimer(ReloadTimerHandle, 
					[this, ReloadTime]() 
					{
						ReloadBullet(ReloadTime);
					}, 
					1.0f, false);
			}

			AFSGameMode* GameMode = Cast<AFSGameMode>(GetWorld()->GetAuthGameMode());
			if ( GameMode )
			{
				GameMode->SetBulletText(BulletCount, 3);
			}
		}
	}
}

void AFSCharacterPlayer::ReloadBullet(int32 InRemainedReloadTime)
{
	if ( GetWorld() == nullptr )
	{
		BulletCount = 30;
		return;
	}

	if ( InRemainedReloadTime == 1 )
	{
		BulletCount = 30;
	}
	else
	{
		--InRemainedReloadTime;
		GetWorld()->GetTimerManager().SetTimer(ReloadTimerHandle,
			[this, InRemainedReloadTime]()
			{
				ReloadBullet(InRemainedReloadTime);
			},
			1.0f, false);
	}

	AFSGameMode* GameMode = Cast<AFSGameMode>(GetWorld()->GetAuthGameMode());
	if (GameMode)
	{
		GameMode->SetBulletText(BulletCount, InRemainedReloadTime);
	}
}

void AFSCharacterPlayer::ForceReloadBullet()
{
	if ( BulletCount <= 0 )
	{
		return;
	}

	BulletCount = 0;
	ReloadBullet(4);
}

ForceReloadBullet은 R키 누르는 액션과 바인딩된다

 

void AFSCharacterPlayer::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	if (GetWorld())
	{
		GetWorld()->GetTimerManager().ClearTimer(ReloadTimerHandle);
	}
	Super::EndPlay(EndPlayReason);
}

중요한 건 EndPlay이다.

EndPlay에서 타이머를 인밸리데이트 안하면 리플레이 시 이미 소멸된 월드에서 타이머가 발동할 수 있다.

그래서 크래시가 나서 수정했다.

 

void AFSGameMode::SetBulletText(int32 InBulletCount, int32 InReloadTime)
{
    if ( BulletWidget )
    {
        UUserWidget* WidgetInstance = BulletWidget.Get();
        if (WidgetInstance)
        {
            UTextBlock* BulletText = Cast<UTextBlock>(WidgetInstance->GetWidgetFromName(TEXT("BulletText")));
            if (BulletText)
            {
                if (InBulletCount <= 0)
                {
                    BulletText->SetText( FText::FromString(FString::Printf(TEXT("Relaoding .. %d"), InReloadTime)));
                }
                else
                {
                    BulletText->SetText(FText::FromString(FString::Printf(TEXT("Bullet : %d"), InBulletCount)));
                }
            }
        }
    }
}

게임 모드에선 위젯 설정을 해준다

자세한 코드는 깃허브에 있다

https://github.com/Lagooneng/FPSScoring

 

GitHub - Lagooneng/FPSScoring: 2025-1 Aegis 동아리 알림제용 FPS Scoring 게임

2025-1 Aegis 동아리 알림제용 FPS Scoring 게임. Contribute to Lagooneng/FPSScoring development by creating an account on GitHub.

github.com