ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 블루아카이브 루트슈터 팬게임 프로젝트(15) - 적 스폰 시스템 & 웨이브 게임모드(1)
    루트슈터 프로젝트 2024. 1. 14. 01:05

    안녕하세요 이번에는 적 스폰 시스템을 구현해보았습니다. 중간에 치명적인 에러가 있어서 (블루프린트에서 메시가 사라지는 오류) 그걸 복구하느라 너무 많은 시간을 소모했네요. 얼추 완성했지만 AI가 적용되지 않는 오류가 있어서 계속 작업을 해야할 것 같습니다. 

     

     

     

    일단 적 스폰 작업을 하기에 앞서, 적의 레벨별 상세한 스탯을 데이터 테이블로 만들어 주었습니다. 적의 레벨별 체력, 데미지, 경험치 등등의 기본 정보들이 담겨있습니다. 

     

     

    EnemySpawner.h

    UCLASS()
    class PROJECTBLUELANDS_API AEnemySpawner : public AActor
    {
    	GENERATED_BODY()
    	
    public:	
    	// Sets default values for this actor's properties
    	AEnemySpawner();
    
    protected:
    	// Called when the game starts or when spawned
    	virtual void BeginPlay() override;
    
    public:	
    	// Called every frame
    	virtual void Tick(float DeltaTime) override;
    
    	UPROPERTY(EditDefaultsOnly, Category = "Enemy Class")
    	TSubclassOf<class AEnemyCharacter> enemyClasses;
    
    	void SpawnEnemy(int enemyLevel, int itemDropRate, int legendDropRate, int rareDropRate, int uncommonDropRate, float enemyHP, float enemyDamage, int enemyEXP);
    };

     

    적의 스폰을 담당하는 액터입니다. 게임모드에서 명령을 받으면 적을 스폰해주는 역할을 할것입니다. 

     

     

    EnemySpawner.cpp

     

    void AEnemySpawner::SpawnEnemy(int enemyLevel, int itemDropRate, int legendDropRate, int rareDropRate, int uncommonDropRate, float enemyHP, float enemyDamage, int enemyEXP)
    {
    	AEnemyCharacter* spawnedEnemy = GetWorld()->SpawnActor<AEnemyCharacter>(enemyClasses, this->GetActorLocation(), this->GetActorRotation());
    
    	if(spawnedEnemy) //스폰 성공시 
    	{
    		spawnedEnemy->InitStats(enemyLevel, itemDropRate, legendDropRate, rareDropRate, uncommonDropRate, enemyHP, enemyDamage, enemyEXP);
    	}
    
    }

     

    적을 스폰하라는 명령을 받으면 실행하는 함수입니다. 적을 스폰한 후 적의 정보들을 담아주기 위해 Init 함수를 실행시켜줍니다. 

     

     

    EnemyCharacter.cpp

    void AEnemyCharacter::InitStats(int enemyLevel, int itemDrop, int legendDrop, int rareDrop, int uncomDrop, float HP, float Damage, int enemyEXP)
    {
        
        enemyHP = HP;
    	itemDropRate = itemDrop;
    	legendDropRate = legendDrop;
    	rareDropRate = rareDrop;
    	uncommonDropRate = uncomDrop;
    	enemyDamage = Damage;
    	exp = enemyEXP;
        SetLevel(enemyLevel);
    
        hpBarWidget = Cast<UEnemyHPBarWidget>(hpBarComponent->GetWidget());
        if(hpBarWidget)
        {
            hpBarWidget->Init(enemyName, this->GetCharacterLevel());
        }
        
    }

     

    적이 스폰된 후 받은 정보들로 초기화를 해주는 함수입니다. 모든 정보를 받은 후 적의 체력바 또한 초기화 해줍니다.

     

     

    WaveGameMode.h

    UCLASS()
    class PROJECTBLUELANDS_API ABluelandsGameWaveMode : public ABluelandsGameModeBase
    {
    	GENERATED_BODY()
    
    public:
    	ABluelandsGameWaveMode();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	int32 waveRound = 0;
    	int32 enemyLeft;
    
    	UPROPERTY(EditDefaultsOnly)
    	TSubclassOf<class AEnemySpawner> spawnerClass;
    	void SpawnEnemy(int howMany);
    
    private:
    	class UDataTable* arEnemyDataTable;
    	class UDataTable* mgEnemyDataTable;
    	
    };

     

    이 게임모드 클래스는 예전에 만들었던 게임모드 베이스 클래스를 상속받은 새로운 게임모드 클래스입니다. 부모 클래스는 적의 죽음과 아이템 드랍을 처리해주는 기능들만 들어있다면 이곳에서는 웨이브 형태의 게임을 위한 기능들을 구현해놓을 생각입니다. 

     

     

    WaveGameMode.cpp

    ABluelandsGameWaveMode::ABluelandsGameWaveMode()
    {
        static ConstructorHelpers::FObjectFinder<UDataTable> arEnemyTable(TEXT("/Game/DataTables/EnemyStat/DT_PMC_AR_Normal"));
        if(arEnemyTable.Succeeded()) arEnemyDataTable = arEnemyTable.Object; //돌격소총 PMC 노말몹
    }
    
    void ABluelandsGameWaveMode::BeginPlay()
    {
        Super::BeginPlay();
        waveRound = 1;
        SpawnEnemy(5);
    
    }
    
    void ABluelandsGameWaveMode::SpawnEnemy(int howMany) //각 라운드 시작시 발동됨
    {
        
        enemyLeft = 0;
        TArray<AActor*> spawners;
        UGameplayStatics::GetAllActorsOfClass(GetWorld(), spawnerClass, spawners);
    
        for(int i=0; i<spawners.Num(); i++)
        {
            AEnemySpawner* spawner = Cast<AEnemySpawner>(spawners[i]);
            if(spawner && player) 
            {
                FEnemyTableRow* enemyRow = nullptr; 
                enemyRow = arEnemyDataTable->FindRow<FEnemyTableRow>(FName(*(FString::FormatAsNumber(player->GetCharacterLevel()))), FString(""));
                if(enemyRow == nullptr) continue;
    
                spawner->SpawnEnemy((*enemyRow).enemyLevel, (*enemyRow).itemDropRate, (*enemyRow).legendDropRate, 
                    (*enemyRow).rareDropRate, (*enemyRow).uncommonDropRate, (*enemyRow).enemyHP, (*enemyRow).enemyDamage, (*enemyRow).enemyEXP);
                enemyLeft++;
            }
        }
    }

     

    먼저 게임모드에서 적의 스탯에 대한 정보를 데이터 테이블로 받아오고 웨이브가 시작되면 정해진 수만큼의 적을 소환시켜줄 것입니다. 그 다음 적들의 스탯에 대한 정보를 넘겨 적들의 기본적인 스탯설정을 시켜줄 수 있게 해줍니다. 완전하게 세팅하기 전에 일단 필드의 모든 스폰 액터들을 불러온 후 그 수만큼 적을 스폰시켜 보았습니다. 더 자세한 세팅은 나중에 할 예정이고, 일단 적들이 잘 스폰되는지만 보겠습니다. 

     

     

     

    스폰 액터는 단순합니다. sphere collision 하나 생성 후 적 클래스만 등록시켜주면 됩니다. 

     

     

     

     

    그리고 스폰 포인트를 6개 정도 만들어 보았습니다 .

     

     

     

    그렇게 해서 적들을 스폰시켜보았습니다만, AI가 적용되지 않습니다. 이상하네요 이거는 다음에 고쳐보도록 해야겠습니다. 

Designed by Tistory.