《贪吃蛇游戏编程》C语言控制台字符界面版

今天周末,闲来无事,看到网友的问题,需要C语言版的贪吃蛇。于是就坐下来写一个C语言控制台版的,开发软件使用的是Vsual Studio 2019 。整个程序只有一个tanchishe.c文件,编译生成tanchishe.exe,然后在Windows环境直接打开可以进入游戏。
  • 运行效果如第一张动画所示。
    在这里插入图片描述

  • 1.引入一些需要的头文件,定义一些常量,全局变量,结构体等。
    在这里插入图片描述

  • 2.编写基本操作函数在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 3.编写打印信息函数和主函数
    在这里插入图片描述
    由于控制台字符界面,行间距和字间距默认不一致,所以行间爬行看起来比字符间的速度快,实际上是跨步的速度是一致的。

//author:   Hengda
//date:		2020年4月19日
//版权所有,CSDN:https://blog.csdn.net/one312
#include <stdio.h>//引入所需头文件
#include <string.h>//字符串
#include <malloc.h>
#include <stdlib.h>
#include <conio.h>
#include <math.h>

#define SPAN_WIDTH 48 //蛇可运动区域宽度
#define SPAN_HEIGHT 32 //蛇可运动区域高度
#define GAME_WIDTH SPAN_WIDTH+2+1 //画面宽度(+2是两边围墙 +1是行尾换行符)
#define GAME_HEIGHT SPAN_HEIGHT+2 //画面高度(+2是上下围墙)
#define SPEED_LEVEL_DIFF_SPEED 100 //速度等级之间的的速度差

typedef struct body_node{
    
     int x; int y; struct body_node *next;} BODY_NODE;
char spanArr[GAME_HEIGHT][GAME_WIDTH] = {
    
     ' '};// 存储整个画面
BODY_NODE* snakeP = NULL,apple = {
    
     0,0,NULL };//蛇头指针,苹果
char appleImage = 'O',snakeImage = '@',emptyImage=' ', direction = 'r';//苹果图标,蛇图标,空区域图标,默认运动方向(l r u d)
unsigned int score = 0;

char info[9][60] = {
    
    
	"GAME OVER !!!",
	"得分:%d ",
	"《贪吃蛇游戏》",
	"C语言控制台字符界面版",
	"作者:Hengda",
	"日期:2020/04/19",
	"版权所有",
	"1.按Enter键继续游戏",
	"2.按其他键退出"
};

void setSpanCharByXY(int x, int y, char c) {
    
     spanArr[y + 1][x + 1] = c; }//+1原因是有边框

char getSpanCharByXY(int x, int y) {
    
     return spanArr[y + 1][x + 1]; }//+1原因是有边框

void init_sanke(){
    
    //生成蛇
	snakeP = (BODY_NODE*)malloc(sizeof(BODY_NODE));//初始蛇头位置
	snakeP->x = SPAN_WIDTH / 2;
	snakeP->y = SPAN_HEIGHT / 2;
	snakeP->next = NULL;
	setSpanCharByXY(snakeP->x, snakeP->y, snakeImage);
}

void free_snake() {
    
    //释放蛇所占内存
	BODY_NODE* P=snakeP,*Q = NULL;
	while (P->next != NULL) {
    
    
		Q = P;
		P = P->next;
		free(Q);
		Q = NULL;
	}
	free(P);
	P = NULL;
}

void init_apple() {
    
    //生成随机且不与蛇重叠的Apple
	apple.x = -1;
	apple.y = -1;
	while (apple.x < 0 || apple.y < 0 || getSpanCharByXY(apple.x, apple.y) == '#') {
    
    
		apple.x = rand()% SPAN_WIDTH;
		apple.y = rand()% SPAN_HEIGHT;
	}
	setSpanCharByXY(apple.x, apple.y, appleImage);
}

void eateAppleOrAddHead(int appleX, int appleY) {
    
    //吃苹果
	BODY_NODE* node = (BODY_NODE*)malloc(sizeof(BODY_NODE));
	node->x = appleX;
	node->y = appleY;
	node->next = snakeP;
	snakeP = node;
	setSpanCharByXY(appleX, appleY, snakeImage);//碰到苹果,则把苹果变成自己的身体
}

void popTail() {
    
    //去尾
	BODY_NODE * P=snakeP;
	if (P == NULL || P->next == NULL) return;//蛇不存在或者蛇只有一节,不做删尾操作
	while(P->next->next != NULL) {
    
    P = P->next;};
	setSpanCharByXY(P->next->x, P->next->y, emptyImage);
	free(P->next);
	P->next = NULL;
}

int snake_Step(int nextX, int nextY) {
    
    //蛇移动一步
	//碰到自己的身体,或者越界则gameover //nextX >= SPAN_WIDTH || nextY >= SPAN_HEIGHT || nextX < 0 || nextY < 0 ||
	if (getSpanCharByXY(nextX, nextY) == snakeImage) return 0;
	else if (getSpanCharByXY(nextX, nextY) == appleImage) {
    
    
		eateAppleOrAddHead(nextX, nextY);
		score++;
		init_apple();//生成新苹果
	}else {
    
    
		eateAppleOrAddHead(nextX, nextY);
		popTail();
	}
	return 1;
}

int snake_Move_By_Drection(char direction) {
    
    //蛇朝指定方向移动
	if (direction == 'l') return snake_Step(snakeP->x - 1, snakeP->y);
	else if (direction == 'u') return snake_Step(snakeP->x, snakeP->y - 1);
	else if (direction == 'r') return snake_Step(snakeP->x + 1, snakeP->y);
	else if(direction == 'd') return snake_Step(snakeP->x, snakeP->y + 1);
	return 0;
}

char get_direction() {
    
    //获取方向 UP(向上方向键)为: 0X4800 DOWN(向下方向键)为 : 0X5000 LEFT(向左方向键)为 : 0X4b00 RIGHT(向右方向键)为 : 0X4d00
	if ( kbhit() && getch()) {
    
    
		switch (getch()) {
    
    
			case 0x4b: if(direction != 'r') direction = 'l'; break;
			case 0x48: if (direction != 'd') direction = 'u'; break;
			case 0x4d: if (direction != 'l') direction = 'r'; break;
			case 0x50: if (direction != 'u')direction = 'd'; break;
		}
	}
	return direction;
}

void display(){
    
    //更新画面
	system("cls");//mac 用这个 system("clear");
	spanArr[GAME_HEIGHT -1][GAME_WIDTH -1] = '\0';
	printf("%s", spanArr);//打印画面
}

void int_span(){
    
    // 清盘
	for (int j = 0; j < GAME_HEIGHT; j++)
		for (int i = 0; i < GAME_WIDTH; i++)
			if (i == 0 || (j == 0 && i != GAME_WIDTH - 1) || i == GAME_WIDTH - 2 || j == GAME_HEIGHT - 1) {
    
     spanArr[j][i] = snakeImage; }
				else if (i == GAME_WIDTH - 1) {
    
     spanArr[j][i] = '\n'; }
					else {
    
     spanArr[j][i] = emptyImage; }
}

void display_Info() {
    
    //打印信息
	int gameWidth = GAME_WIDTH;
	int gameHeight = GAME_HEIGHT;
	int infoNum = 0;
	char str[60] = "";
	infoNum = (sizeof(info)/ 60)/sizeof(char);
	for (int i = 0; i < infoNum;i++) {
    
    
		if (i == 1) sprintf(str,info[i],score);
		else strcpy(str, info[i]);
		memcpy(spanArr[gameHeight / 2 - infoNum + i*2] + gameWidth / 2 - strlen(str) / 2, str, strlen(str));
	}
}

int main(int argc, char* argv[]) {
    
    //主函数
	char info[10] = "";
	int gameWidth = GAME_WIDTH;
	int gameHeight = GAME_HEIGHT;
	while (1) {
    
    
		score = 0;
		int_span();
		init_sanke();
		init_apple();
		while (1) {
    
    
			display();//刷新棋盘
			if (!snake_Move_By_Drection(get_direction())) {
    
    //读取运动方向 并控制移动一步
				free_snake();
				display_Info();
				score = 0;
				display();//刷新有些画面
				if (getchar() == '\n') break;//等待按键
				else return 0;
			}
		}
	}
	return 0;
}

项目源程序下载地址:https://github.com/hengda-git/c-tanchishe

猜你喜欢

转载自blog.csdn.net/one312/article/details/105620279