본문 바로가기

포트폴리오

DirectX - 2D MapleStory

1. 포트폴리오 영상


2. 로고 셰이더 효과

(메이플스토리 셰이더를 이용한 페이드 효과)

DirectX 시작 후 처음으로 적용한 효과입니다 !

해당 효과를 처리하기 위해 필요한 값으로는 '비율'이 필요했습니다.

if (input.vUV.x <= g_ratio)
{
	float4 color = smoothstep(float4(0.f, 0.f, 0.f, 0.f), float4(1.f, 1.f, 1.f, 1.f), 
    				 (g_ratio - input.vUV.x) + 0.3f);
	output.vTarget0 = g_DiffuseTex.Sample(g_DiffuseSmp, input.vUV) * color;
}

HLSL에서 제공되는 함수인 smoothstop() 함수를 사용했으며

uv.x 값에 제한을 걸어 좌측서부터 서서히 밝아지는 효과를 구현했습니다. 


3. 데이터 파일(xml) 읽어오기 및 데이터 파일 첨부파일 추가

실제 게임에서 사용되는 데이터들을 xml 형태로 저장하여 게임 플레이에 읽어온 데이터 값을 적용시키는 작업 !

DataManager.xlsx
0.03MB
SoundData.xml
0.00MB
TextureData.xml
0.01MB
CharacterAniFrameData.xml
0.00MB
CharacterColliderSize.xml
0.00MB

위 데이터 파일들이 이번 포트폴리오를 작업함에 있어서 사용되는 데이터 파일들이다.

파일을 읽어오는데 있어서 사용되는 외부 라이브러리(lib)인 'tinyxml2'를 사용하였다. 

(tinyxml2 사용 방법은 별도로 설명하지 않겠다.)

void CTitleScene::RunResLoadThread()
{
	m_pThread->Awake();

	// .Xml 파일 읽기
	// > 텍스처 
	m_pThread->SetLoadType(eLoadType::LT_TEXTURE);
	string fileName = "../Bin/Data/TextureData.xml";
	m_pThread->ReadXmlData(fileName, "Texture");

	// > 사운드
	m_pThread->SetLoadType(eLoadType::LT_SOUND);
	fileName = "../Bin/Data/SoundData.xml";
	m_pThread->ReadXmlData(fileName, "Sound");

	// > 캐릭터 
	{
		// 충돌체 크기
		m_pThread->SetLoadType(eLoadType::LT_COLLISION);
		fileName = "../Bin/Data/CharacterColliderSize.xml";
		m_pThread->ReadXmlData(fileName, "Collider");

		// 애니메이션 프레임별 시간
		m_pThread->SetLoadType(eLoadType::LT_ANIFRAME);
		fileName = "../Bin/Data/CharacterAniFrameData.xml";
		m_pThread->ReadXmlData(fileName, "CharacterAniFrame");
	}
}

위 코드는 xml 데이터 파일을 읽어오는 코드이며, 내부적으로 데이터를 저장하지만 데이터를 읽어오는 코드까지만 :) 


4. 스레드(Thread)와 Command Pattern

이 부분에 대하여 글을 쓰기가 가장 까다롭다 !

읽어들인 데이터를 실제 스레드를 돌려서 각 데이터 매니저에 저장한다.

결과론적으로 먼저 얘기하면 "스레드에서 커맨드 패턴을 활용하여 데이터 저장" 방식을 사용하여 데이터를 저장

4-1. 스레드에서 데이터 파일 저장

(게임에 필요한 데이터를 로드 하고 저장한다.)

말 그대로 단일 스레드를 만들어서 스레드에서 읽어들인 데이터를 저장한다.

이 방식에는 의도하지 않은 문제가 발생했는데 ... 정확하게 무슨 현상인지 용어를 알 수 없지만 

스레드가 실행되는 중 다른 행동에 대하여 너무 버벅거림이 심하다는 문제가 발생했다.

이를 정확한 용어로 얘기할 수 없지만..(사실 잊어버렸다 ㅜㅜ..)

이 문제에 대하여 검색결과 '작업 큐(Queue)'를 이용하여 해당 문제를 해결할 수 있다고 한다.

 

4-2. 스레드에서 커맨드 패턴을 활용하여 데이터 저장

커맨드(Command)를 컨트롤할 수 있는 CommandControl 클래스 생성한다.

이후 Control 객체가 작업 큐를 통하여 처리해야 할 일을 가져와서 하나씩 처리하게 되는 방식이다.

- Command Control 

    Queue(작업 큐) 

         Texture Data[0]  처리 -> Sound Data[0] → 처리  

            CollisionSize Data[0] → 처리 → Animation Frame Time Data[2] → 처리 끝 !

        

        → Texture Data[1]  처리 -> Sound Data[1] → 처리  

            CollisionSize Data[1] → 처리 → Animation Frame Time Data[1] → 처리 끝 !

 

위와 같은 처리 방식으로 진행되며, 이를 풀어서 얘기하면 각 인덱스의 처리가 끝나면

다음 인덱스의 객체가 커맨드 작업 큐로 들어가며 이를 스레드에서 다시 처리하는 방식이다.

미흡하지만 아래 코드가 ResLoadThread 스레드 클래스에서 커맨드 패턴(Command Pattern)을 이용한 코드다 !

void CResLoadThread::execute()
{
	if (m_pTitleSceneComp == nullptr)
	{
		return;
	}

	// CommandControl 클래스 멤버변수인 ResCommand*(m_pTextureCommand, m_pSoundCommand) 등록
	// 해당 ResCommand* 객체로 ResCommand 클래스내 연결된 멤버 함수를 호출하여 실제 리소스를 로드한다.
	
	static int textureIndex		= 0;
	static int soundIndex		= 0;
	static int collisionIndex	= 0;
	static int aniFrameIndex	= 0;

	// 텍스처 파일 로드
	if (textureIndex < (int)m_vecTextureResCommand.size())
	{
		CResCommand* pTextureCommand = m_vecTextureResCommand[textureIndex++];
		m_pCommandControl->SetTextureCommand(pTextureCommand);
		bool isTextureLoad = m_pCommandControl->TextureFileLoad();
		if (isTextureLoad == true)
		{
			m_resLoadCount++;
			return;
		}
		else
		{
			tassert(true);
		}
	}

	// 사운드 파일 로드 
	if (soundIndex < (int)m_vecSoundResCommand.size())
	{
		CResCommand* pSoundCommand = m_vecSoundResCommand[soundIndex++];
		m_pCommandControl->SetSoundCommand(pSoundCommand);
		bool isSoundLoad = m_pCommandControl->SoundFileLoad();
		if (isSoundLoad == true)
		{
			m_resLoadCount++;
			return;
		}
		else
		{
			tassert(true);
		}
	}

	// 캐릭터 충돌체 파일 로드
	if (collisionIndex < (int)m_vecPlayerCollision.size())
	{
		PPlayerCollisionSize pPlayerCollision = m_vecPlayerCollision[collisionIndex++];
		if (m_pCommandControl->CollisionFileLoad(pPlayerCollision) == true)
		{
			m_resLoadCount++;
			return;
		}
	}

	// 캐릭터 애니메이션 프레임
	if (aniFrameIndex < (int)m_vecPlayerAniFrame.size())
	{
		PAnimationFrameInfo pPlayerCollision = m_vecPlayerAniFrame[aniFrameIndex++];
		if (m_pCommandControl->AnimFrameFileLoad(pPlayerCollision) == true)
		{
			m_resLoadCount++;
			return;
		}
	}
}

로고 이미지 출처 : http://www.thisisgame.com/webzine/community/tboard/?n=243758&board=38