贪吃蛇小游戏-----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)的函数 //随机创建蛇身并存储到蛇身数组 //创建食物 ...
 
随机推荐
- socketpair初识
			
#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/typ ...
 - Android 在一个程序中启动另一个程序(包名,或者类名)
			
http://hi.baidu.com/xiaofanqing/item/6fd724f7c5bb6dce531c26b7 Android 开发有时需要在一个应用中启动另一个应用,比如Launcher ...
 - 2018.09.16 loj#10243. 移棋子游戏(博弈论)
			
传送门 题目中已经给好了sg图,直接在上面跑出sg函数即可. 最后看给定点的sg值异或和是否等于0就判好了. 代码: #include<bits/stdc++.h> #define N 2 ...
 - UVa 508 Morse Mismatches (模糊暴力)
			
题意:莫尔斯电码,输入若干个字母的Morse编号,一个字典和若干编码.对于每个编号,判断它可能的是哪个单词, 如果有多个单词精确匹配,输出第一个单词并加一个“!”:如果无法精确匹配,那么在编码尾部增加 ...
 - C#基础:在using中创建对象
			
在using中创建的对象的类必须是实现了IDispose接口的类,示例代码如下: static void Main(string[] args) { Method(); Console.WriteLi ...
 - N个数的最大公约数
			
#include <iostream> using namespace std; int main() { int c; ]={,,,}; ;i<;i++) { ]<m[i]) ...
 - 3D indoor map positioning with a smartphone image
			
menu 1. 基于Tango的三维建模技术(SLAM)(视觉SLAM,RGBD单目深度摄像机+罗盘仪)导出或不导出->Android 三维游戏开发技术(普通Android手机) 2. 基于An ...
 - PAT甲 1029. Median (25)                                                                                            2016-09-09 23:11             27人阅读              评论(0)              收藏
			
1029. Median (25) 时间限制 1000 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given an incr ...
 - 使用 Project Siena 生成一个 Windows Store 应用
			
继 App Studio 之后微软又一力作 Project Siena [Win8 应用神器]给初学开发 或 对 Windows Store 应用感兴趣的同学们的一个福利,可以通过 一个简单的应用可以 ...
 - MLLib实践Naive Bayes
			
引言 本文基于Spark (1.5.0) ml库提供的pipeline完整地实践一次文本分类.pipeline将串联单词分割(tokenize).单词频数统计(TF),特征向量计算(TF-IDF),朴 ...