转载自: https://blog.csdn.net/qq_40953281/article/details/79315254
[其中对蛇倒退、stop时蛇会消失,共两处作出调整,以下运行环境为window10 vistual c++6.0]
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <Windows.h>
#include <time.h>
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'p'
//------------------------------------------------------------------------------
void welcome(); //开始界面
void gotoxy(int x, int y); //设置光标函数
void creatgraph(); //play主界面画面[上下边框、蛇]
void gotoprint(int x, int y); //光标设置
void creatfood(); //随机数生成食物
int judge(); //判断蛇是否与墙壁发生碰撞、蛇头是否和身体重叠在一块
void Finish(); //游戏失败后打印分数
int ClickControl(); //监听点击事件
void MovingBody(); //蛇移动
void Eating(); //蛇吃东西
void gotdelete(int x, int y); //清空■[用" "代替]
void ChangeBody(int a, int b); //蛇移动后,得到蛇新的链表
void if_change_click(); //判断蛇是否能改变前进方向
typedef struct Snake{ //蛇
int x;
int y;
Snake *Next;
}snake;
struct Food{ //食物
int x;
int y;
};
//--------------------------全局变量定义--------------------------
Food food;
snake *head, *tail;
char name[20]; //玩家名字
int score = 0; //玩家分数
char click = 1;
char tmp_for_click = 1; //记录每次键盘敲击的字符
char way_before_stop = 1; //记录敲下stop之前蛇的运行方向
int speed; //蛇的前进速度
//----------------------------------------------------函数----------------------------------------------------
int main(){
system("color 0B"); //设置背景
welcome(); //展示欢迎界面
creatgraph(); //展示play界面
creatfood(); //创造食物
if(ClickControl() == 0){
return 0;
}
return 0;
}
//======================欢迎界面======================
void welcome(){
gotoxy(15,10);
printf("/==============================================/");
gotoxy(15, 20);
printf("/==============================================/");
gotoxy(20, 13);
printf("WELCOME TO THE GAME OF RETRO SNAKE");
gotoxy(14, 16);
printf("请在英文输入法中操作,wasd控制p暂停");
gotoxy(20, 18);
printf("PLEASE ENTER YOUR NAME:");
scanf("%s", &name);
system("cls");
}
//======================play主界面样式======================
void creatgraph(){
//[ 0] [2] [58]
// ■ ■■■...■■■ . ■ ■
//[ 1]
// ■ ■
//[ 2]. .
//[ 3]. .
//[ 4]. .
//
//[29]
// ■ ■■■...■■■ . ■ ■
//
//-------呈正方形,各边30个-------
int i;
for(i=0; i<60; i+=2){ //因为一个■[宽占2,高占1]
gotoprint(i, 0); //上边框
gotoprint(i, 29); //下边框
}
for(i=1; i<29; i++){
gotoprint(0, i); //左边框
gotoprint(58, i); //右边框
}
gotoxy(63, 10); //右侧屏幕记录打印
printf("hello %s, welcome to play", name);
gotoxy(63, 15);
printf("your score is: %d 分", score);
//蛇初始化[位置、长度(用链表)]
head = (snake*)malloc(sizeof(snake)); //蛇头
head->x = 16;
head->y = 15;
tail = (snake*)malloc(sizeof(snake)); //尾端[此tail不是蛇身体一部分,仅作为蛇链表结尾]
tail ->Next = NULL;
tail->x = 4;
tail->y = 2;
snake *p = (snake*)malloc(sizeof(snake)); //蛇初始身体;
snake *q = (snake*)malloc(sizeof(snake));
p->x = 16;
p->y = 16;
q->x = 16;
q->y = 17;
head->Next = p; //蛇各部分连接
p->Next = q;
q->Next = tail;
}
//======================坐标相关======================
void gotoxy(int x, int y){
COORD pos; //结构体[记录一个字符在控制台屏幕上的坐标]
HANDLE hOutput; //资源句柄
pos.X = x;
pos.Y = y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //GetStdHandle: 获得输入输出屏幕句柄
SetConsoleCursorPosition(hOutput, pos); //根据pos定位光标
}
void gotoprint(int x, int y){
gotoxy(x, y);
printf("■");
}
void gotodelete(int x, int y){
gotoxy(x, y);
printf(" ");
}
//======================食物相关======================
void creatfood(){
//srand: 随机数发生器初始化函数 time(NULL): 系统时间[单位秒]
//这样写是为了每次运行都产生不同的随机数
srand((int)time(NULL));
lable:
food.x = rand()%54+2; //2-56
food.y = rand()%27+1; //1-28
if(food.x % 2 != 0){
food.x = food.x+1; //因为食物占两格,所以食物只能出现在x%2=0的位置上
}
snake *judge = head; //遍历, 排除蛇身和食物在同一位置
while(true){
if(judge->Next == NULL){
break;
}
if(food.x == judge->x && food.y == judge->y){ //如果食物和身体重复,就重新生成食物
goto lable;
}
judge = judge->Next;
}
gotoxy(food.x, food.y);
printf("口");
}
//是否吃到食物判定[如果吃到了,蛇链表长度加1]
void Eating(){
if(head->x == food.x && head->y == food.y){
creatfood();
snake *_new = (snake *)malloc(sizeof(snake));
snake *p;
p = head;
while(true){
if(p->Next->Next == NULL){
break;
}
p = p->Next;
}
p->Next = _new; //如果吃到了食物,蛇链就长长一个,分数也加10分
_new->Next = tail;
score += 10;
gotoxy(77, 15); //分数打印
printf("%d", score);
}
}
//======================键盘监听======================
int ClickControl(){
while(true){ //一直都在监听ww
if(judge() == 0){
return 0;
}
if(_kbhit()){ //检查当前是否有键盘输入,若有则返回一个非0值,否则返回0
tmp_for_click = _getch(); //得到键盘敲的字符,并根据字符去让蛇运动
}
//无论敲不敲键盘,蛇都会按照当前click值去选择方向前进
MovingBody();
Eating();
}
return 1;
}
//======================蛇移动相关======================
void MovingBody(){
int count = 0; //统计蛇一共多长
int a = head->x, b = head->y; //记录头蛇头坐标;
snake *p = head;
while(true){ //清空蛇[不会清空蛇尾]
if(p->Next == NULL){
break;
}
gotodelete(p->x, p->y);
count++;
p = p->Next;
}
if_change_click();
switch(click){ //根据键盘事件, 重新画出蛇
case up:
head->y -= 1;
ChangeBody(a, b);
break;
case down:
head->y += 1;
ChangeBody(a, b);
break;
case left:
head->x -= 2;
ChangeBody(a, b);
break;
case right:
head->x += 2;
ChangeBody(a, b);
break;
case stop:
click = way_before_stop; //让click重新等于停止之前蛇运行方向值
goto label2;
_getch(); //程序会等待你按下任意键,再执行下面的语句
break;
}
label2:
p = head;
while(true){ //输出蛇头新位置、以及整个蛇身的。
if(p->Next == NULL){
break;
}
gotoprint(p->x, p->y);
p = p->Next;
}
p = head;
gotoxy(0, 28);
if(count <= 10){
speed = 150;
}
else{
if(count > 10 && count <=20){
speed = 100;
}else{
if(count > 20 && count <= 40){
speed = 50;
}else{speed = 10;}
}
}
Sleep(speed);
}
void ChangeBody(int a, int b){
//无论蛇怎么移动, 下一段身体都会继承上一段身体的位置
snake *p = head->Next; //记录蛇头下一段身体数据[p将继承蛇头的位置]
int mid1, mid2, mid3, mid4;
mid1 = p->x;
mid2 = p->y; //记录下一段身体坐标
//从蛇头下下一段开始,不断继承上一段坐标
while(true){
//主要是p->Next继承p的坐标[所以p->Next不能为tail, 也就是p->Next->Next!=NULL]
if(p->Next->Next == NULL){
break;
}
mid3 = p->Next->x; //mid3,mid4: 记录下一段身体的坐标
mid4 = p->Next->y;
p->Next->x = mid1; //下一段身体坐标改为前一段身体坐标[继承]
p->Next->y = mid2;
mid1 = mid3; //继承后,mid1,mid2改为mid3,mid4的值,用于下下一段身体的继承;
mid2 = mid4;
p = p->Next;
}
p = head->Next; //蛇头下一段,继承蛇头
if(p->Next != NULL)
{
p->x = a;
p->y = b;
}
}
//此函数限制: 只有tmp_for_click为[stop, right, up, left, right]时,click才会改变, 也就是click从开始运行时,就一直是这5个值中的一个
//如果蛇在向上跑,但是玩家点击向下,此时蛇不会改变方向
void if_change_click(){
if(click == 1 && tmp_for_click == down){//开始的时候,不会给定蛇运动方向,但此时蛇不能向下运动
return;
}
if(tmp_for_click == stop){
click = tmp_for_click;
return;
}
if((tmp_for_click == right || tmp_for_click == left) && (click != right && click != left)){
click = tmp_for_click;
way_before_stop = click; //way_before_stop总是记录stop之前,蛇运行方向的值
return;
}
if((tmp_for_click == up || tmp_for_click == down) && (click != up && click != down)){
click = tmp_for_click;
way_before_stop = click;
return;
}
}
//======================判断蛇头是否和墙壁发生碰撞、蛇是否与身体碰撞======================
int judge(){
if(head->x ==0 || head->x == 58 || head->y == 0 || head->y == 29){ //判断蛇头是否和墙壁发生碰撞
Finish();
return 0;
}
snake *p = head->Next; //判断蛇头是否和蛇身体发生重叠
while(true){
if(p->Next == NULL){ //蛇身遍历完了[没有发生任何碰撞]
break;
}
if(head->x == p->x && head->y == p->y){ //蛇头和身体重叠;
Finish();
return 0;
}
p = p->Next;
}
return 1;
}
//======================游戏失败逻辑======================
void Finish(){
system("cls");
gotoxy(15, 10);
printf("/==============================================/");
gotoxy(15, 20);
printf("/==============================================/");
gotoxy(18, 14);
printf("GAME OVER o(* ̄▽ ̄*)o");
gotoxy(20, 16);
printf("Your Score is %d hiahiahia", score);
gotoxy(18, 18);
printf("还不错哦, 继续努力O(∩_∩)O");
gotoxy(0, 27);
system("pause");
}
c学习------贪吃蛇实现
猜你喜欢
转载自blog.csdn.net/qq_32446743/article/details/85125818
今日推荐
周排行