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()); } - 적 같은 UI는 직접 생성해서 할당하는 것이기 때문에 반드시 직접 가져와야 사용할 수 있다.
- 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개면 전체 균등이다.
- 패딩 : Left - Top - Right - Bottom 순서로 값을 입력한다.
- 프로그래스 바 : 채우는것처럼 조정할 수 있는 이미지
- 디테일 - 스타일 - 색조 : 배경 색
- 프로그래스
- 퍼센트 : 0 ~ 1까지 프로그래스 바가 채워지는 비율이다.
- Set Percent라고 한다.
- 바 채우기 타입 : 프로그래스가 어떤 방식으로 채워지는지 정하는 옵션이다.
- 퍼센트 : 0 ~ 1까지 프로그래스 바가 채워지는 비율이다.
- 보더 : 테두리만 출력되고 테두리는 ‘배경 이미지’와 조정 가능한 ‘패딩’을 적용할 수 있다.
- 패널
- 캔버스 패널 : 실제로 게임 화면에 보여질 화면과 1 : 1로 디자인되는 위젯이다.
- 적측은 캔버스를 가지지 않는다.
- 스크린에 배치될 위젯들은 ‘캔버스 패널’로부터 시작한다.
- 그리드 패널 : 공간을 균등하게 분할하는 패널이다.
- 디테일 - 슬롯의 ‘행’과 ‘열’이 패널 내부의 요소를 행 과 열 로 공간 분할이 가능하다.
- 행 합치기 : 행 스판
- 열 합치기 : 열 스판(열 범위)
- 크기 박스 : 디테일의 자손 레이아웃에 너비 높이 등을 지정하면 크기 박스에 붙는 하위 위젯들의 사이즈가 해당 옵션들의 비율로 정해지는 위젯이다.
- 세로 박스 : 그리드 박스처럼 여러개의 위젯을 세로로 배치할 수 있는 패널이다.
- 가로 정렬 : 가로로 균등하게 채워주는 옵션이다.
- 세로 정렬 : 세로로 균등하게 채워주는 옵션이다.
- 캔버스 패널 : 실제로 게임 화면에 보여질 화면과 1 : 1로 디자인되는 위젯이다.
- 앵커 : 위젯의 위치 중심점을 옮기는 옵션이다.
- 정렬 : 앵커를 기준으로 위치를 맞추는 옵션이다.
- 콘텐츠 크기에 맞춤 ; 체크하면 콘텐츠의 크기에 맞춰서 패널의 크기가 늘어난다.
- 위젯 이름 우측 - ‘변수 여부’ : 해당 위젯을 이벤트 그래프에서 편집이 가능하도록 설정하는 옵션이다.
컨트롤러
- 빙의 : 컨트롤러가 한 캐릭터를 맡아서 조종하는 것을 의미한다.
- 컨트롤러는 1개고, 캐릭터는 여러개다.
- 컨트롤러는 캐릭터에게 명령을 내리는 역할이다.