[ Unreal Engine 5 / #4 적 스폰 생성 ]

SeungWoo·2024년 9월 2일
0
post-thumbnail

징벌락

  • 오일러 각
    오일러가 도입한 강체(rigid body)의 회전 시스템

  • 3차원 공간에 존재하는 어떠한 강체를 회전하고 싶으면 세개의 축을 통한 회전으로 표현할 수가 있다.
    대신 회전을 할 때에는 이 세축이 종속적일 수 밖에 없는데,
    ( 이부분이 매우 중요하다. 세축이 종속적이기 때문에 짐벌 락이라고 표현함 )
    z축을 돌리는 순간 x,y축은 함께 돌기 때문이다.
    • alpha: z-축(파란색)을 회전축으로 하여 회전된 x-y 좌표축의 각도
    • beta: 회전된 x-축(즉, N-축, 녹색)을 회전축으로 하여 회전된 z-y 좌표축의 각도
    • gamma: 위에서 회전된 z-축(즉, Z축, 빨간색)을 회전축으로 하여 회전된 x-y 좌표축의 각도

출처: https://handhp1.tistory.com/3 [망고 먹는 개발자:티스토리]


축이 3개로 나눠져 있는 3D 상태에서 회전 하다가 2개축이 겹쳐지는 현상 이것을 징벌락이라고 부른다

player를 바라보고 적이 따라오게 하기

  • 큐브를 추가해서 앞 위 그룹으로 조절 한다

CEnemy.h

public:
	FRotator rot;

CEnemy.cpp

#include "Kismet\KismetMathLibrary.h"

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);

	//추가 XZ를 고정시키면서 징벌락 현상을 방지한다 
	rot = UKismetMathLibrary::MakeRotFromXZ(GetActorForwardVector(), dir);
	//rot = UKismetMathLibrary::FindLookAtRotation(P, P + dir);
	SetActorRotation(rot);
}

유효성 검사

  • 메모리주소 : 0X000000
  • ISVAILD : 0XFSd... 쓰레기 값이 들어있다
    • 누군가 삭제했는데 참조하려 할때 ( 댕글리 포인트 )
    • 멀티 참조일 경우 혹여나 삭제했을지 모르는 참조 포인터를 비교할때 쓰는게 아주 좋다


nullptr 체크 외에도 pending kill 상태인지, garbage 인지 체크한다. 실제로 언리얼의 공식 독스를 보면

Return true if the object is usable
: non-null and not pending kill or garbage

라고 되어 있는걸 볼 수 있습니다. 결국 nullptr인지 pending kill인지 garbage인지, 총 3가지를 체크하는 것입니다.

  • Pending Kill
    • garbage : GC에 수집
    • Pending Kill : 곧 사라질 오브젝트
    • 오브젝트가 Destroy한다면 바로 사라지는 것이 아니라 실제로 pending kill 상태가 되고, 이후에 삭제된다.

적 Spawn 하기

적 스폰을 위해 C++ 클래스를 하나 제작
CEnemyGOD.h

public:
	// 필요속성 : 생성시간 경과시간 적공자
	UPROPERTY(EditAnywhere)
	float creatTime = 2.0f;
	float currentTime = 0;

	UPROPERTY(EditDefaultsOnly, Category = "Settings")
	TSubclassOf<class ACEnemy> enemyFatory;

	UFUNCTION()
	void CreateEnemy();

CEnemyGOD.cpp

#include "CEnemy.h"

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

	CreateEnemy();
}

// 일정시간에 한번씩 적을 만들고 싶다
void ACEnemyGOD::CreateEnemy()
{
	// 일정시간에 한번씩 적을 만들고 싶다
	// 1. 시간이 흘렀으니까 
	currentTime += GetWorld()->GetDeltaSeconds();
	// 2. 생성 시간이 됐으니까
	// -> 만약 경과시간이 생성시간을 초과했다면
	if (currentTime >= creatTime)
	{
		// 3. 적을 만들고 싶다 
		GetWorld()->SpawnActor<ACEnemy>(enemyFatory, GetActorLocation(), FRotator::ZeroRotator);
		// 4. 경과 시간 초기화 
		currentTime = 0;
	}
}
  • 월드에 존재하는 에너미를 제거했더니 오류 발생
    • 원인
      • 이유는 CEnemy.cpp 클래스에 target 엑터를 할당해 해당 엑터를 찾아 그쪽 방향으로 이동하게 했는데 nullptr이 되면서 할당 받지 못해 팅긴것이다
    • 해결
      • beginPlay()에서 target를 형변환하여 해당 액터를 찾는다

CEnemy.cpp

 void ACEnemy::BeginPlay()
{
	Super::BeginPlay();
	
	target = Cast<ACPlayer>(UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass()));


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

	if (ran_num == 1 && IsValid(target))
	{
		//	Target - enemy =  p0까지의 반향
		dir = target->GetActorLocation() - GetActorLocation();
		dir.Normalize(); // Nomalize
	}
	else
	{
		dir = FVector::DownVector;
	}
}

Collision

  • Collision 처리를 하지않아 Enemy끼리 부딪히면 부숴지는 현상이 발생한다 이제 Enemy끼리는 부딪혀도 파괴되지않게 하는 방법을 알아보자

    • 코드로 하는 방법
    • Project세팅을 통해 충돌그릅을 지어 만드는 방법
  • 코드로 하는 방법

Enemy.cpp

void ACEnemy::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// 방법 1
	// 설계도 같은거 쓰고 있니?
	auto enemy = Cast<ACEnemy>(OtherActor);
	if (enemy)
	{
		return;
	}
	// 방법 2
	// 부딪힌 녀석이 같은 이름에 Enemy가 포함되어 있니?
	/*
	if (OtherActor->GetName().Contains("Enemy"))
	{
		return;
	}
	*/
	// -> 아무 처리하지 않는다
	OtherActor->Destroy();
	Destroy();
}
  • Project세팅을 통해 충돌그릅을 지어 만드는 방법
  • projectSetting -> collsion

  • preset으로 channel로 넣고 세팅한 뒤

  • BodyMesh만 프리셋으로 만든 충돌처리로 완료하고 위앞을 구분하기위해 만든 두 cube는 ignore로 표시한다
profile
This is my study archive

0개의 댓글