挑战!贪吃蛇小游戏的实现(3)

经过(1)(2)两篇文章的介绍,相信大家对该游戏的实现已经有了具体的思路,废话不多说,让我们开始实现相关的代码吧!

 1.游戏主逻辑


void test()
{int ch = 0;srand((unsigned int)time(NULL));do{Snake snake = { 0 };GameStart(&snake);GameRun(&snake);GameEnd(&snake);SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar();} while (ch == 'Y');SetPos(0, 27);
}
int main()
{setlocale(LC_ALL, "");//修改当前地区为本地模式test();return 0;
}

2.游戏开始

void GameStart(pSnake ps)
{system("mode con cols=100 lines=30");//设置控制台窗口大小为30行100列system("title 贪吃蛇");//设置窗口名HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false;//隐藏控制台光标SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//打印地图CreateMap();//初始化蛇InitSnake(ps);//创造第一个食物CreateFood(ps);
}

2.1打印欢迎界面

在游戏正式开始之前,做一些功能提醒

void WelcomeToGame()
{SetPos(40, 15);printf("欢迎来到贪吃蛇小游戏");SetPos(40, 25);system("pause");system("cls");SetPos(25, 12);printf("用↑ ↓ ← →分别控制蛇的移动,F3为加速,F4为减速");SetPos(25, 13);printf("加速能够获得更高的分数");SetPos(40, 25);//让任意键继续出现的位置好看些system("pause");system("cls");
}

2.2创建地图

墙体打印的宽字符 #define WALL L'✖'

创建地图函数CreateMap

void CreateMap()
{int i = 0;SetPos(0, 0);for (i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}SetPos(0, 26);for (i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}for (i = 1; i < 26; i++){SetPos(0, i);wprintf(L"%lc", WALL);}for (i = 1; i < 26; i++){SetPos(56, i);wprintf(L"%lc", WALL);}
}

2.3初始化蛇身

蛇最开始的长度为5节,每节对应链表的一个节点,蛇身的每一个节点都有自己的坐标。创建5个节点,然后将每一个节点放在链表中进行管理。创建完蛇身后,将蛇的每一节打印在屏幕上,然后再设置当前游戏的1状态,蛇移动的速度,默认的方向,初始成绩,蛇的状态和每个食物的分数。

蛇身打印的宽字符: #define BODY L'〇'

初始化蛇身函数InitSnake 

#define POS_X 24

#define POS_Y 5

void InitSnake(pSnake ps)
{pSnakeNode cur = NULL;int i = 0;//创建蛇身节点并初始化坐标,头插法for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake()::malloc()");return;}cur->next = NULL;cur->x = POS_X + i * 2;cur->y = POS_Y;if (ps->_pSnake == NULL){ps->_pSnake = cur;}else{cur->next = ps->_pSnake;ps->_pSnake = cur;}}//打印蛇的身体while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//初始化贪吃蛇数据ps->_sleepTime = 200;ps->_Score = 0;ps->_foodWeight = 10;ps->_Dir = RIGHT;ps->_Status = OK;
}

2.4创建食物

  • 先随机生成食物的坐标:x坐标必须是2的倍数并且食物的坐标不能和蛇身的每个节点坐标重复
  • 创建食物节点,打印食物,食物打印宽字符:#define FOOD L'❤'

创建食物的函数CreateFood

void CreateFood(pSnake ps)
{int x = 0;int y = 0;
again:do{x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);//产生的x坐标应该是2的倍数,这样才能和蛇头对齐pSnakeNode cur = ps->_pSnake;//获取指向蛇头的指针while (cur){if (cur->x == x && cur->y == y){goto again;}cur = cur->next;}pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));//创建食物if (pFood == NULL){perror("CreateFood::malloc()");return;}else{pFood->x = x;pFood->y = y;SetPos(pFood->x, pFood->y);wprintf(L"%lc", FOOD);ps->_pFood = pFood;}}

3.游戏运行

  • 游戏运行期间,右侧帮助打印信息,提示玩家
  • 根据游戏状态检查游戏是否继续
  • 如果游戏继续,继续检测按键状态,确定蛇下一步移动的方向以及是否加速减速暂停退出
  • 确定了上述信息后,蛇继续移动
void GameRun(pSnake ps)
{PrintHelpInfo();do{SetPos(64, 10);printf("得分:%5d", ps->_Score);printf("每个食物得分:%02d", ps->_foodWeight);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 = END_NORMAL;break;}else if (KEY_PRESS(VK_SPACE)){pause();}else if (KEY_PRESS(VK_F3))//加速,休眠时间减少,每次得分增加{if (ps->_sleepTime >= 50){ps->_sleepTime -= 30;ps->_foodWeight += 2;}}else if (KEY_PRESS(VK_F4)){if (ps->_foodWeight > 2){ps->_sleepTime += 30;ps->_foodWeight -= 2;}}Sleep(ps->_sleepTime);//睡眠一下SnakeMove(ps);//走一步} while (ps->_Status == OK);
}

3.1KEY_PRESS

为了检测按键状态,我们封装了一个宏

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

3.2打印帮助信息PrintHelpInfo

void PrintHelpInfo()
{//打印提示信息SetPos(64, 15);printf("不能穿墙,不能咬到自己");SetPos(64, 16);printf("用↑↓←→分别控制蛇的移动");SetPos(64, 17);printf("F3为加速,F4为减速");SetPos(64, 18);printf("ESC:退出游戏 space:暂停游戏");
}

3.3蛇身移动

  • 先创建下一个节点,根据移动方向和蛇头的坐标,蛇移动到下一个位置的坐标
  • 确定了下一个位置后,看下一个位置是否是食物(NextIsFood),是食物就做吃食物处理(EatFood),不是食物就做前进一步处理(NoFood)。
  • 蛇身移动以后,判断此次移动是否会撞墙(KillByWall)或者撞到自己(KillBySelf),从而影响游戏的状态
void SnakeMove(pSnake ps)
{//创建下一个节点pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNextNode == NULL){perror("SnakeMove()::malloc()");return;}pNextNode->next = NULL;//要根据蛇头的坐标和方向确定下一个节点switch (ps->_Dir){case UP:{pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;}break;case DOWN:{pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;}break;case LEFT:{pNextNode->x = ps->_pSnake->x-2;pNextNode->y = ps->_pSnake->y;}break;case RIGHT:{pNextNode->x = ps->_pSnake->x+2;pNextNode->y = ps->_pSnake->y;}break;}if (NextIsFood(pNextNode, ps)){EatFood(pNextNode,ps);}else{NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps);}

NextIsFood

int NextIsFood(pSnakeNode psn, pSnake ps)
{return ((psn->x == ps->_pFood->x) && (psn->y == ps->_pFood->y));
}

EatFood


void EatFood(pSnakeNode psn, pSnake ps)//第一个参数是下一个节点的指针,第二个参数是维护蛇的指针
{//头插法psn->next = ps->_pSnake;ps->_pSnake = psn;pSnakeNode cur = ps->_pSnake;//打印蛇while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->_Score += ps->_foodWeight;free(ps->_pFood);//释放食物节点CreateFood(ps);//创建新的食物
}

NoFood

将下一个节点头插入蛇的身体,并且将之前蛇身的最后一个节点打印为空格,放弃掉原来蛇身的最后一个节点

void NoFood(pSnakeNode psn, pSnake ps)//将下一个节点插入蛇的身体,并且将蛇身的最后一个节点打印为空
{//头插法psn->next = ps->_pSnake;ps->_pSnake = psn;pSnakeNode cur = ps->_pSnake;//打印蛇while (cur->next->next){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}SetPos(cur->next->x, cur->next->y);printf(" ");free(cur->next);cur->next = NULL;	
}

KillByWall

判断蛇头的坐标是否与墙体坐标冲突

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;}
}

KillBySelf

判断蛇头的坐标是否和蛇身冲突

void KillBySelf(pSnake ps)//从第二个节点开始检测是否和头相撞了
{pSnakeNode cur = ps->_pSnake->next;while (cur){if ((ps->_pSnake->x == cur->x) && (ps->_pSnake->y == cur->y)){ps->_Status = KILL_BY_SELF;}}
}

4.游戏结束

当游戏状态不再是OK时,要告知游戏结束的原因并且释放蛇身节点

void GameEnd(pSnake ps)
{pSnakeNode cur = ps->_pSnake;SetPos(24, 12);switch (ps->_Status){case END_NORMAL:printf("您主动退出游戏\n");break;case KILL_BY_SELF:printf("撞上自己,游戏结束\n");break;case KILL_BY_WALL:printf("装上墙壁,游戏结束\n");break;}//释放蛇身节点while (cur){pSnakeNode del = cur;cur = cur->next;free(del);}free(ps->_pFood);ps->_pFood = NULL;ps->_pSnake = NULL;
}

以上就是贪吃蛇小游戏的全部核心代码啦,完整的代码请大家移步我的码云:

https://gitee.com/peach-table

新年新气象!让我们用一条贪吃蛇来迎接2024的好运吧~

祝大家新的一年身体健康万事如意,发!大!财!☼

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

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

相关文章

【Unity3D】ASE制作天空盒

找到官方shader并分析 下载对应资源包找到\DefaultResourcesExtra\Skybox-Cubed.shader找到\CGIncludes\UnityCG.cginc观察变量, 观察tag, 观察代码 需要注意的内容 ASE要处理的内容 核心修改 添加一个Custom Expression节点 code内容为: return DecodeHDR(In0, In1);outp…

在Win系统部署WampServer并实现公网访问本地服务【内网穿透】

目录 推荐 前言 1.WampServer下载安装 2.WampServer启动 3.安装cpolar内网穿透 3.1 注册账号 3.2 下载cpolar客户端 3.3 登录cpolar web ui管理界面 3.4 创建公网地址 4.固定公网地址访问 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0…

企业资产|企业资产管理系统|基于springboot企业资产管理系统设计与实现(源码+数据库+文档)

企业资产管理系统目录 目录 基于springboot企业资产管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、用户审核管理 3、资产分类管理 4、资产信息管理 5、资产信息添加 6、资产借出统计 7、资产归还审核 8、资产维修管理 9、资产维修…

c++笔记理解

1.封装 &#xff08;1&#xff09;构造函数不是必须在的 可以通过行为修改属性 &#xff08;2&#xff09;private和protected区别在于继承那里要学 &#xff08;3&#xff09;类默认是私有&#xff0c;struct是共有 私有的好处&#xff1a;控制数据的有效性&#xff0c;意…

MySQL 8.0.36 WorkBench安装

一、下载安装包 百度网盘链接&#xff1a;点击此处下载安装文件 提取码&#xff1a;hhwz 二、安装&#xff0c;跟着图片来 选择Custom,然后点Next 顺着左边框每一项的加号打开到每一个项的最底层&#xff0c;点击选中最底层的项目&#xff0c;再点击传过去右边的绿色箭头&a…

Codeforces Round 530 (Div. 2)

CF1099A Snowball 题目 有一个重量为 w 的雪球正在高度为 h 的地方向下滚动。每秒它的高度会减少 1。同时在高度 i 的位置它的重量会增加 i&#xff08;包括初始位置&#xff09; 同时在滚动的路线上有 2 块石头&#xff0c;第 i 块石头的高度为 hi​&#xff0c;即雪球会在 hi…

【论文阅读|基于 YOLO 的红外小目标检测的逆向范例】

基于 YOLO 的红外小目标检测的逆向范例 摘要1 引言2 相关工作2.1 逆向推理2.2 物体检测方法 3 方法3.1 总体架构3.2 逆向标准的可微分积分 4 实验4.1 数据集和指标4.2 实验环境4.4 OL-NFA 为少样本环境带来稳健性 5 结论 论文题目&#xff1a; A Contrario Paradigm for YOLO-b…

详解 leetcode_078. 合并K个升序链表.小顶堆实现

/*** 构造单链表节点*/ class ListNode{int value;//节点值ListNode next;//指向后继节点的引用public ListNode(){}public ListNode(int value){this.valuevalue;}public ListNode(int value,ListNode next){this.valuevalue;this.nextnext;} }package com.ag; import java.ut…

[树形DP] 最长乘积链

题目 1.最长乘积链 - 蓝桥云课 (lanqiao.cn) 初始思路 对问题进行分析&#xff0c;对每个点dfs去求走不同路的最远距离与次远距离求乘积&#xff0c;时间复杂度为O(n^2) 看了答案怎么弄的优化 解题思路 总的来说 预处理&#xff08;对每个结点的信息进行统计&#xff09…

AWS无服务器直播解决方案

随着媒体系统的发展&#xff0c;越来越多的直播客户想要一个即开即用的平台&#xff0c;在不需要管理和运维底层资源的同时使用一站式的媒体平台。九河云对多家云厂商有所了解及有一定合作&#xff0c;下面将按客户的需求介绍aws的无服务器直播解决方案。 架构概述&#xff1a…

Flutter插件开发指南02: 事件订阅 EventChannel

Flutter插件开发指南02: 事件订阅 EventChannel 视频 https://www.bilibili.com/video/BV1zj411d7k4/ 前言 上一节我们讲了 Channel 通道&#xff0c;但是如果你是卫星定位业务&#xff0c;原生端主动推消息给 Flutter 这时候就要用到 EventChannel 通道了。 本节会写一个 1~…

Unity编辑器扩展之是否勾选Text组件BestFit选项工具(此篇教程也可以操作其他组件的属性)

想要批量化是否勾选项目预制体资源中Text组件BestFit属性&#xff08;此篇教程也可以操作其他组件的属性&#xff0c;只不过需要修改其中对应的代码&#xff09;&#xff0c;可以采用以下步骤。 1、在项目的Editor文件中&#xff0c;新建一个名为TextBestFitBatchProcessor的…

Linux篇:指令

一 基本常识&#xff1a; 1. 文件文件内容文件的属性 2. 文件的操作对文件内容的操作对文件属性的操作 3. 文件的类型&#xff1a; d&#xff1a;目录文件 -&#xff1a;普通文件 4. 指令是可执行程序&#xff0c;指令的代码文件在系统的某一个位置存在的。/u…

Linux---进程间通讯(上)

一、进程间通讯的目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件&#xff0…

分享10款自媒体人常用ai写作工具,总有一款适合你 #其他#AI写作

你是否因为写作困顿而感到沮丧&#xff1f;是不是希望能够找到一个能给你提供无限灵感和提高创作效率的利器&#xff1f;AI写作助手就是你的绝佳选择&#xff01;现在我向大家推荐几款好用的AI写作助手&#xff0c;它们将让你的创作之旅更加流畅、富有创意。 1.七燕写作 这是一…

十二、通过色彩空间转换进行更换图片背景

项目功能实现&#xff1a;对一张白色背景的图片进行更换成蓝色背景&#xff0c;类似抠图更换背景操作 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 inrange.h #pragma once#include<opencv2/opencv.hpp>using namespace cv;class INRANGE{ public:v…

华为OD机试真题-围棋的气-2023年OD统一考试(C卷)---python代码

题目&#xff1a; 代码&#xff1a; """ # 输入&#xff1a;2的倍数 第一个为行号 0-18 第二个为列号 0-18第一行为黑色 第二行为白色思路&#xff1a;先求黑色&#xff0c;进行去重棋子的位置&#xff0c;再求白色 逐个棋子求坐标。 """ d…

OpenLayers6入门,如何销毁已经创建好的OpenLayers地图容器

专栏目录: OpenLayers入门教程汇总目录 前言 本章介绍如何销毁已经创建好的OpenLayers地图容器。 在某些场景下,可能会需要销毁之前的地图,重新创建新的地图的需要,因此本章介绍一下在开始创建地图前如何先销毁之前的地图的功能。 二、依赖和使用 "ol": &qu…

用CSS3画一个三角形

<style> .up{width:0;height:0;border: 100px solid transparent;border-top: 100px solid red;/*红色*/ } .down{width:0;height:0;border: 100px solid transparent;border-bottom: 100px solid blue;/*蓝色*/ } .left{width:0;height:0;border: 100px solid transpare…

【爬虫JS逆向-工具篇】浏览器内存漫游加密参数Hook实战教程

文章目录 1. 写在前面2. 环境搭建2. 加密定位实战 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋友可以关…