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

news2024/11/29 8:44:01

大家好久不见,我是残念我回来了,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流
本文由:残念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;
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

196算法之谜在 JSP 中使用内置对象 request 获取 form 表单的文本框 text 提交的数据。

(1&#xff09;编写 inputNumber . jsp &#xff0c;该页面提供一个 form 表单&#xff0c;该 form 表单提供一个文本框 text &#xff0c;用于用户输入一个正整数&#xff0c;用户在 form 表单中输入的数字&#xff0c;单击 submit 提交键将正整数提交给 huiwenNumber . jsp 页…

基于JSP+Mysql+HTml+Css仓库出入库管理系统设计与实现

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

Leetcode二十二题:合并K个升序链表【22/1000 python】

“合并K个升序链表”&#xff0c;这是一道中等难度的题目&#xff0c;经常出现在编程面试中。以下是该问题的详细描述、解题步骤、不同算法的比较、代码示例及其分析。 问题描述 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中…

BUCK 电路详解

参考内容&#xff1a; 手撕Buck&#xff01;Buck公式推导过程 电力电子的基础应用 《精通开关电源设计&#xff08;第二版&#xff09;》 Buck电源芯片输出有问题&#xff1f;检查这几样 原来PWM这么简单&#xff01; BUCK 电路构建 根据高中所学习的物理知识可以很容易的想到…

Harmony鸿蒙南向驱动开发-MIPI CSI接口使用

功能简介 CSI&#xff08;Camera Serial Interface&#xff09;是由MIPI联盟下Camera工作组指定的接口标准。CSI-2是MIPI CSI第二版&#xff0c;主要由应用层、协议层、物理层组成&#xff0c;最大支持4通道数据传输、单线传输速度高达1Gb/s。 物理层支持HS&#xff08;High …

18_SPI通信外设

SPI通信外设 SPI通信外设SPI外设简介SPI框图SPI基本结构主模式全双工连续传输非连续传输 SPI通信外设 SPI外设简介 STM32内部集成了硬件SPI收发电路&#xff0c;可以由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU的负担 可配置8位/16位数据帧、高位先行/低位先…

基于 MATLAB 和 App Designer 的 UI 交互框架开发的一款电力系统潮流计算工具

基于 MATLAB 和 App Designer 的 UI 交互框架开发的一款电力系统潮流计算工具 文章目录 基于 MATLAB 和 App Designer 的 UI 交互框架开发的一款电力系统潮流计算工具一、软件介绍二、软件功能1、数据输入 2、潮流作业设置3、 潮流结果报表及可视化三、 软件设计思路1 、牛顿拉…

蓝桥杯备考day4

1.1 二分查找模板 bool check(int x) {// 进行某些操作 } // 二分查找函数 int binarySearch() {int l 1, r n; // 初始化左右边界while (r - l > 1) // 当右边界与左边界相差大于1时{int mid (l r) >> 1; // 取中间位置if (check(mid)) // 如果满足条件r mid; …

[目标检测] OCR: 文字检测、文字识别、text spotter

概述 OCR技术存在两个步骤&#xff1a;文字检测和文字识别&#xff0c;而end-to-end完成这两个步骤的方法就是text spotter。 文字检测数据集摘要 daaset语言体量特色MTWI中英文20k源于网络图像&#xff0c;主要由合成图像&#xff0c;产品描述&#xff0c;网络广告(淘宝)MS…

AcWing-直方图中最大的矩形

131. 直方图中最大的矩形 - AcWing题库 所需知识&#xff1a;单调栈 思路&#xff1a;要求最大矩形&#xff0c;所以需要使矩形的高与长的乘积最大即可&#xff0c;依次从左到右将每一列当作中心列&#xff0c;向两边扩散&#xff0c;直到两边的高都小于该列的高&#xff0c;…

Prj文件的几种制作方式

0.序&#xff1a; 多数平面坐标的设计成果&#xff0c;不论是CAD文件&#xff0c;还是BIM模型&#xff0c;还是投影单独存储的tif影像&#xff0c;还是国土部门申请的平面坐标的文本文件&#xff0c;要想和底图叠加&#xff0c;都需要通过正确的投影匹配起来。 多数软件都提供…

解决源 “MySQL 8.0 Community Server“ 的 GPG 密钥已安装,但是不适用于此软件包。请检查源的公钥 URL 是否配置正确。

源 “MySQL 8.0 Community Server” 的 GPG 密钥已安装&#xff0c;但是不适用于此软件包。请检查源的公钥 URL 是否配置正确。 失败的软件包是&#xff1a;mysql-community-server-8.0.31-1.el7.x86_64 GPG 密钥配置为&#xff1a;file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql…

8. 托盘图标与菜单

内容概要&#xff1a; 托盘图标的设置与事件 右键菜单的相关操作 窗口组件&#xff1a; 1.组件的属性 组件属性&#xff1a;位置 组件属性&#xff1a;可视 2.组件的事件 窗口_托盘事件-带有参数的事件的使用方法 3.组件的方法 置托盘图标 菜单的操作 1.创建菜单 …

模型训练----apex库报错IndexError: tuple index out of range

问题描述 在训练模型的过程中遇到了apex库的报错IndexError: tuple index out of range导致无法训练。在github查询后找到了解决方法 问题解决 需要修改/apex-master/apex/amp/utils.py这个文件的代码 从93行开始修改 if x in cache:cached_x cache[x]next_functions_ava…

nvm更新node版本

1、nvm安装和管理多个 Node.js 版本&#xff1a;NVM 允许用户在计算机上同时安装多个不同版本的 Node.js。这使得开发人员可以轻松地在不同的项目中使用不同的 Node.js 版本&#xff0c;而无需手动安装或卸载。 2、nvm切换 Node.js 版本&#xff1a;通过 NVM&#xff0c;用户可…

软考122-上午题-【软件工程】-需求分析

一、软件需求 在进行需求获取之前&#xff0c;首先要明确需要获取什么&#xff0c;也就是需求包含哪些内容。 软件需求是指用户对目标软件系统在功能、行为、性能、设计约束等方面的期望。通常&#xff0c;这些需求包括功能需求、性能需求、用户或人的因素、环境需求、界面需…

深入探索力扣第12题:整数转罗马数字的算法之旅

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作http://t.csdnimg.cn/Q59WX作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打…

国家统计局行政区划获取及入库ES实践

我们先看下最终效果&#xff1a; 1. ES索引新建 PUT administrative_division {"mappings": {"properties": {"province": {"type": "keyword"},"province_code": {"type": "keyword"},&q…

Factory Method 工厂方法

意图 定义一个用户创建对象的接口&#xff0c;让子类决定实例化哪一个类&#xff0c;Factory Method使一个类的实例化延迟到其子类 结构 其中 Product定义工厂方法做创建的对象的接口。ConcreteProduct实现Product接口Creator声明工厂方法&#xff0c;该方法返回一个Product…

海外软文通稿代发 - 大舍传媒

引言 在当今高度信息化的时代&#xff0c;企业和个人品牌形象的塑造与传播变得越来越重要。为了在国际舞台上获得更大的竞争优势&#xff0c;许多企业和品牌纷纷将视线投向了国外市场。而在这个过程中&#xff0c;专业的软文通稿代发服务成为了他们的得力助手。本文将向您介绍…