주녘공부일지

[C++] 벽돌깨기 게임 ( WinAPI ) 본문

GameDevelopment/[C++] Project

[C++] 벽돌깨기 게임 ( WinAPI )

주녘 2024. 9. 15. 00:37

1. 벽돌깨기 게임 ( WinAPI )

- 알카노이드를 레퍼런스로 하여 제작한 게임

https://github.com/godgjwnsgur7/WinAPI_BrickBreaking/tree/main/BrickBreaking

 

WinAPI_BrickBreaking/BrickBreaking at main · godgjwnsgur7/WinAPI_BrickBreaking

Contribute to godgjwnsgur7/WinAPI_BrickBreaking development by creating an account on GitHub.

github.com

2. 게임 핵심 구현 요소

1) Vector2

- 위치 벡터, 방향 벡터 등 범용적으로 사용하기 편리하도록 Vector2 구조체를 구현하여 사용함

struct Vector2
{
	float x, y;
	Vector2();
	Vector2(float x, float y);
	Vector2 operator-(const Vector2& other) const;
	Vector2 operator+(const Vector2& other) const;
	Vector2 operator*(float scalar) const;
	float Dot(const Vector2& other) const;
	Vector2 Normalize() const;
};

2) 일정 주기로 호출 ( Update )

- deltaTime 개념을 넣어 일정 주기로 Update 메서드를 호출

- Update에서 각 객체들의 상태를 업데이트하고, 갱신된 내용을 그려줌

int APIENTRY wWinMain( ... )
{
    ...
    
    while (1)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { ... }
        else
        {
            DWORD currentTime = GetTickCount64();
            deltaTime += (currentTime - previousTime);
            previousTime = currentTime;

            if (deltaTime > 10)
            {
                Update();
                deltaTime = 0;
                InvalidateRect(winhWnd, NULL, FALSE);
            }
        }
    }

    return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND: { ... }
        break;  
    case WM_CREATE:
        Start();
        break;
    case WM_MOUSEMOVE:
        OnMouseMoveEvent(lParam);
        break;
    case WM_PAINT:
        Draw(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

3) 더블 버퍼링, 메모리 풀

- 더블 버퍼링 :  메모리 DC를 생성해 미리 그림을 그린 후 실제 출력할 화면 DC에 고속 복사

- 메모리 풀 : 많이 사용될 수 있는 객체에 대하여 일정 메모리 크기만큼 미리 점유시켜놓고 사용

void Draw(HWND& hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    HDC memDC = CreateCompatibleDC(hdc);
    HBITMAP memBitmap = CreateCompatibleBitmap(hdc, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
    SelectObject(memDC, memBitmap);

    FillRect(memDC, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

    // 아이템
    for (Item& item : items)
        if (item.isUsing)
            item.Draw(memDC);

    // 블럭
    for (std::vector<Brick>& brick : bricks)
    {
        for (Brick& b : brick)
        {
            if (b.GetCount() > 0)
                b.Draw(memDC);
            else
                b = NULL;
        }
    }
    
    // 공
    for (Ball& ball : balls)
        if (ball.isUsing)
            ball.Draw(memDC);
    
    // 바
    bar.Draw(memDC);

    BitBlt(hdc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, memDC, 0, 0, SRCCOPY);

    DeleteObject(memBitmap);
    DeleteDC(memDC);

    EndPaint(hWnd, &ps);
}

4) 원과 직사각형의 충돌 판단 ( Ball <-> Bar, Brick )

- 직사각형의 모서리 영역 중에 원의 원점과 가장 가까운 위치 좌표를 가져와 거리를 측정

- 거리가 원의 반지름보다 적다면 충돌이 일어났다고 판단

bool Ball::CheckCollisionBar(Bar& bar)
{
	int closestX = std::max((float)(bar.GetRect().left), std::min(pos.x, (float)(bar.GetRect().right)));
	int closestY = std::max((float)(bar.GetRect().top), std::min(pos.y, (float)(bar.GetRect().bottom)));

	int distanceX = pos.x - closestX;
	int distanceY = pos.y - closestY;

	if ((distanceX * distanceX + distanceY * distanceY) <= (radius * radius))
	{
		float diffX = pos.x - bar.GetPos().x;
		float barHalfLength = bar.GetLength() / 2;

		float velocityX = diffX / barHalfLength;
		velocity = { velocityX * 2.0f , -1 };

		if (pos.y >= bar.GetPos().y - 10 - radius)
			pos.y = bar.GetPos().y - 10 - radius;

		return true;
	}

	return false;
}

3. 플레이 영상





'GameDevelopment > [C++] Project' 카테고리의 다른 글

[C++] 종스크롤 슈팅 게임 ( WinAPI )  (1) 2024.10.30
[C언어] 콘솔 비행기 게임  (1) 2024.09.11