3 minute read

카메라(정확히는 TargetArmLength)의 최소 길이(확대 제한)와 최대 길이(축소 제한),

기본값과 카메라휠을 돌려서 확대/축소할 때 얼만큼씩 길이를 조절할 지..

Main.h

// About CameraZoom
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CameraZoom")
	float MinZoomLength = 100.f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CameraZoom")
	float MaxZoomLength = 800.f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CameraZoom")
	float DefaultArmLength = 500.f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CameraZoom")
	float ZoomStep = 30.f;

카메라줌 함수 - 마우스 휠 값을 매개변수로 받을 것임

void CameraZoom(const float Value);

FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }


따라서 축 매핑에 추가

스케일값이 -1인 이유는 1로 했었을 때, 마우스휠을 위로 굴리면 축소되고 아래로 굴리면 확대되었음

하지만 난 그 반대로 하고 싶었기 때문에 -1로 바꿈

이미지

Main.cpp

#include "Camera/PlayerCameraManager.h"


void AMain::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)

PlayerInputComponent->BindAxis("CameraZoom", this, &AMain::CameraZoom);
void AMain::CameraZoom(const float Value)
{
	if (Value == 0.f || !Controller) return;

	const float NewTargetArmLength = CameraBoom->TargetArmLength + Value * ZoomStep;
	CameraBoom->TargetArmLength = FMath::Clamp(NewTargetArmLength, MinZoomLength, MaxZoomLength);
}




Enemy.h

UENUM(BlueprintType)
enum class EEnemyMovementStatus :uint8
{
	EMS_Idle			UMETA(DeplayName = "Idle"),
	EMS_MoveToTarget	UMETA(DeplayName = "MoveToTarget"),
	EMS_Attacking		UMETA(DeplayName = "Attacking"),

	EMS_MAX				UMETA(DeplayName = "DefaultMAX")
};

enum클래스 아직 공부 안 함, 이전 포스트에 이 코드 빠뜨린듯?

그리고 전투범위오버랩 불 변수 추가됨, 당연히 기본값은 false(생성자에서 기본값 지정)

UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "AI")
bool bOverlappingCombatSphere;


인식범위에서 오버랩 해제됐을 때

유휴 상태로 변하고 이동 멈춤

void AEnemy::AgroSphereOnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (OtherActor)
	{
		AMain* Main = Cast<AMain>(OtherActor);
		if (Main)
		{
			SetEnemyMovementStatus(EEnemyMovementStatus::EMS_Idle);
			if (AIController)
			{
				AIController->StopMovement();
			}
		}
	}
}


전투범위에 오버랩됐을 때

불 변수 true, 공격 상태로 변경

void AEnemy::CombatSphereOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor)
	{
		AMain* Main = Cast<AMain>(OtherActor);
		if (Main)
		{
			bOverlappingCombatSphere = true;
			SetEnemyMovementStatus(EEnemyMovementStatus::EMS_Attacking);
		}
	}
}


전투범위 오버랩 해제됐을 때

불 변수 false, 현재 공격 상태면 플레이어 쫓아가기

void AEnemy::CombatSphereOnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (OtherActor)
	{
		AMain* Main = Cast<AMain>(OtherActor);
		if (Main)
		{
			bOverlappingCombatSphere = false;
			if (EnemyMovementStatus == EEnemyMovementStatus::EMS_Attacking)
			{
				MoveToTarget(Main);
			}
		}
	}
}

+그리고 MoveToTarget()에선 당연히

	SetEnemyMovementStatus(EEnemyMovementStatus::EMS_MoveToTarget);

상태를 바꿔줍니다.


이미지

이미지

이미지



무기 장착은 일단… (플레이어는 문제 없는데 npc가 문제)

사용자 클래스 Item 상속받음

Weapon.h

UENUM(BlueprintType)
enum class EWeaponState :uint8
{
	EWS_Pickup		 UMETA(DisplayName = "Pickup"),
	EWS_Equipped	 UMETA(DisplayName = "Equipped"),

	EWS_Max  UMETA(DisplayName = "DefaultMax"),
};

/**
 * 
 */
UCLASS()
class YARO_API AWeapon : public AItem
{
	GENERATED_BODY()

protected:
	// Called when the game starts or when spawned
	//virtual void BeginPlay() override;
	
public:
	AWeapon();

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Item")
	EWeaponState WeaponState;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "SkeletalMesh")
	class USkeletalMeshComponent* SkeletalMesh;


	virtual void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) override;

	virtual void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) override;

	void Equip(class AMain* Char);
	void Equip_NPC(class AYaroCharacter* Char, class AWeapon* Wand);

	FORCEINLINE void SetWeaponState(EWeaponState State) { WeaponState = State; }
	FORCEINLINE EWeaponState GetWeaponState() { return WeaponState; }
};

Weapon.cpp

AWeapon::AWeapon()
{
    SkeletalMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalMesh"));
    SkeletalMesh->SetupAttachment(GetRootComponent());

    WeaponState = EWeaponState::EWS_Pickup;

}


플레이어가 무기 자신에게 오버랩됐을 때 Main에 있는 ActiveOverlappingItem에 할당

void AWeapon::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    //UE_LOG(LogTemp, Log, TEXT("%s"), *(this->GetName()));
    Super::OnOverlapBegin(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);
    if ((WeaponState == EWeaponState::EWS_Pickup) && OtherActor)
    {
        AMain* Main = Cast<AMain>(OtherActor);
        if (Main)
        {
            Main->SetActiveOverlappingItem(this);
        }
    }
}


오버랩 해제되면 null로 바꿔줌

void AWeapon::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
    Super::OnOverlapEnd(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex);
    if (OtherActor)
    {
        AMain* Main = Cast<AMain>(OtherActor);
        if (Main)
        {
            Main->SetActiveOverlappingItem(nullptr);
        }
    }
}


무기 장착 함수, 매개변수로 플레이어를 받음

플레이어 메쉬에서 RigntHandSocket이라는 소켓을 가져온 뒤 무기 본인(액터, Item클래스가 액터 상속받음) 부착

void AWeapon::Equip(AMain* Char)
{
    if (Char)
    {
        SkeletalMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
        SkeletalMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);

        SkeletalMesh->SetSimulatePhysics(false);

        const USkeletalMeshSocket* RightHandSocket = Char->GetMesh()->GetSocketByName("RightHandSocket");
        if (RightHandSocket)
        {
            RightHandSocket->AttachActor(this, Char->GetMesh());
            bRotate = false;
            Char->SetEquippedWeapon(this);
            Char->SetActiveOverlappingItem(nullptr);

        }
    }
}


이것이 RightHandSocket

이미지


그리고 무기를 장착하기 위해선 무기의 (오버랩)범위 안에 들어간 뒤 왼쪽 마우스를 클릭해야함!

액션 매핑에 왼쪽 마우스 추가

이미지


왼쪽 마우스 버튼 클릭에 관련된 변수 및 함수들 + 무기 장착 관련

Main.h

	bool bLMBDown;
	void LMBDown();
	void LMBUp();

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Items)
	class AWeapon* EquippedWeapon;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Items)
	class AItem* ActiveOverlappingItem;

	FORCEINLINE void SetEquippedWeapon(AWeapon* WeaponToSet) { EquippedWeapon = WeaponToSet; }
	FORCEINLINE void SetActiveOverlappingItem(AItem* Item) { ActiveOverlappingItem = Item; }


void AMain::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) 에서 바인딩

	PlayerInputComponent->BindAction("LMB", IE_Pressed, this, &AMain::LMBDown);
	PlayerInputComponent->BindAction("LMB", IE_Released, this, &AMain::LMBUp);


void AMain::LMBDown()
{
	bLMBDown = true;

	if (ActiveOverlappingItem)
	{
		AWeapon* Weapon = Cast<AWeapon>(ActiveOverlappingItem);
		if (Weapon)
		{
			Weapon->Equip(this);
			SetActiveOverlappingItem(nullptr);
		}
	}
}

void AMain::LMBUp()
{
	bLMBDown = false;
}



카메라 확대/축소, 무기장착, Enemy 상태변환 등 영상으로 확인



무기를 장착해야해서 기존 애니메이션들 손 모양도 좀 바꿔주고,

공격 애니메이션을 만드려고 했는데 쉽지 않음… ㅠ

시간이 엄청 오래 걸림…….. 아직 완성도 못 함




다음 할 것 : npc 무기 장착 방법 연구… 공격 애니메이션 만들기? 적의 공격 시스템도..

Updated: