게임제작기법연구

게임제작기법연구 7주차

ckhyeok 2020. 5. 26. 18:27

[SoftRenderer 구현 및 검토]

현재 프로젝트에서 여러 게임 오브젝트를 구현하십시오.

GameObject2D.h

#pragma once

class GameObject2D {

	public:
		GameObject2D() = default;
		GameObject2D(const Mesh* InMeshPtr) : _MeshPtr(InMeshPtr) { }
		GameObject2D(std::string name, const Mesh* InMeshPtr) : _name(name), _MeshPtr(InMeshPtr) {}
		Transform2D& GetTransform() { return _Transform; }
		const Mesh* GetMesh() { return _MeshPtr; }
		FORCEINLINE bool HasMesh() const { return (_MeshPtr != nullptr); }
		std::string GetName() { return _name; };
protected:
	Transform2D _Transform;
	const Mesh* _MeshPtr = nullptr;
	std::string _name;
};

 

GameEngine.h

#pragma once
class GameEngine
{
public:
	GameEngine() = default;

public:
	bool Init();
	bool LoadScene();
	bool LoadResource();

public:
	InputManager& GetInputManager() { return _InputManager; }
	GameObject2D* GetPlayer() { return _Player.get(); }	
	Camera2D* GetCamera() { return _Camera.get(); }
	std::vector<std::unique_ptr<GameObject2D>>& GetObject() { return _Object; }

	GameObject2D* FindGameObject(std::string name);

private:
	std::unique_ptr<GameObject2D> _Player;
	std::unique_ptr<Mesh> _QuadMesh;
	std::unique_ptr<Camera2D> _Camera;
	std::unordered_map<std::string, std::unique_ptr<Mesh>> _Mesh;
	std::vector<std::unique_ptr<GameObject2D>> _Object;

	InputManager _InputManager;
};

 

GameEngine.cpp

#include "Precompiled.h"
#include "InputManager.h"
#include "Mesh.h"
#include "Transform2D.h"
#include "GameObject2D.h"
#include"Camera2D.h"
#include "GameEngine.h"
bool GameEngine::Init()
{
	if (!_InputManager.GetXAxis || !_InputManager.GetYAxis || !_InputManager.SpacePressed)
	{
		return false;
	}
	if (!LoadResource())
	{
		return false;
	}
	if (!LoadScene())
	{
		return false;
	}

	return true;
}

bool GameEngine::LoadScene()
{
	const float initScale = 100.0f;
	_Player = std::make_unique<GameObject2D>(_QuadMesh.get());
	_Player->GetTransform().SetScale(Vector2::One * initScale);
	
	for (int i = 0; i < 5; i++)
	{
		_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
		_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
		_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(initScale * i, initScale * i));
	}
	for (int i = 0; i < 5; i++)
	{
		_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
		_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
		_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(initScale * i, -initScale * i));
	}
	for (int i = 0; i < 5; i++)
	{
		_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
		_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
		_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(-initScale * i, initScale * i));
	}
	for (int i = 0; i < 5; i++)
	{
		_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
		_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
		_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(-initScale * i, -initScale * i));
	}

	_Camera = std::make_unique<Camera2D>();

	return true;
}

bool GameEngine::LoadResource()
{
	_QuadMesh = std::make_unique<Mesh>();
	_Mesh["QuadMesh"] = std::make_unique<Mesh>();

	static float squareHalfSize = 0.5f;
	static int vertexCount = 4;
	static int triangleCount = 2;
	static int indexCount = triangleCount * 3;

	_QuadMesh->_Vertices = {
		Vector2(-squareHalfSize, -squareHalfSize),
		Vector2(-squareHalfSize, squareHalfSize),
		Vector2(squareHalfSize, squareHalfSize),
		Vector2(squareHalfSize, -squareHalfSize)
	};


	_QuadMesh->_Indices = {
		0, 2, 1,
		0, 3, 2
	};

	_Mesh["QuadMesh"]->_Vertices = {
				Vector2(-squareHalfSize, -squareHalfSize),
		Vector2(-squareHalfSize, squareHalfSize),
		Vector2(squareHalfSize, squareHalfSize),
		Vector2(squareHalfSize, -squareHalfSize)
	};
	_Mesh["QuadMesh"]->_Indices = {
		0, 2, 1,
		0, 3, 2
	};
	return true;
}

GameObject2D* GameEngine::FindGameObject(std::string name)
{
	for (int i = 0; i < _Object.size(); i++)
	{
		if(name == _Object[i].get()->GetName())
		{
			return _Object[i].get();
		}
	}

	return nullptr;
}

  

SoftRenderer2D.cpp 의 Render2D

// 렌더링 로직
void SoftRenderer::Render2D()
{
	// 격자 그리기
	DrawGrid2D();

	////////////////////// 월드 공간 //////////////////////
	Matrix3x3 viewMat = _GameEngine.GetCamera()->GetViewMatrix();

	Transform2D& playerTransform = _GameEngine.GetPlayer()->GetTransform();
	Matrix3x3 finalMat = playerTransform.GetModelingMatrix();

	// 게임 로직에서 변경한 피벗 위치의 출력
	_RSI->PushStatisticText(playerTransform.GetPosition().ToString());
	
	const Mesh* mesh = _GameEngine.GetPlayer()->GetMesh();
	size_t vertexCount = mesh->_Vertices.size();
	size_t indexCount = mesh->_Indices.size();
	size_t triangleCount = indexCount / 3;

	auto& object = _GameEngine.GetObject();
	for (int i = 0; i < object.size(); i++)
	{
		const Mesh* mesh = object[i]->GetMesh();

		size_t vertexCount = mesh->_Vertices.size();
		size_t indexCount = mesh->_Indices.size();
		size_t triangleCount = indexCount / 3;

		Vector2* vertices = new Vector2[vertexCount];
		std::memcpy(vertices, &mesh->_Vertices[0], sizeof(Vector2) * vertexCount);
		int* indices = new int[indexCount];
		std::memcpy(indices, &mesh->_Indices[0], sizeof(int) * indexCount);

		Matrix3x3 final = viewMat * object[i]->GetTransform().GetModelingMatrix();

		for (int vi = 0; vi < vertexCount; ++vi)
		{
			vertices[vi] = final * vertices[vi];
		}

		for (int ti = 0; ti < triangleCount; ++ti)
		{
			int bi = ti * 3;
			_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 1]], _CurrentColor);
			_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 2]], _CurrentColor);
			_RSI->DrawLine(vertices[indices[bi + 1]], vertices[indices[bi + 2]], _CurrentColor);
		}
	}


	// 렌더러가 사용할 정점 버퍼와 인덱스 버퍼 생성
	Vector2* vertices = new Vector2[vertexCount];
	std::memcpy(vertices, &mesh->_Vertices[0], sizeof(Vector2) * vertexCount);
	int* indices = new int[indexCount];
	std::memcpy(indices, &mesh->_Indices[0], sizeof(int) * indexCount);

	// 각 정점에 행렬을 적용
	for (int vi = 0; vi < vertexCount; ++vi)
	{
		vertices[vi] = finalMat * vertices[vi];
		vertices[vi] = viewMat * vertices[vi];
	}

	// 변환된 정점을 잇는 선 그리기
	for (int ti = 0; ti < triangleCount; ++ti)
	{
		int bi = ti * 3;
		_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 1]], _CurrentColor);
		_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 2]], _CurrentColor);
		_RSI->DrawLine(vertices[indices[bi + 1]], vertices[indices[bi + 2]], _CurrentColor);
	}

	delete[] vertices;
	delete[] indices;
}

 현재 프로젝트에서 카메라를 따르는 플레이어를 구현하십시오.

// 게임 로직
void SoftRenderer::Update2D(float InDeltaSeconds)
{
	InputManager input = _GameEngine.GetInputManager();
	

	Transform2D& playerTransform = _GameEngine.GetPlayer()->GetTransform();
	Transform2D& cameraTransform = _GameEngine.GetCamera()->GetTransform();

	Vector2 deltaPosition = Vector2(input.GetXAxis(), input.GetYAxis()) * _MoveSpeed * InDeltaSeconds;

	playerTransform.AddPosition(deltaPosition);
	cameraTransform.SetPosition(playerTransform.GetPosition() * InDeltaSeconds + cameraTransform.GetPosition() * (1.0f - InDeltaSeconds));

	_CurrentColor = input.SpacePressed() ? LinearColor::Red : LinearColor::Blue;
} 

코드를 공유하고 GIF 애니메이션 결과를 첨부하십시오.

 

다이어그램, 핸드 드로잉 등을 사용하여 전체 softrenderer 프로세스, 파이프 라인, 아키텍처를 요약하십시오.

우선 SoftRenderer는 아래 3가지의 모듈과 1개의 플레이어로 구성 돼 있으며, 3가지의 모듈을 합쳐서 작동이 됩니다.

소프트렌더러의 파이프 라인은 아래와 같이 구성 돼 있습니다.(개인적인 생각입니다.)

GameEngine, GameObject2D 클래스의 각 멤버 변수 유형에 대한 적절한 이유를 제공하십시오.

게임오브젝트 같은 경우에는 처음부터 끝까지 다 검색해야 하기 떄문에 시간복잡도가 O(n) 인 Vector를 선택하였습니다.

'게임제작기법연구' 카테고리의 다른 글

게임제작기법연구 10주차  (0) 2020.06.16
게임제작기법연구 8주차  (0) 2020.06.02
게임제작기법연구 6주차  (0) 2020.05.19
게임제작기법연구 5주차  (0) 2020.05.12
게임제작기법연구 4주차  (0) 2020.05.05