贪吃蛇小游戏-----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)的函数 //随机创建蛇身并存储到蛇身数组 //创建食物 ...
随机推荐
- part1:10-TFTP与NFS服务器配置
1.交叉开发 嵌入式系统开发多采用交叉开发模式,所谓嵌入式交叉开发就是指在宿主机上进行程序的编写,然后通过交叉编译生成目标机平台可以运行的二进制代码,最后再下载到目标平台上的特定位置运行.产生嵌入式软 ...
- KbmMW 4.50.00 测试版发布
We are happy to announce the release of kbmMW v. 4.50.00 Beta Professional and Enterprise Edition wi ...
- 第一个Django应用
Django教程:http://www.liujiangblog.com/course/django/2 第一个Django应用 该应用包括以下两个部分: 一个可以让公众用户进行投票和查看投票结果的站 ...
- 在“开始”菜单中的“运行”一栏输入特定命令打开windows程序
winver 检查Windows版本 wmimgmt.msc 打开Windows管理体系结构(wmi) wupdmgr Windows更新程序 wscript Windows脚本宿主设置 ...
- gj12-1 协程和异步io
1 并发.并行.同步.异步.阻塞.非阻塞 并发.并行 并发是报一个时间段内有几个程序在同一个cpu上运行,但是任意时刻只有一个程序在cpu上运行.在一个时间段内某一个请求很快,能够响应的用户就越多,高 ...
- UML学习归纳整理
转载自:https://www.jianshu.com/p/83afa19c5096 写在前面 之前在学校比较系统的学习过统一建模语言UML,但长时间没使用遗忘了许多,最近因工作需要,所以对UML重新 ...
- Blender3d做大型项目真实地形快速建模
https://www.rr-sc.com/thread-16531254-1-1.html Blender3d是一款优秀的动画和建模工具,但在做一些大型建设项目时需要在真实地形上来表现,Blende ...
- (匹配 匈牙利)棋盘游戏 -- Hdu --1281
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1281 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- noip第9课作业
1. 打印乘法表 [问题描述] 用for循环实现输出1至9的乘法表 [样例输出] 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4 ...
- Codeforces805 A. Fake NP 2017-05-05 08:30 327人阅读 评论(0) 收藏
A. Fake NP time limit per test 1 second memory limit per test 256 megabytes input standard input out ...