ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 블루아카이브 루트슈터 팬게임 프로젝트(26) - 패시브 트리 기능
    루트슈터 프로젝트 2024. 1. 30. 21:51

     

    안녕하세요. 루터슈터 게임은 RPG 게임이기 때문에 레벨업에 따라 할당할 수 있는 패시브 트리가 있다면 좋을 것이라고 생각하였기 때문에 간단하게 나마 패시브 트리를 구현해 보았습니다. 

     

     

     

    UENUM(BlueprintType) //패시브에 대한 ENUM
    enum class EPassiveTree : uint8
    {
    	EPT_DEFAULT   			UMETA(DisplayName = "Not Allocated"),
    	EPT_SMALL_HEALTH    	UMETA(DisplayName = "small Increase Health"),
    	EPT_SMALL_WP_DAMAGE  	UMETA(DisplayName = "small Increase Weapon Damage"),
    	EPT_SMALL_CRIT_DAMAGE   UMETA(DisplayName = "small Increase Critical Damage"),
    	EPT_SMALL_CRIT_CHANCE 	UMETA(DisplayName = "small Increase Critical Chance"),
    	EPT_SMALL_REGEN	 		UMETA(DisplayName = "small HP Regen"),
    	EPT_MIDDLE_HEALTH		UMETA(DisplayName = "middle Increase Health"),
    	EPT_MIDDLE_WP_DAMAGE	UMETA(DisplayName = "middle Increase Weapon Damage"),
    	EPT_MIDDLE_CRIT_DAMAGE  UMETA(DisplayName = "middle Increase Critical Damage"),
    	EPT_MIDDLE_CRIT_CHANCE 	UMETA(DisplayName = "middle Increase Critical Chance"),
    	EPT_MIDDLE_REGEN	 	UMETA(DisplayName = "middle HP Regen"),
    	EPT_MIDDLE_RELOAD		UMETA(DisplayName = "middle Reload Speed"),
    	EPT_LARGE_SLOW_REGEN	UMETA(DisplayName = "large HP Regen Large Lv10"),
    	EPT_LARGE_ACCELERATION	UMETA(DisplayName = "large Inrease Fire Rate Lv10"),
    	EPT_LARGE_MIRACLE		UMETA(DisplayName = "large No bullet use Lv20"),
    	EPT_LARGE_HEALTH_BULLET	UMETA(DisplayName = "large HP added to damage Lv20"),
    	EPT_LARGE_BENEDICTIO	UMETA(DisplayName = "large Benedictio Lv30"),
    	EPT_LARGE_DOUBLE_REGEN	UMETA(DisplayName = "large Double HP Regen Lv30")
    };

     

    먼저 각각의 패시브 슬롯에 대한 ENUM을 선언해 주었습니다. 각 ENUM 요소들은 패시브 슬롯 하나를 담당하게 됩니다. 

     

     

    PassiveSlot.h

    UCLASS()
    class PROJECTBLUELANDS_API UPassiveSlot : public UUCustomUI
    {
    	GENERATED_BODY()
    
    protected:
    	virtual FReply NativeOnMouseButtonDown(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent) override;
    
    public:
    	virtual void Init() override;
    	
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (UIMax = 31, UIMin = -1))
    	int slotLevel; //몇렙의 패시브 슬롯인가?
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
    	UImage* icon; //패시브의 이미지
    
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
    	UImage* backColor; //패시브 등급에 따른 뒷배경색깔
    
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
    	UImage* allocatedColor; //선택된 패시브라면 색깔 변경
    
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
    	EPassiveTree slotPassiveType; //슬롯에 담긴 패시브 종류
    
    };

     

    그리고 패시브 슬롯 UI 클래스를 하나 만들어줍니다. 이 슬롯에는 어떤 레벨에 선택할 수 있는 패시브 슬롯인지, 이 패시브의 종류는 무엇인지에 대한 정보를 저장하는 변수들이 저장돼있습니다. 

     

    또한 이 패시브 슬롯이 마우스로 눌렸을 때 플레이어의 레벨을 검사한 후 할당될 수 있다면 할당작업을 해야 하기 때문에 NativeOnMouseButtonDown 함수를 오버라이드 하였습니다. 

     

     

    void UPassiveSlot::Init()
    {
        if(player)
        {
            if(player->playerPassive[this->slotLevel] == this->slotPassiveType)
            {
                allocatedColor->SetColorAndOpacity(FLinearColor::Green);
            }
            else allocatedColor->SetColorAndOpacity(FLinearColor::White);
        }
    }
    
    FReply UPassiveSlot::NativeOnMouseButtonDown(const FGeometry &InGeometry, const FPointerEvent &InMouseEvent)
    {
    
        FEventReply reply; //return 변수 선언 
        reply.NativeReply = Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
    
    
        if(InMouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton) == true) //왼쪽 마우스 버튼이 눌렸다면 드래그를 통해 장비교체 
        {
            if(player) 
            {
                player->ChangePassive(this->slotLevel, this->slotPassiveType);    
            }
        }
    
        return reply.NativeReply;
    }

     

    cpp 파일입니다. Init 함수는 만약 이 패시브 슬롯이 플레이어에 의해 할당된 패시브라면, 슬롯의 주변 색깔을 녹색으로 만들어 할당된 패시브 슬롯이라는 표시를 해주는 함수입니다. 

    그리고 슬롯이 클릭됐다면 플레이어에게 할당된 패시브를 변경하도록 플레이어의 함수를 선언해 줍니다. 

     

    플레이어의 패시브 변경 함수입니다. 먼저 패시브 슬롯의 레벨이 플레이어의 레벨보다 높으면 할당이 되면 안되므로 한번 검사해준 후 패시브를 변경해줍니다. 그리고 패시브가 변경됐으므로 패시브창을 한번 새로고침 해주도록 UI에게 함수를 선언해줍니다.

    void APlayerCharacter::ChangePassive(int slotLv, EPassiveTree passiveType)
    {
    	if( slotLv < 0 || slotLv >= 30 || slotLv > GetCharacterLevel() - 1) return;
    
    	playerPassive[slotLv] = passiveType;
    	if(passiveUI) passiveUI->RefreshPassiveTree();
    
    }

     

     

    void UPassiveUI::Init()
    {
        TArray<UWidget*> widgets;
        WidgetTree->GetAllWidgets(widgets);
    
        for(auto widget : widgets)
        {
            UPassiveSlot* pSlot = nullptr;
            pSlot = Cast<UPassiveSlot>(widget);
            if(!pSlot) continue;
            
            pSlot->player = this->player;
            pSlot->Init();
            passiveSlots.Add(pSlot);
        }
    }
    
    void UPassiveUI::RefreshPassiveTree()
    {
        for(auto slot : passiveSlots)
        {
            if(slot->player) slot->Init();
        }
    }

     

    패시브 슬롯이 아닌 패시브 슬롯이 모여있는 패시브 UI의 클래스의 cpp 파일입니다. 여기에서는 패시브 슬롯들의 포인터를 모두 TArray에 저장한 후 그들의 주인인 플레이어를 지정해 줍니다. 그리고 패시브 슬롯들을 새로고침 하는 함수도 밑에 작성해 두었습니다. 

     

     

    패시브 슬롯의 블루프린터 입니다. 패시브의 아이콘과 뒷배경 색깔 등이 설정되어 있습니다. 

     

     

     

    패시브 슬롯마다 고유한 패시브트리 ENUM을 설정하는것도 잊으시면 안됩니다.

     

     

     

    패시브 슬롯들이 모인 패시브 UI의 블루프린트 입니다. 레벨업 할 때 마다 새로운 패시브 슬롯을 할당할 수 있도록 하였습니다. 옆의 디테일 패널에 슬롯의 레벨이 몇인지 등록하는것도 잊으시면 안됩니다. 

     

     

     

     

     

    https://youtu.be/QbIGbolK6H4?si=ine3D0RwYJjRda0Y

     

    이번 결과물은 동영상으로 대체하였습니다. 패시브를 변경하면서 무기 공격력, 체력 증가등의 효과가 바뀌는 것을 확인할 수 있습니다. 

Designed by Tistory.