공부/Unreal

24.08.23

월러비 2024. 8. 24. 23:46

UI

무기 타입에 따라 UI 출력 바꾸기

  • 무기가 바뀌면 플레이어의 ‘유저 인터페이스’ 변수를 통해서 UpdateWeaponType 을 호출한다.
    • 웨폰 컴포넌트에 WeaponTypeChanged라는 무기 타입 변경시 호출되는 델리게이트가 있다.
  • CUserWidget_Player
    • 함수는 블루프린트에서 재정의하고, C에서는 ‘호출만’ 한다.
    • 열겨형 자료형을 사용하기 위해서는 헤더 파일에 사용하려는 열거 자료형이 있는 클래스 헤더를 추가해야한다.
    • 헤더 파일 - 블루프린트 임플리멘테이블 이벤트 메크로로 설정하고 ‘업데이트 무기’를 선언하고 ‘무기 타입’을 받을 수 있도록 한다.
    //header
    public:
    	UFUNCTION(BlueprintImplementableEvent, Category = "UserInterface")
    		void UpdateWeaponType(EWeaponType InType);
    
  • CPlayer
    • WeaponType 정의를 CPP가 아닌 헤더에서 사용했으니, 헤더 파일에 웨폰 컴포넌트 헤더를 추가해야한다.
    • Max라고 뜨는것은 블루프린트 파일에서 수정해야한다.
      • 나중에 직접 해봐라
    • 헤더 파일 - ‘무기 타입 변경 활성’ 델리게이트 함수 선언하고 ‘이전 무기타입, 새로운 무기타입’을 받는다.
    //header
    FUNCTION()
    		void OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType);
    
    • CPP 파일 - ‘무기 타입 변경 활성’ 델리게이트 연결 함수 정의 - ‘유저 인터페이스’의 ‘업데이트 무기 타입’ 함수에 ‘새로운 무기 타입’을 넣고 호출한다. - ‘유저 인터페이스’의 ‘업데이트 무기 타입’에 ‘무기 타입 : 없음’을 넣고 호출한다. - ‘무기’의 ‘무기 타입 변경 활성’ 변수의 ‘함수 연결’에 ‘연결할 함수가 있는 클래스 : 플레이어, 연결할 함수 : 무기 타입 변경 활성(플레이어에서 정의)’ 를 넣고 호출한다.
    //CPP
    void ACPlayer::OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType)
    {
    	UserInterface->UpdateWeaponType(InNewType); //바뀐 무기 타입 전달
    }
    
    Weapon->OnWeaponTypeChanged.AddDynamic(this, &ACPlayer::OnWeaponTypeChanged); //무기 변경 델리게이트 함수 연결
    
    //위젯 있으면 출력
    //유저 인터페이스 설정
    if (!!UiClass)
    {
    	UserInterface = CreateWidget<UCUserWidget_Player, APlayerController>(GetController<APlayerController>(), UiClass);
    	UserInterface->AddToViewport();
    	UserInterface->UpdateWeaponType(EWeaponType::Max); //첫 시작은 무기 없음으로 설정
    	UserInterface->UpdateCrossHairVisibility(false); 
    }
    
  • WB_Player
    • FName : 이름만을 다루는 이름 식별자
    • FText : 보여주기 만을 하는 문자열
      • UI들은 모두 FText다.
    • Weapon 텍스트와 WeaponNumber 텍스트를 ‘변수 여부’ 체크한다.
    • 그래프(상단 디자이너 버튼 오른쪽) - ‘업데이트 무기 타입’ 이벤트 검색 - Weapon 텍스트 Get으로 배치 - 이벤트의 열거형 매개변수 핀을 끌고 ‘to string(열거형을 스트링으로)’ 검색 하고 연결한 결과를 SetText 의 입력 Text 핀과 연결한다. - WeaponNumber 텍스트를 Get으로 배치한다. - 핀을 끌고 ‘SetText’를 검색하고 이전 Text 노드와 연결한다. - UpdateWeaponType의 매개변수 열거형 핀을 끌고 ‘toint(byte)’를 검색하고 마지막 SetText 노드와 text 입력으로 연결한다.

조준선 출력

  • 조준선은 움직이거나 연사할때 조준선이 흐트러지는 효과가 있지만 지금은 하지 않았다.
  • 적에게 조준점 갖다 대면 빨갛게 변하는건 직접 해봐라
  • CUserWidget_Player
    • 헤더 파일 - ‘업데이트 조준점 보이기’ 함수를 선언하고 ‘보이기 확인’ 변수를 받는다.
    //header
    UFUNCTION(BlueprintImplementableEvent, Category = "UserInterface")
    		void UpdateCrossHairVisibility(bool bInVisible); //크로스헤어 보여주기 활성
    
  • CPlayer
    • CPP 파일 - BeginPlay 함수 확인 - ‘유아이 클래스’ 확인하는 조건문 확인 - ‘유저 인터페이스’의 ‘업데이트 조준점 보이기’ 함수에 false를 넣고 호출한다. - ‘무기 타입 변경 활성’ 함수 확인 - ‘보이기 확인’ 변수를 선언하고 false로 설정한다. - ‘새로운 무기 타입’이 ‘무기 타입 : 활’이라면 : ‘보이기 확인’ 변수를 true로 설정한다. - ‘유저 인터페이스’의 ‘업데이트 조준점 보이기’에 ‘보이기 확인’ 변수를 넣고 호출한다.
    //CPP
    //위젯 있으면 출력
    //유저 인터페이스 설정
    if (!!UiClass)
    {
    	UserInterface = CreateWidget<UCUserWidget_Player, APlayerController>(GetController<APlayerController>(), UiClass);
    	UserInterface->AddToViewport();
    	UserInterface->UpdateWeaponType(EWeaponType::Max); //첫 시작은 무기 없음으로 설정
    	UserInterface->UpdateCrossHairVisibility(false); 
    }
    
    void ACPlayer::OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType)
    {
    	UserInterface->UpdateWeaponType(InNewType); //바뀐 무기 타입 전달
    
    	bool bVisible = false; //보이기 설정
    
    	//활이 아니면 크로스헤어 안띄운다.
    	if (InNewType == EWeaponType::Bow)
    	{
    		bVisible = true;
    	}
    
    	UserInterface->UpdateCrossHairVisibility(bVisible);
    }
    
  • WB_Player
    • 이미지는 색이나 조준선 투명같은걸 조절할때 쓰는것같다.
    • 그리드 패널에 ‘보더’ 배치 - 이름 변경 : Top - 앵커 조정 : 가운데 - 위치 조정 : 0, 0 (보더의 중앙이 화면의 중앙에 오게된다.) - 정렬 조정 : 0.5 , 1.5 - 패딩 조정 : 0.0 - 선호 크기 스케일 조정 : 1.25 , 1.25 - Top 보더에 ‘이미지’ 위젯 배치 - 이미지 크기 조정 - Top ‘콘텐츠 크기에 맞춤’ 체크 - Top 복사 후 ‘Bottom’ 으로 이름 변경 - 정렬 조정 : 0.5 , -0.5 - Top 복사 후 ‘Left’로 이름 변경 - 정렬 조정 : 0.5 , 1.5 - 이미지 크기 조정 : 10 , 2.5 - Left 복사 후 ‘Right’로 이름 변경 - 정렬 조정 - -0.5 , 0.5 - Top부터 Right까지 4개 ‘변수 여부’ 체크
    • 이벤트 그래프 - ‘업데이트 조준점 보이기’ 이벤트 검색 - ‘fi’ 노드를 검색하고 순서 핀과 Condition 핀은 서로 연결한다. - 변수 생성 : Visible을 생성하고 ‘ESlate Visibility’로 설정한다. - Visibility 변수 노드를 Set으로 배치하고 if가 true 일땐 ‘Visible’ , false일땐 ‘Hidden’으로 설정하고 연결한다. - 두 Visible 노드를 하나의 ‘Set Visible’ 노드를 검색해서 연결하고, 타깃 : Top , In Visibility 핀 : Visible 변수 Get을 연결한다. - 이후 Set Visibility를 3개 복사해서 연결하고 Bottom 부터 Right까지 연결한다.

Enemy UI - 컨트롤러 이름, 체력바 띄우기

  • HP바는 ‘보더’를 깔아서 작업한다.
    • 보더 : 배경 선
  • 보더를 깔았으니 배경은 넣지 않는다.
  • CUserWidget_Enemy
    • 생성
  • CUserWidget_Enemy
    • 헤더 파일 - ‘업데이트 체력’ 함수를 선언하고 ‘현재 체력, 최대 체력’을 받는다. - ‘업데이트 이름’ 함수를 선언하고 ‘이름’ 주소를 ‘상수’로 받는다. - ‘업데이트 컨트롤러 이름’ 함수를 선언하고 ‘이름’ 주소를 ‘상수’로 받는다.
    //header
    public:
    	UFUNCTION(BlueprintImplementableEvent, Category = "UserInterface")
    		void UpdateHealth(float InHealth, float InMaxHealth);
    
    	UFUNCTION(BlueprintImplementableEvent, Category = "UserInterface")
    		void UpdateName(const FString& InName);
    
    	UFUNCTION(BlueprintImplementableEvent, Category = "UserInterface")
    		void UpdateControllerName(const FString& InName);
    
  • CHealthPointComponent
    • 헤더 파일 - 델리게이트 선언 : ‘이름 : 체력 변함 , 현재 체력, 최대 체력’을 넣고 선언한다. - 델리게이트 자료형인 ‘체력 변함’ 의 ‘체력 변함 활성’ 변수 선언 - ‘체력 가져오기’ 함수 선언하고 ‘체력’을 반환하도록 정의한다. - ‘최대 체력 가져오기’ 함수 선언하고 ‘최대 체력’을 반환하도록 정의한다.
    //header
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FHealthPointChanged, float, InHealth, float, InMaxHealth);
    
    public:
    	FHealthPointChanged OnHealthPointChanged;
    	
    FORCEINLINE float GetHealth() { return Health; }
    FORCEINLINE float GetMaxHealth() { return MaxHealth; }
    
    • CPP 파일 - ‘데미지’ 함수 확인 - ‘체력 변함 확인’ 변수의 ‘함수 연결 확인’ 함수가 true 라면 : ‘체력 변함 활성’ 함수의 ‘연결 함수 실행’에 ‘체력, 최대 체력’을 넣고 호출한다.
    //CPP
    if (OnHealthPointChanged.IsBound())
    {
    	OnHealthPointChanged.Broadcast(Health, MaxHealth);
    }
    
  • CEnemy_AI
    • 적 같은 UI는 직접 생성해서 할당하는 것이기 때문에 반드시 직접 가져와야 사용할 수 있다.
      • 부모 클래스로 반환되기 때문에 파생 클래스로 ‘캐스트’ 해줘야한다.
    • 헤더 파일 - 무기 컴포넌트 포인터 변수 ‘무기’를 선언한다. - 생성자 선언 - BeginPlay 재정의 선언 - Tick 함수 재정의 선언 - 위젯 컴포넌트 포인터의 ‘라벨 위젯’ 변수 선언 - 델리게이트 연결 함수인 ‘체력 변함 활성’ 함수에 ‘현재 체력, 최대 체력’을 넣어 선언한다.
    //header
    public:
    	UPROPERTY(VisibleAnywhere)
    		class UCWeaponComponent* Weapon;
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class UWidgetComponent* LabelWidget;
    
    public:
    	ACEnemy_AI();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	virtual void Tick(float DeltaTime) override;
    	
    private:
    	UFUNCTION()
    		void OnHealthPointChanged(float InHealth, float InMaxHealth);
    
    • CPP 파일 - 생성자 함수 정의 - Tick 실행 - 무기 컴포넌트의 ‘엑터 컴포넌트 생성’ 함수 호출 - 클래스 제한을 <UserWidget_Enemy> 클래스로 지정하고 ‘라벨 클래스’ 변수를 선언한다. - ‘클래스 가져오기’ 함수에 ‘라벨 클래스 변수 주소, 위젯 레퍼런스 주소’를 넣고 호출한다. - BeginPlay 함수 정의 - ‘라벨 위젯’의 ‘위젯 띄우기’ 함수 호출 - ‘라벨 위젯’의 ‘유저 위젯 오브젝트 가져오기’ 함수를 호출한 결과를 ‘파생 유저 위젯’ 클래스로 지정하여 ‘캐스트’ 함수 호출하고 해당 클래스로 변수를 선언하여 저장한다. - ‘체력’의 ‘체력 변함 활성’ 델리게이트 변수의 ‘함수 연결’에 ‘연결할 함수가 있는 클래스 : Enemy_AI, 연결할 함수 : 체력 변함’을 넣고 호출한다. - ‘라벨’의 ‘업데이트 체력’에 ‘체력의 체력 가져오기 함수 호출, 체력의 최대체력 가져오기 함수 호출’을 넣고 호출한다. - ‘라벨’의 ‘업데이트 이름’에 ‘이름 가져오기 함수 호출’을 넣고 호출한다. - ‘라벨’의 ‘업데이트 컨트롤러 이름’에 ‘컨트롤러 가져오기 함수 호출의 이름 가져오기 함수 호출’을 넣고 호출한다. - ‘체력 변함 활성’ 함수 정의 - ‘라벨 위젯’의 ‘유저 위젯 오브젝트 가져오기’ 함수를 호출한 결과를 ‘파생 유저 위젯’ 클래스로 지정하여 ‘캐스트’ 함수 호출하고 해당 클래스로 변수를 선언하여 저장한다. - ‘라벨’의 ‘업데이트 체력’에 ‘체력의 체력 가져오기 함수 호출, 체력의 최대체력 가져오기 함수 호출’을 넣고 호출한다.
    //CPP
    ACEnemy_AI::ACEnemy_AI()
    {
    	PrimaryActorTick.bCanEverTick = true;
    
    	CHelpers::CreateComponent<UWidgetComponent>(this, &LabelWidget, "Label", GetMesh());
    	CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
    
    	TSubclassOf<UCUserWidget_Enemy> labelClass;
    	CHelpers::GetClass(&labelClass, "WidgetBlueprint'/Game/Widgets/WB_Enemy.WB_Enemy_C'");
    
    	LabelWidget->SetWidgetClass(labelClass);
    	LabelWidget->SetRelativeLocation(FVector(0, 0, 220));
    	LabelWidget->SetDrawSize(FVector2D(120, 0));
    	LabelWidget->SetWidgetSpace(EWidgetSpace::Screen);
    
    }
    
    void ACEnemy_AI::BeginPlay()
    {
    	Super::BeginPlay();
    
    	HealthPoint->OnHealthPointChanged.AddDynamic(this, &ACEnemy_AI::OnHealthPointChanged);
    
    	LabelWidget->InitWidget();
    
    	UCUserWidget_Enemy* label = Cast<UCUserWidget_Enemy>(LabelWidget->GetUserWidgetObject());
    	label->UpdateHealth(HealthPoint->GetHealth(), HealthPoint->GetMaxHealth());
    
    	label->UpdateName(GetName());
    	label->UpdateControllerName(GetController()->GetName());
    
    }
    
    void ACEnemy_AI::OnHealthPointChanged(float InHealth, float InMaxHealth)
    {
    	UCUserWidget_Enemy* label = Cast<UCUserWidget_Enemy>(LabelWidget->GetUserWidgetObject());
    	label->UpdateHealth(HealthPoint->GetHealth(), HealthPoint->GetMaxHealth());
    }
    
  • WB_Enemy
    • 생성 - CUserWidget_Enemy에서 파생된 블루프린트 클래스
    • 크기 박스 배치 - 너비와 높이 오버라이드 체크 - 높이 오버라이드 조정 : 96 , 너비 오버라이드 조정 : 192 - 세로 박스 배치 - 텍스트 위젯 배치하고 이름을 Name으로 바꾼다. - 컬러 및 오퍼시티 조정 : 0, 0, 1, 1 - 텍스트 복사 후 이름을 ControllerName으로 바꾼다. - 보더 배치 - 패딩 조정 : 2.0 - 브러시 컬리 조정 : A_0.5 - 보더에 ‘프로그래스 바’ 위젯 배치하고 Health로 이름 변경 - Health 색조 조정 : A_0 - 프로그래스 바 채우기 타입 : Left to Right
    • 이벤트 그래프 - ‘업데이트 이름’ 검색 - Name 텍스트 Get으로 배치 - ‘SetText’ 검색 후 순서 연결, 타깃 핀 : Name의 Get, InText 핀 : ‘업데이트 이름’의 ‘In Name’ - ‘업데이트 컨트롤러 이름’ 검색 - Name 연결과 마찬가지로 연결 - ‘업데이트 체력’ 검색 - ‘Set Percent’ 검색 후 순서 연결, 타깃 : Health Get - ‘업데이트 체력’의 ‘현재 체력’과 ‘최대 체력’을 ‘/’를 검색해서 연결하고 결과를 ‘Set Percent’ 노드의 ‘InPercent’ 핀에 연결한다.
  • BP_CEnemy_Melee
    • 생성 - CEnemy_AI 파생 불루 프린트 클래스
    • 레벨 에디터 배치
    • Weapon - DA_Sword 할당
    • C에서 설정한 - 라벨 위젯 -

위젯 블루프린트 설명

  • DPI (Dot Per Inch) : 인치당 점이 몇개 찍혀있냐를 수치로 나타내는 단위이다.
    • 예전에는 ‘픽셀’로 수치를 디자인했지만, 현재는 기기마다 해상도가 달라졌기 때문에 ‘인치’ 단위로 바뀌었다.
    • 1인치에 ‘점(dot)’이 몇개 들어가느냐다.
      • 보통 1 / 96 (1인치에 96개의 점)으로 잡는다.
  • 보통 위젯의 디자인은 1280 * 720 (16 : 9) 비율을 맞춰서 디자인한다.
  • ‘패널’ 위젯은 애당 위젯 위에 어떠한 위젯들을 올릴 수 있는 위젯이다.
  • ‘캔버스’를 작업할때는 상단의 ‘Fill Screen’ 옵션 버튼으로 작업하지만, 적 UI같은 것을 작업할때는 ‘Desired On Screen’ 옵션 버튼으로 작업한다.
  • 일반
    • 보더 : 테두리만 출력되고 테두리는 ‘배경 이미지’와 조정 가능한 ‘패딩’을 적용할 수 있다.
      • 패딩 : Left - Top - Right - Bottom 순서로 값을 입력한다.
        • 값이 2개면 첫 값이 ‘가로 양쪽 값’ , 두번쨰 값이 ‘세로 위 아래 값’이다.
        • 값이 1개면 전체 균등이다.
    • 프로그래스 바 : 채우는것처럼 조정할 수 있는 이미지
      • 디테일 - 스타일 - 색조 : 배경 색
      • 프로그래스
        • 퍼센트 : 0 ~ 1까지 프로그래스 바가 채워지는 비율이다.
          • Set Percent라고 한다.
        • 바 채우기 타입 : 프로그래스가 어떤 방식으로 채워지는지 정하는 옵션이다.
  • 패널
    • 캔버스 패널 : 실제로 게임 화면에 보여질 화면과 1 : 1로 디자인되는 위젯이다.
      • 적측은 캔버스를 가지지 않는다.
      • 스크린에 배치될 위젯들은 ‘캔버스 패널’로부터 시작한다.
    • 그리드 패널 : 공간을 균등하게 분할하는 패널이다.
      • 디테일 - 슬롯의 ‘행’과 ‘열’이 패널 내부의 요소를 행 과 열 로 공간 분할이 가능하다.
      • 행 합치기 : 행 스판
      • 열 합치기 : 열 스판(열 범위)
    • 크기 박스 : 디테일의 자손 레이아웃에 너비 높이 등을 지정하면 크기 박스에 붙는 하위 위젯들의 사이즈가 해당 옵션들의 비율로 정해지는 위젯이다.
    • 세로 박스 : 그리드 박스처럼 여러개의 위젯을 세로로 배치할 수 있는 패널이다.
      • 가로 정렬 : 가로로 균등하게 채워주는 옵션이다.
      • 세로 정렬 : 세로로 균등하게 채워주는 옵션이다.
  • 앵커 : 위젯의 위치 중심점을 옮기는 옵션이다.
  • 정렬 : 앵커를 기준으로 위치를 맞추는 옵션이다.
  • 콘텐츠 크기에 맞춤 ; 체크하면 콘텐츠의 크기에 맞춰서 패널의 크기가 늘어난다.
  • 위젯 이름 우측 - ‘변수 여부’ : 해당 위젯을 이벤트 그래프에서 편집이 가능하도록 설정하는 옵션이다.

컨트롤러

  • 빙의 : 컨트롤러가 한 캐릭터를 맡아서 조종하는 것을 의미한다.
  • 컨트롤러는 1개고, 캐릭터는 여러개다.
    • 컨트롤러는 캐릭터에게 명령을 내리는 역할이다.

'공부 > Unreal' 카테고리의 다른 글

24.08.27  (6) 2024.08.28
24.08.26  (1) 2024.08.27
24.08.22  (0) 2024.08.24
24.08.21  (3) 2024.08.23
24.08.20  (1) 2024.08.23