贪吃蛇小游戏-----C语言实现
1.分析
众所周知,贪吃蛇游戏是一款经典的益智游戏,有PC和手机等多平台版本,既简单又耐玩。该游戏通过控制蛇头方向吃食物,从而使得蛇变得越来越长,蛇不能撞墙,也不能装到自己,否则游戏结束。玩过贪吃蛇的朋友都知道这个小游戏有一圈“墙”、还有食物以及蛇,还有吃了食物之后的分数。所以通过C语言实现贪吃蛇,可以分为以下几个模块来实现:
a)编程实现“墙”
b)实现随机食物的生成
c)蛇的构建
d)以上三部分都实现了之后,实现游戏运行的部分,包括蛇的移动、吃食物、判断是否撞墙或者撞到自己。
e)游戏结束时的相关操作
2.具体思路
要通过C语言实现贪吃蛇,首先就要用C语言将贪吃蛇的相关信息描述出来。C语言提供了结构体类型,我们可以用结构体描述蛇的结点(结点的横纵坐标)、运动状态、总分数、每个食物的分数等等。
首先实现进入游戏的"welcome"界面,为了将“欢迎来到贪吃蛇游戏”打印到屏幕的中间,可以运用库函数先设置窗口的大小(system("mode con cols=100 lines=30");将窗口设置为长100,宽30),再通过库函数中的GetStdHandle函数、SetConsoleCursorPosition函数(把光标定位到我们需要的位置)将这句话打印到屏幕中央。
其次可以通过相同的方法将光标固定到我们需要的位置,用特殊字符‘■’打印实现墙(注意,‘■’在c中占用两个字符,所以在设置循环条件时要格外注意)
接着通过编程实现蛇的移动,本文中蛇是通过单链表实现的,因此在实现蛇的移动时,如果蛇接下来走的位置(上下左右)为食物,将这个位置的用指针表示,可以将食物头插到用_psnake指针维护的蛇身中,如果接下来的位置不是食物,同样头插到蛇身中,再将蛇的最后一个结点打印时输出为空格字符,然后free最后一个节点。
3.代码如下
snake.h:
#pragma once #include<Windows.h>
#include<stdio.h>
#include<time.h>
#include<stdlib.h> #define WALL "■"
#define FOOD "●" #define INIT_X 20
#define INIT_Y 18
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode *next;
}SnakeNode, *pSnakeNode; //蛇的方向
enum Diretion
{
UP,
DOWN,
LEFT,
RIGHT
}; //状态
enum GameState
{
OK,
NORMAL_END,
KILL_BY_WALL,
KILL_BY_SELF
};
//游戏结构体
typedef struct Snake
{
pSnakeNode _psnake;//维护蛇身的指针
pSnakeNode _pFood;//维护食物的位置
int _TotalScore;//总分数
int _AddScore;//增加的分数
int _SleepTime;//休眠时间
enum Direction _Dir;
enum GameStatus _Status;
}Snake, *pSnake; void GameStart(pSnake ps);
void WelcomeToGame();//欢迎界面函数
void SetPos(int x, int y);
void CreateMap();//创建地图
void InitSnake(pSnake ps);
void CreateFood(pSnake ps);//创建食物
void GameRun(pSnake ps);//运行游戏
void pause();//暂停函数 void snakmove(pSnake ps);
int NextHasFood(pSnakeNode pn, pSnakeNode pf);//判断下个结点是否为食物
void EatFood(pSnake ps,pSnakeNode pn);//吃食物
void NoFood(pSnake ps, pSnakeNode pn);//没有食物
void KillBYWALL(pSnake ps);
void KillBySelf(pSnake ps);
void GameEnd(pSnake ps);
snake.c:
#include"snake.h"
void SetPos(int x, int y)
{
COORD pos = { };
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
pos.X = x; pos.Y = y;
SetConsoleCursorPosition(handle, pos);//把光标定位到我们需要的位置了
}
void WelcomeToGame()//欢迎界面函数
{
//设置窗口大小
system("mode con cols=100 lines=30");
SetPos(, );//分装的函数用来定位光标
printf("欢迎来到贪吃蛇小游戏\n");
SetPos(, );
system("pause");//暂停
system("cls");//清空屏幕
SetPos(, );
printf("用↑,↓,←,→来控制蛇的移动,F1为加速,F2为减速\n");
SetPos(, );
printf("加速获得分数更多\n");
SetPos(, );
system("pause");
system("cls");
} void CreateMap()
{
int i = ;
//上
for (i = ; i <= ; i += )
{
SetPos(i, );
printf(WALL);
}
//下
for (i = ; i <= ; i += )
{
SetPos(i, );
printf(WALL);
}
//左
for (i = ; i <= ; i++)
{
SetPos(, i);
printf(WALL);
}
//右
for (i = ; i <= ; i++)
{
SetPos(, i);
printf(WALL);
}
}
pSnakeNode BuyNode()
{
pSnakeNode pRet = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pRet == NULL)
{
perror("BuyNode::malloc()");
exit(EXIT_FAILURE);
}
pRet->x = ;
pRet->y = ;
pRet->next = NULL;
return pRet;
}
void InitSnake(pSnake ps)
{
pSnakeNode first = BuyNode();//创建蛇头
pSnakeNode cur = NULL;
first->x = INIT_X;
first->y = INIT_Y;
int i = ;
for (i = ; i <= ; i++)
{
cur = BuyNode();//创建蛇身
cur->x = first->x + ;
cur->y = first->y;
cur->next = first;
first = cur;
}
//打印蛇
while (cur)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
ps->_psnake = first;
} void CreateFood(pSnake ps)
{
pSnakeNode pfood = BuyNode();
pSnakeNode cur = ps->_psnake;
pfood->y = rand() % + ;
do
{
pfood->x = rand() % + ;//0-54,+2产生2-56
} while (pfood->x % != );
while (cur)
{
if (cur->x == pfood->x&&cur->y == pfood->y)
{
CreateFood(ps);
}
cur = cur->next;
}
ps->_pFood = pfood;
SetPos(pfood->x, pfood->y);
printf(FOOD);
} void GameStart(pSnake ps)
{
//打印欢迎界面
WelcomeToGame();
//创建地图,画墙
CreateMap();
//初始化蛇
InitSnake(ps);
//初始化食物
CreateFood(ps);
//游戏运行
ps->_AddScore = ;//每次增加的分数
ps->_TotalScore = ;//总分
ps->_Dir = RIGHT;//方向
ps->_SleepTime = ;//0.2秒
ps->_Status = OK;//状态
} void pause()//暂停函数
{
while ()
{
Sleep();
if (GetAsyncKeyState(VK_SPACE))
{
return;
}
}
} int NextHasFood(pSnakeNode pn, pSnakeNode pf)
{
return (pn->x == pf->x) && (pn->y == pf->y);
} void EatFood(pSnake ps, pSnakeNode pn)//吃食物
{
pSnakeNode cur = NULL;
pn->next = ps->_psnake;//头插
ps->_psnake = pn;
cur = ps->_psnake;
ps->_TotalScore += ps->_AddScore;
while (cur)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
CreateFood(ps);
} void NoFood(pSnake ps, pSnakeNode pn)//没有食物
{
pSnakeNode cur = NULL;
pn->next = ps->_psnake;//头插
ps->_psnake = pn;
cur = ps->_psnake;
while (cur->next->next)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
SetPos(cur->x, cur->y);
printf(FOOD);
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;
} void snakmove(pSnake ps)//蛇的移动
{
pSnakeNode pNextNode = BuyNode();
SetPos(, );
printf("总分:%d", ps->_TotalScore);
SetPos(, );
printf("每个食物的得分:%d ", ps->_AddScore);
//上
switch (ps->_Dir)
{
case UP:
{
pNextNode->x = ps->_psnake->x;
pNextNode->y = ps->_psnake->y - ;
if (NextHasFood(pNextNode,ps->_pFood))
{
//下一个节点是食物
EatFood(ps,pNextNode);
}
else
{
NoFood(ps,pNextNode);
}
break;
}
case DOWN:
{
pNextNode->x = ps->_psnake->x;
pNextNode->y = ps->_psnake->y + ;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
case LEFT:
{
pNextNode->x = ps->_psnake->x-;
pNextNode->y = ps->_psnake->y;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
case RIGHT:
{
pNextNode->x = ps->_psnake->x+;
pNextNode->y = ps->_psnake->y ;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
default:
{
break;
}
}
} void KillBYWALL(pSnake ps)
{
if ((ps->_psnake->x == ) ||
(ps->_psnake->x == ) ||
(ps->_psnake->y == ) ||
(ps->_psnake->y == ))
{
ps->_Status = KILL_BY_WALL;
}
} void KillBySelf(pSnake ps)
{
pSnakeNode tnext = ps->_psnake->next;
while (tnext)
{
if ((tnext->x == ps->_psnake->x) && (tnext->y == ps->_psnake->y))
{
ps->_Status = KILL_BY_SELF;
return;
}
tnext = tnext->next;
} }
void PrintHelpInfo()
{
SetPos(, );
printf("用↑,↓,←,→来控制蛇的移动");
SetPos(, );
printf("F1为加速,F2为减速\n");
SetPos(, );
printf("加速获得分数更多\n");
SetPos(, );
printf("按空格暂停游戏\n"); } void GameEnd(pSnake ps)
{
pSnakeNode cur = ps->_psnake;
SetPos(, );
if (ps->_Status == NORMAL_END)
{
SetPos(, );
printf("游戏正常接结束\n");
SetPos(, );
}
else if (ps->_Status == KILL_BY_SELF)
{
SetPos(, );
printf("蛇撞到自己了\n");
SetPos(, );
}
else if (ps->_Status == KILL_BY_WALL)
{
SetPos(, );
printf("撞到墙了\n");
SetPos(, );
}
while (cur)
{
pSnakeNode del = cur;
cur = cur->next;
free(del);
del = NULL;
}
ps->_psnake = NULL;
free(ps->_pFood);
ps->_pFood = NULL;
} void GameRun(pSnake ps)
{
PrintHelpInfo();
do
{
//确定方向
if (GetAsyncKeyState(VK_UP)&&(ps->_Dir!=DOWN))
{
ps->_Dir = UP;
}
else if (GetAsyncKeyState(VK_DOWN) && ps->_Dir != UP)
{
ps->_Dir = DOWN;
}
else if (GetAsyncKeyState(VK_LEFT) && ps->_Dir != RIGHT)
{
ps->_Dir = LEFT;
}
else if (GetAsyncKeyState(VK_RIGHT) && ps->_Dir != LEFT)
{
ps->_Dir = RIGHT;
}
else if (GetAsyncKeyState(VK_SPACE))
{
//暂停游戏
pause();
}
else if (GetAsyncKeyState(VK_ESCAPE))
{
//结束游戏
ps->_Status = NORMAL_END;
break;
}
else if (GetAsyncKeyState(VK_F1))
{
//加速
if (ps->_SleepTime >= )
{
ps->_SleepTime -= ;
ps->_AddScore += ;
}
}
else if (GetAsyncKeyState(VK_F2))
{
//减速
if (ps->_SleepTime <= )
{
ps->_SleepTime += ;
ps->_AddScore -= ;
}
if (ps->_SleepTime > )
{
ps->_AddScore = ;//不能一直减
}
}
Sleep(ps->_SleepTime);//睡眠
//蛇的移动
snakmove(ps);
KillBYWALL(ps);
KillBySelf(ps);
} while (ps->_Status == OK);
}
test.c:
#include"snake.h" void test()
{
srand((unsigned)time(NULL));
Snake snake = { };//创建贪吃蛇
GameStart(&snake);
GameRun(&snake);
GameEnd(&snake);
} int main()
{
test();
system("pause");
return ;
}
贪吃蛇小游戏-----C语言实现的更多相关文章
- C++ 简单的控制台贪吃蛇小游戏
由于比较懒,所以不怎么写,觉得这样不应该.我应该对自己学的做出整理,不管是高端低端,写出来是自己的. // 贪吃蛇.cpp : 定义控制台应用程序的入口点. // #include "std ...
- JS高级---案例:贪吃蛇小游戏
案例:贪吃蛇小游戏 可以玩的小游戏,略复杂,过了2遍,先pass吧 先创建构造函数,再给原型添加方法.分别创建食物,小蛇和游戏对象. 食物,小蛇的横纵坐标,设置最大最小值,运动起来的函数,按上下左右键 ...
- Java GUI学习,贪吃蛇小游戏
JAVA GUI练习 贪吃蛇小游戏 前几天虽然生病了,但还是跟着狂神学习了GUI的方面,跟着练习了贪吃蛇的小项目,这里有狂神写的源码点我下载,还有我跟着敲的点我下载,嘿嘿,也就注释了下重要的地方,这方 ...
- 用GUI实现java版贪吃蛇小游戏
项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public static void main(String[] args) { JFrame jFr ...
- Java 用java GUI写一个贪吃蛇小游戏
目录 主要用到 swing 包下的一些类 上代码 游戏启动类 游戏数据类 游戏面板类 代码地址 主要用到 swing 包下的一些类 JFrame 窗口类 JPanel 面板类 KeyListener ...
- html5面向对象做一个贪吃蛇小游戏
canvas加面向对象方式的贪吃蛇 2016-08-25 这个小游戏可以增加对面向对象的理解,可以加强js逻辑能力,总之认真自己敲一两遍收获还是不少啊!!适合刚学canvas的同学练习!! 废话不多说 ...
- 用python+pygame写贪吃蛇小游戏
因为python语法简单好上手,前两天在想能不能用python写个小游戏出来,就上网搜了一下发现了pygame这个写2D游戏的库.了解了两天再参考了一些资料就开始写贪吃蛇这个小游戏. 毕竟最开始的练手 ...
- Java贪吃蛇小游戏
贪吃蛇 思路 首先构思游戏布局,计算合理的坐标系. 绘制静态数据(广告.初始小蛇.提示信息.棋盘) 添加键盘监听事件,改变游戏状态以及小蛇运动方向 添加定时器,让小蛇在一段时间内移动一定的距离 随机产 ...
- JavaScript-简单的贪吃蛇小游戏
实现逻辑: //获取Html中的格子(行,列) //建立数组存储所有格子(x,y) //建立数组用于存储蛇身(x,y) //生成随机坐标(x,y)的函数 //随机创建蛇身并存储到蛇身数组 //创建食物 ...
随机推荐
- Phantomjs 生成多页PDF
开篇 最近使用 Phantomjs 生成PDF,其中遇到一些问题,导致PDF生成失败,如出现空白文件或一页数据量太大,都是由于没有设置好格式导致.特别是分页问题,感觉资料很少,除了在 StackOve ...
- 2018.10.12 NOIP模拟 棋盘问题(切比雪夫距离)
传送门 貌似是防ak题? 考试的时候想到了做四次cdqcdqcdq于是给自己多套了一个lognlognlogn结果还MLEMLEMLE 0分.(记得最后5分钟调出来的时候是那么的欣喜 下来发现并不需要 ...
- 2018.09.02 bzoj1025: [SCOI2009]游戏(计数dp+线筛预处理)
传送门 要将所有置换变成一个轮换,显然轮换的周期是所有置换长度的最小公倍数. 于是我们只需要求长度不超过n,且长度最小公倍数为t的不同置换数. 而我们知道,lcm只跟所有素数的最高位有关. 因此lcm ...
- Django入门与实践-第24章:我的账户视图(完结)
http://127.0.0.1:8000/settings/account/ #好的,那么,这部分将是我们最后的一个视图.之后,我们将专心来改进现有功能. #accounts/views.py fr ...
- php文件上传代码解析
php文件上传代码解析 is_uploaded_file() //函数判断指定的文件是否是通过 HTTP POST 上传的,返回一个布尔值. $_FILES['upfile']['tmp_name' ...
- 2) 下载Maven
http://maven.apache.org/ http://maven.apache.org/download.cgi Maven 3.3.3 (Binary tar.gz) Maven 3.3. ...
- 主程序与DLL之间的全局变量问题
http://www.cnblogs.com/railgunman/archive/2010/11/29/1891200.html 主程序与DLL之间的全局变量问题 有几个朋友经常向我问题在DLL ...
- ASP.NET MVC+Redis (准备工作)
今天准备更新这个项目的第二篇博客.有一点需要说明的是之前觉得用的是Asp.net的WebPage,经过查看微软的官方文档还有相关的博客,相比较而言使用起来需要安装一个自动工具WebMatrix可以很快 ...
- vs 2015 结合新配置的IIS 发布网站过程中遇到的问题及解决办法?
1.由于扩展配置问题而无法提供您请求的页面.如果该页面是脚本,请添加处理程序 错误: HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面.如果该页面是脚本,请添 ...
- [工具]JSON校验、转换在线工具
1. 在线JSON代码检验.检验.美化.格式化工具[简单易用的格式化工具]: http://tools.jb51.net/code/json 2. JSON在线格式化工具[代码高亮及可控缩进大小的格式 ...