C++ 코드를 사용해서 아이템을 구현해보았다.

스코어를 쌓을 수 있는 코인, 체력을 회복하는 회복포션, 범위 안에 들어가면 터지는 지뢰가 있다.

아이템들은 플레이어와 닿았을 때의 충돌처리가 가장 중요한 것 같다.

 

 

언리얼 충돌 옵션들

Collsion 카테고리의 여러 옵션들을 보면 충돌과 물리에 대한 옵션들이 많이 있는데, 상황에 맞게 어떻게 쓸 수 있는지 정리해보았다.

 

Collsion Preset

  • NoCollision : 충돌 자체를 처리하지 않을 때
  • BlockAll : 모든 것들을 막을 때(벽이나, 바닥같은)
  • OverlapAll : 모든 객체 통과하는지 감지(주로 트리거 장치에 주로 사용)
  • BlockAllDynamic : 움직이는 객체만 막음(플레이어만 상호작용하고 싶을 때)
  • OverlapAllDynamic : 움직이는 객체만 처리함(센서용으로 많이 사용)
  • Pawn : Pawn 타입 객체들 전용으로 충돌처리

 

Collsion Enabled

  • Collision Enable(Query and Physics) : 충돌, 물리적 감지 모두 활성화 ← 보통의 상황에 주로 사용
  • Query Only(No Physics Collsion) : 충돌만 감지(overlap, hit) 물리적 감지 반응 x
  • Physics Only(Noe Query Collsion) : 물리적 감지 x

 

이렇게 다양한 옵션들이 있으니 상호작용하는 물체마다 적절한 옵션을 넣어주면 될 것 같다.

 

아이템 클래스 설계

아이템들을 구현하기 위해 설계를 어떻게 하면 좋을지 고민해보았다.

 

이렇게 공통 특성을 묶어서 설계하면 코드의 유지보수가 엄청 편해진다는 것을 이해했다.

 

Interface 정의
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ItemInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
{
	GENERATED_BODY()
};

class PRACTICE_API IItemInterface
{
	GENERATED_BODY()

public:
	UFUNCTION()
	virtual void OnItemOverlap(
		UPrimitiveComponent* OverlappedComp,  // SphereComponent
		AActor* OtherActor,  // SphereComponent에 부딪힌 다른 Actor
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex,
		bool bFromSweep,
		const FHitResult& SweepResult
	) = 0;
	UFUNCTION()
	virtual void OnItemEndOverlap(
		UPrimitiveComponent* OverlappedComp,  // SphereComponent
		AActor* OtherActor,  // SphereComponent에 부딪힌 다른 Actor
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex
	) = 0;
		
	virtual void ActivateItem(AActor* Activator) = 0;
	virtual FName GetItemType() const = 0;
};

인터페이스는 순수가상함수로만 이뤄진 클래스를 말한다.

모두 순수가상함수로 정의해서 상속받은 클래스에서 무조건 해당 함수를 정의하게 만들어줬고, 오버랩 이벤트를 사용해주었다.

 

참고로 인터페이스 클래스라고해도 cpp 파일은 삭제하지 않는 편이 좋다고 한다. 엔진에서 컴파일할 때 존재를 알려주는 역할? 로 작용한다고 한다.

 

BaseItem 정의
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h"
#include "BaseItem.generated.h"

class USphereComponent;

UCLASS()
class PRACTICE_API ABaseItem : public AActor, public IItemInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABaseItem();

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	FName ItemType;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
	USceneComponent* Scene;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
	USphereComponent* Collision;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
	UStaticMeshComponent* StaticMesh;

	virtual void OnItemOverlap(
		UPrimitiveComponent* OverlappedComp,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex,
		bool bFromSweep,
		const FHitResult& SweepResult
	) override;
	virtual void OnItemEndOverlap(
		UPrimitiveComponent* OverlappedComp,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex
	) override;
	virtual void ActivateItem(AActor* Activator) override;
	virtual FName GetItemType() const override;

	virtual void DestroyItem();


	
};

BaseItem에서는 아이템들이 가지게 될 루트 컴포넌트와 충돌 컴포넌트, 메쉬를 정의해주었다.

블루프린트에서도 접근할 수 있도록 매크로도 추가해주었다.

 

+ 스크린상에서 로그 띄우는 방법

GEngine->AddOnScreenDebugMessage(id, 몇초동안 띄울지, 폰트색상, 출력하고싶은 문구);

이렇게 해주면 된다.

GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, FString::Printf(TEXT("Overlap!!")));

나는 이렇게 사용해줬다. id 의 -1은 id가 로그출력될 때마다 바로바로 생성된다는 의미로 이해하면 될 것 같다.

 

 

결과

 

이렇게 구현한대로, 플레이어와 아이템이 닿으면 아이템이 사라지고 로그가 스크린에 표출되는 것을 볼 수 있다.

하지만 지뢰에서 SphereCollision의 반지름을 300.0f 나 크게 설정해줬는데 로그를 보면 ExplosionCollision이 아니라 Mine 자체의 Collision에서 로그가 나오는 것을 볼 수 있다.

왜그런지는 내일 다시 코드를 살펴보고 수정해야 할 사항이다.

 

 

마지막 말

Overlap과 Physics의 Collision은 어떤 차이점이 있을까? 물리를 추가하면 중력이나 여러 부가적인 기능 때문에 무거워지는 것 같지만 어떤 상황에서 Overlap과 물리의 Collision을 사용하는 건지 궁금해졌다.

어떤 상황이 두 기능의 특징들을 잘 살릴 수 있는지 테스트를 해보려고 한다.