• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

ProjectDark - 02 - Create Weapon Base

23 Aug 2021

Reading time ~3 minutes

Weapon

역시 게임에는 무기가 필요하지

현재 다크사이더스3에서 갖고온 무기 모델들은 쌍검, 쌍절곤, 창, 오함마 이다.(Nunchaku가 쌍절곤인걸 오늘 알았다….)

이 무기들 중 2개를 갖고 보스를 만나러 가는 것으로 만들어 줄것이다.

그럼 장착하는 것과 공격 이 필요하다.

이 무기들의 큰 틀을 갖고 베이스 클래스를 만들어 주자.

WeaponBase Class

Actor를 상속받아 WeaponBase를 만들어준다.

WeaponBase.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "WeaponBase.generated.h"

UENUM(BlueprintType)
enum class EWeaponType : uint8
{
	WT_DualSword UMETA(DisplayName = "DualSword"),
	WT_Hammer UMETA(DisplayName = "Hammer"),
	WT_Nunchaku UMETA(DisplayName = "Nunchaku"),
	WT_Spear UMETA(DisplayName = "Spear"),
	WT_Sword UMETA(DisplayName = "Sword")
};

enum class EDualWeaponDirection
{
	Left, Right
};

USTRUCT(Atomic, BlueprintType)
struct FWeaponInfo
{
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		EWeaponType WeaponType;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		UAnimMontage* AtkMontage;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		int MaxComboCount;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TArray<int> ComboDamage;
};

UCLASS()
class MAINPLAYERCODES_API AWeaponBase : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AWeaponBase();

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

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	void SetActiveActor(bool IsActive);

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mesh")
	class USkeletalMeshComponent* WeaponMesh;

private:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mesh", meta = (AllowPrivateAccess = "True"))
	FWeaponInfo WeaponInfo;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Mesh", meta = (AllowPrivateAccess = "True"))
	float CurrentDamage;

public:
	virtual void AttachToPlayer();

	virtual void Deattach();

	virtual void Equip();

	virtual void TakeOff();

	virtual void AttackStart(const int32& ComboIndex, const float& AddDamage);

	virtual void AttackEnd();

	virtual void DualAttackStart(const int32& ComboIndex, const float& AddDamage, const EDualWeaponDirection& WeaponDirection);

	virtual void DualAttackEnd(const EDualWeaponDirection& WeaponDirection);

protected:
	UFUNCTION()
		virtual void WeaponBeginOverlap(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

public:
	FORCEINLINE const FWeaponInfo& GetWeaponInfo() const { return WeaponInfo; }

	FORCEINLINE const float& GetCurrentDamage() const { return CurrentDamage; }
	FORCEINLINE void SetCurrentDamage(const float& Damage) { CurrentDamage = Damage; }
};
WeaponBase.cpp
// Fill out your copyright notice in the Description page of Project Settings.


#include "WeaponBase.h"

#include "Kismet/GameplayStatics.h"
#include "GameFramework/Character.h"
#include "Components/SkinnedMeshComponent.h"

#include "MainPlayer.h"

// Sets default values
AWeaponBase::AWeaponBase()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	
	WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));
	RootComponent = WeaponMesh;
	//WeaponMesh->SetupAttachment(RootComponent);
}

// Called when the game starts or when spawned
void AWeaponBase::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AWeaponBase::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AWeaponBase::SetActiveActor(bool IsActive)
{
	SetActorHiddenInGame(!IsActive);

	SetActorEnableCollision(!IsActive);

	SetActorTickEnabled(!IsActive);
}

void AWeaponBase::AttachToPlayer()
{
	ACharacter* PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(),0);
	
	WeaponMesh->USkinnedMeshComponent::SetMasterPoseComponent(PlayerCharacter->GetMesh(), true);
	AttachToComponent(PlayerCharacter->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale);
	AMainPlayer* MainPlayer = Cast<AMainPlayer>(PlayerCharacter);
	if (MainPlayer)
	{
		MainPlayer->AttachWeapon(this);
	}
}

void AWeaponBase::Deattach()
{
	
}

void AWeaponBase::Equip()
{
	SetActiveActor(true);
}

void AWeaponBase::TakeOff()
{
	SetActiveActor(false);
}

void AWeaponBase::AttackStart(const int32& ComboIndex, const float& AddDamage)
{
	CurrentDamage = GetWeaponInfo().ComboDamage[ComboIndex - 1] + AddDamage;
}

void AWeaponBase::AttackEnd()
{
}

void AWeaponBase::DualAttackStart(const int32& ComboIndex, const float& AddDamage, const EDualWeaponDirection& WeaponDirection)
{
	CurrentDamage = GetWeaponInfo().ComboDamage[ComboIndex - 1] + AddDamage;
}

void AWeaponBase::DualAttackEnd(const EDualWeaponDirection& WeaponDirection)
{
}

void AWeaponBase::WeaponBeginOverlap(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// 공격
}

쌍검과 쌍절곤 때문에 왼쪽 오른쪽을 따로 분리해 놓은 것과 오함마와 창은 하나의 히트박스를 갖고 있기 때문에 attackStart에서 처리해 줄 것이다.

그리고 무기에 어떤 애니메이션 몽타주를 갖고있는지 각 콤보마다 공격력을 어떻게 해줄것인지, 그리고 콤보가 몇개까지 있는지 구조체로 정의해준다.

그리고 SkeletalMesh로 왜 무기를 만든 이유는 추후 설명하겠다.

데미지는 플레이어의 데미지도 같이 합산해서 한다(레벨업, 스텟조정 때문에)

이 클래스를 부모로 해서 각각 만들어준다.



Unreal Share Tweet +1