-
블루아카이브 루트슈터 팬게임 프로젝트(14) - 플레이어 레벨, 경험치 시스템루트슈터 프로젝트 2024. 1. 12. 15:00
안녕하세요 이번 포스팅은 플레이어의 레벨과 경험치 관리 시스템 및 UI에 대한 포스팅입니다. 루트슈터 장르는 RPG이기 때문에 FPS,TPS 슈터게임이지만 레벨이 존재합니다. 플레이어는 적을 계속 처치하면서 경험치를 얻고 레벨업을 할 수 있어야 합니다. 제 게임에서는 플레이어의 레벨에 따라 플레이어의 기본 체력이 상승하고, 다음 레벨까지 요구하는 경험치양이 계속 변동합니다. 그렇기 때문에 먼저 이를 데이터 테이블로 작성해줍니다.
이런식으로 만들어 줍니다. 다음 레벨로 갈때 필요한 경험치와 그 레벨에서 제공되는 체력(방어구로 얻어지는 스탯 제외), 누적 경험치를 데이터 테이블로 만들어 줬습니다. 누적 경험치는 지금 사용하고 있지는 않지만 혹시 몰라서 만들어 뒀습니다.
ABluelandsGameModeBase::ABluelandsGameModeBase() { static ConstructorHelpers::FObjectFinder<UDataTable> playerLevelTable(TEXT("/Game/DataTables/DT_Player_LevelTable")); if(playerLevelTable.Succeeded()) playerLevelDataTable = playerLevelTable.Object; } void ABluelandsGameModeBase::ActorDied(AActor* DeadActor) { if(DeadActor == player) //플레이어 사망시 { } else //적 사망 { AEnemyCharacter* enemy = Cast<AEnemyCharacter>(DeadActor); player->GetEXP(enemy->exp); //플레이어 경험치 획득 if(enemy) { UE_LOG(LogTemp, Error, TEXT("Enemy Dead!!")); //if(Cast<AHumanEnemy>(enemy)) Cast<AHumanEnemy>(enemy)->gun->Destroy(); //인간형 적 무기 파괴 for(int i=0; i<enemy->itemDropRate/100; i++){SpawnItem(DeadActor);} //아이템 드랍확률 350%라면 3번은 확정드랍 if(FMath::RandRange(1,100) < enemy->itemDropRate%100) SpawnItem(DeadActor); } DeadActor->Destroy(); //적 사망시 적의 드랍률 정보를 확인하고 그 확률에 맞춰 아이템 드랍 } }
그리고 게임모드의 생성자에서 저 데이터 테이블을 불러와 줍니다.
그리고 액터의 죽음을 처리하는 함수에서 적이 사망시 플레이어에게 경험치를 주면 됩니다. 적에 대한 정보도 데이터 테이블로 구성해놓는게 좋을 것 같기는 한데, 일단은 블루프린트에 제가 숫자로 설정해놓았습니다.
void ABluelandsGameModeBase::PlayerLevelUp() { int newLevel = player->GetCharacterLevel() + 1; player->SetLevel(newLevel); FPlayerLevelTableRow* levelRow = nullptr; levelRow = playerLevelDataTable-> FindRow<FPlayerLevelTableRow>(FName(*(FString::FormatAsNumber(newLevel))), FString("")); if(levelRow) { player->expForNextLevel = (*levelRow).expForNextLevel; player->playerMaxHPByLevel = (*levelRow).hp; } }
그리고 플레이어가 레벨업 시 게임모드에서는 플레이어를 새로운 레벨로 설정해주고 그 레벨에 맞는 체력, 다음 레벨업 까지 필요한 경험치 양을 갱신해 줍니다.
PlayerCharacter.h
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) float playerMaxHP; float playerMaxHPByLevel; //레벨로만 얻는 체력 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) float playerNowHP; //플레이어의 경험치 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) int nowEXP; //현재 가지고 있는 경험치 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) int expForNextLevel; // 다음 레벨까지 경험치 void GetEXP(int exp); // 경험치 획득 void LevelUp(); // 레벨업
플레이어에게 레벨과 경험치, 체력에 관한 변수들과 함수들을 선언해줍니다. 여기서 playerMaxHP는 플레이어의 레벨에 따른 체력 + 아이템으로 얻어지는 체력을 합산한 결과를 저장할 변수이고 playerMaxHPByLevel은 순수하게 레벨로 정해지는 체력만 저장됩니다. playerNowHP는 게임중 현재 체력을 저장합니다.
경험치, 레벨에 관련된 변수는 주석에 써져있는 그대로 입니다.
PlayerCharacter.cpp
void APlayerCharacter::GetEXP(int exp) { if(this->GetCharacterLevel() == 30) return; nowEXP += exp; if(expForNextLevel <= nowEXP) { int temp = nowEXP - expForNextLevel; LevelUp(); nowEXP = temp; } } void APlayerCharacter::LevelUp() { Cast<ABluelandsGameModeBase>(UGameplayStatics::GetGameMode(this))->PlayerLevelUp(); playerMaxHP = playerMaxHPByLevel + playerStat[0]; }
그리고 플레이어가 경험치를 먹었을때 nowEXP에 현재 플레이어가 모은 경험치 양에 더해주고, 다음 레벨업까지 경험치 조건을 충족했는지 검사합니다. 만약 요구조건이 충족됐다면 레벨업을 시켜준 후 남은 경험치를 다시 더해줍니다.
만약 경험치가 499/500인 상태에서 30의 경험치를 얻었다면 529/500 이므로 1업을 시켜준 후 남은 29를 다시 플레이어의 현재 경험치에 합산해주는 방식입니다.
레벨업 함수에서는 위에서 설명한 게임모드의 플레이어 레벨업 함수를 발동시켜줍니다. 그리고 레벨업을 하면 플레이어의 최대 체력에 변화가 생기므로 한번 초기화 해주면 됩니다.
플레이어 경험치바의 UI입니다. 경험치 진행도를 나타내는 progressbar와 플레이어의 레벨이 같이 나타나져 있습니다.
퍼센티지에 바인딩 되는 블루프린트 함수입니다. 매우 간단하기에 더 설명할 것이 없지만 여기서 exp 수치들은 정수이므로 한번 실수로 변환해서 나누기를 진행해야 퍼센티지가 잘 나타납니다.
플레이어 레벨 텍스트 바인딩 함수입니다.
구현 결과 제대로 경험치바가 구동되고 있습니다. 아마도 다음에는 적이 플레이어의 레벨에 맞게 스폰되도록 구현해볼 예정입니다. 이제 슬슬 플레이어 캐릭터로 할 모델링을 구매해야 할 것 같네요.
'루트슈터 프로젝트' 카테고리의 다른 글
블루아카이브 루트슈터 팬게임 프로젝트(16) - 플레이어 캐릭터 모델링 교체 & 리타겟팅 (0) 2024.01.14 블루아카이브 루트슈터 팬게임 프로젝트(15) - 적 스폰 시스템 & 웨이브 게임모드(1) (1) 2024.01.14 블루아카이브 루트슈터 팬게임 프로젝트(13) - 체력, 잔탄 UI (1) 2024.01.11 블루아카이브 루트슈터 팬게임 프로젝트(12) - 방어구 스탯 적용 (1) 2024.01.10 블루아카이브 루트슈터 팬게임 프로젝트(11) - 방어구 추가 (0) 2024.01.09