일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- CTF
- TSet
- 운영체제
- frequency-domain spectrum analysis
- MLFQ
- RBAC
- dtft
- 게임 개발
- MAC
- pdlc
- sampling theory
- AINCAA
- DP
- Unity #Indie Game
- DSP
- Double free
- 유스케이스
- 메카님
- 유니티
- Security
- Race condition
- STCF
- stride
- linear difference equation
- ret2libc
- dirty cow
- Rr
- 게임개발
- 언리얼엔진
- 배경 그림
- Today
- Total
다양한 기록
[UE Game Framework] #8 Item System 본문
트리거 박스의 설정
- 루트에 트리거 박스를 설정하고 자식에 메시 컴포넌트를 부착
- 이펙트는 기본값으로 비활성화 상태로 두고 오버랩 이벤트 발생 시 발동되도록 설정
- 이펙트 종료 시 액터가 제거되도록 설정
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ABItemBox.generated.h"
UCLASS()
class ARENABATTLE_API AABItemBox : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AABItemBox();
protected:
UPROPERTY(VisibleAnywhere, Category = Box)
TObjectPtr<class UBoxComponent> Trigger;
UPROPERTY(VisibleAnywhere, Category = Box)
TObjectPtr<class UStaticMeshComponent> Mesh;
UPROPERTY(VisibleAnywhere, Category = Effect)
TObjectPtr<class UParticleSystemComponent> Effect;
};
ABItemBox.h
트리거, 메쉬, 이펙트를 가짐
// Fill out your copyright notice in the Description page of Project Settings.
#include "Item/ABItemBox.h"
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "Physics/ABCollision.h"
// Sets default values
AABItemBox::AABItemBox()
{
Trigger = CreateDefaultSubobject<UBoxComponent>(TEXT("Trgger"));
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
Effect = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Effect"));
RootComponent = Trigger;
Mesh->SetupAttachment(Trigger);
Effect->SetupAttachment(Trigger);
Trigger->SetCollisionProfileName(CPROFILE_ABTRIGGER);
static ConstructorHelpers::FObjectFinder<UStaticMesh> BoxMeshRef(TEXT("/Script/Engine.StaticMesh'/Game/ArenaBattle/Environment/Props/SM_Env_Breakables_Box1.SM_Env_Breakables_Box1'"));
if (BoxMeshRef.Object)
{
Mesh->SetStaticMesh(BoxMeshRef.Object);
}
Mesh->SetRelativeLocation(FVector(0.0f, -3.5f, -30.0f));
Mesh->SetCollisionProfileName("NoCollision");
static ConstructorHelpers::FObjectFinder<UParticleSystem> EffectRef(TEXT("/Script/Engine.ParticleSystem'/Game/ArenaBattle/Effect/P_TreasureChest_Open_Mesh.P_TreasureChest_Open_Mesh'"));
if (EffectRef.Object)
{
Effect->SetTemplate(EffectRef.Object);
Effect->bAutoActivate = false;
}
}
트리거, 메시, 이펙트 설정
그리고 상자 만들어서 배치
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ABItemBox.generated.h"
UCLASS()
class ARENABATTLE_API AABItemBox : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AABItemBox();
protected:
UPROPERTY(VisibleAnywhere, Category = Box)
TObjectPtr<class UBoxComponent> Trigger;
UPROPERTY(VisibleAnywhere, Category = Box)
TObjectPtr<class UStaticMeshComponent> Mesh;
UPROPERTY(VisibleAnywhere, Category = Effect)
TObjectPtr<class UParticleSystemComponent> Effect;
// 연결하려는 델리게이트가 Dynamic이라 UFUNCTION 지정 필요
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult);
UFUNCTION()
void OnEffectFinished(class UParticleSystemComponent* ParticleSystem);
};
트리거랑 이펙트 델리게이트에 연결할 함수 두 개 선언
// Fill out your copyright notice in the Description page of Project Settings.
#include "Item/ABItemBox.h"
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "Physics/ABCollision.h"
// Sets default values
AABItemBox::AABItemBox()
{
Trigger = CreateDefaultSubobject<UBoxComponent>(TEXT("Trgger"));
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
Effect = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Effect"));
RootComponent = Trigger;
Mesh->SetupAttachment(Trigger);
Effect->SetupAttachment(Trigger);
Trigger->SetCollisionProfileName(CPROFILE_ABTRIGGER);
Trigger->SetBoxExtent(FVector( 40.0f, 42.0f, 30.0f ));
Trigger->OnComponentBeginOverlap.AddDynamic(this, &AABItemBox::OnOverlapBegin);
static ConstructorHelpers::FObjectFinder<UStaticMesh> BoxMeshRef(TEXT("/Script/Engine.StaticMesh'/Game/ArenaBattle/Environment/Props/SM_Env_Breakables_Box1.SM_Env_Breakables_Box1'"));
if (BoxMeshRef.Object)
{
Mesh->SetStaticMesh(BoxMeshRef.Object);
}
Mesh->SetRelativeLocation(FVector(0.0f, -3.5f, -30.0f));
Mesh->SetCollisionProfileName("NoCollision");
static ConstructorHelpers::FObjectFinder<UParticleSystem> EffectRef(TEXT("/Script/Engine.ParticleSystem'/Game/ArenaBattle/Effect/P_TreasureChest_Open_Mesh.P_TreasureChest_Open_Mesh'"));
if (EffectRef.Object)
{
Effect->SetTemplate(EffectRef.Object);
Effect->bAutoActivate = false;
}
}
void AABItemBox::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult)
{
Effect->Activate(true);
Mesh->SetHiddenInGame(true);
SetActorEnableCollision(false);
Effect->OnSystemFinished.AddDynamic(this, &AABItemBox::OnEffectFinished);
}
void AABItemBox::OnEffectFinished(UParticleSystemComponent* ParticleSystem)
{
Destroy();
}
닿으면 사라지고, 이펙트까지 잘 보임
이제 아이템 상자에서 무기를 얻을 수 있도록 설정할 것
데이터 애셋 만들어서 관리해주기
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "ABItemData.generated.h"
UENUM(BlueprintType)
enum class EItemType : uint8
{
Weapon = 0,
Potion,
Scroll
};
/**
*
*/
UCLASS()
class ARENABATTLE_API UABItemData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Type)
EItemType Type;
};
데이터 애셋
이걸 상속받은 무기 아이템을 만들 수 있음
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Item/ABItemData.h"
#include "ABWeaponItemData.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API UABWeaponItemData : public UABItemData
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category = Weapon)
TObjectPtr<USkeletalMesh> WeaponMesh;
};
이런식으로 설정 가능
포션이랑 스크롤은 상속 안받고 그냥 사용
프로젝트에서 사용할 아이템 애셋
- 무기 타입 : 캐릭터에 무기를 부착 - 공격거리, 공격반경, 공격속도, 공격대미지
- 포션 타입 : 캐릭터의 HP를 회복
- 스크롤 타입 : 캐릭터의 기본 스탯을 상승 - 기본공격력, 기본방어력, 최대HP, 이동속도
* 구체적인 건 다음에 할 예정
의존성 분리를 위한 설계 규칙
프로젝트의 주요 레이어
- 게임 레이어 : 게임 로직을 구체적으로 구현하는데 사용 (캐릭터, 게임 모드 등등)
- 미들웨어 레이어 : 게임에 사용되는 미들웨어 모듈 (UI, 아이템, 애니메이션, AI 등등)
- 데이터 레이어 : 게임 구성하는 기본 데이터 (스탯 정보, 캐릭터 레벨 테이블 등등)
위에서 아래로는 직접 참조, 아래에서 위로는 인터페이스를 통해 접근
아이템 획득 시 캐릭터가 아이템 습득하도록 해야 함
인터페이스 만들고 TakeItem 추가
박스에서 인터페이스의 함수를 콜할 것임
스위치문으로 아이템 구분을 할 수도 있긴 한데 델리게이트 쓸 거임
델리게이트 배열로 만들어줌
C#은 델리게이트 그냥 배열로 넣을 수 있는데 C++은 구조체로 감싸야 할 수 있는듯
바인딩해주기
void AABCharacterBase::TakeItem(UABItemData* InItemData)
{
if ( InItemData )
{
TakeItemActions[(uint8)InItemData->Type].ItemDelegate.ExecuteIfBound(InItemData);
}
}
void AABCharacterBase::DrinkPotion(UABItemData* InItemData)
{
UE_LOG(LogABCharacter, Log, TEXT("Drink Potion"));
}
void AABCharacterBase::EquipWeapon(UABItemData* InItemData)
{
UE_LOG(LogABCharacter, Log, TEXT("Equip Weapon"));
}
void AABCharacterBase::ReadScroll(UABItemData* InItemData)
{
UE_LOG(LogABCharacter, Log, TEXT("Read Scroll"));
}
로그 지정해서 테스트 해보기
각 오브젝트에서 저렇게 지정해주고 테스트
확인 가능함
이제 무기 상자 획득했을 때 캐릭터 손에 무기 주기
캐릭터의 특정 본에 부착할 수 있도록 소켓 이름을 줄 수 있음
스켈레탈 메시 설정
메시 지정은 아까 에디터에서 해줬음
무기 획득 성공
스켈레탈 메시 직접 들어가서 메시 변경하는 것도 가능
소프트 레퍼런싱
소프트 레퍼런싱 vs 하드 레퍼런싱
- 액터 로딩 시 TObjectPtr로 선언한 언리얼 오브젝트도 따라서 메모리에 로딩됨 (하드 레퍼런싱)
- 게임 진행에 필수적인 언리얼 오브젝트는 이렇게 선언해도 되지만 아이템은 굳이 그럴 필요 없음
- 필요한 데이터만 로딩하도록 TSoftObjectPtr로 선언하면 대신 애셋 주소 문자열을 지정
- 필요 시에 애셋을 로딩하도록 구현을 변경할 수 있으나 애셋 로딩 시간이 소요됨
- 현재 게임에서 로딩되어 있는 스켈레탈 메시 목록 살펴보기?
- 콘솔 명령어: Obj List Class=SkeletalMesh
에디터 끄고 틸드 명령하고 콘솔 명령어 치면..
아이템 안먹었는데 드래곤 소드 스켈레탈 메시가 로딩되어 있음
아이템 박스에서 소프트 레퍼런싱으로 바꿔주고 에디터 재빌드
그러면 에러 뜸
소프트 레퍼런싱이라 아직 로딩이 된 건지 아닌지 모르기 때문
로딩되지 않은 상태면 동기적으로 로딩하고, Get으로 가져와야 함
왠진 모르겠는데, 드래곤 소드가 항상 로드되는 문제가 있었음
DerivedDataCache 폴더 삭제 등의 시도가 있었는데 결과적으로는,
데이터 에셋에 등록해뒀던 스켈레탈 메시를 클리어 후 재등록하고, 에디터 재시작하니까
소프트 레퍼런스가 정상 작동하는 걸 확인할 수 있었음
'언리얼 엔진 > Unreal Game Framework' 카테고리의 다른 글
[UE Game Framework] #9 Infinity Map (0) | 2025.01.06 |
---|---|
[UE Game Framework] #7 Character Stat & Widget (0) | 2025.01.05 |
[UE Game Framework] #6 Character Attack Hit Check (0) | 2025.01.05 |
[UE Game Framework] #5 Character Combo Action (0) | 2025.01.04 |
[UE Game Framework] #4 Character Animation Setting (0) | 2025.01.04 |