[ Unreal Engine 5 / #2 Bullet, Enemy, Collusion]

SeungWoo·2024년 8월 29일
0
post-thumbnail

Player

  • UPROPERY()

  • 클래스는 객체 또는 설계도라고도 하며 그 설계도로 만든것이 인스턴스이다

  • 객체들의 특징을 멤버라고 하고 그 멤버 ( 메소드 )

    • 속성 ( PROPERTY ) = 명사 = 함수( 기능 )
  • 바인딩을 하기위해 Project Setting에 Input값 Axis Mappings 값을 바꿔준다

    • Action Mappings : 단발성
    • Axis Mappings : 축, 지속성


CPlayer.h

public:
	// 이동속도는 속성
	UPROPERTY(EditAnywhere, Category="Settings")
	float speed = 500;

	float h;
	float v;

	void Horizontal(float value);
	void Vertical(float value);

CPlayer.cpp

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	// 사용자 입력과 처리함수 묶어주자. ( 바인딩 )
	PlayerInputComponent->BindAxis(TEXT("Horizontal"),
		this, &ACPlayer::Horizontal);
	PlayerInputComponent->BindAxis(TEXT("Vertical"),
		this, &ACPlayer::Vertical);
}

void ACPlayer::Horizontal(float value)
{
	h = value;
}

void ACPlayer::Vertical(float value)
{
	v = value;
}

  • this 포인터는 어디서 있는걸까?

  • 기본적으로 Stack은 대략 1메가 바이트로 정도로 정해두고 이것이 넘어가면 stack overflow 가 발생한다
    • heap은 개발자가 할당하고 해제해야하는 동적메모리 공간 언리얼에서 UPROPERTY() 함수가 어느정도 제어 해준다

CPlayer.cpp

void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// 사용자의 입력에 따라 이동하고 싶다
	// 1. 사용자의 입력을 받아야 한다
	// 등속운동, 등가속운동
	// P = P0 + vt
    
	// 2. 방향이 필요하다
	FVector dir(0, h, v);
    
	// 3. 해당 방향으로 이동하고 싶다
	FVector P0 = GetActorLocation();
	FVector vt = dir * speed * DeltaTime;
	
	FVector P = P0 + vt;
	SetActorLocation(P);
}

  • 언리얼의 구조 설계

Bullet

  • C++클래스 를 하나만들고 기존 Player 와 같은 형체를 만들기 위해 Component를 그대로 복사해서 가져온다
    CBullet.h
public:
	UPROPERTY(VisibleAnywhere)
	class UBoxComponent* BoxComp;

	UPROPERTY(VisibleAnywhere)
	class UStaticMeshComponent* BodyMesh;

	// 이동속도는 속성
	UPROPERTY(EditAnywhere, Category = "Settings")
	float speed = 1000;

CBullet.cpp

ACBullet::ACBullet()
{
 	// 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;

	BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
	RootComponent = BoxComp;

	// box size
	BoxComp->SetBoxExtent(FVector(50));
	BoxComp->SetCollisionProfileName(TEXT("OverlapAll"));
	BoxComp->SetRelativeScale3D(FVector((1, 0.25f, 0.5f)));

	BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
	BodyMesh->SetupAttachment(BoxComp);

	// 에셋 등록
	ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh
	(TEXT("/Script/Engine.StaticMesh'/Engine/BasicShapes/Cube.Cube'"));
	// 에셋이 로드가 됐다면...
	if (TempMesh.Succeeded())
	{
		BodyMesh->SetStaticMesh(TempMesh.Object);
	}

	// Matrial �ε��ϱ�
	ConstructorHelpers::FObjectFinder<UMaterial> TempMat
	(TEXT("/Script/Engine.Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
	if (TempMat.Succeeded())
	{
		// -> ����ƽ�޽� �Ҵ�
		BodyMesh->SetMaterial(0, TempMat.Object);
	}
	BodyMesh->SetCollisionProfileName(TEXT("NoCollision"));
}
  • 총알은 쏘는 방향에서 일직선으로 움직이게

CBullet.cpp

void ACBullet::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// p = p0 + vt
	FVector P = GetActorLocation()
		+ FVector::UpVector * speed * DeltaTime;
	SetActorLocation(P);

}
  • 그 후 Fire Action를 하나 등록 한다

  • player 스크립트로 넘어와 오른쪽 마우스키를 누를 경우 나가게 만들기 위해 블랫 생성 위치와 Bullet Actor를 선언

CPlayer.h

public:

	... 생략

	// 사용자가 발사버튼을 누르면 총알을 발사하고 싶다
	// 필요속성 : 총알공장, 발사위치, 
	UPROPERTY(EditDefaultsOnly, Category = "Settings")
	TSubclassOf<class ACBullet> bulletFactory;
	
	void Fire();
  • WASD 입력값처러 바인딩을 하면 Fire()가 발동되게 한다

CPlayer.cpp

void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);


	PlayerInputComponent->BindAxis(TEXT("Horizontal"),
		this, &ACPlayer::Horizontal);
	
	PlayerInputComponent->BindAxis(TEXT("Vertical"),
		this, &ACPlayer::Vertical);

	PlayerInputComponent->BindAction(TEXT("Fire"),
		IE_Pressed, this, &ACPlayer::Fire);
}

void ACPlayer::Fire()
{
	GetWorld()->SpawnActor<ACBullet>(
		bulletFactory, GetActorLocation(), FRotator::ZeroRotator);
}

Enemy

  • Enemy또한 몸체를 만들기 위해 Bullet 처럼 몸체를 일단 만든다

  • 그 후 에너미는 플레이를 추격하지만 30% 확률로 쫓아오게 할 것이다

  • 추격

  • Target( Player )와 Enemy의 위치를 빼서 그 사이의 거리를 구한다

CEnemy.h

public:
	... 생략
	// 필요속성 : 타겟
	UPROPERTY(EditAnywhere)
	class AActor* target;

	FVector dir;
  • Target Actor가 되는 AACtor클래스를 선언한다

CEnemy.cpp

void ACEnemy::BeginPlay()
{
	Super::BeginPlay();
	
	// 태어날때 한번 방향을 정하고 그대로 움직인다
	// 30% 확률
	int32 ran_num = FMath::RandRange(1, 3);

	if (ran_num == 1)
	{
		//	Target - enemy =  Target의 방향
		dir = target->GetActorLocation() - GetActorLocation();
		dir.Normalize(); // Nomalize
	}
	else
	{
		dir = FVector::DownVector;
	}

}

void ACEnemy::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);


	// 해당 방향으로 이동하고 싶다
	// 등속운동, 등가속운동
	// P = P0 + vt
	FVector P0 = GetActorLocation();
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

Collusion

CEnemy.cpp

ACEnemy::ACEnemy()
{
	...생략 ( 몸체 )

	BoxComp->OnComponentBeginOverlap.AddDynamic
}
  • OnComponentBeginOverlap 부분의 커서를 가져놓고 F12를 눌러 들어간다

  • 여기서 Ctrl+F 키를 눌러 검색해도되고 FComponentBeginOverlapSignature 에 커서를 가져다 놓고 F12를 눌러보면
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SixParams( 
FComponentBeginOverlapSignature, 
UPrimitiveComponent, OnComponentBeginOverlap, 
UPrimitiveComponent*, OverlappedComponent, 
AActor*, OtherActor,
UPrimitiveComponent*, OtherComp,
int32, OtherBodyIndex, 
bool, bFromSweep, 
const FHitResult &, SweepResult);
  • 구문을 찾아서 UPrimitiveComponent부터 SweepResult까지 복사
UPrimitiveComponent, OnComponentBeginOverlap, 
UPrimitiveComponent*, OverlappedComponent, 
AActor*, OtherActor,
UPrimitiveComponent*, OtherComp,
int32, OtherBodyIndex, 
bool, bFromSweep, 
const FHitResult &, SweepResult);
  • 복사한 부분을 함수로 선언한다
    CEnemy.h
public:

	UFUNCTION()
	void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor, UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex, bool bFromSweep,
		const FHitResult& SweepResult);

CEnemy.cpp

ACEnemy::ACEnemy()
{
	...생략 ( 몸체 )

	BoxComp->OnComponentBeginOverlap.AddDynamic(this, &ACEnemy::OnComponentBeginOverlap);
}

void ACEnemy::OnComponentBeginOverlap(
UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor, 
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep, 
const FHitResult& SweepResult)
{
	
	OtherActor->Destroy();

	Destroy();
}
  • 충돌 델리이벤트 함수를 부르는 방법이다
profile
This is my study archive

0개의 댓글