Notice
Recent Posts
Recent Comments
Link
빙수달 게임 개발 노트
[WindowAPI] 알카노이드(Alkanoid) / 벽돌깨기 만들기 본문
#include "framework.h"
#include "Alkanoid.h"
#include <math.h>
#include <time.h>
#include <cmath>
#define MAX_LOADSTRING 100
#define BSIZE 10 // 원의 반지름
class CCircle
{
public:
int mx;
int my;
float VectorX;
float VectorY;
void DrawCircle(HDC hdc); // 원 화면에 출력
void Initialize(int x, int y); // 원 그려지는 시작점
void Translate(); // 원 이동
void WallCrash(); // 원이 벽 충돌할 때
void ReflectfloorCollision(); // 원이 직사각형과 충돌할 때
void BrickCollision();
};
static RECT reflectfloor; // 발판
int MaxNum = 100;
int CurrentNum = 0;
static RECT rectView; // 전체 화면
CCircle* CircleStack = new CCircle[MaxNum];
int brickWidth = 100; // 벽돌 가로 크기
int brickHeight = 50; // 벽돌 세로 높이
void InitializeBrick();
void DrawBrick(HDC hdc);
RECT brick[4][5];
bool brickActive[4][5];
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
POINT centerPoint = { 700,150 };
RECT rt = { 0,0, 500,800 };
SYSTEMTIME st;
static int x, y;
CCircle circle;
switch (message)
{
case WM_CREATE:
{
srand((unsigned int)time(NULL));
GetClientRect(hWnd, &rectView);
AdjustWindowRect(&rt, WS_OVERLAPPEDWINDOW, true);
MoveWindow(hWnd, 0, 0, rt.right - rt.left, rt.bottom - rt.top, true);
SetTimer(hWnd, 1, 3, NULL);
reflectfloor = { 190,720,300,740 };
InitializeBrick();
}
break;
case WM_SIZE:
{
GetClientRect(hWnd, &rectView);
InvalidateRect(hWnd, NULL, TRUE);
}
break;
case WM_TIMER:
{
for (int i = 0; i < CurrentNum; i++)
{
CircleStack[i].Translate(); // 원이 움직임
CircleStack[i].WallCrash(); // 원이 벽에 충돌함
CircleStack[i].ReflectfloorCollision(); // 원이 사각형에 충돌함
CircleStack[i].BrickCollision();
}
InvalidateRgn(hWnd, NULL, TRUE);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
for (int i = 0; i < CurrentNum; i++) // 공 출력
{
CircleStack[i].DrawCircle(hdc);
}
Rectangle(hdc, reflectfloor.left, reflectfloor.top, reflectfloor.right, reflectfloor.bottom); // 반사판 출력
DrawBrick(hdc);
EndPaint(hWnd, &ps);
}
break;
case WM_CHAR:
{
break;
}
case WM_KEYDOWN:
{
if (wParam == VK_LEFT)
{
OffsetRect(&reflectfloor, -15, 0);
if (reflectfloor.left < rectView.left)
{
reflectfloor.left = 0;
reflectfloor.right = 110;
}
}
if (wParam == VK_RIGHT)
{
OffsetRect(&reflectfloor, 15, 0);
if (reflectfloor.right > rectView.right)
{
reflectfloor.left = 390;
reflectfloor.right = 500;
}
}
InvalidateRgn(hWnd, NULL, TRUE);
}
break;
case WM_LBUTTONDOWN:
{
CircleStack[CurrentNum].Initialize(LOWORD(lParam), HIWORD(lParam));
CurrentNum++;
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void CCircle::DrawCircle(HDC hdc)
{
Ellipse(hdc, mx - BSIZE, my - BSIZE, mx + BSIZE, my + BSIZE);
}
void CCircle::Initialize(int x, int y)
{
mx = x;
my = y;
VectorX = -5;
VectorY = 5;
}
void CCircle::Translate()
{
mx -= VectorX * 1.0f;
my += VectorY * 1.0f;
}
void CCircle::WallCrash()
{
if (my + BSIZE > rectView.bottom || my - BSIZE < rectView.top)
{
VectorY *= -1;
}
else if (mx + BSIZE > rectView.right || mx - BSIZE < rectView.left)
{
VectorX *= -1;
}
}
void CCircle::ReflectfloorCollision()
{
// 반사판의 top/bottom에 대한 충돌 (Y축 반전)
// 반사판의 left/right에 대한 충돌 (X축 반전 및 아래 방향으로 튕겨나감
if (my + BSIZE >= reflectfloor.top && my - BSIZE <= reflectfloor.bottom) // 공이 반사판 top, bottom에 부딪혔을 때
{
if (reflectfloor.left <= mx && mx <= reflectfloor.right)
{
VectorY *= -1.0f;
return;
}
}
if (mx + BSIZE >= reflectfloor.left && mx - BSIZE <= reflectfloor.right) // 공이 반사판 left, right에 부딪혔을 때
{
if (reflectfloor.top <= my&& my<= reflectfloor.bottom)
{
VectorX *= -1.0f;
return;
}
}
/*if(reflectfloor.left - (BSIZE / sqrt(2)) < mx && mx < reflectfloor.left)*/
if (sqrt(pow(reflectfloor.left - mx, 2) + pow(reflectfloor.top - my, 2)) <= BSIZE) // 공이 반사판 왼쪽 상단 모서리에 부딪혔을 때
{
VectorY *= -1.0f;
VectorX *= -1.0f;
return;
}
if (sqrt(pow(mx - reflectfloor.right, 2) + pow(reflectfloor.top - my, 2)) < BSIZE) // 공이 반사판 오른쪽 상단 모서리에 부딪혔을 때
{
VectorY *= -1.0f;
VectorX *= -1.0f;
return;
}
if (sqrt(pow(reflectfloor.left - mx, 2) + pow(my - reflectfloor.bottom, 2)) < BSIZE) // 공이 반사판 왼쪽 하단 모서리에 부딪혔을 때
{
VectorY *= -1.0f;
VectorX *= -1.0f;
return;
}
if (sqrt(pow(mx - reflectfloor.right, 2) + pow(my - reflectfloor.bottom, 2)) < BSIZE) // 공이 반사판 오른쪽 상단 모서리에 부딪혔을 때
{
VectorY *= -1.0f;
VectorX *= -1.0f;
return;
}
}
void InitializeBrick()
{
int startX = 0;
int startY = 0;
for (int row = 0; row < 4; row++)
{
for (int col = 0; col < 5; col++)
{
int left = startX + col * brickWidth; // 각 열에 맞춰 X 좌표 계산
int top = startY + row * brickHeight; // 각 행에 맞춰 Y 좌표 계산
int right = left + brickWidth; // 사각형의 오른쪽 경계 계산
int bottom = top + brickHeight; // 사각형의 아래쪽 경계 계산
brick[row][col] = { left, top, right, bottom };
brickActive[row][col] = true;
}
}
}
void DrawBrick(HDC hdc)
{
for (int row = 0; row < 4; row++)
{
for (int col = 0; col < 5; col++)
{
// 사각형 출력
if (brickActive[row][col])
{
Rectangle(hdc, brick[row][col].left, brick[row][col].top,
brick[row][col].right, brick[row][col].bottom);
}
}
}
}
void CCircle::BrickCollision()
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
if (brickActive[i][j])
{
if (my + BSIZE >= brick[i][j].top && my - BSIZE <= brick[i][j].bottom) // 반사판에 대한 충돌
{
if (brick[i][j].left < mx + BSIZE && mx + BSIZE < brick[i][j].right)
{
VectorY *= -1;
brickActive[i][j] = false;
break;
}
}
if (mx + BSIZE >= brick[i][j].left && mx - BSIZE <= brick[i][j].right)
{
if (brick[i][j].top < my + BSIZE && my + BSIZE < brick[i][j].bottom)
{
VectorX *= -1;
brickActive[i][j] = false;
break;
}
}
}
}
}
}
업데이트 할 점
1. 공 속도 늘리기
2. 점수
3. 게임 오버 판정
4. 아이템(공 개수 or 공 속도 감소 등)
5. 2번 이상 맞을 수 있는 벽돌
6. 더블 버퍼링 적용
'Programming > WindowAPI' 카테고리의 다른 글
| [WindowAPI] 키보드 입력 사각형 처리 (0) | 2025.01.09 |
|---|---|
| [WindowAPI] 격자 그리기 (0) | 2025.01.08 |
| [WindowAPI] 원 그리기 (1) | 2025.01.08 |