稍微看了下
还是好难啊啊啊啊啊QAQ
Please请对我好一点啊啊啊啊啊TAT
放代码慢慢分析
代码依旧是有俱乐部培训的师兄提供
什么时候能自己写啊[望天]
代码渣画画渣读书废
都不知道怎么有勇气活到现在的是么嗯哼?
会写注释的程序员都是好男人/女人
#include <windows.h>
#include <list>
#include <stdlib.h>
#include <time.h>
#define LEFT 0
#define RIGHT 1
#define UP 2
#define DOWN 3
#define COL_NUM 20
#define ROW_NUM 20
#define BLOCK_SIZE 25
void Game_Init(HWND hwmd);
void SetFood();
void Game_Exit();
void Game_Render(HDC hdc);
bool Game_Update(HWND hwmd);
struct Block //For every little block
{
int col;
int row;
bool operator== (Block& b) {
return col == b.col && row == b.row;
}
bool operator!= (Block& b) {
return !((*this) == b);
}
};
std::list<Block> snake;
Block food;
int direction;
HBRUSH redBrush, orangeBrush, whiteBrush;
inline void Fill_Block(HDC hdc, Block& b);
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int iCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG msg; /* Here messages to the application are saved */
WNDCLASS wndclass; /* Data structure for the windowclass */
static char szClassName[ ] = "WindowsApp";
/* 第一步:注册窗口类 */
wndclass.hInstance = hInstance;
wndclass.lpszClassName = szClassName;
wndclass.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; /* Catch double-clicks */
wndclass.cbWndExtra = 0;
wndclass.cbClsExtra = 0;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
/* Register the window class, and if it fails quit the program */
if (!RegisterClass (&wndclass))
return 0;
/* 第二步:创建窗口 */
hwnd = CreateWindow(
szClassName,
TEXT("MyApp"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,// initial x position
CW_USEDEFAULT,// initial y position
600,// initial x size
600,// initial y size
NULL,
NULL,
hInstance,
NULL
);
/* 第三步:显示窗口 */
ShowWindow (hwnd, iCmdShow);
UpdateWindow(hwnd);
/* 第四步:消息循环 */
while (GetMessage (&msg, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&msg);
/* Send message to WindowProcedure */
DispatchMessage(&msg);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return msg.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message) /* handle the messages */
{
case WM_CREATE:
Game_Init(hwnd);
return 0;
case WM_DESTROY:
Game_Exit();
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
Game_Render(hdc);
EndPaint(hwnd, &ps);
return 0;
case WM_TIMER:
if(wParam == 1) {
if(!Game_Update(hwnd)) {
KillTimer(hwnd, 1);
MessageBox(hwnd, "Game Over!", NULL, 0);
DestroyWindow(hwnd);
}
}
return 0;
case WM_KEYDOWN:
if(wParam == VK_LEFT && direction != RIGHT) direction = LEFT;
if(wParam == VK_RIGHT && direction != LEFT) direction = RIGHT;
if(wParam == VK_UP && direction != DOWN) direction = UP;
if(wParam == VK_DOWN && direction != UP) direction = DOWN;
return 0;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
void Game_Init(HWND hwmd)
{
srand(time(NULL));
direction = LEFT;
Block b;
b.row = 9;
b.col = 9;
int i;
for (i = 0; i < 7; i++)
{
snake.push_back(b);
b.col++;
}
SetFood();
//create some brushes
HDC hdc = GetDC(hwmd);
redBrush = (HBRUSH)CreateSolidBrush(RGB(255, 0, 0));
orangeBrush = (HBRUSH)CreateSolidBrush(RGB(255, 102, 0));
whiteBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
ReleaseDC(hwmd, hdc);
SetTimer(hwmd, 1, 200, NULL);
}
void SetFood()
{
while(true) {
food.row = rand() % ROW_NUM;
food.col = rand() % COL_NUM;
//if food is not in snake position, quit loop
std::list<Block>::iterator it = snake.begin();
for (; it != snake.end(); it++)
{
if(food == (*it)) {
break;
}
}
if(it == snake.end()) break;
}
}
void Game_Exit()
{
DeleteObject(redBrush);
DeleteObject(orangeBrush);
}
void Game_Render(HDC hdc)
{
SelectObject(hdc, (HPEN)GetStockObject(NULL_PEN));
//draw white area
SelectObject(hdc, whiteBrush);
Rectangle(hdc, 0, 0, COL_NUM * BLOCK_SIZE, ROW_NUM * BLOCK_SIZE);
//draw snake
SelectObject(hdc, redBrush);
std::list<Block>::iterator it = snake.begin();
for (; it != snake.end(); it++)
{
Fill_Block(hdc, *it);
}
//draw food
SelectObject(hdc, orangeBrush);
Fill_Block(hdc, food);
}
void Fill_Block(HDC hdc, Block& b)
{
Rectangle(hdc, b.col * BLOCK_SIZE, b.row * BLOCK_SIZE, (b.col + 1) * BLOCK_SIZE, (b.row + 1) * BLOCK_SIZE);
}
bool Game_Update(HWND hwmd)
{
Block head = snake.front();
switch(direction){
case LEFT:
head.col--;
if(head.col < 0) return false;
break;
case RIGHT:
head.col++;
if(head.col >= COL_NUM) return false;
break;
case UP:
head.row--;
if(head.row < 0) return false;
break;
case DOWN:
head.row++;
if(head.row >= ROW_NUM) return false;
break;
}
std::list<Block>::iterator it = snake.begin();
for (; it != snake.end(); it++)
{
if(head == *it)
return false;
}
snake.push_front(head);
HDC hdc = GetDC(hwmd);
SelectObject(hdc, (HPEN)GetStockObject(NULL_PEN));
SelectObject(hdc, redBrush);
Fill_Block(hdc, head);
if(head == food) {
SetFood();
SelectObject(hdc, orangeBrush);
Fill_Block(hdc, food);
}
else {
SelectObject(hdc, whiteBrush);
Block tail = snake.back();
snake.pop_back();
Fill_Block(hdc, tail);
}
ReleaseDC(hwmd, hdc);
return true;
}
有一个类block
定义了每个小block的位置(row和col)
下面又为snake定义了<block>list,为food定义了一个block
WinMain函数里面没有什么大变动
主要看窗口过程函数里面的操作。
首先理解几个函数的意思:
void Game_Init(HWND hwmd)
{
srand(time(NULL));
direction = LEFT;
Block b;
b.row = 9;
b.col = 9;
int i;
for (i = 0; i < 7; i++)
{
snake.push_back(b);
b.col++;
}
SetFood();
//create some brushes
HDC hdc = GetDC(hwmd);
redBrush = (HBRUSH)CreateSolidBrush(RGB(255, 0, 0));
orangeBrush = (HBRUSH)CreateSolidBrush(RGB(255, 102, 0));
whiteBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
ReleaseDC(hwmd, hdc);
SetTimer(hwmd, 1, 200, NULL);
}
大抵上是游戏刚开始的时候定义了一条在位置坐标(9,9)的方向向左的一条长度为7个格子的snake
和setfood放置食物(另一个函数)
还定义了各种刷子brush的RGB颜色值
ReleaseDC是释放窗口
使用GetDC或者GetWindowDC等API时,会向系统检索设备上下文环境,换句话说,就是系统动态分配了资源让你可以拥有对这个设备(这个设备可以是屏幕、窗口、客户区域等)一定的控制权,比如绘图。
使用完毕后,这个动态分配的资源应该还给系统,于是要ReleaseDC。有借有还,再借不难。有借无还,系统玩完。
函数原型:int ReleaseDC(HWND hWnd, HDC hdc);
参数:
hWnd:指向要释放的设备上下文环境所在的窗口的句柄。
hDC:指向要释放的设备上下文环境的句柄。
返回值:返回值说明了设备上下文环境是否释放;如果释放成功,则返回值为1;如果没有释放成功,则返回值为0。
还设置了一个时钟
SetTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器。计时器属于系统资源,使用完应及时销毁。
SetTimer的函数原型如下:
UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc ) ;
其中:
hWnd是和timer关联的窗口句柄,此窗口必须为调用SetTimer的线程所有;如果hWnd为NULL,没有窗口和timer相关联并且nIDEvent参数被忽略
nIDEvent是timer的标识,为非零值;如果hWnd为NULL则被忽略;如果hWnd非NULL而且与timer相关联的窗口已经存在一个为此标识的timer,则此次SetTimer调用将用新的timer代替原来的timer。timer标识和窗口相关,两个不同的窗口可以拥有nIDEvent相同的tiemr
uElapse是以毫秒指定的计时间隔值,范围为1毫秒到4,294,967,295毫秒(将近50天),这个值指示Windows每隔多久时间给程序发送WM_TIMER消息。
lpTimerFunc是一个回调函数的指针,俗称TimerFunc;如果lpTimerFunc为NULL,系统将向应用程序队列发送WM_TIMER消息;如果lpTimerFunc指定了一个值,DefWindowProc将在处理WM_TIMER消息时调用这个lpTimerFunc所指向的回调函数,因此即使使用TimerProc代替处理WM_TIMER也需要向窗口分发消息。
关于SetTimer的返回值:如果hWnd为NULL,返回值为新建立的timer的ID,如果hWnd非NULL,返回一个非0整数,如果SetTimer调用失败则返回0
KillTimer的函数原型为:BOOL KillTimer( HWND hWnd, UINT_PTR uIDEvent ) ; 参数意义同SetTimer。
void SetFood()
{
while(true) {
food.row = rand() % ROW_NUM;
food.col = rand() % COL_NUM;
//if food is not in snake position, quit loop
std::list<Block>::iterator it = snake.begin();
for (; it != snake.end(); it++)
{
if(food == (*it)) {
break;
}
}
if(it == snake.end()) break;
}
}
一起来看SetFood()
即随机找个位置个food,但是要满足不在snake体内的条件。
若在snake体内则跳出这个循环。
void Game_Exit()即为游戏退出
销毁格子
void Game_Render(HDC hdc)
{
SelectObject(hdc, (HPEN)GetStockObject(NULL_PEN));
//draw white area
SelectObject(hdc, whiteBrush);
Rectangle(hdc, 0, 0, COL_NUM * BLOCK_SIZE, ROW_NUM * BLOCK_SIZE);
//draw snake
SelectObject(hdc, redBrush);
std::list<Block>::iterator it = snake.begin();
for (; it != snake.end(); it++)
{
Fill_Block(hdc, *it);
}
//draw food
SelectObject(hdc, orangeBrush);
Fill_Block(hdc, food);
}
这个看名字看不出来干嘛的- -
看备注是构造这个游戏世界的意思么
刚刚是构造了snake和food
这个是把snake和food都用特定颜色填充到世界里
void Fill_Block(HDC hdc, Block& b)
{
Rectangle(hdc, b.col * BLOCK_SIZE, b.row * BLOCK_SIZE, (b.col + 1) * BLOCK_SIZE, (b.row + 1) * BLOCK_SIZE);
}
Rectangle是画矩形函数
函数名: rectangle
功 能: 画一个矩形
用 法: void far rectangle(int left, int top, int right, int bottom);
参数说明:(left ,top )为矩形的左上坐标,(right,bottom)为矩形的右下坐标,两者可确定一个矩形的大小
bool Game_Update(HWND hwmd)
{
Block head = snake.front();
switch(direction){
case LEFT:
head.col--;
if(head.col < 0) return false;
break;
case RIGHT:
head.col++;
if(head.col >= COL_NUM) return false;
break;
case UP:
head.row--;
if(head.row < 0) return false;
break;
case DOWN:
head.row++;
if(head.row >= ROW_NUM) return false;
break;
}
std::list<Block>::iterator it = snake.begin();
for (; it != snake.end(); it++)
{
if(head == *it)
return false;
}
snake.push_front(head);
HDC hdc = GetDC(hwmd);
SelectObject(hdc, (HPEN)GetStockObject(NULL_PEN));
SelectObject(hdc, redBrush);
Fill_Block(hdc, head);
if(head == food) {
SetFood();
SelectObject(hdc, orangeBrush);
Fill_Block(hdc, food);
}
else {
SelectObject(hdc, whiteBrush);
Block tail = snake.back();
snake.pop_back();
Fill_Block(hdc, tail);
}
ReleaseDC(hwmd, hdc);
return true;
}
Game_Update应该是贪吃蛇的核心。即snake的移动。
键盘上的上下左右定义成0,1,2,3来识别方向。
当吃到food的时候,尾巴的那一格red格子不变成白色的格子。
===============================================
分析完了
但是自己写还是不会啊怎么破!!!!
一个上午了分析了一章ppt
还有许许多多的ppt
今早7点半起~
果然比睡到12点然后再捶胸敦子心情舒畅一些
刚宿舍还合力杀死了一只超级大的蟑螂QAQ吓死
总之今天可以奖励自己一下么
肚子还疼着TAT