【Chapter 3】基于Chp2的贪吃蛇的例子
来源:互联网 发布:机房 蓝屏 网络攻击 编辑:程序博客网 时间:2024/05/16 00:38
稍微看了下
还是好难啊啊啊啊啊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 25void 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 positionCW_USEDEFAULT,// initial y position 600,// initial x size 600,// initial y sizeNULL,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 brushesHDC 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 loopstd::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 areaSelectObject(hdc, whiteBrush);Rectangle(hdc, 0, 0, COL_NUM * BLOCK_SIZE, ROW_NUM * BLOCK_SIZE);//draw snakeSelectObject(hdc, redBrush);std::list<Block>::iterator it = snake.begin();for (; it != snake.end(); it++){Fill_Block(hdc, *it);}//draw foodSelectObject(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 brushesHDC 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 loopstd::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 areaSelectObject(hdc, whiteBrush);Rectangle(hdc, 0, 0, COL_NUM * BLOCK_SIZE, ROW_NUM * BLOCK_SIZE);//draw snakeSelectObject(hdc, redBrush);std::list<Block>::iterator it = snake.begin();for (; it != snake.end(); it++){Fill_Block(hdc, *it);}//draw foodSelectObject(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
- 【Chapter 3】基于Chp2的贪吃蛇的例子
- 基于python的贪吃蛇
- Python写的贪吃蛇游戏例子
- 程序员的自我修养 读书笔记 chp2
- 基于单片机的贪吃蛇游戏
- 基于控制台的贪吃蛇小游戏
- 基于c语言的贪吃蛇游戏
- 基于Qt 的贪吃蛇实现
- 基于JS、canvas的小游戏--贪吃蛇
- (转) 基于jquery写的贪吃蛇游戏
- 基于java的贪吃蛇设计与实现
- 基于正点原子战舰开发板的贪吃蛇游戏
- 基于H5的移动端贪吃蛇游戏开发
- 贪吃蛇完整版(基于window消息机制的C语言)
- 基于广度优先搜索的自适应贪吃蛇实现
- 基于Linux下的GTK+2.0贪吃蛇游戏开发
- 简单的贪吃蛇
- 我的贪吃蛇
- 谷歌眼镜进行XE11升级 可以语音搜索谷歌日历
- 制作gif工具GIF Movie Gear
- 360炮轰搜狗浏览器“泄密”
- windows JDK 配置
- 循环单链表
- 【Chapter 3】基于Chp2的贪吃蛇的例子
- 九大视频接口
- Android组件间的交互和进程间IPC通信
- js判断手机访问网站自动跳转到手机版
- ffmpeg 多线程初始化,需要做的事
- Linux远程连接Windows:rdesktop
- 关于 AemulaOldies 的备忘录
- UVA - 10099 The Tourist Guide
- (Warshall13.1.1)POJ 2253(计算任意一对顶点之间的连通性||求最大路的最小值——图的传递闭包)