C语言贪吃蛇实现,以及一些有趣的想法(可加速减速)

文章目录

  • 每日一言
  • 代码:
    • Snake.h
    • Snake.c
    • test.c
  • 可以增加游戏趣味性的想法
  • 结语

每日一言

结局每隔一段时间就会到来,我经历它,就像飞机穿过云层。


跟着课程敲了一下午,终于写好了~
用到了一些没用过的函数,总结介绍一下

⭐首先是设置光标位置,它可以让我们指哪打哪,非常好用awa,以下是一个封装好的函数

//设置光标位置
void SetPos(int y, int x) {//获得设备句柄HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//根据句柄设置光标的位置COORD pos = { x,y };//先行后列更符合习惯SetConsoleCursorPosition(handle, pos);}

⭐接着是隐藏光标,光标总是一闪一闪的实在是有点烦(bushi
以下是让光标消失的魔法

//以下为隐藏光标代码
//控制台光标信息
CONSOLE_CURSOR_INFO cursor_info = { 0 };
//获得设备句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleCursorInfo(handle, &cursor_info);
//隐藏光标
cursor_info.bVisible = false;
//将更改应用到对应的控制台
SetConsoleCursorInfo(handle, &cursor_info);

⭐接下来是修改命令框大小与设置命令框标题

//设置命令框大小system("mode con cols=100 lines=50");//设置命令框标题system("title 贪吃蛇");

⭐然后是设置本地环境,让你可以打印出宽字符,需要包含#include<locale.h>

//设置本地环境,设置后支持宽字符的使用
setlocale(LC_ALL, "");

⭐还有最重要的如何检测一个键是否被按过,以下是一个被定义的宏,通过它来检查按键

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)) & 1 ? 1 : 0)

VK代表虚拟键值

以上只是这些函数的简单介绍,如果想详细了解的可以点击🌳虚拟键码

⭐接下来是要写完整个贪吃蛇用到的知识

  1. C语言(重要)
  2. 数据结构中的单链表(重要)
  3. WIN32 API (会用一点点就行)

代码:

Snake.h

#pragma once#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<locale.h>
#include<time.h>//检测一个键是否被按过
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)) & 1 ? 1 : 0)//方向
enum DIRECTION {UP = 1,DOWN,LEFT,RIGHT
};//游戏状态
enum GAME_STATUS
{OK = 1,KILL_BY_WALL,KILL_BY_SELF,GAMEOVER
};//蛇身
typedef struct SnakeNode {int x;int y;struct SnakeNode* next;
}SnakeNode, * pSnakeNode;//整条蛇
typedef struct Snake{int Score;//分数int FoodWight;//一个食物的分数int SleepTime;//每走一步需要的时间pSnakeNode pSnake;//维护整条蛇的指针pSnakeNode pFood;//维护食物的指针enum DIRECTION Dir;//方向enum GAME_STATUS Status;//游戏状态}Snake, * pSnake;//设置光标位置
void SetPos(int x, int y);//游戏开始前的准备工作
void GameStart(pSnake snake);//游戏运行时的维护工作
void GameRun(pSnake snake);//游戏结束时的维护工作
void GameEnd();

Snake.c

#include "Snake.h"//设置光标位置
void SetPos(int y, int x) {//获得设备句柄HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//根据句柄设置光标的位置COORD pos = { x,y };//先行后列更符合习惯SetConsoleCursorPosition(handle, pos);}//打印地图
void PrintMap() {int i = 0;//上SetPos(0, 0);for (i = 0; i < 58; i+=2) {wprintf(L"%c",L'■');}//下SetPos(26, 0);for (i = 0; i < 58; i+=2) {wprintf(L"%c", L'■');}//左for (i = 1; i < 26; i++) {SetPos(i, 0);wprintf(L"%c", L'■');}//右for (i = 1; i < 26; i++) {SetPos(i, 56);wprintf(L"%c", L'■');}
}//游戏介绍
void WelcomeToGame() {SetPos(13, 40);printf("欢迎来到贪吃蛇小游戏");SetPos(18, 41);system("pause");//暂停一下system("cls");//清空屏幕SetPos(12, 25);printf("用↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速");SetPos(13, 25);printf("加速将能得到更高的分数。");SetPos(18, 40);system("pause");//暂停一下system("cls");//清空屏幕
}//初始化蛇
void InitSnake(pSnake snake) {//初始化游戏数据snake->FoodWight = 10;snake->Dir = RIGHT;snake->Score = 0;snake->SleepTime = 200;snake->Status = OK;//创建蛇身(单链表)pSnakeNode cur = NULL;int i = 0;for (i = 0; i < 2; i++) {//创建蛇身节点cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (!cur) {perror("InitSnake() cur malloc fail");return;}//设置蛇的出生地cur->x = 5;cur->y = 24 + i * 2;//头插法cur->next = NULL;if (snake->pSnake == NULL) {snake->pSnake = cur;}else {cur->next = snake->pSnake;snake->pSnake = cur;}}//打印蛇的身体cur = snake->pSnake;while (cur) {SetPos(cur->x, cur->y);wprintf(L"●");cur = cur->next;}
}//创建食物
void CreateFood(pSnake snake) {int x = 0;int y = 1;roll://生成食物坐标//列应为2的倍数while (y % 2 != 0) {x = rand() % 25 + 1;y = rand() % 53 + 2;}//食物不能生成在蛇身上pSnakeNode cur = snake->pSnake;while (cur) {//如果与蛇身重复,则重新生成食物坐标if (cur->x == x && cur->y == y){goto roll;}cur = cur->next;}//创建食物pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));if (!pFood) {perror("CreateFood() pFood malloc fail");return;}else {//设置食物坐标pFood->x = x;pFood->y = y;//printf("x = %d y = %d", x, y);//打印食物SetPos(pFood->x, pFood->y);wprintf(L"☆");//将食物信息给到游戏snake->pFood = pFood;}//SetPos(27, 0);
}//游戏开始前的准备工作
void GameStart(pSnake snake) {//以下为隐藏光标代码//控制台光标信息CONSOLE_CURSOR_INFO cursor_info = { 0 };//获得设备句柄HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);GetConsoleCursorInfo(handle, &cursor_info);//隐藏光标cursor_info.bVisible = false;//将更改应用到对应的控制台SetConsoleCursorInfo(handle, &cursor_info);//设置命令框大小system("mode con cols=100 lines=30");//设置命令框题目system("title 贪吃蛇");//游戏介绍WelcomeToGame();//打印地图PrintMap(snake);//初始化蛇InitSnake(snake);//创建食物CreateFood(snake);}//打印游戏说明
void PrintHelpInfo() {SetPos(15, 64);printf("不能碰墙,不能咬到自己");SetPos(16, 64);printf("用↑.↓.←.→ 分别控制蛇的移动");SetPos(17, 64);printf("F3为加速,F4为减速");SetPos(18, 64);printf("ESC :退出游戏.space:暂停游戏.");
}//判断下一个位置是不是食物
bool IsFood(pSnake snake, pSnakeNode pNextNode) {if (snake->pFood->x == pNextNode->x && snake->pFood->y == pNextNode->y) {return true;}return false;
}//吃食物
void EatFood(pSnake snake,pSnakeNode pNextNode) {//头插pNextNode->next = snake->pSnake;snake->pSnake = pNextNode;//打印蛇pSnakeNode cur = snake->pSnake;while (cur) {SetPos(cur->x, cur->y);wprintf(L"●");cur = cur->next;}//加分数snake->Score += snake->FoodWight;//释放掉食物节点占用的内存free(snake->pFood);snake->pFood = NULL;//创建一个新的食物CreateFood(snake);
}//下个位置不是食物
void NotEatFood(pSnake snake, pSnakeNode pNextNode) {//头插pNextNode->next = snake->pSnake;snake->pSnake = pNextNode;//找到尾节点的前一个节点,顺便打印蛇身pSnakeNode cur = snake->pSnake;while (cur->next->next != NULL) {SetPos(cur->x, cur->y);wprintf(L"●");cur = cur->next;}//在蛇尾打印空格SetPos(cur->next->x, cur->next->y);printf("  ");//释放尾节点free(cur->next);cur->next = NULL;
}void SnakeMove(pSnake snake) {//创建下一个节点pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));if (!pNextNode) {perror("SnakeMove() pNextNode malloc fail");return;}//确定下一个节点的位置switch (snake->Dir) {case UP:{pNextNode->x = snake->pSnake->x - 1;pNextNode->y = snake->pSnake->y;break;}case DOWN:{pNextNode->x = snake->pSnake->x + 1;pNextNode->y = snake->pSnake->y;break;}case LEFT:{pNextNode->x = snake->pSnake->x;pNextNode->y = snake->pSnake->y - 2;break;}case RIGHT:{pNextNode->x = snake->pSnake->x;pNextNode->y = snake->pSnake->y + 2;break;}}//判断下一个节点是不是食物if (IsFood(snake,pNextNode)){//吃食物EatFood(snake, pNextNode);}else {//不是食物就正常走NotEatFood(snake, pNextNode);}//判断是否撞墙if (snake->pSnake->x == 26 ||snake->pSnake->x == 0 ||snake->pSnake->y == 0 ||snake->pSnake->y == 56){snake->Status = KILL_BY_WALL;return;}//判断是否撞到自己pSnakeNode cur = snake->pSnake->next;while (cur) {if (pNextNode->x == cur->x && pNextNode->y == cur->y) {snake->Status = KILL_BY_SELF;return;}cur = cur->next;}
}void pause() {while (1) {Sleep(300);//按空格退出暂停if (KEY_PRESS(VK_SPACE)){break;}}
}void GameRun(pSnake snake) {//打印游戏说明PrintHelpInfo();//蛇的移动do {//打印得分与食物分值SetPos(10, 64);printf("得分: %5d ", snake->Score);printf("每个食物分值:%2d分", snake->FoodWight);//判断玩家是否要改变蛇的方向//按上不能往下if (KEY_PRESS(VK_UP) && snake->Dir != DOWN) {snake->Dir = UP;}else if (KEY_PRESS(VK_DOWN) && snake->Dir != UP) {snake->Dir = DOWN;}else if (KEY_PRESS(VK_LEFT) && snake->Dir != RIGHT) {snake->Dir = LEFT;}else if (KEY_PRESS(VK_RIGHT) && snake->Dir != LEFT) {snake->Dir = RIGHT;}else if (KEY_PRESS(VK_SPACE)) {//暂停pause();}else if (KEY_PRESS(VK_F3)) {//加速if (snake->SleepTime >= 50){snake->SleepTime -= 30;snake->FoodWight += 2;}}else if (KEY_PRESS(VK_F4)) {//减速if (snake->SleepTime <= 320){snake->SleepTime += 30;snake->FoodWight -= 2;}}else if (KEY_PRESS(VK_ESCAPE)) {snake->Status = GAMEOVER;return;}//休眠一下Sleep(snake->SleepTime);//蛇走一步SnakeMove(snake);} while (snake->Status == OK);}//游戏结束时的维护工作
void GameEnd(pSnake snake) {//判断玩家是怎么输的if (snake->Status == KILL_BY_SELF) {SetPos(10, 18);printf("很可惜,你咬到自己了");}else if (snake->Status == KILL_BY_WALL) {SetPos(10, 18);printf("很可惜,你被墙撞死了");}else if (snake->Status == GAMEOVER) {SetPos(10, 18);printf("你选择了退出游戏");}//释放蛇身的节点pSnakeNode cur = snake->pSnake;while (cur) {pSnakeNode del = cur;cur = cur->next;free(del);}
}

test.c

#include "Snake.h"//int main() {
//	//设置命令框大小
//	system("mode con cols=100 lines=50");
//	//设置命令框标题
//	system("title 贪吃蛇");
//
//	//COORD pos = { 40,10 };
//
//	//控制台光标信息 结构体
//	CONSOLE_CURSOR_INFO cursor_info = { 0 };
//
//	//获得设备句柄
//	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//
//	GetConsoleCursorInfo(handle, &cursor_info);
//
//	//设置光标大小
//	//cursor_info.dwSize = 50;
//
//	//隐藏光标
//	cursor_info.bVisible = false;
//
//	//设置控制台
//	SetConsoleCursorInfo(handle, &cursor_info);
//
//	//根据句柄设置光标的位置
//	COORD pos = { 20,5 };
//	SetConsoleCursorPosition(handle, pos);
//	
//
//	printf("12345");
//
//
//	getchar();
//	return 0;
//}//int main() {
//	//设置本地环境,设置后支持宽字符的使用
//	setlocale(LC_ALL, "");
//	int i = 0;
//	for (i = 0; i < 60; i++)
//	{
//		SetPos(i, 0);
//		wprintf(L"%c", L'■');
//	}
//	for (i = 0; i < 30; i++)
//	{
//		SetPos(0 , i);
//		wprintf(L"%c", L'■');
//	}
//
//	return 0;
//}int main() {//设置本地环境,设置后支持宽字符的使用setlocale(LC_ALL, "");//设置随机数种子srand((unsigned int)time(NULL));int op = 0;do {//设置一条蛇Snake snake = { 0 };//游戏开始前的准备工作GameStart(&snake);//游戏运行时的维护工作GameRun(&snake);//游戏结束时的维护工作GameEnd(&snake);SetPos(13, 18);printf("重开一局?(Y/N):");op = getchar();//接收选项//拿走缓冲区内的换行getchar();} while (op == 'Y' || op == 'y');SetPos(15, 24);printf("退出游戏");SetPos(27, 0);return 0;
}

可以增加游戏趣味性的想法

  1. 在场上随机投放道具,吃到了可以获得2次穿墙机会(传送门)
  2. 在场上随机投放道具,吃到了令玩家的按键功能相反(按上蛇往下走)
  3. 可以吃道具,扩大地图,或者随着蛇的增大地图随之变大
  4. 给贪吃蛇染上新颜色
  5. 可以增加贪吃蛇选皮肤界面
  6. 可以吃道具,吃到后蛇分成两半,一边用wasd键操控,一边用上下左右键操控(该道具整局只在一条蛇时概率出现)
  7. 增加音效

结语

请给自己些耐心,一口吃不成胖子。
山外青山楼外楼,莫把百尺当尽头。
保持空杯心态加油努力吧!


都看到这里啦!真棒(*^▽^*)

可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家

编程小白写作,如有纰漏或错误,欢迎指正


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

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

相关文章

【Linux的网络编程】

1、OSI的七层网络模型有哪些&#xff0c;每一层有什么作用&#xff1f; 答&#xff1a;&#xff08;1&#xff09;应用层&#xff1a;负责处理不同应用程序之间的通信&#xff0c;需要满足提供的协议&#xff0c;确保数据发送方和接收方的正确。 &#xff08;2&#xff09;表…

【力扣100】70.爬楼梯 || python中的@cache || 装饰器

添加链接描述 思路&#xff1a; 最后一节楼梯的方式来自倒数第二节和倒数第三节的方法所以使用递归来做&#xff0c;定义递归出口n分别为1,2时候的方法种数&#xff1a;1种和2种类似于斐波那契数列超时了 优化&#xff1a; 5. 因为每次递归都要从n算到n为1和2的时候&#xff0…

安卓Java面试题 1-10

&#x1f525; 1、简述Android的4大组件是哪些&#xff0c;它们的作用&#xff1f;&#x1f525; Android的4大组件 1&#xff1a;Activity&#xff1a;Activity是Android程序与用户交互的窗口&#xff0c;是Android构造块中最基本的一种&#xff0c;它需要为保持各界面的状态…

Pytorch学习 day06(torchvision中的datasets、dataloader)

torchvision的datasets 使用torchvision提供的数据集API&#xff0c;比较方便&#xff0c;如果在pycharm中下载很慢&#xff0c;可以URL链接到迅雷中进行下载&#xff08;有些URL链接在源码里&#xff09;代码如下&#xff1a; import torchvision # 导入 torchvision 库 # …

VM 虚拟机 ubuntu 解决无法连接网络问题

添加网卡法 就是在虚拟机的设置那里多增加一个网卡

如何度量关键成果KR的完成情况?

明确度量指标 首先&#xff0c;需要为每一个关键成果&#xff08;Key Result&#xff09;设定明确的度量指标。这些指标应该是具体、可衡量的&#xff0c;以便能够清晰地反映关键成果的完成情况。例如&#xff0c;如果关键成果是提高网站的用户转化率&#xff0c;那么度量指标…

NOIP 2016普及组初赛试题及解析

NOIP 2016普及组初赛试题及解析 一. 单项选择题 (共20题,每题1.5分,共计30分。每题有且仅有一个正确答案.)。二. 问题求解(共2题,每题5分,共计10分)三. 阅读程序写结果(共4题,每题8分,共计32分)四. 完善程序 (前4空,每空2.5分,后6空,每空3分,共28分)一. 单项选…

论文阅读_解释大模型_语言模型表示空间和时间

英文名称: LANGUAGE MODELS REPRESENT SPACE AND TIME 中文名称: 语言模型表示空间和时间 链接: https://www.science.org/doi/full/10.1126/science.357.6358.1344 https://arxiv.org/abs/2310.02207 作者: Wes Gurnee & Max Tegmark 机构: 麻省理工学院 日期: 2023-10-03…

Linux设备模型(八) - sysfs

一&#xff0c;sysfs目录介绍 sysfs是一个基于内存的虚拟的文件系统&#xff0c;有kernel提供&#xff0c;挂载到/sys目录下&#xff0c;负责以设备树的形式向user space提供直观的设备和驱动信息。 sysfs以不同的视角展示当前系统接入的设备&#xff1a; /sys/block 历史遗…

滑动窗口算法

前言 滑动窗口作为一个考点较高的算法&#xff0c;广泛应用于子串问题中&#xff0c;本文将进行详细讲解。 一、滑动窗口是什么 滑动窗口是双指针算法的一种&#xff0c;基本思路为维护一个窗口&#xff0c;然后从前往后遍历元素进行运算。 二、滑动窗口算法和其他双指针算法…

Unity Samples和帧动画的问题

拖动序列帧图片和自己创建clip的帧率不同 我今天在创建帧动画的时候用了两种方式第一种是直接拖动序列帧图片到Hierachy&#xff0c;然后生成的第二种是这样我发现两者播放的动画速率不一样最后查了半天查不到原因。最后发现是Samples的原因&#xff0c;而且Unity把Samples这个…

分类预测 | Matlab基于GWO-RBF灰狼算法优化径向基神经网络的分类预测

分类预测 | Matlab基于GWO-RBF灰狼算法优化径向基神经网络的分类预测 目录 分类预测 | Matlab基于GWO-RBF灰狼算法优化径向基神经网络的分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 Matlab基于GWO-RBF灰狼算法优化径向基神经网络的分类预测。基于灰狼算法(GWO…

记一次Flink任务无限期INITIALIZING排查过程

1.前言 环境&#xff1a;Flink-1.16.1&#xff0c;部署模式&#xff1a;Flink On YARN&#xff0c;现象&#xff1a;Flink程序能正常提交到 YARN&#xff0c;Job状态是 RUNNING&#xff0c;而 Task状态一直处于 INITIALIZING&#xff0c;如下图&#xff1a; 通过界面可以看到…

小火星露谷模组管理页面简介

1. 已有详细介绍的功能 模组管理页面部分功能已经有较为详细的介绍&#xff1a; 添加模组&#xff1a;https://svmbbs.smallfire.cn/d/15-dian-nao-zhong-yi-jing-you-duo-ge-mo-zu-ya-suo-wen-jian-ru-he-pi-liang-an-zhuang一键更新模组&#xff1a;https://svmbbs.smallfi…

python基础——入门必备知识

&#x1f4dd;前言&#xff1a; 本文为专栏python入门基础的第一篇&#xff0c;主要带大家先初步学习一下python中的一些基本知识&#xff0c;认识&#xff0c;了解一下python中的一些专有名词&#xff0c;为日后的学习打下良好的基础,。本文主要讲解以下的python中的基本语法&…

苹果发布iOS17.4正式版升级,罕见带来一大波新功能!苹果数据备份软件 iOS系统管理软件 苹果数据备份到icloud iOS系统数据处理

近日&#xff0c;苹果发布了iOS17.4正式版&#xff0c;没想到的是居然有一大波新功能&#xff0c;如果你也是用iPhone的话&#xff0c;尤其是iPhone15新系列的&#xff0c;那么推荐你一定要升级下。下面让我给大家详细讲讲&#xff1a; 「电池健康」升级 电池设置界面得到了优…

LightDB支持 no_expand hint【24.1】【oracle兼容】

LightDB 从 24.1 开始支持 oracle no_expand hint。 no_expand hint 用于取消OR-expansion优化&#xff0c;不进行OR-expansion优化。 OR-expansion 在 Oracle 中 优化器会基于cost 优化带析取的查询块&#xff08;OR&#xff09;, 会拆分这个查询块为多个查询块&#xff0c;…

项目快速搭建脚手架

1.单体项目 5分钟搭建一个Spring Boot 前后端分离系统-Ballcat Ballcat 也会为每个版本的升级改动列出详细的更新日志&#xff0c;以及增量 SQL。 Github 地址 &#xff1a;https://github.com/ballcat-projects/ballcat Gitee 地址&#xff1a;https://gitee.com/ballcat-pro…

数字孪生10个技术栈:原型设计,界面从无到有雏形的第一步。

一、什么是原型设计 可视化界面的原型设计是指在设计过程中创建一个低保真或高保真的可视化模型&#xff0c;以展示和演示最终产品的外观、布局和交互。它是设计师和开发团队在实际开发之前用来验证和确认设计方案的一个重要步骤。 可视化界面的原型设计主要包括以下几个方面&…

【OpenCV】仿 IOS 锁屏时钟

OpenCV 是一个开源的计算机视觉&#xff08;Computer Vision&#xff09;与机器学习软件库&#xff0c;提供了多种图像处理算法与接口。在图像处理中&#xff0c;按位运算是一类重要的运算&#xff0c;可以用于提取图像的重要部分。本文主要记录如何使用 OpenCV-Python 绘制仿 …