贪吃蛇游戏制作

news2024/9/23 5:34:17

目录

  • 前言

  • 游戏设计

  • 游戏三部曲

  • 函数说明

  • 优化设计

1

前言

    终极目标:打造酷炫贪吃蛇游戏

    制作环境:   

     VS2015(支持VC++2010,VS各个版本)           

     easyx图形库(稍微改下VC6.0也可以实现)

 

2

游戏设计

贪吃蛇的制作思路就是蛇头带动蛇尾移动,主要还是看蛇头和蛇头的下一个位置。蛇头的下一个位置只有空地,墙,食物,和自己的身体。

普通模式:蛇头的下一个位置是墙、自己的身体,游戏gameover!

穿墙模式:蛇头的下一个位置是自己的身体,游戏gameover!蛇头的下一个位置是墙,将下一个位置换成墙另一边的空地(这个时候蛇头带动蛇尾移动就不需要考虑那么多了)。

无敌模式:可穿墙,咬到自己的身体也可以继续游戏(屏蔽了gameover功能)。

我们先来分析蛇头下一个位置的可能结果

  • 空地

图片

蛇头当然是直接过去

 case SPACE://直接移动

    map[snake[SnakeSize - 1].X][snake[SnakeSize - 1].Y] = SPACE;//地图蛇尾所在地置空    for (int i = SnakeSize - 1; i > 0; i--)            //蛇尾到蛇头整体移动一位    {      snake[i] = snake[i - 1];    }    map[snake[0].X][snake[0].Y] = SNAKE;            //蛇头置 蛇    snake[0] = next;                      //将下一个位置赋值给蛇头    map[snake[0].X][snake[0].Y] = HEAD;              //设置头    break;

图片

普通模式就直接gameover了,穿墙模式就需要设计蛇头的下一个为墙另一边的空地,然后蛇头带动蛇尾移动过去。

case WALL:    if (mode)    //模式1模式2可穿墙    {      map[snake[SnakeSize - 1].X][snake[SnakeSize - 1].Y] = SPACE;//蛇尾置空      for (int i = SnakeSize - 1; i > 0; i--)            //蛇尾到蛇头整体移动一位      {        snake[i] = snake[i - 1];      }      map[snake[0].X][snake[0].Y] = SNAKE;            //蛇头置 蛇      switch (SnakeDir)                      //穿墙      {      case'A':next.Y = COL - 2; break;      case 'D':next.Y = 1; break;      case 'W': next.X = ROW - 2; break;      case 'S':next.X = 1; break;      default:        break;      }      snake[0] = next;                      //蛇头移动到新位置      map[snake[0].X][snake[0].Y] = HEAD;              //新的蛇头所在的位置    }    else {      MessageBox(GetHWnd(), L"游戏结束", L"SORRY", MB_OK);      exit(0);    }    break;
  • 食物

图片

蛇吃掉食物,身体变长,然后重新出现一个食物

case FOOD://食物        蛇尾不变    for (int i = SnakeSize; i > 0; i--)              //蛇尾到蛇头整体移动一位    {      snake[i] = snake[i - 1];                    }    map[snake[0].X][snake[0].Y] = SNAKE;            //蛇头 置 蛇    snake[0] = next;                      //将下一个位置赋值给蛇头    score++;      //分数加一            (SnakeSize)++;    //蛇尺度加一    map[snake[0].X][snake[0].Y] = HEAD;              //地图上重置蛇头    addfood();    break;

 

  • 身体

图片

普通模式,穿墙模式gameover!无敌模式,就屏蔽掉gameover功能

case SNAKE:    if (mode == 2)    //模式二无敌    {      break;    }    else {      MessageBox(GetHWnd(), L"游戏结束", L"SORRY", MB_OK);      exit(0);    }    break;
  • 还有就是方向,当蛇往右走的时候你不能将方向变成向左。

  case'A':  case'a':  case 75:    if (SnakeDir != 'D') SnakeDir = 'A';  //蛇不能后退    break;

  • 添加食物

食物出现的地方只能是空地,不能出现在墙上,自己的身体上

void addfood(){  int row, col;  do  {      row = rand() % (ROW - 1) + 1;    col = rand() % (COL - 1) + 1;  } while (map[row][col] != SPACE); //当map[row][col]为空地时结束循环  map[row][col] = FOOD;              //空地变食物}

大致思路就是这个样子滴,贪吃蛇就是判断蛇头的下一个位置是什么东西,然后分别考虑。需要区分的是地图有一个数组map存放,蛇有另外一个数组snake存放蛇的位置(为了控制蛇的移动)。

3

游戏三部曲

1、加载游戏数据(初始化    init();)

2、绘制图形(绘图    DrawMap();)

3、玩家操作(数据更新 move();ChangeDir();)

init();    //初始化游戏

while(1)

{

    DrawMap();    //绘制游戏
    move();            //数据更新

}

先把大纲列出来

 

01

主函数 main()

定义两个时间控制移动速度

DWORD t1, t2;

主函数将大致思路拟好​​​​​​​

int main(){  initgraph(640, 480);  //窗口大小  init();               //初始化  while (1)  {    DrawMap();    if (kbhit())    {      ChangeDir();      move();      t2 = GetTickCount();  //从新获取时间,为了更好的游戏体验      t1 = t2;    }    t2 = GetTickCount();  //不断获取时间,控制移动速度    if (t2 - t1 > 50)    {      move();      t1 = t2;    }  }  closegraph();  return 0;}

然后呢需要定义一些变量来管理

#define ROW 46#define COL 64//枚举enum game{  SPACE, WALL, SNAKE, FOOD, HEAD//空地  墙  蛇  食物};/************全局变量************/int mode = 0;      //游戏模式int score = 0;     //分数DWORD t1, t2;      //定义两个时间控制移动速度int map[ROW][COL];    //地图大小COORD snake[1024];    //蛇      typedef struct _COORD {SHORT X;SHORT Y;} COORD, *PCOORD;size_t SnakeSize;    //蛇的尺度    typedef unsigned int     size_t;char SnakeDir;      //蛇移动方向

02

初始化函数 init()

我们需要初始化那些东西呢!

  1. 初始化地图,将墙给定义出来

  2. 地图上初始化蛇的位置,先来条小蛇3个格子

  3. 初始化蛇的一些属性,长度,方向,还有游戏分数

  4. 添加食物

void init(){  srand((unsigned)time(NULL));  setbkcolor(WHITE);  //设置背景颜色
  memset(map, SPACE, sizeof(map));  //每一行的 第一个 和 最后一个 是墙  for (int i = 0; i < ROW; i++)  {    map[i][0] = map[i][COL - 1] = WALL;  }  //每一列的 第二个 和 倒数第二 个是墙  for (int j = 1; j < COL - 1; j++)  {    map[0][j] = map[ROW - 1][j] = WALL;  }  //定义蛇头和蛇的身体  map[3][5] = HEAD;  map[3][4] = map[3][3] = SNAKE;  //初始化蛇  SnakeSize = 3;  //蛇 长  SnakeDir = 'D';  //蛇方向向右  snake[0].X = 3;  snake[0].Y = 5;  snake[1].X = 3;  snake[1].Y = 4;  snake[2].X = 3;  snake[2].Y = 3;  addfood();}

03

绘图函数 DrawMap()

绘制地图就用填充矩形绘图函数fillrectangle();这样可以填充一些颜色,让蛇看起来很nice,梦凡还将蛇头弄成彩色的,感觉逼味十足。地图上的空地,食物,蛇墙用来枚举,这样表达起来很清楚。

void DrawMap(){  BeginBatchDraw();  //开始绘图  setbkcolor(WHITE);  //设置背景颜色为白色  settextcolor(RGB(238,0,0));  cleardevice();    //清屏  WCHAR arr[10];    //保存成绩  wsprintf(arr, L"总分:%d", score);  //将成绩格式化输出到字符串arr中   outtextxy(0, 0, arr);        //显示成绩  for (int y = 0; y < ROW; y++)    //y轴方向向下  {    for (int x = 0; x < COL; x++)  //x轴方向下上    {      switch (map[y][x])      {      case SPACE:        break;      case WALL:        setlinecolor(BLACK);          setfillcolor(RGB(238, 233, 233));  //灰色        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);        break;      case SNAKE:        setlinecolor(RGB(0, 245, 255));    //绿色         setfillcolor(WHITE);        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);        break;      case HEAD:        //画七彩蛇头        switch (rand() % 7)        {        case 0:          setfillcolor(RGB(255, 0, 0));    //红色 255 0 0          solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        case 1:          setfillcolor(RGB(255, 165, 0));    //橙  255 165 0           solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        case 2:          setfillcolor(RGB(255, 255, 0));    //黄  255 255 0          solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        case 3:          setfillcolor(RGB(0, 255, 0));    //绿色  0, 255, 0          solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        case 4:          setfillcolor(RGB(0, 255, 255));    //青  0 255 255          solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        case 5:          setfillcolor(RGB(0, 0, 255));    //蓝  0 0 255          solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        case 6:          setfillcolor(RGB(160, 32, 240));  //紫  160 32 240          solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);          break;        default:          break;        }        break;      case FOOD:        setfillcolor(RGB(255, 0, 0));      //红色        solidrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);        break;      default:        break;      }    }  }  EndBatchDraw();}

04

数据更新函数 move()

数据更新,不断获取玩家操作,蛇每隔0.05s移动一次

  • 先来获取玩家操作

void ChangeDir(){  switch (getch())  {  case'A':  case'a':  case 75:    if (SnakeDir != 'D') SnakeDir = 'A';  //蛇不能后退    break;  case'D':  case'd':  case 77:    if (SnakeDir != 'A') SnakeDir = 'D';    break;  case'W':  case'w':  case 72:    if (SnakeDir != 'S') SnakeDir = 'W';    break;  case'S':  case's':  case 80:    if (SnakeDir != 'W') SnakeDir = 'S';    break;  case 32:    getch();    break;  default:    break;  }}

  • 蛇的移动,需要先判断蛇头的下一个位置是什么

  COORD next;    //蛇头的下一个位置  switch (SnakeDir)  {  case'A':    next.X = snake[0].X;    next.Y = snake[0].Y - 1;    break;  case'W':    next.X = snake[0].X - 1;    next.Y = snake[0].Y;    break;  case'D':    next.X = snake[0].X;    next.Y = snake[0].Y + 1;    break;  case'S':    next.X = snake[0].X + 1;    next.Y = snake[0].Y;    break;  default:    break;  }

  • 然后根据下一个位置进行相应的匹配,开头已经说明了各项功能,这里就不列举了。​​​​​​​

switch (map[next.X][next.Y])  {  case SPACE://直接移动    break;  case WALL:    break;  case SNAKE:    break;  case FOOD://食物        蛇尾不变    break;  default:break;  }

4

函数说明

  • 先来介绍一个easyx提供的结构体COORD,很简单

typedef struct _COORD {SHORT X;SHORT Y;} COORD, *PCOORD;
  • 用的还算多的变量    size_t

typedef unsigned int     size_t;  //保证变量为正整数
  • 获取时间的函数 GetTickCount();

返回值为DWORD类型

typedef unsigned long       DWORD;

特点:精准度高

5

程序打包

为什么需要程序打包?

当你的程序有依赖库,各种素材文件时需要打包保证用户不会因为失误删掉一些对程序有影响的文件。

图片

6

优化设计

优化的话就是利用链表代替数组来创作贪吃蛇,数组有局限性,定义了多大就多大,本程序定义的是1024,如果哪位小伙伴分数达到了1024分就会出现Bug。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/759043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记一次linux服务器k8s服务失败,重新安装centos系统并部署k8s以及服务【2023年7月15日】

周五&#xff0c;突然收到微信消息说&#xff1a;兄嘚~ 网站无法访问了&#xff01; 我以为就是普通的小问题&#xff0c;连上服务器看报错呢&#xff0c;执行kubectl get nodes [rootnode101 ~]# kubectl get nodes The connection to the server 127.0.0.1:6443 was refused…

FL Studio 21具有哪些功能?flstudio21会有什么新功能

FL Studio 21 是一个功能完备的音乐制作环境&#xff0c;能够进行多轨道音频录制、音序处理和混音&#xff0c;可以帮助用户创作专业质量的音乐轨道。 借助 VST 托管、灵活的混音器、高级 MIDI 和 ReWire 支持&#xff0c;您将轻松驾驭各种音乐风格。 歌曲或循环可以导出为 .wa…

[QT编程系列-15]: 基础框架 - 信号与槽,connect函数详解

目录 一、线程内不同对象的通信 1.1 connect函数介绍 1.2 connect的用法 1.3 代码示例 二、不同线程间不同对象的通信 2.1 概述 2.2 代码案例 一、线程内不同对象的通信 1.1 connect函数介绍 在使用 Qt 框架进行开发时&#xff0c;connect 函数是用于建立信号与槽机…

hadoop -- Hbase

HBase是一个分布式、可扩展、面向列的数据存储&#xff08;百万级别列&#xff09;、可伸缩、高可靠性、实时读写的NoSQL 数据库。 HBase利用 Hadoop的 HDFS作为其文件存储系统&#xff0c; 利用MapReduce 来处理HBase中的海量数据&#xff0c; 利用Zookeeper作为分布式协同服…

AIGC之文本内容生成概述(下)——Transformer

在上一篇文章中&#xff0c;我们一口气介绍了LSTM、Word2Vec、GloVe、ELMo等四种模型的技术发展&#xff0c;以及每种模型的优缺点与应用场景&#xff0c;全文超过一万字&#xff0c;显得冗长且繁杂&#xff0c;在下文部分我们将分开介绍Transformer、BERT、GPT1/GPT2/GPT3/Cha…

electron+vue3全家桶+vite项目搭建【23】url唤醒应用,并传递参数

文章目录 引入实现效果实现步骤测试代码 引入 demo项目地址 很多场景下我们都希望通过url快速唤醒应用&#xff0c;例如百度网盘&#xff0c;在网页中唤醒应用&#xff0c;并传递下载链接&#xff0c;在electron中要实现这样的效果&#xff0c;就需要针对不同的平台做对应的处…

SpringMVC【SpringMVC拦截器、 SpringMVC跨域请求、SSM整合】(七)-全面详解(学习总结---从入门到深化)

目录 SpringMVC拦截器_拦截器过滤敏感词案例 SpringMVC跨域请求_同源策略 SpringMVC跨域请求_跨域请求 SpringMVC跨域请求_控制器接收跨域请求 SSM整合_需求分析 SSM整合_创建父工程 SSM整合_创建dao子工程 SSM整合_创建service子工程 SSM整合_创建controller子工程 …

Gradle和Aritifactory,实现上传Apk并发送消息到钉钉

Gradle和Aritifactory 本文链接&#xff1a;https://blog.csdn.net/feather_wch/article/details/131746580 文章目录 Gradle和AritifactoryGradle基本介绍Gradle插件开发流程本地仓库artifactory搭建添加仓库使用本地仓库gradle插件仓库引入 插件buildSrc开发步骤xxxPluginPg…

【力扣周赛】第 354 场周赛

文章目录 Q1&#xff1a;6889. 特殊元素平方和思路——简单模拟题竞赛时代码 Q2&#xff1a;6929. 数组的最大美丽值思路——差分数组&#xff0c;计算每个数字可能出现的次数竞赛时代码 Q3&#xff1a;6927. 合法分割的最小下标思路——投票法求出现次数超过半数的元素 模拟竞…

dede tag彩色随机大小的样式修改方法

dede tag彩色随机大小的样式修改方法&#xff0c;打开include/common.func.php 在最下面添加以下代码&#xff1a; //TAG彩色 jinmengqiang.cn function getTagStyle() { $minFontSize8; //最小字体大小,可根据需要自行更改 $maxFontSize18; //最大字体大小,可根据需要自行更改…

(中等)剑指Offer II 062.实现前缀树 Java

Trie&#xff0c;又称前缀树或字典树&#xff0c;是一棵有根树&#xff0c;其每个节点包含以下字段&#xff1a; 指向子节点的指针数组children&#xff0c;对于本题而言&#xff0c;数组长度为26&#xff0c;即小写英文字母的数量。此时children[0]对应着小写字母a&#xff0…

数据结构(王道)——队列

一、队列的定义 三个重要名词&#xff1a;队头、队尾、空队列。 二、队列的基本操作 队列总结&#xff1a; 三、队列的顺序表实现 基本操作&#xff1a; 静态创建队列顺序表 队列顺序表的初始化操作&#xff1a; 入队操作&#xff1a; 入队操作优化&#xff1a; 最优版入队操作…

Navicat-Cracker NavicatCrackerDlg.cpp:332 -3已解决Navicat 162版本注册问题的详细分析与解决方案

博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;&#x1f3fb; 《java 面试题大全》 &#x1f369;惟余辈才疏学浅&#xff0c;临摹之作或有不妥之处&#xff0c;还请读者海涵指正。☕&#x1f36d; 《MYSQL从入门到精通》数据库是开发者必会基础之…

一零六五、零基础入门数据挖掘-心跳信号分类预测(阿里云天池赛)

目录 赛制官方链接 赛题简介 赛制说明 长期赛&#xff08;2021年7月&#xff5e;&#xff09; 正式赛&#xff08;3月12日 - 5月12日&#xff09; 大赛组织 赛题背景 赛题数据 评测标准 结果提交 代码实现 赛制官方链接 零基础入门数据挖掘-心跳信号分类预测_学习赛_…

哈希表以及用js封装一个哈希表

最近在学数据结构和算法&#xff0c;正好将学习的东西记录下来&#xff0c;我是跟着一个b站博主学习的&#xff0c;是使用js来进行讲解的&#xff0c;待会也会在文章后面附上视频链接地址&#xff0c;大家想学习的可以去看看 本文主要讲解哈希表&#xff0c;其他数据结构后续学…

轻松入门Python量化交易(三)

大家好&#xff0c;我们接第二部分继续分析金融数据。 配对图和相关矩阵 证券中的相关性分析为我们提供了有趣的投资策略。市场中一个广为人知的策略叫做“Long-Short”&#xff0c;即买入一家公司的证券&#xff0c;同时卖出另一家公司的证券&#xff0c;相信这两个资产在市…

《微服务架构设计模式》第八章 外部API模式

内容总结自《微服务架构设计模式》 外部API模式 一、API设计难题二、API Gateway 模式1、简介2、所有者模式3、好处和弊端4、设计问题5、实现一个API Gateway 三、使用GraphQL 实现API Gateway四、总结 一、API设计难题 1、移动客户端的API设计难题 在此设计中&#xff0c;移动…

动态规划(二) —— 打家劫舍系列问题总结

前言 除了背包系列问题&#xff0c;打家劫舍系列问题同样也是动态规划的经典题目。在这篇文章中荔枝将会把打家劫舍系列问题做一下总结&#xff0c;再仔细体会动态规划的思想&#xff0c;希望能帮到有需要的小伙伴~~~ 文章目录 前言 一、Leecode198.打家劫舍 1.1 分析 1.2 …

C2C、B2B、B2C、O2O电商定义区别

如今是电子商务高度发展的时代&#xff0c;大多数传统企业商家都开始采取转型战略帮助企业发展&#xff0c;商业模式的选择是转型的关键点&#xff0c;下面小编向你详细介绍一下B2B、B2C、C2C、O2O这些商务模式&#xff0c;帮助你快速理解它们。 BBusiness&#xff0c;即企业;…

Servlet实现文件下载的功能

download.html <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head><title>文件下载</title><base href"<%request.getContextPath()"/"%>>"> </head>…