수학/이득우의 게임 수학 - 실습 예제

2차원 벡터의 표현과 입력을 통한 벡터의 위치 변경

monstro 2025. 8. 21. 00:49
728x90
반응형

1) 2차원 벡터의 표현

struct Vector2
{
public:

	...

	// 연산자 - 스칼라 곱과 벡터의 합 연산을 지정
	...
	FORCEINLINE constexpr Vector2 operator*(float InScalar) const;
	FORCEINLINE constexpr Vector2 operator+(const Vector2& InVector) const;
	
	...

	// 정적멤버변수 - Dimension을 사용하여 n차원을 지정 
	...
	static constexpr BYTE Dimension = 2;

	// union을 사용하여 멤버변수 X와 Y를 사용하지 않고도
	// array를 통해서도 접근할 수 있도록 설정
	union
	{
		struct
		{
			float X, Y;
		};

		std::array<float, Dimension> Scalars = { 0.f, 0.f };
	};
};

// 벡터 - 스칼라 곱 정의
FORCEINLINE constexpr Vector2 Vector2::operator*(float InScalar) const
{
	return Vector2(X * InScalar, Y * InScalar);
}

// 벡터 - 벡터 합 정의
FORCEINLINE constexpr Vector2 Vector2::operator+(const Vector2& InVector) const
{
	return Vector2(X + InVector.X, Y + InVector.Y);
}

...

 

2차원 벡터의 역할을 수행할 Vector2 구조체를 정의하였다

다른 기능도 많이 정의되어 있지만, 현재는 크게 스칼라 곱벡터의 합만 정의하였다

해당 구조체 내부에 union을 추가하여 Vector2의 X나 Y가 아닌 배열로도 접근이 가능하도록 설정하였다

따라서 X와 Y 값을 변경하면 Scalars 배열의 값도 변경되고, Scalars 배열 값을 변경하면 X와 Y 값도 변경된다

 

2) 입력을 통한 벡터의 위치 변경

// 물체의 위치를 보관
Vector2 currentPosition(100.f, 100.f);

// 게임의 로직을 진행
void SoftRenderer::Update2D(float InDeltaSeconds)
{
	// 사용자로부터 입력을 받기 위해 가져올 레퍼런스
	auto& g = Get2DGameEngine();
	const InputManager& input = g.GetInputManager();

	// 벡터를 이동시키기 위한 속도
	static float moveSpeed = 100.f;
	
	// 매핑된 키로부터 사용자가 입력한 값을 가져오고, 입력값 * 속도 * 프레임시간의 값으로 2차원 벡터를 생성
	Vector2 inputVector = Vector2(input.GetAxis(InputAxis::XAxis), input.GetAxis(InputAxis::YAxis));	
	Vector2 deltaPosition = inputVector * moveSpeed * InDeltaSeconds;

	// 물체의 최종 위치 설정
	currentPosition += deltaPosition;
}

// 게임을 화면에 렌더
void SoftRenderer::Render2D()
{
	// 화면에 렌더하기 위해 가져올 레퍼런스
	auto& r = GetRenderer();
	const auto& g = Get2DGameEngine();

	// 배경에 격자 그리기
	DrawGizmo2D();

	// 밝은 회색의 선을 사용해 currentPostion 벡터와 평행한 벡터를 표현
	// 순서대로 평행한 벡터의 길이, 평행한 양의 벡터, 평행한 음의 벡터
	static float lineLength = 500.f;
	Vector2 lineStart = currentPosition * lineLength;
	Vector2 lineEnd = currentPosition * -lineLength;
	r.DrawLine(lineStart, lineEnd, LinearColor::LightGray);

	// currentPosition 벡터를 파란색 픽셀로 표현
	// 시각적으로 잘 보이기 위해 주변에 8개의 점을 추가
	r.DrawPoint(currentPosition, LinearColor::Blue);
	r.DrawPoint(currentPosition + Vector2::UnitX, LinearColor::Blue);
	r.DrawPoint(currentPosition - Vector2::UnitX, LinearColor::Blue);
	r.DrawPoint(currentPosition + Vector2::UnitY, LinearColor::Blue);
	r.DrawPoint(currentPosition - Vector2::UnitY, LinearColor::Blue);
	r.DrawPoint(currentPosition + Vector2::One, LinearColor::Blue);
	r.DrawPoint(currentPosition - Vector2::One, LinearColor::Blue);
	r.DrawPoint(currentPosition + Vector2(1.f, -1.f), LinearColor::Blue);
	r.DrawPoint(currentPosition - Vector2(1.f, -1.f), LinearColor::Blue);

	// currentPosition 벡터의 현재 좌표를 우상단에 출력
	r.PushStatisticText("Coordinate : " + currentPosition.ToString());
}

 

입력을 통해 벡터의 위치를 변경하는 스크립트의 구성은 위와 같다 

크게 다음과 같이 구분할 수 있다

  • Update2D 함수 : 매 프레임마다 진행하며 플레이어의 입력을 받아 currentPosition 벡터를 갱신
  • Render2D 함수 : currentPosition 벡터렌더하여 화면에 표시 

 

- 최종 실행 결과

728x90
반응형