游戏贪吃蛇(c语言)

  • 一、项目背景
  • 二、设计目的
  • 三、项目功能需求
    • 1、初始化游戏
    • 2、控制蛇的运行轨迹
    • 3、控制蛇的长度
    • 4、控制食物生成
    • 5、计算分数
    • 6、结束条件
  • 四、系统的功能结构图
  • 五、总体设计
    • 1、初始化模块
    • 2、游戏控制模块
    • 3、运行控制模块
    • 4、食物生成模块
  • 六、详细设计
    • 1、主函数
    • 2、初始化模块
    • 3、游戏控制模块
    • 4、运行控制模块
    • 5、食物生成模块
  • 七、代码

一、项目背景

​ 贪吃蛇是一款经典的小游戏,一条小蛇在一个区域里自由游走,目的是吃掉随机出现的食物,每吃掉一个食物蛇的身体会变长一点,如果在移动过程中蛇头碰到墙壁或者自己的身体游戏结束。所以吃掉的食物越多,游戏将变得更难**。**

二、设计目的

  • 如何设计贪吃蛇游戏中基础数据结构
  • 如何实现蛇的移动以及食物生成等的功能
  • 如何使用Windows编程的回调机制处理消息,实现游戏控制

三、项目功能需求

1、初始化游戏

  • 在窗口上画出游戏区域,并初始化长度为1的蛇,同时生成一个食物

2、控制蛇的运行轨迹

  • 通过键盘来控制蛇的运行方向

3、控制蛇的长度

  • 当蛇吃到食物时,蛇的身体会随之变长

4、控制食物生成

  • 当当前食物被吃掉时,需要在游戏区域内随机生成一个新的食物

5、计算分数

  • 计算玩家得分,每吃到一个食物时,分数加1

6、结束条件

  • 当玩家控制的蛇撞到墙壁或者自己的身体时,游戏结束

四、系统的功能结构图

五、总体设计

功能模块介绍

1、初始化模块

  • 实现游戏区域的绘制以及蛇与食物的生成**。**
  • 通过对键盘消息的监测实现游戏的暂停和重新开始**。**

2、游戏控制模块

  • 通过对蛇头位置的判断,判断在移动过程中蛇头碰到墙壁或者自己的身体,结束游戏

3、运行控制模块

  • 通过对键盘消息的监测与当前运行方向来实现蛇的运行控制

4、食物生成模块

  • 通过蛇头和食物相对位置的判断,实现蛇吃食物的效果,更新分数。同时在区域内随机生成新的食物**。**

六、详细设计

1、主函数

程序入口为WinMain函数,

函数中实现创建Windows

窗口功能,获取并分发消息。

处理流程如图。

2、初始化模块

功能设计

  • 绘制游戏运行的整个界面,监控键盘事件,实现游戏的暂停和重新开始**。**
  • 初始化蛇和食物。在游戏开始时,在游戏区域中心生成1个单位长度的蛇并在区域内随机生成食物。

3、游戏控制模块

功能设计

  • 主要是在游戏进行过程中检测蛇头是否撞墙或者撞到自己身体来控制游戏是否结束。

4、运行控制模块

功能设计

  • 根据键盘输入改变蛇的下一个前进方向。
  • 实现蛇的动态移动。

5、食物生成模块

功能设计

  • 判断贪吃蛇是否吃到食物。
  • 在游戏区域内随机生成新的食物。

七、代码

#include <windows.h>
#include <time.h>
#include <stdlib.h>
#include <conio.h>/*定义4个方向*/
#define UP      1  /*向上,蛇头y坐标不断减小*/
#define DOWN    2  /*向下,蛇头y坐标不断增大*/
#define LEFT    3  /*向左,蛇头x坐标不断减小*/
#define RIGHT   4  /*向右,蛇头x坐标不断增大*/#define SNAKE_WIDTH  20  /*单节蛇的大小*/
#define X_WIDTH      20  /*游戏区的宽度*/
#define Y_HEIGHT     20  /*游戏区的高度*/
#define GETSCORE     10  /*吃一个食物的得分*/
#define ID_TIMER     1   /*定时器ID*/
#define TIMERSET     600 /*定时间隔*/
#define FALSE 0
#define TRUE 1
#define APP_NAME "Snake"
#define APP_TITLE TEXT("贪吃蛇")
#define P 80
#define R 82static int  iDirect = RIGHT;  /*方向(注:方向由蛇头决定)*/
static int  iScore;  /*吃到的食物数量*/int  iIsOver = FALSE;struct Snake
{POINT   point;struct Snake *pstNext, *pstBefore;
} stSnake;  /*定义蛇头*/struct Snake * pstLast = NULL, *pstFood = NULL;int aiPointExist[X_WIDTH][Y_HEIGHT]; /*定义游戏区坐标布尔值,表示相应点的蛇身以及是否有食物。*/
int aiFood[X_WIDTH][Y_HEIGHT];       /*定义了食物的坐标*/
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{MSG msg;WNDCLASS    wndcls;                                          /*WNDCLASS结构变量,包含窗口类全部信息*//*设置窗口样式*/wndcls.cbClsExtra = 0;                                       /*窗口类无拓展*/wndcls.cbWndExtra = 0;                                       /*窗口实例无拓展*/wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  /*窗口背景为白色*/wndcls.hCursor = LoadCursor(hInstance, IDC_ARROW);           /*窗口采用箭头光标*/wndcls.hIcon = LoadIcon(hInstance, IDI_APPLICATION);         /*窗口最小化图标为缺省图标*/wndcls.hInstance = hInstance;                                /*当前实例句柄*/wndcls.lpfnWndProc = WndProc;                                /*定义窗口处理函数*/wndcls.lpszClassName = APP_NAME;                             /*定义窗口类名*/wndcls.lpszMenuName = NULL;                                  /*窗口无菜单*/wndcls.style = CS_HREDRAW | CS_VREDRAW;                      /*当窗口水平或垂直宽度变化时重绘窗口*/RegisterClass(&wndcls);                                      /*注册窗口类*//*创建Windows窗口*/HWND hwnd = CreateWindow(APP_NAME, APP_TITLE,WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT, CW_USEDEFAULT, (X_WIDTH + 15) * SNAKE_WIDTH, (Y_HEIGHT + 5) * SNAKE_WIDTH,NULL, NULL, hInstance, NULL);ShowWindow(hwnd, nCmdShow);                                  /*显示窗口*/UpdateWindow(hwnd);                                          /*绘制用户区*//*判断是否有Windows消息*/while (GetMessage(&msg, NULL, 0, 0))                         /*从调用线程的消息队列中取出一条消息*/{TranslateMessage(&msg);                              /*对"消息对"的转化*/DispatchMessage(&msg);                               /*将取出的消息传到窗口的回调函数去处理*/}return msg.wParam;
}/*新食物刷新*/
void NewFood(HWND hwnd)
{pstFood = (struct Snake *)malloc(sizeof(struct Snake));SYSTEMTIME st;/*在窗口位置内随机产生新的食物*/GetLocalTime(&st);                                           /*获取当地的当前系统日期和时间*/srand(st.wMilliseconds);pstFood->point.x = rand() % X_WIDTH;pstFood->point.y = rand() % Y_HEIGHT;/*判断新食物位置是否是蛇身位置*/while (aiPointExist[pstFood->point.x][pstFood->point.y]){GetLocalTime(&st);srand(st.wMilliseconds);pstFood->point.x = rand() % X_WIDTH;pstFood->point.y = rand() % Y_HEIGHT;}aiPointExist[pstFood->point.x][pstFood->point.y] = TRUE;InvalidateRect(hwnd, NULL, TRUE);                            /*重绘窗口区域*/
}/*判断前方是否是食物*/
int IsFood()
{if (stSnake.point.x == pstFood->point.x && stSnake.point.y == pstFood->point.y)return TRUE;elsereturn FALSE;
}/*判断是否撞墙或者撞到自己身体*/
int TouchWall()
{struct Snake *pstTemp = pstLast;/*超越边界判断*/if (stSnake.point.x >= X_WIDTH ||stSnake.point.x < 0 ||stSnake.point.y < 0 ||stSnake.point.y >= Y_HEIGHT)return TRUE;/*碰撞自身身体判断*/while (pstTemp != &stSnake){if (stSnake.point.x == pstTemp->point.x &&stSnake.point.y == pstTemp->point.y)return TRUE;pstTemp = pstTemp->pstBefore;}return FALSE;
}void Move(HWND hwnd)
{int iPosition_x, iPosition_y;  /*用于记录蛇头的当前位置(未前进时)*//*标记前方是否为食物,默认为不是食物,表示系通常的前进*/struct Snake * pstTemp = pstLast;/*记录蛇头当前坐标*/iPosition_x = stSnake.point.x;iPosition_y = stSnake.point.y;/*测试前进的地方是否是食物,同时将蛇头前进*/switch (iDirect){case UP:--stSnake.point.y;break;case DOWN:++stSnake.point.y;break;case LEFT:--stSnake.point.x;break;case RIGHT:++stSnake.point.x;break;default:break;}if (!IsFood())/*如果不是食物,作如下处理*/{if (pstTemp != &stSnake)/*最后一节不是蛇头*/{aiPointExist[pstTemp->point.x][pstTemp->point.y] = FALSE;/*由于蛇要前进,原蛇尾位置标记为FALSE*//*蛇尾到蛇头位置节点对应位置分别标记为TRUE*/while (pstTemp != stSnake.pstNext){pstTemp->point.x = pstTemp->pstBefore->point.x;pstTemp->point.y = pstTemp->pstBefore->point.y;pstTemp = pstTemp->pstBefore;}pstTemp->point.x = iPosition_x;pstTemp->point.y = iPosition_y;aiPointExist[pstTemp->point.x][pstTemp->point.y] = TRUE;}else  /*pstLast == &snake,即蛇只有蛇头*/aiPointExist[iPosition_x][iPosition_y] = FALSE;if (TouchWall())iIsOver = TRUE;                      /*则标记游戏结束*/elseaiPointExist[stSnake.point.x][stSnake.point.y] = TRUE;  /*不然移动后的蛇头位置标记为有方块了*/InvalidateRect(hwnd, NULL, TRUE);       /*刷新游戏区*/}/*如果是食物,作如下处理*/else{++iScore;pstFood->pstBefore = pstLast;pstLast->pstNext = pstFood;if (pstTemp != &stSnake){pstFood->point.x = pstLast->point.x;pstFood->point.y = pstLast->point.y;while (pstTemp != stSnake.pstNext){pstTemp->point.x = pstTemp->pstBefore->point.x;pstTemp->point.y = pstTemp->pstBefore->point.y;pstTemp = pstTemp->pstBefore;}pstTemp->point.x = iPosition_x;pstTemp->point.y = iPosition_y;}else  /*pstLast == &snake,即蛇只有蛇头*/{pstFood->point.x = iPosition_x; pstFood->point.y = iPosition_y;}pstLast = pstFood;NewFood(hwnd);}
}void startGame(HWND hwnd)
{int x, y;for (x = 0; x < X_WIDTH; ++x)for (y = 0; y < Y_HEIGHT; ++y)aiPointExist[x][y] = FALSE;/*初始化变量为FALSE,表示没有食物和蛇*/aiFood[x][y] = FALSE;iDirect = RIGHT;   /*游戏开局,设定蛇的默认方向向右*//*在游戏区中间位置生成长度为1的蛇*/stSnake.point.x = X_WIDTH / 2;stSnake.point.y = Y_HEIGHT / 2;pstLast = &stSnake;iIsOver = FALSE;/*将游戏结束变量设为FALSE*/aiPointExist[stSnake.point.x][stSnake.point.y] = TRUE;/*将新生成蛇的位置的aiPointExist变量设为TRUE*/NewFood(hwnd);/*随机生成一个食物*/SetTimer(hwnd, ID_TIMER, TIMERSET, NULL);/*设置计数器*/
}void keyDown(HWND hwnd, WPARAM wParam, int iPause)
{if (!iPause&&!iIsOver)/*游戏运行时,才可以进行运行控制*/{switch (wParam){case VK_UP:if (iDirect != DOWN)/*更改的移动方向不能与原方向相反*/{iDirect = UP;/*改变当前移动方向*/Move(hwnd);/*移动*/}break;case VK_DOWN:if (iDirect != UP){iDirect = DOWN;Move(hwnd);}break;case VK_LEFT:if (iDirect != RIGHT){iDirect = LEFT;Move(hwnd);}break;case VK_RIGHT:if (iDirect != LEFT){iDirect = RIGHT;Move(hwnd);}break;default:break;}}
}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{HDC             hdc;PAINTSTRUCT     ps;TEXTMETRIC      tm;HBRUSH          hBrush;static int      cxChar, cyChar;TCHAR           szScore[] = TEXT("得分:"),szInfor_1[] = TEXT("========游戏说明========"),szInfor_2[] = TEXT("1.按方向键移动小蛇;"),szInfor_3[] = TEXT("2.按P暂停游戏;"),szInfor_4[] = TEXT("2.按R重新开始游戏;"),szInfor_5[] = TEXT("3.蛇头撞到墙,结束游戏;"),szInfor_6[] = TEXT("4.蛇头碰到蛇身,游戏结束;"),szInfor_7[] = TEXT("5.每吃一个米粒得1分"),szInfor_8[] = TEXT("========================"),szInfor_9[] = TEXT("========================"),szInfor_10[] = TEXT("   您的得分是:"),szInfor_11[] = TEXT("======================="),szGameOver[] = TEXT("游戏结束!"),szPause[] = TEXT("游戏暂停!"),szBuffer[X_WIDTH],*szText = NULL;int             x, y;static int     iPause = FALSE;switch (message){case WM_CREATE:hdc = GetDC(hwnd);/*返回窗口客户区的设备上下文环境*/GetTextMetrics(hdc, &tm);/*该函数把程序当前的字体信息,存放到TEXTMETRIC*/cyChar = tm.tmExternalLeading + tm.tmHeight;ReleaseDC(hwnd, hdc);startGame(hwnd);return 0;case WM_TIMER:if (iPause) return 0;Move(hwnd);if (iIsOver){KillTimer(hwnd, ID_TIMER);InvalidateRect(hwnd, NULL, TRUE);}return 0;case WM_KEYDOWN:keyDown(hwnd, wParam, iPause);if (wParam == P){iPause = !iPause;InvalidateRect(hwnd, NULL, TRUE);return 0;}if (wParam == R){startGame(hwnd);return 0;}case WM_PAINT:hdc = BeginPaint(hwnd, &ps);hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);SetViewportOrgEx(hdc, SNAKE_WIDTH, SNAKE_WIDTH, NULL);/*画游戏区的边框*/MoveToEx(hdc, -1, -1, NULL);LineTo(hdc, X_WIDTH * SNAKE_WIDTH + 1, -1);LineTo(hdc, X_WIDTH * SNAKE_WIDTH + 1, Y_HEIGHT * SNAKE_WIDTH + 1);LineTo(hdc, -1, Y_HEIGHT * SNAKE_WIDTH + 1);LineTo(hdc, -1, -1);/*显示屏幕右侧的游戏说明*/TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 0, szInfor_1, lstrlen(szInfor_1));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 20, szInfor_2, lstrlen(szInfor_2));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 50, szInfor_3, lstrlen(szInfor_3));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 80, szInfor_4, lstrlen(szInfor_4));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 110, szInfor_5, lstrlen(szInfor_5));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 140, szInfor_6, lstrlen(szInfor_6));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 170, szInfor_7, lstrlen(szInfor_7));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 200, szInfor_8, lstrlen(szInfor_8));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 300, szInfor_9, lstrlen(szInfor_9));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 320, szInfor_10, lstrlen(szInfor_10));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 340, szInfor_11, lstrlen(szInfor_11));TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH + 100, 320, szBuffer, wsprintf(szBuffer, TEXT("%4d"), iScore));if (iPause)TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 380, szPause, lstrlen(szPause));else if (iIsOver)TextOut(hdc, (X_WIDTH + 1) * SNAKE_WIDTH, 380, szGameOver, lstrlen(szGameOver));hBrush = CreateSolidBrush(RGB(0, 0, 255));  /*定义画刷为蓝色*/SelectObject(hdc, hBrush);for (x = 0; x < X_WIDTH; ++x){for (y = 0; y < Y_HEIGHT; ++y){if (aiPointExist[x][y])Rectangle(hdc, x * SNAKE_WIDTH, y * SNAKE_WIDTH,(x + 1) * SNAKE_WIDTH, (y + 1) * SNAKE_WIDTH);   /*绘制蛇身和食物的矩形*/}}return 0;case WM_DESTROY:KillTimer(hwnd, ID_TIMER);PostQuitMessage(0);return 0;}return DefWindowProc(hwnd, message, wParam, lParam);
}

游戏贪吃蛇(c语言)相关推荐

  1. C语言贪吃蛇游戏代码,贪吃蛇C语言代码实现大全

    一.C语言贪吃蛇代码实现前言 设计贪吃蛇游戏的主要目的是让大家夯实C语言基础,训练编程思维,培养解决问题的思路,领略多姿多彩的C语言. 贪吃蛇是非常经典的一款游戏,本次我们模拟在控制台实现贪吃蛇游戏, ...

  2. 贪吃蛇c语言 游戏中会出现障碍物,贪吃蛇C语言游戏代码.doc

    贪吃蛇C语言游戏代码 //开始编写游戏需要的类 #include //EasyX_2011惊蛰版(绘图库) #include #include #include #define UP1 #define ...

  3. 【从入门到入土系列】C语言制作小游戏-贪吃蛇:Copy+运行即可另附注释

    系列文章 本系列持续更新中,欢迎您的访问! 系列简介 本系列由唐文疏撰写,负责记录博主的学习生涯中的一点一滴.独乐乐不如众乐乐,故此分享给大家.欢迎大家一起讨论.学习和批评指点. 博主只是一个普普通通 ...

  4. 用pygame做一个简单的python小游戏---贪吃蛇

    用pygame做一个简单的python小游戏-贪吃蛇 贪吃蛇游戏博客链接:(方法一样,语言不一样) c++贪吃蛇:https://blog.csdn.net/weixin_46791942/artic ...

  5. Python命令行小游戏—贪吃蛇

    Python命令行小游戏-贪吃蛇 前言 一.贪吃蛇游戏初始界面及地图 1.游戏初始界面 2.游戏地图 二.命令符的设置.输出刷新和按键检测 1.库支持 2.c语言代码 3.Python代码(变量初始化 ...

  6. 贪吃蛇c语言经典程序下载,c语言贪吃蛇源码

    c语言贪吃蛇源码是一款非常经典的休闲益智游戏.c语言贪吃蛇源码游戏画面采用了像素风格,并添加了5中游戏模式,为玩家带来更有趣的游戏体验,有兴趣的玩家可以下载c语言贪吃蛇源码玩玩,回忆下童年的乐趣. 游 ...

  7. 贪吃蛇c语言程序 简书,C语言/C++项目源码分享—贪吃蛇

    /* 项目内容:贪吃蛇 开发环境:vs2013+easyx */ 这个项目是一个小游戏-贪吃蛇项目,代码如下 #include #include //包含easyx图形库,可以使用给我们提供的一些函数 ...

  8. c语言课程设计贪吃蛇报告,贪吃蛇C语言课程设计报告.doc

    贪吃蛇C语言课程设计报告 贪吃蛇游戏设计 姓名: 张力 学号: 完成日期: 月 日 一.设计目的 贪吃蛇游戏程序功能的实现主要是建立在二维数组和图形界面的应用上,通过编写游戏程序能够熟悉掌握相关数组和 ...

  9. 贪吃蛇_C语言_链表实现_SCAU课程设计

    个人大一下课程设计作品,本文中直接附上源代码(通过visual stdio 2019 实现  ): 课题:贪吃蛇(链表实现~) 语言:C/C++ 运行环境(软件):Visual Stdio 2019( ...

最新文章

  1. 分上下半月统计 SQL
  2. java实现人脸识别源码【含测试效果图】——Dao层(IUserDao)
  3. mysql去重取最大值,逻辑类似oracle的over(partition by)函数
  4. Spring --getBean用法
  5. 拼装机器人感想_学习制作机器人的感想作文500字15篇
  6. Linux防火墙-netfilter-iptables
  7. jest单元测试-作用域
  8. mysql用身份证号判断男女_如何根据身份证号码辨别性别呢
  9. android微信红包提醒,微信红包提醒怎么设置 微信红包提醒设置教程
  10. 【SharePoint】SharePoint页面中添加webpart时提示找不到类型或该类型未注册为安全类型解决方案
  11. Python入门:数据结构之字典(dict)(1)
  12. 那些年的广告语【持续更】
  13. 剩余电流动作继电器在浴室中的应用
  14. 医学统计学笔记之设计
  15. 机器人 铁血兵团 魂斗罗_【魂斗罗铁血兵团中文版】魂斗罗铁血兵团中文版下载-街机中国...
  16. 拜读刘天斯的一个开源项目
  17. 代码注释规范之Doxygen
  18. 人脸检测和行人检测2:YOLOv5实现人脸检测和行人检测(含数据集和训练代码)
  19. 协同过滤-SSM服装在线购买购物商城(SSM,JSP,Bootstrap,MYSQL)
  20. OpenDDS开发人员指南中文版3.23(1)简介

热门文章

  1. 高数巨占座问题(c语言)
  2. 【locust】通过ip访问失败
  3. 恶劣天气中如何拍摄360全景图片?
  4. python系列教程143——行缩进
  5. kingcms修改笔记
  6. Go语言if条件判断
  7. POI设置word 2007文本下划线样式及文字底纹
  8. C++基础入门(超详细)
  9. jeefast使用Mybatis进行图片上传
  10. JavaScript闭包的粗浅理解