这好像是第一次发博客hhh,最近学完C语言后浑身精力澎湃总想做点什么东西 (结果差点被现实打的肿透了脸qwq ) 于是四处找项目,最终锁定贪吃蛇,曾经诺基亚上的小游戏给我的印象还是挺深的,最后在浏览其他一些大佬的项目后,了解具体思路就上手尝试做了个简陋一点的版本,由于自己也是初学者,所以 代码有很多的不足,仅供交流参考。
文章目录
前言
贪吃蛇的原理较为简单,简单版本的利用数组就能对其进行主要功能的实现,当然如果有一定的C语言基础,写出这个应该是不难的。编程环境:VScode + gcc 9.2.0(为什么vscode不能装eazyX 呜呜呜)
思路参考这位大佬的博客:https://blog.csdn.net/zs120197/article/details/88420297
需要思路详解可以进去看看,讲的很详细。
效果图如下:
初始界面:
游戏界面:
提示:以下是本篇文章正文内容,下面案例可供参考
一、主要功能的实现
1.界面显示:主要通过光标定位后循环打印某些字符来组成整体画面以及一些常驻信息,然后通过函数来刷新消除显示残留。
2.果子生成:果子分为小果子跟奖励果子,每吃相应数量的小果子就会生成一个奖励果子,通过 srand() 与 rand() 函数生成 伪随机数 来实现。
3.控制部分:通过 _kbhit() 函数及 _getch() 函数 配合if语句进行监控键盘输入,来实现 蛇的控制以及菜单移动。
4.菜单部分:这部分我并没有用传统的输入数字用switch() 函数控制,而是模仿"诺基亚"那样用键盘控制,这部分代码或许会较为冗长,各位自己优化吧嘿嘿。
二、部分函数提要
1.光标定位
由于这个程序并没有应用到 eazyX 的图形库 (为什么vscode装不了呜呜呜) ,所以需要另外的函数来进行界面内光标的定位来进行具体位置的绘制。
// 光标定位
void gotoxy(int x,int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //取句柄
COORD coord; //设置光标
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(handle, coord); //定位到handle这个窗口,把光标移到coord坐标
}
需要深入了解的话参考以下:
https://baike.baidu.com/item/SetConsoleCursorPosition/575826>
https://baike.baidu.com/item/GetStdHandle/6909878?fr=aladdin
https://baike.baidu.com/item/coord/4594820?fr=aladdin
2.Windows界面设置
谁不想让自己写的程序好看点,所以这边调用了系统函数进行黑框框的美化(没有图形库最大的美化只能这样了 ╮(╯_╰)╭ )
// CMD图形界面设置
void WindowsInterface()
{
system("color 87");
system("title Greedy Snake V1.4");
system("mode con:cols=120 lines=29");
}
另外关于system(“color xx”)函数:
第一个为背景色,第二个为字体颜色
0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 湖蓝色 B = 淡浅绿色
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色
( 试了一个小时还是前白后灰最好看 )
三、主要模块
1. 库函数、变量与函数定义
所需的库函数、定义的变量及结构体如下
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<time.h>
#include<conio.h>
#include<time.h>
#define maphigh 28 //定义墙的长宽
#define mapwide 84
unsigned short Snake_size = 500, Snake_speed = 150, Snake_lenth = 3, key = 'w'; //初始化相关
int Scores = 0, fruitBonus = 3, BigfruitBonus = 24; //与分数有关
int coodr = 12; //与菜单控制有关
struct fruit //小果子相关
{
int number;
int x;
int y;
}fruit;
struct Bigfruit //奖励果子相关
{
int number;
int x;
int y;
}Bigfruit;
struct snake //蛇主体相关
{
int x[500];
int y[500];
int len;
int speed;
}snake;
int Deathjudge();
void Menu();
void Game();
void VertionInformation();
void WindowsInterface();
void gotoxy(int x,int y);
void drawmenu();
void drawmap();
void ClearMenu();
void ClearGames();
void control();
void Initialize();
void creatfruit();
void CreatBigFruit();
void Score();
//以上是所需的库函数与定义
2. 游戏主体
游戏的主体主要由绘制、控制、果子生成以及死亡判定组成。先附上游戏主体的主函数:
// 游戏主程序
void Game()
{
Initialize();
for(;;) //空循环实现不断运行游戏(游戏结束不关闭)
{
system("cls"); //系统清屏函数
drawmap(); //游戏初始界面绘制
getch();
for(;;)
{
control(); //控制函数
creatfruit(); //果子生成函数(包含奖励果子)
Score(); //分数系统
Sleep(Snake_speed); //void sleep(int seconds),参数 seconds为要暂停的毫秒数。
if (!Deathjudge()) //死亡条件,死亡时 Deathjudge = 0
{
gotoxy(mapwide/2,maphigh/2);
printf("GAME OVER!!!");
getchar();
break; //游戏结束时开启新一轮循环
}
}
}
}
2.1 绘制部分
绘制部分 利用打印与刷新来保证内容显示不出错,以下是初始界面绘制:
// 绘制游戏界面
void drawmap()
{
int i,k;
//绘制地图
for ( i = 0; i <= mapwide; i += 2) //绘制上下边界
{
gotoxy(i, 0);
printf("█");
gotoxy(i, maphigh);
printf("█");
}
for ( i = 0; i <= maphigh; i++) //绘制左右边界
{
gotoxy(0,i);
printf("█");
gotoxy(mapwide,i);
printf("█");
}
//绘制蛇
snake.len = Snake_lenth;
snake.speed = Snake_speed;
snake.x[0] = mapwide/2;
snake.y[0] = maphigh/2;
gotoxy(snake.x[0],snake.y[0]); //蛇头
printf("█");
for ( k = 1; k < snake.len; k++) //蛇身
{
snake.x[k] = snake.x[k - 1] + 2;
snake.y[k] = snake.y[k - 1];
gotoxy(snake.x[k],snake.y[k]);
printf("█");
}
srand((unsigned int)time(NULL)); //srand()与rand()函数随机生成果子位置
while(1)
{
fruit.x = rand() % (mapwide - 4 ) + 1; // + 1 与果子的符号所占的字符有关
fruit.y = rand() % (maphigh - 2 ) + 1;
if (fruit.x % 2 == 0)
break;
}
gotoxy(fruit.x,fruit.y); //绘制小果子
printf("*");
//右侧内容标注
gotoxy(mapwide + 8, 6); //移动到右侧标注位置
printf(" W");
gotoxy(mapwide + 6, 8);
printf("A S D 进行控制");
gotoxy(mapwide + 6, 12);
printf("按 '空格' 以暂停");
gotoxy(mapwide + 6, 18);
printf("Scores : %d",Scores);
}
以下部分是 游戏界面刷新 ,由于绘制会产生显示残留,目前所掌握的知识也没有更好的办法,所以就只能通过刷新后再绘制来进行消除显示残留,希望后续有大佬可以优化一下,代码如下:
// 刷新游戏界面(清屏并绘制常驻信息)
void ClearGames()
{
int i,k;
system("cls");
for ( i = 0; i <= mapwide; i += 2) //绘制边界
{
gotoxy(i, 0);
printf("█");
gotoxy(i, maphigh);
printf("█");
}
for ( i = 0; i <= maphigh; i++)
{
gotoxy(0,i);
printf("█");
gotoxy(mapwide,i);
printf("█");
}
gotoxy(snake.x[0],snake.y[0]); //绘制蛇
printf("█");
for ( k = 1; k < snake.len; k++)
{
gotoxy(snake.x[k],snake.y[k]);
printf("█");
}
gotoxy(fruit.x,fruit.y); //绘制果子
printf("*");
gotoxy(mapwide + 8, 6); //绘制右侧信息
printf(" W");
gotoxy(mapwide + 6, 8);
printf("A S D 进行控制");
gotoxy(mapwide + 6, 12);
printf("按 '空格&