不是用的数组写的,用的是链表写的,还是小白,请指教,以下为代码
主函数
#include <stdio.h>
#include <windows.h> //提供windows窗口函数
#include <time.h>
#include <stdlib.h>
#include "Snake.h"
int main(void)
{
int menu=0;
creatwindow(100, 30); //创建800*540窗口
while(1)
{
//显示菜单
menu=show_menu();
switch(menu)
{
case 1: p_explain(); break; //操作说明
case 2: start_game(); break; //开始游戏
case 3: high_score(); break; //高分榜
case 4: if(game_over(1)) return 0; ;break; //退出游戏
default: puts("未知错误!"); break;
}
system("cls");
menu = 0;
}
return 0;
}
贪吃蛇应用程序
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <stdbool.h>
#include <windows.h>
#include <conio.h>
#include "Snake.h"
//全局变量
static unsigned int Speed = SPEED; //速度
static unsigned int score = 0; //分数
static unsigned int addscore = 10; //加分
static unsigned int level =1; //关数
static unsigned int score_buff[S_COUNT] = {0}; //高分分数
static unsigned int read_score(void);
static void save_score(void);
//食物
static COORD food = {0, 0};
//隐藏光标
void HideCursor(void)
{
CONSOLE_CURSOR_INFO cursor_info = {1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
//光标位置设置
void setpos(int x, int y)
{
COORD point = {x, y}; //光标要设置的位置x
HANDLE HOutput = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出的句柄
SetConsoleCursorPosition(HOutput, point); //设置光标位置
}
//创建游戏窗口 cols: 窗口的宽度(8)字符数 lines:窗口的高度(18)字符数
void creatwindow(int cols, int lines)
{
char cmd[100]={0};
//窗口大小
sprintf(cmd, "mode con: cols=%d lines=%d", cols, lines);
system(cmd);
//窗口颜色
sprintf(cmd, "color %x%x", L_YELLOW, RED);
system(cmd);
}
//设置前景色 默认背景色为淡黄色
void setcolor(int color)
{
//获取输出窗口句柄
HANDLE Houtput = GetStdHandle(STD_OUTPUT_HANDLE);
//改变画笔颜色
SetConsoleTextAttribute(
Houtput,
BACKGROUND_INTENSITY|
BACKGROUND_GREEN|
BACKGROUND_RED|
color);
}
//显示菜单
int show_menu(void)
{
int result=1;
int key=0;
//清屏
system("cls");
HideCursor();
setpos(42, 8);//显示第一行
setcolor(RED);
printf("贪 吃 蛇");
//显示提示
setpos(50, 27);
setcolor(RED);
printf("Tip:上或下箭头控制选项,回车键确定!");
//初始界面
setpos(40, 11);//显示菜单
setcolor(BACKGROUND_BLUE|GREEN);
printf("> 1.操作说明");
setcolor(BLUE);
setpos(40, 13);//显示菜单
printf(" 2.开始游戏");
setpos(40, 15);//显示菜单
printf(" 3.高分榜");
setpos(40, 17);//显示菜单
printf(" 4.退出游戏");
while(key != VK_RETURN)
{
if(_kbhit())
{
key = getch();
//恢复底色
setcolor(BLUE);
switch(result)
{
case 1:
setpos(40, 11);//显示菜单
printf(" 1.操作说明");
break;
case 2:
setpos(40, 13);//显示菜单
printf(" 2.开始游戏");
break;
case 3:
setpos(40, 15);//显示菜单
printf(" 3.高分榜");
break;
case 4:
setpos(40, 17);//显示菜单
printf(" 4.退出游戏");
break;
default:
break;
}
switch(key)
{
case UP:
result--;
break;
case DOWN:
result++;
break;
default:
break;
}
if(result < 1)
result = 4;
if(result > 4)
result = 1;
//改变对应底色
setcolor(BACKGROUND_BLUE|GREEN);
switch(result)
{
case 1:
setpos(40, 11);//显示菜单
printf("> 1.操作说明");
break;
case 2:
setpos(40, 13);//显示菜单
printf("> 2.开始游戏");
break;
case 3:
setpos(40, 15);//显示菜单
printf("> 3.高分榜");
break;
case 4:
setpos(40, 17);//显示菜单
printf("> 4.退出游戏");
break;
default:
break;
}
}
//恢复底色
setcolor(BLUE);
}
return result;
}
//帮助说明
void p_explain(void)
{
//清屏
system("cls");
setpos(40, 2);//显示标题
setcolor(GREEN);
printf("帮 助 说 明");
setpos(37, 5);
setcolor(BLUE);
printf("1.上箭头或者大写状态下的W键控制蛇向上走");
setpos(37, 7);
printf("2.下箭头或者大写状态下的S键控制蛇向下走");
setpos(37, 9);
printf("3.左箭头或者大写状态下的A键控制蛇向左走");
setpos(37, 11);
printf("4.右箭头或者大写状态下的D键控制蛇向右走");
setpos(37, 13);
printf("5.ESC键退出游戏");
setpos(37, 15);
printf("6.按一下空格暂停游戏,再按一下空格继续游戏");
setpos(37, 17);
printf("7.蛇头咬到自己或者撞到墙壁游戏结束");
setpos(37, 20);
setcolor(RED);
system("pause");
}
//从文件中读取高分分数
static unsigned int read_score(void)
{
FILE * fp=NULL; //文件指针
char * filename = "score.txt"; //文件名
unsigned int count=0;
//如果文件打开失败,打印错误信息
if(!(fp = fopen(filename, "a+b") ) )
{
system("cls");
setpos(46, 15);
setcolor(RED);
fprintf(stderr, "%s打开失败!\n", filename);
}
else //文件打开成功, 读取高分分数到数组
{
rewind(fp);
count = fread(score_buff, sizeof(unsigned int), sizeof(score_buff), fp);
//关闭文件
if(fclose(fp))
{
system("cls");
setpos(46, 15);
setcolor(RED);
fprintf(stderr, "%s关闭失败!\n", filename);
}
}
return count;
}
//分数排序
static void score_sort(void)
{
unsigned int i=0, temp=0;
//插入本局分数
while(score < score_buff[i])
{
i++;
if(i == S_COUNT)
break;
}
temp = i;
//重新排序
if(i != S_COUNT && (score != score_buff[temp]) )
{
i=S_COUNT-1;
while(temp != i)
{
score_buff[i] = score_buff[i - 1]; //最后一个值将去掉,保存新的更高分
i--;
}
score_buff[temp] = score;
}
}
//保存分数到文件中
static void save_score(void)
{
FILE * fp=NULL; //文件指针
char * filename = "score.txt"; //文件名
int i=0;
//如果文件打开失败,打印错误信息
if(!(fp = fopen(filename, "w+b") ) )
{
system("cls");
setpos(46, 15);
setcolor(RED);
fprintf(stderr, "%s打开失败!\n", filename);
}
else //文件打开成功, 读取高分分数到数组
{
//分数排序
score_sort();
//将分数写入文件
for(i = 0; i < S_COUNT; i++)
{
if(score_buff[i]==0)
break;
fwrite(&score_buff[i], sizeof(unsigned int), 1, fp);
}
//关闭文件
if(fclose(fp))
{
system("cls");
setpos(46, 15);
setcolor(RED);
fprintf(stderr, "%s关闭失败!\n", filename);
}
}
}
//制造食物
static void creat_food(snake ps)
{
bool flag = 1;
snake p = ps;
//随机化种子
srand(time(NULL));
//开始随机产生食物的x,y坐标
while(flag)
{
flag = 0; //假设创建食物成功
//随机创建食物x坐标
food.X = rand() % 72 + 1 ; //左右边界 1-72
while(food.X % 2) //中文是两个字节
food.X = rand() % 72 + 1 ; //左右边界 1-72
//随机创建食物y坐标
food.Y = rand() % 28 + 1 ; //上下边界 1-28
//判断食物是否创建在蛇身上
p=ps;
while(p)
{
if((food.X == p->x) && (food.Y == p->y))
{
flag = 1; //如果食物创建在蛇身上则继续创建食物
break;
}
p=p->next;
}
//如果创建食物成功,显示食物
if(!flag)
{
setpos(food.X, food.Y);
setcolor(RED);
printf("田");
}
}
}
//判断是否是食物
static bool isfood(const COORD ps)
{
if((food.X == ps.X) && (food.Y == ps.Y))
return 1;
else
return 0;
}
//判断是否撞墙
static bool iswall(const snake ps)
{
//如果是安全的,在边界内
if(ps->x > L_WALL_X &&
ps->x < R_WALL_X &&
ps->y > U_WALL_Y &&
ps->y < D_WALL_Y)
return 0; //返回没有撞墙
else
return 1; //否则是撞墙的
}
//判断是否咬到自己
static bool iseatself(const snake ps)
{
bool flag = 0;
snake p=ps;
COORD temp={0};
temp.X = ps->x;
temp.Y = ps->y;
//遍历蛇身
while(p->next)
{
//如果蛇头和蛇身坐标相同
if((p->next->x == temp.X) && (p->next->y == temp.Y))
{
flag = 1; //蛇头咬到蛇身
break;
}
else
p=p->next;
}
return flag;
}
//增加蛇身
static void snake_add(snake * ps)
{
snake temp=NULL;
//分配空间
if(!(temp = (snake)malloc(sizeof(*temp))))
{
system("cls");
fprintf(stderr, "无可用的内存!\n");
exit(1);
}
//添加当前食物为蛇身
temp->x = food.X;
temp->y = food.Y;
temp->next = *ps;
*ps = temp;
}
//游戏暂停
static bool game_pause(void)
{
bool isexit = 0; //暂停时是否选择了退出游戏
unsigned int key=0;
char *str1 = "暂停"; //提示暂停
char *str2 = "口口"; //墙
//提示暂停
setpos(34, 0);
setcolor(RED);
printf("%s", str1);
//等待下一次按空格结束暂停
while(1)
{
if(_kbhit()) //如果键盘缓存里有值
{
key=getch(); //获取键盘值
//如果按下空格
if(key == VK_SPACE)
{
//提示暂停恢复
setpos(34, 0);
setcolor(GREEN);
printf("%s", str2);
break; //跳出按键检测
}
//如果按下退出键
if(key == VK_ESCAPE)
{
isexit = 1;
break; //退出标志为1后退出
}
}
}
return isexit;
}
//蛇身移动
static int snake_move(snake psnake)
{
bool pause_flag = 0;
int key=0, dir=4, flag = 0;
int food_count=0;
snake cru=NULL;
COORD temp={0}, p={0};
//获取键值
while(1)
{
//检测按键
if(_kbhit())
{
//只取最后一次按的按键,避免控制延迟
while(_kbhit())
key=getch();
//读取按键值,决定方向
switch(key)
{
case UP: if(dir !=2) dir = 1; break; //上箭头
case 87: if(dir !=2) dir = 1; break; //W
case DOWN: if(dir !=1) dir = 2; break;
case 83: if(dir !=1) dir = 2; break;
case LEFT: if(dir !=4) dir = 3; break;
case 65: if(dir !=4) dir = 3; break;
case RIGHT: if(dir !=3) dir = 4; break;
case 68: if(dir !=3) dir = 4; break;
case VK_ESCAPE: dir = 5; break;
case VK_SPACE: pause_flag = 1; break;
default: break;
}
}
//如果按了空格暂停
if(pause_flag)
{
//如果暂停中按下了退出
if(game_pause())
dir = 5; //方向设为退出
pause_flag = 0; //清暂停标志
}
//前进的方向
switch(dir)
{
//UP
case 1:
temp.X = psnake->x;
temp.Y = psnake->y-1;
break;
//DOWN
case 2:
temp.X = psnake->x;
temp.Y = psnake->y+1;
break;
//LEFT
case 3:
temp.X = psnake->x-2;
temp.Y = psnake->y;
break;
//RIGHT
case 4:
temp.X = psnake->x+2;
temp.Y = psnake->y;
break;
//ESC
case 5:
flag = 1;
break;
default: break;
}
//如果有前进的方向
if(dir)
{
setpos(temp.X, temp.Y);
setcolor(BLUE);
printf("曰");
//如果成功吃到食物
if(isfood(temp))
{
//吃到食物,增加蛇身
snake_add(&psnake);
score+=addscore; //加分
//刷新分数
setpos(SCORE_X, SCORE_Y);
setcolor(BLUE);
printf("%d", score);
food_count++; //吃到的食物加1
//如果吃到5颗食物进入下一关
if(food_count==5)
{
Speed-=10;
if(Speed <= 30)
Speed = 30;
addscore+=10;
food_count=0;
level++;
//刷新关数
setpos(LEVEL_X, LEVEL_Y);
setcolor(BLUE);
if(level>10)
{
level = 10;
printf("无尽");
}
else
printf("%d", level);
}
setpos(food.X, food.Y);
setcolor(BLUE);
printf("曰");
cru = psnake->next;
setpos(cru->x, cru->y);
setcolor(BLACK);
printf("日");
//创建新食物
creat_food(psnake);
}
else
{
cru = psnake;
while(cru->next)
{
p.X = cru->x;
p.Y = cru->y;
cru->x = temp.X;
cru->y = temp.Y;
temp.X = p.X;
temp.Y = p.Y;
setpos(temp.X, temp.Y);
setcolor(BLACK);
printf("日");
cru=cru->next;
}
setpos(cru->x, cru->y);
printf(" ");
cru->x = temp.X;
cru->y = temp.Y;
}
//如果撞墙
if(iswall(psnake))
{
flag = 2;
break;
}
//如果咬到自己
if(iseatself(psnake))
{
flag = 3;
break;
}
Sleep(Speed);
}
//ESC退出游戏
if(flag == 1)
break;
}
//显示游戏结束画面
flag = game_over(flag);
//处理游戏结果
save_score(); //保存分数
score=0;
addscore=10;
Speed=SPEED;
level=1;
return flag;
}
//开始游戏
void start_game(void)
{
snake head=NULL; //创建蛇头
snake cru=NULL;
bool start_flag = 1; //开始游戏标志
int exit_value=0;
while(start_flag)
{
//读取分数
read_score();
//为蛇头分配空间
if(!(head = (snake)malloc(sizeof(*head))))
{
system("cls");
fprintf(stderr, "无可用的内存!\n");
exit(1);
}
head->next=NULL;
//隐藏光标
HideCursor();
creatmap(); //创建地图
initsnake(head); //初始化蛇身
creat_food(head); //创建食物
exit_value=snake_move(head); //蛇开始前进
if(exit_value)
start_flag = 0; //游戏结束
else
start_flag = 1; //游戏继续
while(head != NULL)
{
cru=head->next;
free(head);
head=cru;
}
}
system("cls");
setpos(45, 12);
puts(" 再 见 !");
Sleep(500);
exit(0);
}
//高分榜
void high_score(void)
{
unsigned int count=0, i=0;
//清屏
system("cls");
setpos(40, 2);//显示标题
setcolor(GREEN);
puts("高 分 榜");
//从文件中读取分数
count = read_score();
//如果还没有开始玩过游戏
if(!count)
{
setpos(34, 4);//显示标题
setcolor(GREEN);
printf("您还没有成绩,快去创造记录吧!");
}
else
{
//读出分数
//显示记录分
setpos(40, 4);//显示标题
setcolor(RED);
fprintf(stdout, "%d. %d\n", 1, score_buff[0]);
setcolor(BLUE);
for(i = 1; i < count; i++)
{
setpos(42, 4+2*i);
fprintf(stdout, "%d. %d\n", i+1, score_buff[i]);
}
}
//返回菜单
setpos(34, 27);//显示标题
setcolor(RED);
system("pause");
}
//创建地图
void creatmap(void)
{
unsigned int x=0, y=0;
//清屏
system("cls");
//设置边界为绿色
setcolor(GREEN);
//输出上下边界
for(x = 0; x < 100; x+=2)
{
setpos(x, 0);
printf("口");
setpos(x, 29);
printf("口");
}
//输出左右边界
for(y = 0; y < 30; y++)
{
setpos(0, y);
printf("口");
setpos(74, y);
printf("口");
setpos(98, y);
printf("口");
}
//计分,说明界面
setcolor(BLUE);
setpos(84, 3);
printf("说 明");
setpos(78, 5);
printf("上:上箭头或大写W");
setpos(78, 7);
printf("下:下箭头或大写S");
setpos(78, 9);
printf("左:左箭头或大写A");
setpos(78, 11);
printf("右:右箭头或大写D");
setpos(78, 13);
printf("ESC:退出游戏");
setpos(78, 15);
printf("空格:暂停/继续");
setpos(82, 18);
printf("得分:0"); //18行88列开始显示分数
setpos(82, 21);
printf("关数:1"); //21行88列开始显示关数
}
//初始化蛇
void initsnake(snake psnake)
{
unsigned int i=0;
snake temp=NULL;
snake cru=NULL;
psnake->x = 38;
psnake->y = 15;
temp = psnake;
for(i=1; i < 5; i++)
{
if(!(temp->next = (snake)malloc(sizeof(*temp))))
{
system("cls");
fprintf(stderr, "无可用的内存!\n");
exit(1);
}
temp->next->x = 38-2*i;
temp->next->y= 15;
temp = temp->next;
}
temp->next=NULL;
cru = psnake;
while(cru)
{
setpos(cru->x, cru->y);
setcolor(BLACK);
printf("日");
cru=cru->next;
}
setpos(psnake->x, psnake->y);
setcolor(BLUE);
printf("曰");
}
//继续或退出游戏界面
static bool iscontinue(void)
{
int result=1;
int key=0;
//显示提示
setpos(50, 27);
setcolor(RED);
printf("Tip:上或下箭头控制选项,回车键确定!");
//初始界面
setpos(42, 13);
setcolor(BACKGROUND_BLUE|GREEN);
printf("> 继续游戏");
setcolor(BLUE);
setpos(42, 15);
printf(" 退出游戏");
while(key != VK_RETURN)
{
if(_kbhit())
{
key = getch();
//恢复底色
setcolor(BLUE);
switch(result)
{
case 1:
setpos(42, 13);
printf(" 继续游戏");
break;
case 2:
setpos(42, 15);
printf(" 退出游戏");
break;
default:
break;
}
switch(key)
{
case UP:
result--;
break;
case DOWN:
result++;
break;
default:
break;
}
if(result < 1)
result = 2;
if(result > 2)
result = 1;
//改变对应底色
setcolor(BACKGROUND_BLUE|GREEN);
switch(result)
{
case 1:
setpos(42, 13);
printf("> 继续游戏");
break;
case 2:
setpos(42, 15);
printf("> 退出游戏");
break;
default:
break;
}
}
//恢复底色
setcolor(BLUE);
}
if(result == 2)
result = 0;
return result;
}
//游戏结束界面
bool game_over(int flag)
{
bool isexit = 0;
//清屏
system("cls");
switch(flag)
{
//ESC退出游戏
case 1:
setpos(45, 12);
puts(" 再 见 !");
Sleep(500);
isexit = 1;
break;
//撞墙结束游戏
case 2:
setpos(38, 9);
setcolor(RED);
printf("您撞到墙了!游戏结束!");
setpos(34, 11);
setcolor(BLUE);
printf("本局得分为:%d, 最高得分为%d!", score, score_buff[0]);
if(score > score_buff[0])
{
setcolor(RED);
printf("恭喜你成功打破记录!");
}
//如果选择继续游戏
if(iscontinue())
{
isexit = 0;
}
else
isexit = 1;
break;
//咬到自己结束游戏
case 3:
setpos(38, 9);
setcolor(RED);
printf("您咬到了自己!游戏结束!");
setpos(34, 11);
setcolor(BLUE);
printf("本局得分为:%d, 最高得分为%d!", score, score_buff[0]);
if(score > score_buff[0])
{
setcolor(RED);
printf("恭喜你成功打破记录!");
}
//如果选择继续游戏
if(iscontinue())
{
isexit = 0;
}
else
isexit = 1;
break;
default: puts("异常退出!"); break;
}
return isexit;
}
头文件
#ifndef SNAKE_H_
#define SNAKE_H_
#include <windows.h>
#include <stdbool.h>
//颜色宏定义
/***
0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 浅绿色 B = 淡浅绿色
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色
***/
#define BLACK 0 //黑色
#define BLUE 1 //蓝色
#define GREEN 2 //绿色
#define L_GREEN 3 //浅绿色
#define RED 4 //红色
#define PURPLE 5 //紫色
#define YELLOW 6 //黄色
#define WHITE 7 //白色
#define GRAY 8 //灰色
#define L_BLUE 9 //淡蓝色
#define L_RED 0X0C //淡红色
#define L_PURPLE 0X0D //淡紫色
#define L_YELLOW 0X0E //淡黄色
#define H_WHITE 0X0F //亮白色
//方向键值
#define RIGHT 0x4d
#define LEFT 0x4b
#define UP 0x48
#define DOWN 0x50
//墙的边界
#define U_WALL_Y 0 //边界的上边界
#define D_WALL_Y 29 //边界的下边界
#define L_WALL_X 0 //边界的左边界
#define R_WALL_X 74 //边界的右边界
//分数和关数的显示位置
#define SCORE_X 88 //88列
#define SCORE_Y 18 //15行
#define LEVEL_X 88 //88列
#define LEVEL_Y 21 //20行
//速度
#define SPEED 130
//高分榜显示分数个数
#define S_COUNT 10
//蛇的模板设计
typedef struct Node{
int x;
int y;
struct Node * next;
}node;
typedef node * snake; //一条蛇
//函数原型声明
void HideCursor(void); //隐藏光标
void setpos(int x, int y); //设置光标位置
void creatwindow(int x, int y); //创建游戏窗口
void setcolor(int color); //设置前景色
int show_menu(void); //显示菜单
void creatmap(void); //创建地图
void initsnake(snake head); //初始化蛇
void p_explain(void); //帮助说明
void start_game(void); //开始游戏
void high_score(void); //高分榜
bool game_over(int flag); //游戏结束界面
#endif //SNAKE_H_