[UE Team Project/T.A.] 10. 무기 교체 (CombatComponent, UI)

2024. 10. 11. 13:53·프로젝트/TimelessAdventure
728x90
반응형

개요

이번 포스팅에서는 여러 종류의 무기를 교체하는 방식에 대해 정리해보도록 하겠습니다.


구현 아이디어 설명

포스팅에서 다루지는 않았지만 무기는 총 4종류(맨손, 검, 활, 횃불)가 존재하며, 프로젝트 기획에서 무기는 장비 창을 통해 교체하는 것이 아닌 위젯을 띄워 선택된 위젯을 바탕으로 교체되도록 만들기로 하였습니다.

 

생각해낸 아이디어는 무기 교체 버튼을 누름과 동시에 위젯을 화면에 띄우고 마지막으로 마우스 Hover 이벤트를 받았던 무기로 교체하는 것입니다.

무기 교체 위젯

 

즉, 주먹/검/활/불 칸을 버튼으로 제작하고, Hover 이벤트 발생 시 위젯에 마지막으로 들어온 버튼이 무슨 버튼인지 체크하며 이후 해당 값에 따라 실제 무기를 교체하는 방식으로 제작하게 되었습니다.


Combat Component 무기 교체 로직 구현 

CombatComponent는 현재 들고 있는 무기의 상태를 저장하며, 상태가 변경되는 경우 상태에 해당하는 무기를 새로 스폰하는 로직을 만들어주었습니다.

무기 타입 구분을 위한 열거형
임시/현재 무기의 상태

 

즉, 위젯이 비활성화 되는 동시에 무기 교체 함수 (ChangeWeapon)을 호출하며, 현재 착용중인 무기를 삭제하고 새로운 무기를 스폰하는 방식입니다.

 

CombatComponent.cpp

더보기
// 휠 버튼 Released 이벤트 발생 시 호출되는 함수
void UTA_CombatComponent::MiddleClickEnd()
{
    if (!OwnerPlayer) return;

    if (CombatState == ECombatState::CS_Idle || CombatState == ECombatState::CS_Dash)
    {
        ATA_PlayerController* PC = Cast<ATA_PlayerController>(OwnerPlayer->GetController());
        if (PC)
        {
            // 위젯 안보이도록 설정
            PC->VisibleWeaponSelectWidget(false);
        }

        // 무기 교체 함수 호출
        ChangeWeapon();
    }
}

// 무기 교체 함수
void UTA_CombatComponent::ChangeWeapon()
{
    // 임시 타입(위젯에서 설정된 타입)에 따라 현재 타입 변환
    EquippedState = TempEquippedState;

    // 기존 무기가 존재하는 경우
    if (IsValid(EquippedWeapon))
    {
        // 해당 무기 삭제
        EquippedWeapon->RemoveWeapon();
        EquippedWeapon = nullptr;
    }

    // 무기 장착
    EquipWeapon();
}

// 무기 착용 함수
void UTA_CombatComponent::EquipWeapon()
{
    // 현재 타입에 따른 무기가 존재하는 경우
    if (WeaponClassMap[EquippedState])
    {
        // 무기 스폰 & 장착
        if (WeaponClassMap[TempEquippedState])
        {
            ATA_WeaponBase* NewWeapon = GetWorld()->SpawnActor<ATA_WeaponBase>(WeaponClassMap[TempEquippedState], OwnerPlayer->GetActorTransform());
            if (NewWeapon)
            {
                NewWeapon->EquipWeapon(OwnerPlayer->GetMesh());
                EquippedWeapon = NewWeapon;
            }
        }
    }
}

ChangeWeapon 위젯

위젯의 디자인은 다음과 같으며 모든 버튼에 Hover 이벤트가 발생하는 경우 CombatComponent의 임시 무기 상태(TempEquipState)를 변경하도록 구현하였습니다.

WBP_ChangeWeapon

또한, 간단한 애니메이션을 넣어 무기 교체 위젯이 열리는 순간 점차 커지는 애니메이션을 재생하였습니다.

 

https://apth1023.tistory.com/28

 

[Unreal Engine 5] 위젯 애니메이션 (C++)

서론현재 진행중인 UE5 엔진을 사용한 사이드 프로젝트에서 직접 위젯에 애니메이션을 추가해보며 작업 내용을 간단히 정리해보기 위해 글을 작성하게 되었습니다. 언리얼 엔진에서 위젯 애니

apth1023.tistory.com

 

ChangeWeapon.h

더보기
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UI/TA_CustomWidget.h"
#include "TA_ChangeWeapon.generated.h"

/**
 * 
 */
UCLASS()
class TIMELESSADVENTURE_API UTA_ChangeWeapon : public UTA_CustomWidget
{
	GENERATED_BODY()
	
protected:
	virtual void NativeConstruct() override;

public:
	void OpenWidget();

private:
	UFUNCTION()
	void OnHoverFist();

	UFUNCTION()
	void OnHoverSword();

	UFUNCTION()
	void OnHoverBow();

	UFUNCTION()
	void OnHoverTorch();

	UFUNCTION()
	void OnHoverCancel();

private:
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<class UOverlay> OL_Main;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<class UButton> BTN_Fist;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<class UButton> BTN_Sword;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<class UButton> BTN_Bow;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<class UButton> BTN_Torch;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<class UButton> BTN_Cancel;

	UPROPERTY(meta = (BindWidgetAnim), Transient)
	TObjectPtr<UWidgetAnimation> ChangeWidgetOpen;
};

ChangeWeapon.cpp

더보기
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/TA_ChangeWeapon.h"
#include "Interface/CombatComponentInterface.h"
#include "Component/TA_CombatComponent.h"

#include "Components/Overlay.h"
#include "Components/CanvasPanelSlot.h"
#include "Blueprint/WidgetLayoutLibrary.h"
#include "Components/Button.h"

void UTA_ChangeWeapon::NativeConstruct()
{
	Super::NativeConstruct();

	BTN_Fist->OnHovered.AddDynamic(this, &UTA_ChangeWeapon::OnHoverFist);
	BTN_Sword->OnHovered.AddDynamic(this, &UTA_ChangeWeapon::OnHoverSword);
	BTN_Bow->OnHovered.AddDynamic(this, &UTA_ChangeWeapon::OnHoverBow);
	BTN_Torch->OnHovered.AddDynamic(this, &UTA_ChangeWeapon::OnHoverTorch);
	BTN_Cancel->OnHovered.AddDynamic(this, &UTA_ChangeWeapon::OnHoverCancel);
}

void UTA_ChangeWeapon::OpenWidget()
{
	FVector2D MousePos = UWidgetLayoutLibrary::GetMousePositionOnViewport(GetWorld());
	UCanvasPanelSlot* slot = UWidgetLayoutLibrary::SlotAsCanvasSlot(OL_Main);
	if (slot)
	{
		slot->SetPosition(MousePos);
	}

	PlayAnimation(ChangeWidgetOpen);
}

void UTA_ChangeWeapon::OnHoverFist()
{
	if (OwnerActor)
	{
		ICombatComponentInterface* CombatComponentInterface = Cast<ICombatComponentInterface>(OwnerActor);
		if (CombatComponentInterface)
		{
			CombatComponentInterface->GetCombatComponent()->SetChangeWeaponState(EEquippedState::ES_Idle);
		}
	}
}

void UTA_ChangeWeapon::OnHoverSword()
{
	if (OwnerActor)
	{
		ICombatComponentInterface* CombatComponentInterface = Cast<ICombatComponentInterface>(OwnerActor);
		if (CombatComponentInterface)
		{
			CombatComponentInterface->GetCombatComponent()->SetChangeWeaponState(EEquippedState::ES_Sword);
		}
	}
}

void UTA_ChangeWeapon::OnHoverBow()
{
	if (OwnerActor)
	{
		ICombatComponentInterface* CombatComponentInterface = Cast<ICombatComponentInterface>(OwnerActor);
		if (CombatComponentInterface)
		{
			CombatComponentInterface->GetCombatComponent()->SetChangeWeaponState(EEquippedState::ES_Bow);
		}
	}
}

void UTA_ChangeWeapon::OnHoverTorch()
{
	if (OwnerActor)
	{
		ICombatComponentInterface* CombatComponentInterface = Cast<ICombatComponentInterface>(OwnerActor);
		if (CombatComponentInterface)
		{
			CombatComponentInterface->GetCombatComponent()->SetChangeWeaponState(EEquippedState::ES_Torch);
		}
	}
}

void UTA_ChangeWeapon::OnHoverCancel()
{
	if (OwnerActor)
	{
		ICombatComponentInterface* CombatComponentInterface = Cast<ICombatComponentInterface>(OwnerActor);
		if (CombatComponentInterface)
		{
			CombatComponentInterface->GetCombatComponent()->SetChangeWeaponState(EEquippedState::ES_Cancel);
		}
	}
}

SetChangeWeaponState는 매우 간단히 임시 상태만 수정하도록 구현하였습니다.


결과

Change Weapon

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'프로젝트 > TimelessAdventure' 카테고리의 다른 글

[UE Team Project/T.A.] 13. 프로젝트 마무리 (최종)  (0) 2024.10.22
[UE Team Project/T.A.] 11. Boss AI  (0) 2024.10.22
[UE Team Project/T.A.] 9. 아이템 및 인벤토리 - 3 (UI - Inventory)  (0) 2024.10.11
[UE Team Project/T.A.] 8. 아이템 및 인벤토리 - 2 (UI - Slot)  (0) 2024.10.10
[UE Team Project/T.A.] 7. 아이템 및 인벤토리 - 1 (Component)  (0) 2024.10.10
'프로젝트/TimelessAdventure' 카테고리의 다른 글
  • [UE Team Project/T.A.] 13. 프로젝트 마무리 (최종)
  • [UE Team Project/T.A.] 11. Boss AI
  • [UE Team Project/T.A.] 9. 아이템 및 인벤토리 - 3 (UI - Inventory)
  • [UE Team Project/T.A.] 8. 아이템 및 인벤토리 - 2 (UI - Slot)
리태s
리태s
게임 클라이언트 프로그래머 직무를 준비하며 공부한 내용을 정리한 블로그입니다.
    반응형
    250x250
  • 리태s
    LeeTaes 공부노트
    리태s
  • 전체
    오늘
    어제
    • Home (165)
      • 프로젝트 (20)
        • Isaac 3D (5)
        • TimelessAdventure (13)
        • FruitsPuzzle (2)
      • Game Programming (25)
        • C# (8)
        • Unity Engine (6)
        • Unreal Engine (8)
        • UE_Multiplayer (3)
      • 코딩테스트 (111)
        • 프로그래머스 (Lv. 0) (27)
        • 프로그래머스 (Lv. 1) (31)
        • 프로그래머스 (Lv. 2) (21)
        • 백준 (Study) (29)
        • 알고리즘 (3)
      • CS지식 (7)
        • 운영체제 (7)
      • 일상 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    timelessadventure
    2018 kakao
    Algorithm
    unrealengine
    코딩테스트
    fruitspuzzle
    프로세스
    프로젝트
    fsoftobjectpath
    Summer/Winter Coding
    백준
    delegate
    ai controller
    구현
    C++
    청년취업사관학교
    2019 kakao
    Unreal Engine
    c#
    unity
    dataasset
    sesac
    tsoftobjectptr
    프로그래머스
    2022 kakao
    project t.a develop
    CS지식
    issac3d
    pcce 기출문제
    후기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
리태s
[UE Team Project/T.A.] 10. 무기 교체 (CombatComponent, UI)
상단으로

티스토리툴바