본문 바로가기

[UE4 지뢰찾기] 맵으로 사용될 타일 만들기

Kwonriver 2022. 11. 9.
728x90

맵에 사용될 타일을 생성한다.

유저가 행동할 수 있는 상황에 맞춰 7가지 상태가 존재할 수 있다.

 

 

타일은 항상 7가지 상태 중 하나를 취한다.

TS_Mine 상태가 하나라도 열리게 된다면 게임은 종료된 상태이다.

TS_NotOpenFlagNotMine은 직전 상태를 체크하기 위한 상태이다. 유저가 꽂은 깃발이 진짜 지뢰 위에 있는 것인지 아닌지를 판별하고 갯수를 체크해야하는데 깃발을 다시 일반 타일로 되돌릴 때 수량 체크를 위해 사용한다.

 

Tile.h, Tile.c 에는 위 ETileState 정보를 하나 가지며 여러가지 현재 상태에 대한 정보를 갖고 있게 된다.

Tile클래스 멤버 변수들

 

Tile이 사용하는 스태틱 메쉬는 기본으로 제공되는 Box이며 머테리얼만 변경할 예정이다.

 

Tile 클래스의 멤버 함수들

 

해당 타일이 지뢰를 가진 타일인지 Get, Set하는 함수와 해당 타일 주변의 지뢰 갯수를 반환하는 함수를 가지고 있다.

StartTileAnimation 함수는 해당 타일이 터치되거나 영역 검사에서 검사되었을 때 애니메이션 동작을 시작시키는 함수이다.

ETitleState를 반환하고 설정하는 함수와 스태틱메쉬의 머테리얼을 변경하는 함수가 존재한다.

유저가 해당 타일을 터치, 클릭했을 때 CheckTileState 함수가 동작하며 param를 통해 깃발로 만들었는지, 터치를 해서 개봉한 것인지 체크한다.

 

ATile::ATile()
{
	PrimaryActorTick.bCanEverTick = true;

	TileMeshImage = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TileMeshImage"));
	ConstructorHelpers::FObjectFinder<UStaticMesh> CubeMesh(TEXT("StaticMesh'/Engine/BasicShapes/Cube.Cube'"));
	if (CubeMesh.Succeeded())
	{
		TileMeshImage->SetStaticMesh(CubeMesh.Object);
	}

	RootComponent = TileMeshImage;

	isMine = false;
	TileState = ETileState::TS_NotOpen;
	NearMineCount = 0;
	TileAnimationCurrentTime = 0;
	isAnimationPlaying = false;
	TileAnimationMaxTime = 300.0f;
	DefaultScale = FVector(0.9f);
	SetActorScale3D(DefaultScale);
}

 

생성자에서는 기본적인 타일 상태와 정보를 세팅하며 스태틱 메시 하나를 생성한다. 이 때 기본 Cube를 사용한다.

이 Tile은 게임 시작 시 Board에서 동적으로 생성할 예정이기 때문에 BeginPlay에서는 아무런 작업도 하지 않는다.

 

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

	if (isAnimationPlaying)
	{
		TileAnimationCurrentTime += DeltaTime;
		float scale = (TileAnimationCurrentTime / TileAnimationMaxTime) * 0.5f;
		SetActorScale3D(FVector(scale + 0.4f));	// 가장 작은 값이 0.4f 가 되도록
		
		if (TileAnimationCurrentTime >= TileAnimationMaxTime)
		{
			isAnimationPlaying = false;
			TileAnimationCurrentTime = 0.f;
			SetActorScale3D(DefaultScale);
		}
	}
}

Tick 함수에서는 애니메이션과 관련된 행동을 한다. 

현재 Scale 값을 애니메이션 동작 시간으로 계산하는데 이 때 값이 0-1로 노멀라이즈 된다.

이 스케일값을 그대로 사용하면 크기가 0부터 1까지 변화하기 때문에 사라졌다가 점차 커지는 것처럼 보일 수 있다.

따라서 0.5를 곱해줘 0-0.5 사이로 변경한 뒤 Scale 값을 적용할 때 +0.4f를 하여 최소값을 0.4f 고정한다.

또한 현재 애니메이션 프레임이 최대 프레임을 넘어가는 경우 애니메이션을 종료하고 스케일 값을 기본 값(0.9f)로 변경한다.

 

void ATile::SetTileState(ETileState State)
{
	if (this->TileState == State)
		return;

	this->TileState = State;
}
	
void ATile::SetTileMeshMaterial(UMaterial* pMat)
{
	if (pMat == nullptr)
		return;

	TileMeshImage->SetMaterial(0, pMat);
}

void ATile::StartTileAnimation()
{
	TileAnimationCurrentTime = 0;
	isAnimationPlaying = true;
	SetActorScale3D(FVector(0.4f));
}

 

단순한 Set 함수인데 타일의 상태와 현재와 같으면 상태를 변경하지 않는다.

또한 머테리얼 포인터가 없는 경우에 대비해 nullptr 체크를 해준다.

StartTileAnimation함수는 단순한 트리거 용도의 함수이므로 조건 체크를 하지 않는다.

 

ETileState ATile::CheckTileState(bool isSetFlag)
{
	this->TileMeshImage->SetVisibility(true);

	if (this->TileState == ETileState::TS_NotOpen)
	{
		if (isSetFlag)
		{
			// 유저가 이 타일을 깃발로 체크함
			SetTileState(ETileState::TS_Flag);

			if (this->isMine)
			{
				return ETileState::TS_Flag;
			}
			else
			{
				return ETileState::TS_FlagNotMine;
			}
		}

		// 지뢰 체크, 해당 타일이 지뢰라면 변경함
		if (this->isMine)
		{
			// 지뢰이므로 게임 종료
			SetTileState(ETileState::TS_Mine);
		}
		else if (this->NearMineCount == 0)
		{
			SetTileState(ETileState::TS_OpenClear);
			this->TileMeshImage->SetVisibility(false);
		}
		else if (this->NearMineCount > 0)
		{
			SetTileState(ETileState::TS_OpenCount);
		}
	}
	else if (this->TileState == ETileState::TS_Flag)
	{
		// 깃발인 곳을 눌렀으므로 상태를 일반 상태로 바꿈
		SetTileState(ETileState::TS_NotOpen);
	}
	else if (this->TileState == ETileState::TS_FlagNotMine)
	{
		SetTileState(ETileState::TS_NotOpenFlagNotMine);
	}

	return this->TileState;
}

 

가장 핵심이 되는 현재 상태 체크 함수이다.

기본적으로 타일의 이미지는 완전 오픈되었고 주변에 지뢰가 없어 숫자 표기를 할 이유가 없다면 아무런 메쉬를 그리지 않는다. 따라서 메쉬의 Visiblity가 꺼져있을 때가 있다. 따라서 체크할 때 기본적으로 Visiblity를 활성화하고 특정 상황에서만 끈다.

이 방법이 효율면에서는 좋지 않으나 CheckTileState 함수가 동작하는 횟수가 많지 않기 때문에 특정 상황에서 끄고 키고를 추가하지 않는다. (나중에 유지보수 때 헷갈릴까봐)

 

또한 현재 타일이 오픈되었는지, 깃발인지, 오픈 상태가 아닌지에 따라 체크를 진행한다.

TS_NotOpen 즉, 해당 타일이 한 번도 터치되거나 주변 영역 탐색을 한 적 없는 깨끗하게 닫힌 타일이라면 이 타일에 깃발을 꽂았는지, 터치했는지, 지뢰인지, 지뢰는 아니지만 주변에 지뢰가 있는지에 따라 현재 상태를 변경한다. 

해당 타일을 일반 터치했는데 지뢰라면 게임 종료이다.

 

이 타일이 깃발 상태인데 눌렀다면 NotOpen 상태로 변경한다.

 

이 깃발이 지뢰가 아닌데 깃발이 꽂혀있는 상태에서 유저가 눌렀다면 TS_NotOpenFlagNotMine으로 변경한다.

이 타일 상태는 현재 유저가 체크한 모든 지뢰 갯수, 오류 깃발 갯수를 체크하는데 사용되며 이는 게임의 종료 조건으로 사용된다.

728x90