응애맘마조

8방향 캐릭터 본문

공부/2D과제

8방향 캐릭터

TH.Wert 2023. 1. 27. 23:45

주의 : 해당 게시글의 코드는 캐릭터의 움직임을 구현하기 위해 사용한 것으로 특정 게임의 모션을 사용하였습니다. 기타 표절 목적이나 수익 창출을 위해 사용한 것이 아님을 밝힙니다.

8방향 캐릭터 움직임에 대한 것이 과제였습니다. 캐릭터를 만들 때 각각의 클래스로 만들어서 하는 것이 맞지만 캐릭터의 종류나 이미지, 만약 액션 게임 계열이라면 들 수 있는 무기 등등 경우의 수가 굉장히 많아집니다. 따라서 최상위 클래스를 만들어 상속을 받게 하는 것이 가장 이상적입니다.

//Character.h
#pragma once
enum Dir_State
{
	L,
	T,
	R,
	B,
	LT,
	RT,
	LB,
	RB
};

class Character
{
public:
	ObRect*			col;
	Vector2			moveDir;
	Dir_State		dirState;
	float			frameY[8];
};

최상위 클래스 Character.h입니다. cpp에서는 #include "stdafx.h"만 있으므로 따로 코드블럭으로 작성하지 않겠습니다.

//TitanSoul.h
#pragma once
enum class T_State
{
	IDLE,
	WALK,
	ROLL
};

class TitanSoul : public Character
{
public:
	ObImage*	walk;
	ObImage*	roll;
	T_State		state;

	float		rollTime;

public:
	TitanSoul();
	~TitanSoul();
	void Update();
	void Render();

	void Idle();
	void Walk();
	void Roll();

	void LookAtTarget(Vector2 target);
	void Input();
};

TitanSoul.h 입니다. 캐릭터의 움직임을 위해 게임 내 캐릭터 스프라이트 이미지를 사용하였습니다.

//TitanSoul.cpp
#include "stdafx.h"

TitanSoul::TitanSoul()
{
	col = new ObRect;
	walk = new ObImage(L"Walk.png");
	roll = new ObImage(L"Roll.png");

	col->scale = Vector2(walk->imageSize.x / 6.0f, walk->imageSize.y / 8.0f) * 5.0f;
	col->isFilled = false;

	walk->scale = Vector2(walk->imageSize.x / 6.0f, walk->imageSize.y / 8.0f) * 5.0f;
	walk->maxFrame = Int2(6, 8);
	walk->SetParentRT(*col);

	roll->scale = Vector2(roll->imageSize.x / 6.0f, roll->imageSize.y / 8.0f) * 5.0f;
	roll->maxFrame = Int2(6, 8);
	roll->SetParentRT(*col);
	roll->isVisible = false;

	frameY[L] = 2;
	frameY[R] = 0;
	frameY[T] = 1;
	frameY[B] = 3;
	frameY[LT] = 6;
	frameY[RT] = 7;
	frameY[LB] = 5;
	frameY[RB] = 4;

	state = T_State::IDLE;
}

TitanSoul::~TitanSoul()
{
	SafeDelete(walk);
	SafeDelete(col);
	SafeDelete(roll);
}

void TitanSoul::Update()
{
	switch (state)
	{
	case T_State::IDLE:
		Idle();
		break;
	case T_State::WALK:
		Walk();
		break;
	case T_State::ROLL:
		Roll();
		break;
	}

	col->Update();
	walk->Update();
	roll->Update();
}

void TitanSoul::Render()
{
	col->Render();
	walk->Render();
	roll->Render();
}

void TitanSoul::Idle()
{
	LookAtTarget(INPUT->GetWorldMousePos());
	Input();

	//walk
	if (moveDir != Vector2(0.0f, 0.0f))
	{
		state = T_State::WALK;
		walk->ChangeAnim(ANIMSTATE::LOOP, 0.1f);
	}
}

void TitanSoul::Walk()
{
	LookAtTarget(INPUT->GetWorldMousePos());
	Input();

	//idle
	if (moveDir == Vector2(0.0f, 0.0f))
	{
		state = T_State::IDLE;
	}

	//roll
	if (INPUT->KeyDown(VK_SPACE))
	{
		state = T_State::ROLL;
		roll->isVisible = true;
		walk->isVisible = false;
		roll->ChangeAnim(ANIMSTATE::ONCE, 0.1f);
		rollTime = 0.6f;
	}

	col->MoveWorldPos(moveDir * 200.0f * DELTA);
}

void TitanSoul::Roll()
{
	Input();
	LookAtTarget(roll->GetWorldPos() + moveDir);
	
	col->MoveWorldPos(moveDir * 500.0f * cosf((1.0f - rollTime / 0.6f) * DIV2PI) * DELTA);

	//idle
	rollTime -= DELTA;

	if (rollTime < 0.0f)
	{
		state = T_State::IDLE;
		roll->isVisible = false;
		walk->isVisible = true;
	}
}

void TitanSoul::LookAtTarget(Vector2 target)
{
	Vector2 dir = target - col->GetWorldPos();
	float radian = Utility::DirToRadian(dir);

	if (radian > -DIV8PI && radian < DIV8PI)
	{
		dirState = R;
	}
	else if (radian > DIV8PI && radian < DIV8PI + DIV4PI)
	{
		dirState = RT;
	}
	else if (radian > DIV8PI + DIV4PI && radian < DIV8PI + DIV4PI * 2.0f)
	{
		dirState = T;
	}
	else if (radian > DIV8PI + DIV4PI * 2.0f && radian < DIV8PI + DIV4PI * 3.0f)
	{
		dirState = LT;
	}
	else if (radian > -(DIV8PI + DIV4PI * 3.0f) && radian < -(DIV8PI + DIV4PI * 2.0f))
	{
		dirState = LB;
	}
	else if (radian > -(DIV8PI + DIV4PI * 2.0f) && radian < -(DIV8PI + DIV4PI))
	{
		dirState = B;
	}
	else if (radian > -(DIV8PI + DIV4PI) && radian < -DIV8PI)
	{
		dirState = RB;
	}
	else
	{
		dirState = L;
	}

	walk->frame.y = frameY[dirState];
	roll->frame.y = frameY[dirState];
}

void TitanSoul::Input()
{
	moveDir = Vector2(0.0f, 0.0f);

	if (INPUT->KeyPress('W'))
	{
		moveDir.y = 1.0f;
	}
	else if (INPUT->KeyPress('S'))
	{
		moveDir.y = -1.0f;
	}

	if (INPUT->KeyPress('A'))
	{
		moveDir.x = -1.0f;
	}
	else if (INPUT->KeyPress('D'))
	{
		moveDir.x = 1.0f;
	}

	moveDir.Normalize();
}

cpp파일입니다.

 

읽어주셔서 감사합니다.

'공부 > 2D과제' 카테고리의 다른 글

맵 만들기  (0) 2023.02.01
8방향 몬스터  (0) 2023.01.30
쿠키런 2탄 : 착지, 젤리 먹기, 타격  (0) 2023.01.25
쿠키런 1탄 : 달리기, 점프, 2단 점프, 슬라이드  (0) 2023.01.20
슬라이드 퍼즐  (2) 2023.01.18