Files
WinGUI/GUITest/Snake.t.c
T

531 lines
15 KiB
C
Raw Normal View History

2026-07-28 14:17:49 +08:00
#include "Snake.h"
#include "c_WinGUI.h"
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#define WINDOW_CLASS_NAME SNAKE_MAIN_WINDOW_CLASS
#define BORDERSIZE 15
#define MAXSECTIONS 1024
#define MAXPRIZES 512
typedef enum {
Left,
Right,
Up,
Down,
TDir_Num
}TDir;
typedef struct {
BOOL DirChange;
TDir Dir;
TDir OldDir;
int SecNun;
int Row;
int Col;
int OldRow;
int OldCol;
}TSectInfo;
typedef struct {
TDir Dir;
BOOL SectChangeDir[256];
int TurnCol;
int TurnRow;
}TTurn;
typedef struct {
BOOL Exists;
int Value;
int Col;
int Row;
}TPrize;
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
static HWND hGameWindow;
static SnakeApp_t SnakeApp;
static BOOL NewSect;
static int VK_P = 112;
static unsigned int SnakeTimer = 1;
static long TotalClicks = 0;
static int Sections;
static int NumPrizes;
static TPrize Prizes[MAXPRIZES];
static TSectInfo SectInfo[MAXSECTIONS];
static TTurn TurnList[25];
static int NumTurns;
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
static
BOOL SetupWindow(HWND hWindow) {
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Main Window */
c_WinGUI_EventHandlerDef(WM_DESTROY, Main_Destroy) {
if (SnakeApp.hHeadBitmap) {
DeleteObject(SnakeApp.hHeadBitmap);
}
if (SnakeApp.hBodyBitmap) {
DeleteObject(SnakeApp.hBodyBitmap);
}
if (SnakeApp.hOneHundredBitmap) {
DeleteObject(SnakeApp.hOneHundredBitmap);
}
PostQuitMessage(0);
}
c_WinGUI_EventHandlerDef(WM_CREATE, Main_Create) {
memset(&SnakeApp, 0, sizeof(SnakeApp_t));
SnakeApp.Size = 32;
SnakeApp.hHeadBitmap = LoadBitmap(WinApp.hInstance, "Head");
if (!SnakeApp.hHeadBitmap) {
MessageBox(hwnd, "No head", "Fatal Error", MB_OK);
return FALSE;
}
SnakeApp.hBodyBitmap = LoadBitmap(WinApp.hInstance, "Body");
if (!SnakeApp.hBodyBitmap) {
MessageBox(hwnd, "No body", "Fatal Error", MB_OK);
return FALSE;
}
SnakeApp.hOneHundredBitmap = LoadBitmap(WinApp.hInstance, "Hundred");
if (!SnakeApp.hOneHundredBitmap) {
MessageBox(hwnd, "No hundred", "Fatal Error", MB_OK);
return FALSE;
}
int CXFull = GetSystemMetrics(SM_CXSCREEN);
int CYFull = GetSystemMetrics(SM_CYSCREEN);
SnakeApp.NumXSects = div(CXFull, SnakeApp.Size);
SnakeApp.MaxCols = (SnakeApp.NumXSects.quot-1)*SnakeApp.Size;
int BoardWidth = CXFull - SnakeApp.MaxCols;
div_t StartC = div(BoardWidth, 2);
SnakeApp.StartCol = StartC.quot;
SnakeApp.NumYSects = div(CYFull, SnakeApp.Size);
SnakeApp.MaxRows = (SnakeApp.NumYSects.quot-1)*SnakeApp.Size;
BoardWidth = CYFull - SnakeApp.MaxRows;
StartC = div(BoardWidth, 2);
SnakeApp.StartRow = StartC.quot;
hGameWindow = CreateWindow(SNAKE_GAME_WINDOW_CLASS,
"Game Window",
WS_CHILD | WS_VISIBLE,
SnakeApp.StartCol, SnakeApp.StartRow,
SnakeApp.MaxCols, SnakeApp.MaxRows,
hwnd, NULL, WinApp.hInstance, NULL);
return TRUE;
}
c_WinGUI_EventHandlerDef(WM_SIZE, Main_Size) {
if (hGameWindow) {
MoveWindow(hGameWindow, 0, 0, cx, cy, TRUE);
RECT Rect;
GetClientRect(hGameWindow, &Rect);
int CXFull = Rect.right - Rect.left;
int CYFull = Rect.bottom - Rect.top;
SnakeApp.NumXSects = div(CXFull, SnakeApp.Size);
SnakeApp.MaxCols = (SnakeApp.NumXSects.quot-1)*SnakeApp.Size;
int BoardWidth = CXFull - SnakeApp.MaxCols;
div_t StartC = div(BoardWidth, 2);
SnakeApp.StartCol = StartC.quot;
SnakeApp.NumYSects = div(CYFull, SnakeApp.Size);
SnakeApp.MaxRows = (SnakeApp.NumYSects.quot-1)*SnakeApp.Size;
BoardWidth = CYFull - SnakeApp.MaxRows;
StartC = div(BoardWidth, 2);
SnakeApp.StartRow = StartC.quot;
}
}
c_WinGUI_EventMapBegin(WndProc)
c_WinGUI_EventMap(WM_DESTROY, Main_Destroy);
c_WinGUI_EventMap(WM_CREATE, Main_Create);
c_WinGUI_EventMap(WM_SIZE, Main_Size);
c_WinGUI_EventMapEnd()
/* ------------------------------------------------------------------------------------------------------------------ */
/* GAME */
static void InitializeSections(void);
static void SetColRow(void) {
int i;
for (i=0; i<=Sections; i++) {
SectInfo[i].OldCol = SectInfo[i].Col;
SectInfo[i].OldRow = SectInfo[i].Row;
switch (SectInfo[i].Dir) {
case Up: {
SectInfo[i].Row-=SnakeApp.Size;
break;
}
case Down:{
SectInfo[i].Row+=SnakeApp.Size;
break;
}
case Left: {
SectInfo[i].Col-=SnakeApp.Size;
break;
}
case Right: {
SectInfo[i].Col+=SnakeApp.Size;
break;
}
}
}
for (i = Sections; i>0; i--) {
if (SectInfo[i-1].DirChange) {
SectInfo[i].DirChange = TRUE;
SectInfo[i].Dir = SectInfo[i-1].Dir;
SectInfo[i-1].DirChange = FALSE;
}
}
}
static void SetNewTurnSection(void) {
for (int i=1; i<=Sections; i++) {
if (TurnList[NumTurns].SectChangeDir[i]==TRUE) {
break;
}
TurnList[NumTurns].SectChangeDir[i] = FALSE;
i++;
TurnList[NumTurns].SectChangeDir[i] = TRUE;
}
}
static void Boom(HWND hwnd) {
memset(SectInfo, 0, sizeof(SectInfo));
Sections = 0;
NumPrizes = 0;
for (int i=0; i<10; i++) {
MessageBeep(-1);
}
InitializeSections();
InvalidateRect(hwnd, NULL, TRUE);
}
static void WhiteOut(HWND hwnd, int i) {
HDC PaintDC = GetDC(hwnd);
HDC MemDC = CreateCompatibleDC(PaintDC);
HBITMAP SaveBmp = SelectBitmap(MemDC, SnakeApp.hOneHundredBitmap);
BitBlt(PaintDC, Prizes[i].Col, Prizes[i].Row, 32, 32, MemDC, 0, 0, SRCINVERT);
SelectObject(MemDC, SaveBmp);
DeleteDC(MemDC);
ReleaseDC(hwnd, PaintDC);
}
static void CheckForCollision(HWND hwnd) {
if (SectInfo[0].Col<0) Boom(hwnd);
if (SectInfo[0].Row<0) Boom(hwnd);
if (SectInfo[0].Col + SnakeApp.Size > SnakeApp.MaxCols) Boom(hwnd);
if (SectInfo[0].Row + SnakeApp.Size > SnakeApp.MaxRows) Boom(hwnd);
for (int i=1; i<=Sections; i++) {
if (SectInfo[i].Col == SectInfo[0].Col && SectInfo[i].Row == SectInfo[0].Row) {
Boom(hwnd);
}
}
for (int i=0; i<=NumPrizes; i++) {
if (Prizes[i].Exists) {
if (((SectInfo[0].Row >= Prizes[i].Row) &&
(SectInfo[0].Row <=Prizes[i].Row + (SnakeApp.Size-1)))&&
((SectInfo[0].Col >=Prizes[i].Col) &&
(SectInfo[0].Col <=Prizes[i].Col + (SnakeApp.Size-1)))) {
Prizes[i].Exists = FALSE;
WhiteOut(hwnd, i);
}
}
}
}
static void InitializeSections(void) {
int i;
int StartCol;
int StartRow;
Sections = 5;
StartCol = SnakeApp.Size * 3;
StartRow = SnakeApp.Size * 3;
for (i=0; i<=Sections; i++) {
SectInfo[i].Dir = Right;
SectInfo[i].DirChange = FALSE;
SectInfo[i].Col = StartCol - (SnakeApp.Size * i);
SectInfo[i].Row = StartRow;
SectInfo[i].OldCol = SectInfo[i].Col;
SectInfo[i].OldRow = SectInfo[i].Row;
}
NewSect = FALSE;
}
static void GetOldDir(TDir NewDir) {
TurnList[NumTurns].Dir = NewDir;
TurnList[NumTurns].SectChangeDir[1] = TRUE;
SectInfo[0].OldDir = SectInfo[0].Dir;
SectInfo[0].Dir = NewDir;
SectInfo[0].DirChange = TRUE;
TurnList[0].TurnCol = SectInfo[0].Col;
TurnList[0].TurnRow = SectInfo[0].Row;
}
static void MoveBitmap(HWND hwnd) {
SetColRow();
HDC DC = GetDC(hwnd);
HDC PicDC = CreateCompatibleDC(DC);
CheckForCollision(hwnd);
HBITMAP OldBmp = SelectBitmap(PicDC, SnakeApp.hHeadBitmap);
BitBlt(DC, SectInfo[0].OldCol, SectInfo[0].OldRow, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
BitBlt(DC, SectInfo[0].Col, SectInfo[0].Row, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
SelectObject(PicDC, OldBmp);
OldBmp = SelectBitmap(PicDC, SnakeApp.hBodyBitmap);
BitBlt(DC, SectInfo[1].Col, SectInfo[1].Row, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
BitBlt(DC, SectInfo[Sections].Col, SectInfo[Sections].Row, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
if (NewSect) {
BitBlt(DC, SectInfo[Sections].Col, SectInfo[Sections].Row, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
NewSect = FALSE;
}
SelectObject(PicDC, OldBmp);
SectInfo[0].DirChange = FALSE;
DeleteDC(PicDC);
ReleaseDC(hwnd, DC);
SetNewTurnSection();
}
static void SetSections(void) {
Sections++;
SectInfo[Sections].Dir = SectInfo[Sections-1].Dir;
SectInfo[Sections].DirChange = FALSE;
switch (SectInfo[Sections].Dir) {
case Left: {
SectInfo[Sections].Col = SectInfo[Sections-1].Col + SnakeApp.Size;
SectInfo[Sections].Row = SectInfo[Sections-1].Row;
break;
}
case Right: {
SectInfo[Sections].Col = SectInfo[Sections-1].Col - SnakeApp.Size;
SectInfo[Sections].Row = SectInfo[Sections-1].Row;
break;
}
case Up: {
SectInfo[Sections].Col = SectInfo[Sections-1].Col;
SectInfo[Sections].Row = SectInfo[Sections-1].Row + SnakeApp.Size;
break;
}
case Down: {
SectInfo[Sections].Col = SectInfo[Sections-1].Col;
SectInfo[Sections].Row = SectInfo[Sections-1].Row - SnakeApp.Size;
break;
}
}
SectInfo[Sections].OldCol = SectInfo[Sections-1].Col;
SectInfo[Sections].OldRow = SectInfo[Sections-1].Row;
}
static void SetPrizes(void) {
NumPrizes++;
Prizes[NumPrizes].Exists = TRUE;
Prizes[NumPrizes].Row = (rand() % SnakeApp.NumYSects.quot) * SnakeApp.Size;
Prizes[NumPrizes].Col = (rand() % SnakeApp.NumXSects.quot) * SnakeApp.Size;
}
c_WinGUI_EventHandlerDef(WM_CREATE, Game_Create) {
if (!SetTimer(hwnd, SnakeTimer, 125, NULL)) {
MessageBox(hwnd, "No Timers Available", "Snake Info", MB_OK);
return FALSE;
}
NumPrizes = 0;
InitializeSections();
return TRUE;
}
c_WinGUI_EventHandlerDef(WM_DESTROY, Game_Destroy) {
KillTimer(hwnd, SnakeTimer);
}
c_WinGUI_EventHandlerDef(WM_CHAR, Game_Char) {
if (ch==VK_P) {
KillTimer(hwnd, SnakeTimer);
}
}
c_WinGUI_EventHandlerDef(WM_KEYDOWN, Game_Key) {
switch (vk) {
case VK_DOWN: {
GetOldDir(Down);
break;
}
case VK_UP: {
GetOldDir(Up);
break;
}
case VK_LEFT: {
GetOldDir(Left);
break;
}
case VK_RIGHT: {
GetOldDir(Right);
break;
}
}
MoveBitmap(hwnd);
}
c_WinGUI_EventHandlerDef(WM_PAINT, Game_Paint) {
PAINTSTRUCT PaintStruct;
HDC DC = BeginPaint(hwnd, &PaintStruct);
HDC PicDC = CreateCompatibleDC(DC);
// Draw Head
HBITMAP OldMap = SelectBitmap(PicDC, SnakeApp.hHeadBitmap);
BitBlt(DC, SectInfo[0].Col, SectInfo[0].Row, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
SelectObject(PicDC, OldMap);
// Draw Body
OldMap = SelectBitmap(PicDC, SnakeApp.hBodyBitmap);
for (int i=1; i<=Sections; i++) {
BitBlt(DC, SectInfo[i].Col, SectInfo[i].Row, SnakeApp.Size, SnakeApp.Size, PicDC, 0, 0, SRCINVERT);
}
SelectObject(PicDC, OldMap);
DeleteDC(PicDC);
EndPaint(hwnd, &PaintStruct);
SectInfo[0].DirChange = FALSE;
}
c_WinGUI_EventHandlerDef(WM_TIMER, Game_Timer) {
HBITMAP SaveBmp;
SetFocus(hwnd);
if (id==SnakeTimer) {
MoveBitmap(hwnd);
TotalClicks++;
if ((TotalClicks%10)==0) {
SetSections();
SetPrizes();
HDC PaintDC = GetDC(hwnd);
HDC PicDC = CreateCompatibleDC(PaintDC);
NewSect = TRUE;
SaveBmp = SelectBitmap(PicDC, SnakeApp.hOneHundredBitmap);
BitBlt(PaintDC, Prizes[NumPrizes].Col,
Prizes[NumPrizes].Row,
32, 32, PicDC, 0, 0, SRCINVERT);
SelectObject(PicDC, SaveBmp);
DeleteDC(PicDC);
ReleaseDC(hwnd, PaintDC);
}
}
}
c_WinGUI_EventMapBegin(GameWndProc)
c_WinGUI_EventMap(WM_CREATE, Game_Create);
c_WinGUI_EventMap(WM_DESTROY, Game_Destroy);
c_WinGUI_EventMap(WM_CHAR, Game_Char);
c_WinGUI_EventMap(WM_KEYDOWN, Game_Key);
c_WinGUI_EventMap(WM_PAINT, Game_Paint);
c_WinGUI_EventMap(WM_TIMER, Game_Timer);
c_WinGUI_EventMapEnd()
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
static
BOOL Register(HINSTANCE hInstance) {
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockBrush(GRAY_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = WINDOW_CLASS_NAME;
RegisterClass(&WndClass);
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = GameWndProc;
WndClass.hIcon = NULL;
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockBrush(WHITE_BRUSH);
WndClass.lpszClassName = SNAKE_GAME_WINDOW_CLASS;
return RegisterClass(&WndClass);
}
static
HWND Create(HINSTANCE hInstance, int nCmdShow) {
HWND hwnd = CreateWindow(WINDOW_CLASS_NAME,
"A Snake and it's Tail",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL
);
if (hwnd == NULL) {
return NULL;
}
nCmdShow = SW_SHOWMAXIMIZED;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return hwnd;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_WinGUI_Main(){
MSG msg;
if (!hPrevInstance) {
if (!Register(hInstance)) {
return FALSE;
}
}
WinApp.hInstance = hInstance;
HWND MainHwnd = Create(hInstance, nShowCmd);
if (!MainHwnd) {
return FALSE;
}
WinApp.hwnd = MainHwnd;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}