好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 CuteHamster 于 2019-11-13 17:39 编辑
我几天前在C Primer Pluse这本书上学完了结构体内容,感觉应该能写一些控制台小程序了,
正好今天有时间,于是在网上找了一个贪吃蛇小游戏的C语言源代码来学习借鉴(附上网上的源代码)
[Asm] 纯文本查看 复制代码 #include<stdio.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<conio.h>
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'p'
void welcome(); //开始界面
void Finish(); //结束界面
void creatgraph(); //围墙打印
void gotoxy(int x, int y); //光标跳转,横为X 0,1,2..
void gotoprint(int x, int y); //跳转打印
void gotodelete(int x, int y);//跳转删除
void creatfood(); //食物产生
int ClickControl(); //获取键盘信号
int Judge(); //游戏结束判断
void MovingBody(); //蛇的移动
void Eating(); //蛇吃到东西后的操作(伸长)
void ChangeBody(int a, int b); //蛇的坐标变换,后一个复制前一个STRUCT,a,b为head之前坐标
/*全局变量 + 预处理:*/
typedef struct Snakes
{
int x;
int y;
struct Snakes* next;
}snake;
snake* head, * tail;
struct Food
{
int x;
int y;
}food;
char name[20];
int score = 0;
char click = 1;
int speed;
/************************************************************/
int main()
{
system("color F0");
welcome();
creatgraph();
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("%s", &name, 10);
system("cls");
}
/**********************************************************/
void creatgraph()
{
int i;
for (i = 0; i < 58; i += 2)//打印上下边框
{
gotoprint(i, 0);
gotoprint(i, 26);
}
for (i = 1; i < 26; i++)
{
gotoprint(0, i);
gotoprint(56, i);
}
gotoxy(63, 10);
printf("hello %s,Welcome To Play", name);
gotoxy(63, 15);
printf("Your Score Is:%d = ̄ω ̄= ", score);
gotoxy(63, 20);
printf("This Game Is Created By JOKER");
head = (snake*)malloc(sizeof(snake));
head->x = 16;
head->y = 15;
//gotoprint(head->x, head->y);
tail = (snake*)malloc(sizeof(snake));
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;
//gotoprint(p->x, p->y);
//gotoprint(q->x, q->y);
tail->next = NULL;
tail->x = 4;
tail->y = 2;
}
/**********************************************************/
void gotoxy(int x, int y)
{
COORD pos;
HANDLE hOutput;
pos.X = x;
pos.Y = y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, pos);
}
/**********************************************************/
void gotoprint(int x, int y)
{
gotoxy(x, y);
printf("■");
}
/**********************************************************/
void gotodelete(int x, int y)
{
gotoxy(x, y);
printf(" ");
}
/**********************************************************/
void creatfood()
{
srand((int)time(NULL));
lable:
food.y = rand() % (25 - 1 + 1) + 1;
food.x = rand() % (54 - 2 + 1) + 2;
if (food.x % 2 != 0)
{
food.x = food.x + 1;
}
snake* judge = head;
while (1) //遍历排除蛇身重复
{
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("◎");
}
/**********************************************************/
int ClickControl()
{
char c;
while (1)
{
if (Judge() == 0) return 0;
if (_kbhit())
{
click = _getch();
}
MovingBody();
Eating();
}
return 1;
}
/**********************************************************/
void MovingBody()
{
int count = 0;
int a = head->x, b = head->y;
snake* p = head;
//通过先清空后打印实现动画效果
while (1)
{
if (p->next == NULL) break;
gotodelete(p->x, p->y);
count++;
p = p->next;
}
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 =_getch();
break;
}
p = head;
while (1)
{
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 Eating()
{
if (head->x == food.x && head->y == food.y)
{
creatfood();
snake* _new = (snake*)malloc(sizeof(snake));
snake* p;
p = head;
while (1)
{
if (p->next->next == NULL) break;
p = p->next;
}
p->next = _new;
_new->next = tail;
score += 10;
gotoxy(77, 15);
printf("%d", score);
}
}
/**********************************************************/
void ChangeBody(int a, int b)
{
snake* p = head->next;
int mid1, mid2, _mid1, _mid2;
mid1 = p->x;
mid2 = p->y;
while (1)
{
if (p->next->next == NULL) break;
_mid1 = p->next->x;
_mid2 = p->next->y;
p->next->x = mid1;
p->next->y = mid2;
mid1 = _mid1;
mid2 = _mid2;
p = p->next;
}
p = head->next;
//if (p->next!= NULL)
{
p->x = a;
p->y = b;
}
}
/**********************************************************/
int Judge()
{
if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
{
Finish();
return 0;
}
snake* p = head->next;
while (1)
{
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");
}
仔细阅读之后我发现这个程序还有可以改进的地方:
1.此程序蛇头向后运动会被判定撞上身体,而正常的贪吃蛇是不应该响应向后运动的按键的
2.此程序的食物产生机制,产生一次食物可能要调用多次随机数生成函数,蛇的身体长了运算量可能会比较大,应该一次随机就生成一份食物
3.此程序在每次蛇移动时都会把蛇的身体全部刷新一遍,而事实上只需要改变蛇尾的位置就可以实现蛇的移动了
于是在借鉴原程序的基础上我又自己从头开始重新编了一个C程序,实现了上面的改进:
[C] 纯文本查看 复制代码 #include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <windows.h>
enum
{
WIDTH = 40,//墙的宽度
HEIGHT = 30,//墙的高度
};
//蛇和食物的结构体定义
struct Snake
{
int x;
int y;
Snake* next;
Snake* former;
};
//全局变量
Snake* head;
Snake* tail;
Snake* Food;
char direction = 's';//键盘录入蛇的运动方向
int score = 0;//得分
int PointArray[WIDTH][HEIGHT] = { 0 };//用于生成食物及判定撞击
/*******************************************************************/
void movcoord(int x, int y);//用于操作光标位置
void printstraction(int x, int y);//用于绘制蛇身基本单元
void printbrick(int x, int y);//用于绘制墙的基本单元
void drawwalls();//绘制墙体
void setArray();//用于初始化数组
void changeArray(Snake* p, int value);//用于改变数组里数字的值
void ChangeScore(int score);//用于更新得分
void iniSnake();//用于初始化蛇的图像
void add(Snake* body);//增加蛇的身体长度
void del(Snake* body);//删除蛇的身体单元
void getfoodposition();//生成食物位置
void setfood();//绘制食物
void creatfood();//产生食物
int move();//蛇的前进与进食
//把蛇尾移至新蛇头的位置,然后让旧的蛇尾变成新的蛇头
//在蛇尾添加身体单元
/*******************************************************************/
//用于操作光标位置
void movcoord(int x, int y)
{
COORD coord;
HANDLE ophandle;
coord.X = x;
coord.Y = y;
ophandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(ophandle, coord);
}
//用于绘制墙体和蛇身的基本结构
void printstraction(int x, int y)
{
x *= 2;
movcoord(x, y);
printf("◆");
}
//用于绘制墙的基本单元
void printbrick(int x, int y)
{
x *= 2;
movcoord(x, y);
printf("■");
}
//绘制墙体
void drawwalls()
{
int i;
system("color F0");
for (i = 0;i < WIDTH;i++)
{
printbrick(i, 0);
printbrick(i, HEIGHT-1);
}
for (i = 0;i < HEIGHT;i++)
{
printbrick(0, i);
printbrick(WIDTH - 1, i);
}
movcoord(2 * WIDTH + 4, 0);
printf("方向键:WASD");
movcoord(2 * WIDTH + 4, 2);
printf("按其他键暂停");
movcoord(2 * WIDTH + 4, 4);
printf("Your Score:");
}
//用于初始化数组
void setArray()
{
int i;
for (i = 0;i < WIDTH;i++)
{
PointArray[i][0] = 1;
PointArray[i][HEIGHT - 1] = 1;
}
for (i = 0;i < HEIGHT;i++)
{
PointArray[0][i] = 1;
PointArray[WIDTH - 1][i] = 1;
}
}
//用于改变数组里数字的值
void changeArray(Snake* p,int value)
{
PointArray[p->x][p->y] = value;
}
//用于更新得分
void ChangeScore(int score)
{
movcoord(2 * WIDTH + 4, 5);
printf("%d", score);
}
//用于初始化蛇的图像
void iniSnake()
{
Snake* p = head;
while (1)
{
printstraction(p->x, p->y);
if (p->next == NULL)
break;
p = p->next;
}
}
//增加蛇的身体长度
void add(Snake* body)
{
printstraction(body->x, body->y);
movcoord(0, HEIGHT - 1);
changeArray(body, 1);
}
//删除蛇的身体单元
void del(Snake* body)
{
movcoord(2 * body->x, body->y);
printf(" ");
changeArray(body, 0);
}
//生成食物位置
void getfoodposition()
{
static int general = (WIDTH - 2) * (HEIGHT - 2);
int temp, i, j, flag = 0;
srand(time(NULL));
temp = rand() % (general - score - 3);
for (i = 1;i < WIDTH - 1;i++)
{
for (j = 1;j < HEIGHT - 1;j++)
{
if (temp == 0)
{
flag = 1;
break;
}
else if (!PointArray[i][j])
temp--;
}
if (flag)
break;
}
Food->x = i;
Food->y = j;
}
//绘制食物
void setfood()//放置食物
{
changeArray(Food, 2);
Food->x *= 2;
movcoord(Food->x, Food->y);
printf("◎");
}
//产生食物
void creatfood()
{
getfoodposition();
setfood();
}
//蛇的前进与进食
//把蛇尾移至新蛇头的位置,然后让旧的蛇尾变成新的蛇头
//在蛇尾添加身体单元
int move()
{
static Snake temp;//用于保存蛇尾移动之前的位置
static int speed;
if (score < 10)
speed = 150;
else if (score < 50)
speed = 100;
else
speed = 50;
temp.x = tail->x;
temp.y = tail->y;
switch (direction)
{
case 'w':
case 'W':
tail->x = head->x;
tail->y = head->y - 1;
break;
case 'a':
case 'A':
tail->x = head->x - 1;
tail->y = head->y;
break;
case 's':
case 'S':
tail->x = head->x;
tail->y = head->y + 1;
break;
case 'd':
case 'D':
tail->x = head->x + 1;
tail->y = head->y;
break;
}
if (PointArray[tail->x][tail->y] == 1)
{
return 1;
}
//增加蛇的长度
else if (PointArray[tail->x][tail->y] == 2)
{
Snake* p;
p = (Snake*)malloc(sizeof(Snake));
p->x = temp.x;
p->y = temp.y;
add(tail);
tail->next = head;
head->former = tail;
head = tail;
p->former = tail->former;
tail = p;
head->former = nullptr;
ChangeScore(++score);
creatfood();
Sleep(speed);
return 0;
}
else
{
del(&temp);
add(tail);
tail->next = head;
head->former = tail;
head = tail;
tail = tail->former;
head->former = nullptr;
Sleep(speed);
return 0;
}
}
/***********************************************************************/
void main()
{
extern Snake* head;//蛇头
Snake* middle;//蛇肚
extern Snake* tail;//蛇尾
extern Snake* Food;//食物
extern char direction;//键盘录入蛇的运动方向
extern int score;//得分
extern int PointArray[WIDTH][HEIGHT];//用于生成食物及判定撞击
setArray();//初始化数组
drawwalls();//画出墙体
head = (Snake*)malloc(sizeof(Snake));//为蛇头分配空间
middle = (Snake*)malloc(sizeof(Snake));//为蛇肚分配空间
tail = (Snake*)malloc(sizeof(Snake));//为蛇尾分配空间
Food = (Snake*)malloc(sizeof(Snake));//为食物分配空间
head->x = WIDTH / 2 - 1;
head->y = HEIGHT / 2 - 1;
head->former = nullptr;
head->next = middle;
PointArray[head->x][head->y] = 1;
middle->x = head->x;
middle->y = (head->y + 1);
middle->former = head;
middle->next = tail;
PointArray[middle->x][middle->y] = 1;
tail->x = middle->x;
tail->y = (middle->y + 1);
tail->former = middle;
tail->next = nullptr;
PointArray[tail->x][tail->y] = 1;
creatfood();//创造食物
iniSnake();//画出蛇
ChangeScore(score);//打印实时得分
while ((direction == 's' || direction == 'S') ||
(
direction != 'a' && direction != 'A' &&
direction != 'w' && direction != 'W' &&
direction != 'd' && direction != 'D'
))
direction = _getch();//初始化蛇的前进方向
while (1)
{
static char temp;
static char judge;//用于判断按键是否反向
temp = direction;
//录入按键
if (_kbhit())
{
do
{
direction = _getch();
} while (direction != 'a' && direction != 'A' &&
direction != 'w' && direction != 'W' &&
direction != 's' && direction != 'S' &&
direction != 'd' && direction != 'D'
);
judge = temp - direction;
if (
judge == 3 || judge == -3 ||
judge == 4 || judge == -4 ||
judge == 28 || judge == -28 ||
judge == 29 || judge == -28 ||
judge == 35 || judge == -35 ||
judge == 36 || judge == -36
)
direction = temp;
}
if (move())//判断撞击
//释放内存
{
Snake* p = tail;
while (p->former != nullptr)
{
p = p->former;
free(p->next);
}
free(p);
break;
}
}
Sleep(500);
system("cls");
movcoord(WIDTH / 2, HEIGHT / 2);
printf("你的得分: %d\n", score);
system("pause");
}
程序运行效果图我发在下面评论里面了 |
免费评分
-
查看全部评分
|