C语言,234行代码控制台贪吃蛇

  结果图:

先上全代码:

#include <stdio.h>
#include <Windows.h>//移动光标
#include <stdlib.h>
#include <time.h>//使用时间戳创建随机数种子
#include <conio.h>//监听键盘

#define WIDE 50//定义地图宽度
#define HIGH 28//定义地图高度
#define MAP_MODE "■"//地图与食物模型
#define SNAKE_HEAD "□"//蛇头模型
#define SNAKE_BODY "●"//蛇身模型
#define X 70//光标归位横坐标
#define Y 28//光标归位纵坐标
#define INITLEN 3//初始化蛇长
#define MAXN 100//最大值

int game = 1;//控制游戏是否退出
int initDirection = 'a';//原方向
int direction = 'a';//改变方向

struct Snake {
	int size;//蛇长
	int x[MAXN];//蛇头横坐标
	int y[MAXN];//蛇头纵坐标
}snake;

struct Food {
	int x;//食物横坐标
	int y;//食物纵坐标
	int flag;//此变量用于检测地图上是否需要食物
}food;

//声明部分
//打印地图的函数
void mapPrint();
//初始化蛇
void initSnake();
//打印蛇
void moveSnake();
//光标移动函数
void gotoxy(int x, int y);
//随机出现食物
void creatFood();
//判断游戏状态
int judge();
//结算界面
void gameOver();
//游戏生成
void gameStart();
//
int levelControl();

void main() {
	system("title 贪吃蛇");//更改窗口名
	system("mode con cols=100 lines=29");//更改窗口大小
	printf("输入1开始游戏,输入0退出:");
	scanf_s("%d", &game);
	while (game) gameStart(); 
}

void gameStart() {
	int k = 150;//此变量用于控制延迟(游戏速度)
	k = levelControl();
	system("cls");//清屏
	mapPrint();
	food.flag = 1;
	initDirection = 'a';
	direction = 'a';
	while (game) {
		Sleep(k);//延迟150ms
		if (food.flag) creatFood();//生成食物
		moveSnake();//控制移动
		if (judege()) game = 0;//判断游戏状态
	}
	gameOver();//结算画面
}
int levelControl() {//延迟控制
	int level = 0;
	printf("请输入游戏速度(1-5)(默认为3):");
	scanf_s("%d", &level);
	switch (level) {
	case 1:
		return 250;
	case 2:
		return 200;
	case 3:
		return 150;
	case 4:
		return 100;
	case 5:
		return 50;
	}
}

void gotoxy(int x,int y) {//此函数用于移动光标
	HANDLE handle;
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}

void mapPrint() {
	for (int i = 0;i < HIGH;i++) {//用i控制行
		for (int j = 0;j < WIDE;j++) {//用j控制列
			if (j == 0 || j == WIDE - 1) {//如果是第一列或最后一列
				printf(MAP_MODE);
			}
			else if (i == 0 || i == HIGH - 1) {//如果是第一行或最后一行
				printf(MAP_MODE);
			}
			else {
				printf("  ");
			}
		}
		printf("\n");
	}
	printf("使用wasd控制方向");//操作提示行
	initSnake();
}

void creatFood() {
	srand(time(NULL));//利用时间戳赋予一个种子
	int isCreat = 1;//此变量用于确认食物位置与蛇是否重合
	food.x = rand() % (WIDE * 2 - 4) + 2;//产生横坐标随机数,减4防止与地图重合
	food.y = rand() % (HIGH - 2) + 1;//产生纵坐标随机数
	if (food.x % 2 == 0) {//因蛇头的坐标为偶数,为使吃到食物,食物横坐标须为偶数
		for (int i = 0;i < snake.size;i++) {
			if (snake.x[i] == food.x && snake.y[i] == food.y) isCreat = 0;
		}
		if (isCreat) {
			gotoxy(food.x, food.y);//光标跳跃
			printf(MAP_MODE);//打印食物
			gotoxy(X, Y);//光标归位
			food.flag = 0;
		}
	}
}

//初始化一条蛇
void initSnake() {
	snake.size = INITLEN;//初始化蛇长
	snake.x[0] = WIDE;//定义蛇头在屏幕正中间
	snake.y[0] = HIGH / 2;//蛇头纵坐标
	gotoxy(snake.x[0], snake.y[0]);
	printf(SNAKE_HEAD);//打印蛇头
	for (int i = 1;i < snake.size;i++) {//打印蛇身
		snake.x[i] = snake.x[i - 1] + 2;
		snake.y[i] = snake.y[i - 1];
		gotoxy(snake.x[i], snake.y[i]);
		printf(SNAKE_BODY);
	}
	gotoxy(X, Y);//光标归位
}

//移动
void moveSnake() {
	if (_kbhit()) {//监听键盘
		fflush(stdin);//清空缓存区
		int judgement = _getch();
		if (judgement == 'w' || judgement == 'W' || judgement == 's' || judgement == 'S' || judgement == 'a' || judgement == 'A' || judgement == 'd' || judgement == 'D')
			direction = judgement;//获得键盘输入的值,并赋给direction
	}
	gotoxy(snake.x[snake.size - 1], snake.y[snake.size - 1]);//移除蛇尾
	printf("  ");//打印空格以移除蛇尾
	for (int i = snake.size - 1;i > 0;i--) {//重新打印蛇身,蛇头使用direction控制
		snake.x[i] = snake.x[i - 1];
		snake.y[i] = snake.y[i - 1];
		gotoxy(snake.x[i], snake.y[i]);
		printf(SNAKE_BODY);
	}
	switch (direction) {//改变蛇头位置
	case 'w':
	case 'W':
		if(initDirection != 's' && initDirection != 'S')
			snake.y[0]--;
		else{
			direction = initDirection;
			snake.y[0]++;
		}
		break;
	case 's':
	case 'S':
		if (initDirection != 'w' && initDirection != 'W')
			snake.y[0]++;
		else {
			direction = initDirection;
			snake.y[0]--;
		}
		break;
	case 'a':
	case 'A':
		if (initDirection != 'd' && initDirection != 'D')
			snake.x[0] -= 2;
		else {
			direction = initDirection;
			snake.x[0] += 2;
		}
		break;
	case 'd':
	case 'D':
		if (initDirection != 'a' && initDirection != 'A')
			snake.x[0] += 2;
		else {
			direction = initDirection;
			snake.x[0] -= 2;
		}
		break;
	}
	initDirection = direction;
	gotoxy(snake.x[0], snake.y[0]);//重新打印蛇头
	printf(SNAKE_HEAD);
	gotoxy(X, Y);//光标归位
	if (snake.x[0] == food.x && snake.y[0] == food.y) {//若蛇头吃到食物
		snake.size++;
		food.flag = 1;
	}
}

int judege() {//此函数用于判断游戏状态
	if (snake.x[0] == 0 || snake.x[0] == WIDE * 2 - 2) return 1;//如果撞到左右墙
	if (snake.y[0] == 0 || snake.y[0] == HIGH - 1) return 1;//如果撞到上下墙
	for (int i = 1;i < snake.size;i++) {//如果吃到自己
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) return 1;
	}
	return 0;
}

void gameOver() {
	system("cls");//清屏
	gotoxy(WIDE, HIGH / 2);//跳跃光标
	printf("Game Over!\n");//打印结束语
	printf("请输入0退出游戏,1重新游戏:\n");
	scanf_s("%d", &game);
}

写在最前面,对于gotoxy函数的解释:

gotoxy函数用于移动光标,来控制在何处打印食物,蛇头或蛇身。

void gotoxy(int x,int y) {//此函数用于移动光标
	HANDLE handle;
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}

HANDLE与COORD为系统定制好的一个结构体。

第三行代码获得标准输出句柄,并赋给handle。

COORD pos中的x,y代表光标移动的横坐标和纵坐标。

SetConsoleCursorPosition 函数是用来移动光标的。

贪吃蛇程序实现思路:

1.创建一个地图

2.创建一条蛇

3.随机生成食物

4.控制蛇移动,当蛇吃到食物,蛇变长

5.蛇头撞到墙或者自身,游戏结束

main函数前面就不解释了,从while开始:

gameStart游戏开始,使用levelControl函数控制返回延迟时间,来控制游戏速度

int levelControl() {//延迟控制
	int level = 0;
	printf("请输入游戏速度(1-5)(默认为3):");
	scanf_s("%d", &level);
	switch (level) {
	case 1:
		return 250;
	case 2:
		return 200;
	case 3:
		return 150;
	case 4:
		return 100;
	case 5:
		return 50;
	}
}

然后开始创建地图,调用mapPrint函数:

我写代码习惯还不错,注释基本都写了,我感觉这个看注释就能懂了

void mapPrint() {
	for (int i = 0;i < HIGH;i++) {//用i控制行
		for (int j = 0;j < WIDE;j++) {//用j控制列
			if (j == 0 || j == WIDE - 1) {//如果是第一列或最后一列
				printf(MAP_MODE);
			}
			else if (i == 0 || i == HIGH - 1) {//如果是第一行或最后一行
				printf(MAP_MODE);
			}
			else {
				printf("  ");
			}
		}
		printf("\n");
	}
	printf("使用wasd控制方向");//操作提示行
	initSnake();
}

第一步完成,接下来玩蛇,首先用结构体定义一条蛇:

注释标的很清楚了,MAXN是蛇身最大长,在最开始写了define MAXN 100;

struct Snake {
	int size;//蛇长
	int x[MAXN];//蛇头横坐标
	int y[MAXN];//蛇头纵坐标
}snake;

 mapPrint函数的结尾调用的initSnake函数,初始化一条蛇

其中INITLEN,WIDE,HIGH分别为初始蛇长,宽度,高度,均已define。

须注意snake.x[0] = WIDE;是因为地图模型的■,每个占用两字节。

main函数中定义的宽度为WIDE * 2,所以地图的x轴正中间为WIDE

void initSnake() {
	snake.size = INITLEN;//初始化蛇长
	snake.x[0] = WIDE;//定义蛇头在屏幕正中间
	snake.y[0] = HIGH / 2;//蛇头纵坐标
	gotoxy(snake.x[0], snake.y[0]);
	printf(SNAKE_HEAD);//打印蛇头
	for (int i = 1;i < snake.size;i++) {//打印蛇身
		snake.x[i] = snake.x[i - 1] + 2;
		snake.y[i] = snake.y[i - 1];
		gotoxy(snake.x[i], snake.y[i]);
		printf(SNAKE_BODY);
	}
	gotoxy(X, Y);//光标归位
}

然后生成食物,首先创建一个食物结构体:

struct Food {
	int x;//食物横坐标
	int y;//食物纵坐标
	int flag;//此变量用于检测地图上是否需要食物
}food;

for循环遍历蛇的各点坐标与食物坐标比较防止刷在蛇上面。

void creatFood() {
	srand(time(NULL));//利用时间戳赋予一个种子
	int isCreat = 1;//此变量用于确认食物位置与蛇是否重合
	food.x = rand() % (WIDE * 2 - 4) + 2;//产生横坐标随机数,减4防止与地图重合
	food.y = rand() % (HIGH - 2) + 1;//产生纵坐标随机数
	if (food.x % 2 == 0) {//因蛇头的坐标为偶数,为使吃到食物,食物横坐标须为偶数
		for (int i = 0;i < snake.size;i++) {
			if (snake.x[i] == food.x && snake.y[i] == food.y) isCreat = 0;
		}
		if (isCreat) {
			gotoxy(food.x, food.y);//光标跳跃
			printf(MAP_MODE);//打印食物
			gotoxy(X, Y);//光标归位
			food.flag = 0;
		}
	}
}

接下来是moveSnake函数,首先定义两个全局变量用来控制方向:

int initDirection = 'a';//原方向
int direction = 'a';//改变方向

初始化方向为向左。

第二行if监听键盘是否输入,如果输入,获取输入值赋给judgement,判断是否为wasd,如果是,将其赋给direction。

移除蛇尾并重新打印蛇身,使用switch判断键盘输入的direction,其中if用于判断输入要移动的方向与原来移动的方向是否冲突,若冲突,仍按原来的方向进行移动。

结尾判断蛇头坐标与食物坐标是否重合,若重合蛇变长,食物消失,须重新打印

void moveSnake() {
	if (_kbhit()) {//监听键盘
		fflush(stdin);//清空缓存区
		int judgement = _getch();
		if (judgement == 'w' || judgement == 'W' || judgement == 's' || judgement == 'S' || judgement == 'a' || judgement == 'A' || judgement == 'd' || judgement == 'D')
			direction = judgement;//获得键盘输入的值,并赋给direction
	}
	gotoxy(snake.x[snake.size - 1], snake.y[snake.size - 1]);//移除蛇尾
	printf("  ");//打印空格以移除蛇尾
	for (int i = snake.size - 1;i > 0;i--) {//重新打印蛇身,蛇头使用direction控制
		snake.x[i] = snake.x[i - 1];
		snake.y[i] = snake.y[i - 1];
		gotoxy(snake.x[i], snake.y[i]);
		printf(SNAKE_BODY);
	}
	switch (direction) {//改变蛇头位置
	case 'w':
	case 'W':
		if(initDirection != 's' && initDirection != 'S')
			snake.y[0]--;
		else{
			direction = initDirection;
			snake.y[0]++;
		}
		break;
	case 's':
	case 'S':
		if (initDirection != 'w' && initDirection != 'W')
			snake.y[0]++;
		else {
			direction = initDirection;
			snake.y[0]--;
		}
		break;
	case 'a':
	case 'A':
		if (initDirection != 'd' && initDirection != 'D')
			snake.x[0] -= 2;
		else {
			direction = initDirection;
			snake.x[0] += 2;
		}
		break;
	case 'd':
	case 'D':
		if (initDirection != 'a' && initDirection != 'A')
			snake.x[0] += 2;
		else {
			direction = initDirection;
			snake.x[0] -= 2;
		}
		break;
	}
	initDirection = direction;
	gotoxy(snake.x[0], snake.y[0]);//重新打印蛇头
	printf(SNAKE_HEAD);
	gotoxy(X, Y);//光标归位
	if (snake.x[0] == food.x && snake.y[0] == food.y) {//若蛇头吃到食物
		snake.size++;
		food.flag = 1;
	}
}

最后判断蛇此刻的状态:

int judege() {//此函数用于判断游戏状态
	if (snake.x[0] == 0 || snake.x[0] == WIDE * 2 - 2) return 1;//如果撞到左右墙
	if (snake.y[0] == 0 || snake.y[0] == HIGH - 1) return 1;//如果撞到上下墙
	for (int i = 1;i < snake.size;i++) {//如果吃到自己
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) return 1;
	}
	return 0;
}

结尾添加结束界面:

void gameOver() {
	system("cls");//清屏
	gotoxy(WIDE, HIGH / 2);//跳跃光标
	printf("Game Over!\n");//打印结束语
	printf("请输入0退出游戏,1重新游戏:\n");
	scanf_s("%d", &game);
}

结束

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于文字排版限制,无法在答案中直接插入代码,请根据以下代码编写。 #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #include <windows.h> #define MAP_WIDTH 20 #define MAP_HEIGHT 20 #define SNAKE_INIT_LENGTH 3 int map[MAP_WIDTH][MAP_HEIGHT]; int snake[SNAKE_INIT_LENGTH][2]; int snake_length = SNAKE_INIT_LENGTH; int food[2]; int direction = 0; int score = 0; void init_map() { int i, j; for (i = 0; i < MAP_WIDTH; i++) { for (j = 0; j < MAP_HEIGHT; j++) { map[i][j] = 0; } } } void init_snake() { int i; for (i = 0; i < SNAKE_INIT_LENGTH; i++) { snake[i][0] = MAP_WIDTH / 2 + i; snake[i][1] = MAP_HEIGHT / 2; map[snake[i][0]][snake[i][1]] = 1; } } void init_food() { srand((unsigned int)time(NULL)); food[0] = rand() % MAP_WIDTH; food[1] = rand() % MAP_HEIGHT; while (map[food[0]][food[1]] == 1) { food[0] = rand() % MAP_WIDTH; food[1] = rand() % MAP_HEIGHT; } map[food[0]][food[1]] = 2; } void print_map() { int i, j; system("cls"); printf("Score: %d\n", score); for (i = 0; i < MAP_HEIGHT; i++) { for (j = 0; j < MAP_WIDTH; j++) { if (map[j][i] == 0) { printf(" "); } else if (map[j][i] == 1) { printf("O"); } else if (map[j][i] == 2) { printf("*"); } if (j == MAP_WIDTH - 1) { printf("\n"); } } } } void update_snake() { int i, j; int next_head[2]; switch (direction) { case 0: next_head[0] = snake[0][0] - 1; next_head[1] = snake[0][1]; break; case 1: next_head[0] = snake[0][0] + 1; next_head[1] = snake[0][1]; break; case 2: next_head[0] = snake[0][0]; next_head[1] = snake[0][1] - 1; break; case 3: next_head[0] = snake[0][0]; next_head[1] = snake[0][1] + 1; break; } if (next_head[0] == food[0] && next_head[1] == food[1]) { // 吃到食物 map[snake[snake_length - 1][0]][snake[snake_length - 1][1]] = 0; snake_length++; snake[snake_length - 1][0] = snake[snake_length - 2][0]; snake[snake_length - 1][1] = snake[snake_length - 2][1]; score += 10; init_food(); } else { // 没有吃到食物 map[snake[snake_length - 1][0]][snake[snake_length - 1][1]] = 0; } for (i = snake_length - 1; i > 0; i--) { snake[i][0] = snake[i - 1][0]; snake[i][1] = snake[i - 1][1]; } snake[0][0] = next_head[0]; snake[0][1] = next_head[1]; if (snake[0][0] < 0 || snake[0][0] >= MAP_WIDTH || snake[0][1] < 0 || snake[0][1] >= MAP_HEIGHT || map[snake[0][0]][snake[0][1]] == 1) { // 判断游戏结束 printf("Game Over!\n"); exit(0); } for (i = 0; i < snake_length; i++) { // 更新蛇在地图上的位置 map[snake[i][0]][snake[i][1]] = 1; } } void update_direction() { int ch; if (_kbhit()) { ch = _getch(); if (ch == 224) { ch = _getch(); switch (ch) { case 75: // 左 if (direction != 1) { direction = 0; } break; case 77: // 右 if (direction != 0) { direction = 1; } break; case 72: // 上 if (direction != 3) { direction = 2; } break; case 80: // 下 if (direction != 2) { direction = 3; } break; } } } } int main() { init_map(); init_snake(); init_food(); while (1) { print_map(); update_snake(); update_direction(); Sleep(100); // 让循环运速度慢一点,不然蛇动起来很快闪眼睛 } return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值