C语言——实践小游戏(贪吃蛇)代码版

大家好久不见,我是残念我回来了,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流
本文由:残念ing原创CSDN首发,如需要转载请通知
个人主页:残念ing-CSDN博客,欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:残念ing 的C语言系列专栏——CSDN博客

头文件和主函数的声明

snake.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<locale.h>
#define WALL  L'■'
#define SNAKE L'●'
#define HEADSNAKE L'○'
#define FOOD L'★'
#define POS_X 24
#define POS_Y 5
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1)? 1:0)
//游戏状态
enum GAME_STATUS
{
	OK = 1,//正常运行
	ESC,//正常退出
	KILL_BY_WALL,//撞墙了
	KILL_BY_SELF//撞到自己了
};


//⽅向
enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

//蛇身结点的定义
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode,* pSnakeNode;

//typedef struct SnakeNode* pSnakeNode;

//蛇
typedef struct Snake
{
	pSnakeNode pSnake;//维护整条蛇的指针,指向蛇头
	pSnakeNode pFood;//指向食物的指针
	int Score;//当前累计的分数
	int FoodWeight;//一个食物的分数
	int SleepTime;//整条蛇的睡眠时间,休眠的时间越短,蛇的速度越快,休眠的时间越长,蛇的速度越慢
	enum GAME_STATUS status;//游戏当前的状态
	enum DIRECTION dir;//蛇当前走的方向
}Snake,* pSnake;

//定位控制台光标位置
void setpos(int x, int y);
//游戏准备
void GameStart(pSnake ps);

//打印欢迎界面
void WelcomeToGame();
//绘制地图
void CreateMap();
//初始化贪吃蛇
void InintSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);

//运行整个游戏的逻辑
void GameRun(pSnake ps);//玩游戏的过程


//打印帮助信息
void printfHelpInfo();


//每次的移动
void SnakeMove(pSnake ps);

//判断蛇头下一步要走的位置是不是食物 是返回1,不是返回0;
int NextIsFood(pSnake ps, pSnakeNode pnext);

//是食物就吃
void EatFood(pSnake ps, pSnakeNode pnext);
//不是食物
void NotEatFood(pSnake ps, pSnakeNode pnext);

//检测撞墙
void KillByWall(pSnake ps);
//检测撞到自己
void KillBySelf(pSnake ps);

//游戏结束的善后
void GameEnd(pSnake ps);//善后工作

主函数的详细实现

snake.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"snake.h"

//将光标位置设置到指定的位置
void setpos(int x, int y)
{
	//获取句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置光标的坐标
	COORD tmp = { x,y };
	SetConsoleCursorPosition(handle, tmp);
}

void WelcomeToGame()
{
	setpos(40,10);
	printf("欢迎来到贪吃蛇小游戏!!!");
	setpos(43, 20);
	system("pause");//请按任意键继续进行下一步
	system("cls");//清屏
	setpos(10, 10);
	printf("请用 ↑	↓	←	→	分别来控制蛇的移动,SHIFT为加速,CTRL为减速");
	setpos(40, 12);
	printf("注意:加速将会使你得到更多分");
	setpos(43, 20);
	system("pause");//请按任意键继续进行下一步
	system("cls");//清屏
}


//打印墙
void CreateMap()
{
	//上
	setpos(0, 0);
	for (int i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	setpos(0, 26);
	for (int i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	
	for (int i = 0; i <=25; i++)
	{ 
		setpos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (int i = 0; i <=25; i++)
	{
		setpos(56, i);
		wprintf(L"%lc", WALL);
		
	}

}

//初始化蛇
void InintSnake(pSnake ps)
{
	pSnakeNode cur=NULL;
	for (int i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InintSnake():malloc");
			return;
		}
			cur->x = POS_X +  2 * i;
			cur->y = POS_Y;
			cur->next = NULL;

		//头插
		if (ps->pSnake == NULL)
		{
			ps->pSnake = cur;
		}
		else
		{
			cur->next = ps->pSnake;
			ps->pSnake = cur;
		}
	}
	//打印蛇
	cur = ps->pSnake;
	while (cur)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", SNAKE);
		cur = cur->next;
	}

	//贪吃蛇的基本属性初始化
	ps->dir = RIGHT;
	ps->FoodWeight = 10;
	ps->pFood = NULL;
	ps->Score = 0;
	ps->SleepTime = 200;
	ps->status = OK;
}


//创建食物
void CreateFood(pSnake ps)
{
	int x = 0;
	int y = 0;

again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 24 + 1;
	} while (x % 2 != 0);

	//坐标和蛇的身体的每个节点的做坐标比较
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}

	//创建食物
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("CreateFood()::malloc()");
		return;
	}

	pFood->x = x;
	pFood->y = y;

	ps->pFood = pFood;
	setpos(x, y);
	wprintf(L"%lc", FOOD);

}

void GameStart(pSnake ps)
{
	//设置控制台的信息,窗口大小,窗口名
	system("mode con cols=100 lines=30");//设置窗口的长和宽
	system("title 贪吃蛇");//设置窗口名

	//隐藏关标
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
	CursorInfo.bVisible = false;//隐藏控制台光标
	SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标的状态

	//打印欢迎信息
	WelcomeToGame();
	//绘制地图
	CreateMap();
	//初始化蛇
	InintSnake(ps);
	//创建食物
	CreateFood(ps);
}

void printfHelpInfo()
{
	setpos(63, 15);
	printf("注意:不能穿墙,不能咬到自己");
	setpos(63, 16);
	printf("用↑↓← →分别来控制蛇的移动");
	setpos(63, 17);
	printf("SHIFT为加速,CTRL为减速");
	setpos(63, 18);
	printf("Esc为退出游戏,space为暂停游戏");
}

void pause()
{
	while (1)
	{
		Sleep(100);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}

int NextIsFood(pSnake ps, pSnakeNode pnext)
{
	if (ps->pFood->x == pnext->x && ps->pFood->y == pnext->y)
	{
		return 1;
	}
	else
		return 0;
}


void EatFood(pSnake ps, pSnakeNode pnext)
{
	pnext->next = ps->pSnake;
	ps->pSnake = pnext;

	//打印蛇
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", SNAKE);
		cur = cur->next;
	}

	ps->Score += ps->FoodWeight;

	//释放旧的食物
	free(ps->pFood);
	//新建食物
	CreateFood(ps);
}

void NotEatFood(pSnake ps, pSnakeNode pnext)
{
	//头插法
	pnext->next = ps->pSnake;
	ps->pSnake = pnext;

	//释放尾结点
	pSnakeNode cur = ps->pSnake;
	while (cur->next->next)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", SNAKE);
		cur = cur->next;
	}
	//将尾节点的位置打印成空白字符
	setpos(cur->next->x, cur->next->y);
	printf("  ");

	free(cur->next);
	cur->next = NULL;//易错
}

void KillByWall(pSnake ps)
{
	if (ps->pSnake->x == 0 || ps->pSnake->x == 56 || ps->pSnake->y == 0 || ps->pSnake->y == 26)
	{
		ps->status = KILL_BY_WALL;
	}
}

void KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->pSnake->next;
	while (cur)
	{
		if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y)
		{
			ps->status = KILL_BY_SELF; 
			return;
		}
		cur = cur->next;
	}

}


void SnakeMove(pSnake ps)
{
	pSnakeNode pnext = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pnext == NULL)
	{
		perror("SnakeMove()::malloc()");
		return;
	}
	pnext->next = NULL; 

	switch (ps->dir)
	{
	case UP:
		pnext->x = ps->pSnake->x;
		pnext->y = ps->pSnake->y - 1;
		break;
	case DOWN:
		pnext->x = ps->pSnake->x;
		pnext->y = ps->pSnake->y + 1;
		break;
	case LEFT:
		pnext->x = ps->pSnake->x - 2;
		pnext->y = ps->pSnake->y;
		break;
	case RIGHT:
		pnext->x = ps->pSnake->x + 2;
		pnext->y = ps->pSnake->y;
		break;
	}

	//下一个坐标是不是食物
	if (NextIsFood(ps, pnext))
	{
		//是食物就吃
		EatFood(ps, pnext);
	}
	else
	{
		//不是食物就走
		NotEatFood(ps, pnext);
	}

	//检测撞墙
	KillByWall(ps);
	//检测撞到自己
	KillBySelf(ps);
}

void GameRun(pSnake ps)
{
	//打印帮助信息
	printfHelpInfo();
	//检测按键
	do
	{
		//当前的分数情况
		setpos(63,10);
		printf("总得分:%5d 每个食物: %02d",ps->Score,ps->FoodWeight);
		//检查按键
		// 上 下 左 右 ESC 空格 shift Ctrl
		if (KEY_PRESS(VK_UP) && ps->dir != DOWN)
		{
			ps->dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->dir != UP)
		{
			ps->dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT)
		{
			ps->dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT)
		{
			ps->dir = RIGHT;
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->status = ESC;
			break;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			//游戏要暂定
			pause();//暂定和回复暂定
		}
		else if(KEY_PRESS(VK_RSHIFT))
		{
			if (ps->SleepTime >= 80)
			{
				ps->SleepTime -= 30;
				ps->FoodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_RCONTROL))
		{
			if (ps->FoodWeight > 2)
			{
				ps->SleepTime += 30;
				ps->FoodWeight -= 2;
			}
		}
		
		//睡眠一下
		Sleep(ps->SleepTime);
		//走一步
		SnakeMove(ps);
	} while (ps->status==OK);
}


void GameEnd(pSnake ps)
{
	setpos(17, 15);
	switch (ps->status)
	{
	case ESC:
		printf("退出游戏\n");
		break;
	case KILL_BY_WALL:
		printf("撞到墙了!!!!,游戏结束\n");
		break;
	case KILL_BY_SELF:
		printf("咬到自己了!!!!,游戏结束\n");
		break;
	}
	//释放贪吃蛇的链表资源
	pSnakeNode  cur = ps->pSnake;
	pSnakeNode del = NULL;

	while (cur)
	{
		del = cur;
		cur = cur->next;
		free(del);
	}
	free(ps->pFood);
	ps = NULL;
}

关于代码的测试

snake_test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
void test()
{
	int ret = 0;
	do
	{
		ret = 0;
		Snake snake = { 0 };
		GameStart(&snake);//游戏开始前的初始化
		GameRun(&snake);//玩游戏的过程
		GameEnd(&snake);//游戏的善后
		Sleep(800);
		system("cls");//清屏
		setpos(40, 15);
		printf("要再来一次吗???(Y/N)");
		ret=getchar();
		getchar();//清理\n
	} while (ret=='Y'||ret=='y');
}
int main()
{
	//修该适合本地中文环境
	setlocale(LC_ALL, "");
	test();//贪吃蛇的测试
	return 0;
}

这是详细代码,之后会给大家详细解答。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/534835.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux网络名称空间的调试方法全面分析

Linux网络名称空间是一种广泛使用的技术&#xff0c;用于隔离网络环境&#xff0c;特别是在容器化和微服务架构中&#x1f4e6;。然而&#xff0c;随着网络名称空间的广泛应用&#xff0c;开发者和系统管理员可能会遇到需要调试网络名称空间配置和性能的情况&#x1f50d;。本文…

智能驾驶的关键技术:自主泊车轨迹规划

智能驾驶的关键技术&#xff1a;自主泊车轨迹规划 搭载先进的车载传感器、控制器、执行器等装置&#xff0c;具备复杂环境感知、智能化决策等功能的车辆&#xff0c;我们称之其为智能车。智能车的车载决策规划模块用于生成车辆的行驶行为&#xff0c;直接体现车辆行驶的智慧水…

【Tars-go】腾讯微服务框架学习使用01--初始化服务

1 初始INIT-Demo运行 按照官网描述 go get 安装框架依赖 # < go 1.16 go get -u github.com/TarsCloud/TarsGo/tars/tools/tarsgo go get -u github.com/TarsCloud/TarsGo/tars/tools/tars2go # > go 1.16 go install github.com/TarsCloud/TarsGo/tars/tools/tarsgolat…

【网安小白成长之路】6.pkachu、sql-lbas、upload-lbas靶场搭建

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f51e; 《网安小白成长之路(我要变成大佬&#x1f60e;&#xff01;&#xff01;)》真实小白学习历程&#xff0c;手把手带你一起从入门到入狱&#x1f6ad; &…

python---3--sort、lambdalen(list1)、sorted_numbers = sorted(numbers)、list.sort()

学习目标&#xff1a; lambda len(list1) sorted_numbers sorted(numbers)list.sort() 目录 学习目标&#xff1a; 学习内容&#xff1a; 匿名函数 lambda表达式 lambda [参数]: 函数 不需要return len(list1) sorted_numbers sorted(numbers) list.sort(keyNone, r…

进程通信(管道)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言 两个进程直接可以进行数据的直接传递吗&#xff1f;答案显然是不可以。 为什么&#xff1f; 我们简单概括就是进程具有独立性&#xff0c;如果说有两个进程&#xff0c;第一个进程可以访问第二个进程的数据&#xff…

ssm“健康早知道”微信小程序

采用技术 ssm“健康早知道”微信小程序的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 需求分析 利用ssm、Java、MyEclipse和mysql数据库等知识点&#xff0c;结合相关设…

【CSDN创作优化2】内嵌图片 `<img>` 标签`height`和`width`属性

【CSDN创作优化2】内嵌图片 标签height和width属性 写在最前面<img> 标签简介控制图像尺寸&#xff1a;height和width属性实例为什么要指定height和width注意事项 使用百分比进行响应式设计小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字…

idea 配置各种背景颜色-护眼绿

idea 配置各种背景颜色 1、打开 IDEA 软件&#xff0c;点击左上角的【File】——>【Settings】 2、点击左侧栏中的【Editor】——>【Color Scheme】选项&#xff0c;点击右侧的【scheme】下拉选择你想要的颜色方案。 3、背景色设置护眼绿或其他特定颜色的背景&#xf…

scratch绘制五边形花朵 2024年3月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch绘制五边形花朵 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程…

训练营第二十天(二叉树 part06)

训练营第二十天&#xff08;二叉树 part06&#xff09; 654.最大二叉树 力扣题目地址(opens new window) 题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出…

C++模板初阶(个人笔记)

模板初阶 1.泛型编程2.函数模板2.1函数模板的实例化2.2模板参数的匹配规则 3.类模板3.1类模板的实例化 1.泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 //函数重载 //交换函数的逻辑是一致的&#xff0c…

Java 类加载过程

Java 类加载过程 类的生命周期类的加载过程加载验证准备解析初始化 类的生命周期 类的生命周期&#xff1a; 加载&#xff08;Loading&#xff09;— 验证&#xff08;Verification&#xff09;— 准备&#xff08;Preparation&#xff09;— 解析&#xff08;Resolution&#…

【ArcGIS微课1000例】0109:ArcGIS计算归一化水体指数(NDWI)

文章目录 一、加载数据二、归一化水体指数介绍三、归一化水体指数计算四、注意事项一、加载数据 加载配套数据0108.rar(本实验的数据与0108的一致)中的Landsat8的8个单波段数据,如下所示: Landsat8波段信息对照表如下表所示: 接下来学习在ArcGIS平台上,基于Landsat8数据…

贪心算法|763.划分字母区间

力扣题目链接 class Solution { public:vector<int> partitionLabels(string S) {int hash[27] {0}; // i为字符&#xff0c;hash[i]为字符出现的最后位置for (int i 0; i < S.size(); i) { // 统计每一个字符最后出现的位置hash[S[i] - a] i;}vector<int> …

前端开发攻略---利用Flexbox和Margin实现智能布局:如何巧妙分配剩余空间,让你的网页设计更上一层楼?

1、演示 2、flex布局 Flex布局是一种用于Web开发的弹性盒子布局模型&#xff0c;它可以让容器内的子元素在空间分配、对齐和排列方面具有更大的灵活性。以下是Flex布局的基本用法&#xff1a; 容器属性&#xff1a; display: flex;&#xff1a;将容器指定为Flex布局。flex-dire…

「每日跟读」英语常用句型公式 第9篇

「每日跟读」英语常用句型公式 第9篇 1. Go-to ___ 第一选择___ What’s your go-to snack when you’re hungry? (你饿的时候第一选择的零食是什么&#xff1f;) Who’s your go-to friend for advice? (你第一选择的朋友是谁来寻求建议&#xff1f;) Which is your go-t…

51单片机使用uart串口和助手简单调试

基础知识 参考 特殊功能寄存器PCON&#xff08;控制波特率是否加倍SMOD&#xff09;、TMOD&#xff08;T0,T1计时器的功能方式&#xff09;、TCON&#xff08;T0,T1计时器的控制&#xff09;、串口中断、SCON&#xff08;串口数据控制寄存器&#xff09; 关闭定时器1中断&…

生产问题排查指南:从定位到解决

✨✨祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 一、引言 二、 观察和定位问题 监控系统 日志分析 用户反馈 其他观察方式 注意事项…

开源模型应用落地-qwen1.5-7b-chat与sglang实现推理加速的正确姿势(一)

一、前言 SGLang is a structured generation language designed for large language models (LLMs). It makes your interaction with LLMs faster and more controllable by co-designing the frontend language and the runtime system。简单来说就是,SGLang简化了LLM程序的…