0基础学习C++做贪吃蛇, 边玩儿边学习!(八)switch分支语句和键盘控制——自由移动的蛇

这篇具有很好参考价值的文章主要介绍了0基础学习C++做贪吃蛇, 边玩儿边学习!(八)switch分支语句和键盘控制——自由移动的蛇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

点击链接回顾前几篇:
(一)标准输出cout——一条安静的蛇
(二)代码详解和Sleep()——蛇之闪现
(三)SetConsoleCursorPosition光标移动效果——一条前进的蛇
(四)预定义和函数调用——妄图得分的蛇
(五)for循环和作用域——可长可短的蛇
(六)结构体和while循环——各具特色的蛇
(七)数组和移动逻辑——徐徐移动的蛇

本节我们添加对键盘方向键的响应,实现按照键盘实时输入来改变前进方向,这将是一条真正自由移动的蛇!

最后效果如下:
0基础学习C++做贪吃蛇, 边玩儿边学习!(八)switch分支语句和键盘控制——自由移动的蛇
首先,在程序开头预处理语句之后加入一句:

//初始方向
int Arrow = 77;

这里定义了一个int型的全局变量Arrow,初始化为77。
什么意思呢?

当我们敲击键盘时,按键对应符号的键值就会出现在STDIN(标准输入)缓存区中,一般这个值是它的ascii码,比如,当我们输入a,它的ASCII是97,当我们按照int型来读取时,就会读到65。

#include<iostream>
#include<conio.h>
using namespace std;
int main() {
    cout << _getch();
}

编译执行,输入A,键盘显示65。
_getch()函数用来获取一个字符,但不显示在屏幕上。这个函数包含在头文件conio.h中。
不同于其他按键,方向键有两个键值,需要用_getch()读两次。

方向键 键值
224,72
224,80
224,75
224,77

可以看到,四个方向键的第一个键值都是224,第二个各不相同。如果我们用_getch()读取两次,第一次读到224,第二次读到77,就说明“→”被按下。

因此,我们用int型变量Arrow来记录当前方向,每当方向改变时,我们就更新Arrow。

那么如何实现变向呢?
在第六篇、第七篇中,我们在turn()函数中用一个长度为5的数组来记录蛇身每一个点的坐标,在每个循环中用蛇头右方那个位置的坐标来覆盖蛇尾坐标,并将h(对move()中head的引用)重定向到这个坐标,将t重定向到原来t的后一位,也就是新的尾部坐标。
回忆一下turn()函数

//倾向
void turn(int& h, int& t) {//h表示需要存储蛇头坐标的元素的下标,t表示蛇尾的
    body[t].X = body[h].X + 1;//将头部前面一格的位置保存在body[t]中
    h = t;//将t的值赋给h,此时body[h]表示的是新头部
    (t == LENGTH - 1) ? t = 0 : t++;//当t等于LENGTH时令t为0,否则t++
}

为什么之前几篇中的蛇都是向右移动呢?就是因为这里我们对body[h]的X坐标加了1,在控制台屏幕坐标系中,横向为X轴,向右为正方向,纵向为Y轴,向下为正方向。坐标原点是左上角。
所以,显然的,蛇头朝四个方向移动的坐标变化分别为:

方向 横坐标 纵坐标
不变 Y-1
不变 Y+1
X-1 不变
X+1 不变

所以,我们修改turn()函数为:

//设置新的蛇身数组
void turn(int& h, int& t) {
    //定义一个COORD型变量dir初值为{0,0}
    COORD dir = { 0,0 };
    //根据Arrow的值来设置dir,使之成为蛇头坐标的变化量。
    switch (Arrow) {
    case 72:
        dir.Y--;
        break;
    case 80:
        dir.Y++;
        break;
    case 75:
        dir.X--;
        break;
    case 77:
        dir.X++;
        break;
    default:
        break;
    }
    //用新的蛇头坐标覆盖原来的蛇尾坐标
    body[t].X = body[h].X + dir.X;
    body[t].Y = body[h].Y + dir.Y;
    h = t;//将t的值赋给h,此时body[h]表示的是新头部
    (t == LENGTH - 1) ? t = 0 : t++;//当t等于LENGTH时令t为0,否则t++
}

这里面出现了一个新的C++关键字,switch
用法如下:
形式:

   switch (expression)
    {
    case /* constant-expression */:
        /* code */
        break;
    case /* constant-expression */:
        /* code */
        break;
    default:
        break;
    }

先计算expression的值,然后拿他和每个case后的值对比,若相等,就从此case的冒号后执行。

break;
//此语句表示跳出while循环,或if 循环,或switch语句

所以turn()中的switch分支语句表示,按照Arrow可能的值执行不同的操作:
当Arrow等于72时,dir.Y- -
当Arrow等于80时,dir.Y++
当Arrow等于75时,dir.X- -
当Arrow等于77时,dir.X++

++是自增运算符,Y++相当于Y=Y+1(将Y+1的值赋给Y)
–同理

再看move()的变化

//移动
void move() {
    int head = LENGTH - 1;//head和tail表示头尾所在的下标。
    int  tail = 0;
    while (1) {//while(1)恒成立,此为无限循环
        Sleep(200);//休眠200毫秒
        if (_kbhit())//此两百毫秒内若有输入
            if (_getch() == 224)
                Arrow = _getch();
        draw(body[head], BodySymbol);//变头为体
        draw(body[tail], NoSymbol);//去尾
        turn(head, tail);//新的头尾
        draw(body[head], HeadSymbol);//画新头
    }
}

可以看到,在Sleep()和draw()语句之间,多了三行语句。这些语句涉及到一个很常见的C++关键字——if
他的形式是:

if(条件语句一){
执行……
}
else if(条件语句二){
……}
else if(条件语句三){}
else {
……
}

当一成立,则执行一的代码,并且下一句是整个 if 结构的下一行。
不然,判断二,若成立则执行二的代码,
……

直到else,当以上所有条件都不成立,执行else语句。
switch和if,就是计算机编程中赫赫有名的分支结构。只要用好分支结构,循环结构,顺序结构,任何现实需求都可以被转换成计算机编程逻辑。

== 表示等于,用来判断符号左右两侧的操作数是否相同,若相等,则为真,不等,则为假。
比如:

int x=5;
if(x==5) cout<<"is 5"<<endl;
else cout<<"not 5"<<endl;

先判断括号内的值。x==5成立,所以 if 的值为真,所以执行输出“is 5”。

if 条件语句可以省略else从句,如果每个分支只有一个语句,可以不写大括号。

如:

if(a>0)a++;
else if(a==0) a=0;
else a--;

具体看一下这三行。

        if (_kbhit())//此两百毫秒内若有输入
            if (_getch() == 224)
                Arrow = _getch();

第一句,若有输入(_kbhit()函数表示当前缓存区是否有输入,若有,则返回1,若无,则返回0)
第二句,获取输入,判断是否为224。

_getch()函数来自<conio.h>头文件,该函数获取一个键盘输入。(与前面见过的getch()一样,不过这是更规范的用法)
_kbhit()用来检测缓存区是否存在输入,若有,返回一个非0数(真)。

第三句,若为224,再用_getch()读一次(此时读到的是方向键的第二个键值),将值赋给Arrow()。

此时会出现一个问题,那就是当我们输入与当前前进方向相反的箭头时,蛇其实会倒退,为了解决这个问题,我们需要在赋值前对_getch()的值校验。

修改如下:

 if (_getch() == 224) {
                int newArrow = _getch();
                if (Arrow + newArrow != 152)//72+80=152,75+77也是152,因此可以这样校验
                    Arrow = newArrow;
            }

在主循环中,剩下的四句没变。
现在的move()函数作用就是初始化head和tail的指向后,进入循环while(),这个循环将贯穿游戏的全过程,我们称之为——游戏主循环
现在梳理一下游戏主循环的内容:
1,睡眠200ms;
2,判断是否有输入,若有,判断是否是方向键,若是,校验后将键值赋给Arrow;若不是或没有输入,绘制身体。
3,去头,擦尾,根据Arrow画新头。
4,继续下一循环。

最后给出全部代码:

#include <iostream>
#include<conio.h>
#include <windows.h>
//初始长度
#define LENGTH 5
//输出符号
#define NoSymbol ' '
#define BodySymbol 'o'
#define HeadSymbol 'O'
//初始方向
int Arrow = 77;
using namespace std;
//窗口句柄ppp
HANDLE handle;
//蛇体坐标数组
COORD body[LENGTH];
//显示
void draw(COORD pos, char symbol) {
    SetConsoleCursorPosition(handle, pos);//设置handle指向窗口光标位置为pos
    cout << symbol;
}
//预备
void ready() {
    for (int i = 0;i < LENGTH;i++) {
        body[i].X = i;//body数组内元素的横坐标从0到LENGTH-1递增
        body[i].Y = 10;//纵坐标不变
        draw(body[i], BodySymbol);//在数组每个元素代表的坐标处打印蛇身
    }
    draw(body[LENGTH - 1], HeadSymbol); // 将数组最后一个元素代表的坐标处重新绘制蛇头
}
//设置新的蛇身数组
void turn(int& h, int& t) {
    //定义一个COORD型变量dir初值为{0,0}
    COORD dir = { 0,0 };
    //根据Arrow的值来设置dir,使之成为蛇头坐标的变化量。
    switch (Arrow) {
    case 72:
        dir.Y--;
        break;
    case 80:
        dir.Y++;
        break;
    case 75:
        dir.X--;
        break;
    case 77:
        dir.X++;
        break;
    default:
        break;
    }
    //用新的蛇头坐标覆盖原来的蛇尾坐标
    body[t].X = body[h].X + dir.X;
    body[t].Y = body[h].Y + dir.Y;
    /*
    if (Arrow % 2)
        body[t].X = body[h].X + Arrow - 76;
    else body[t].Y = body[h].Y + Arrow / 4 - 19;
*/
    h = t;//将t的值赋给h,此时body[h]表示的是新头部
    (t == LENGTH - 1) ? t = 0 : t++;//当t等于LENGTH时令t为0,否则t++
}

//移动
void move() {
    int head = LENGTH - 1;//head和tail表示头尾所在的下标。
    int  tail = 0;
    while (1) {//while(1)恒成立,此为无限循环
        Sleep(200);//休眠200毫秒
        if (_kbhit())//此两百毫秒内若有输入
            if (_getch() == 224) {
                int newArrow = _getch();
                if (Arrow + newArrow != 152)//72+80=152,75+77也是152,因此可以这样校验
                    Arrow = newArrow;
            }
        draw(body[head], BodySymbol);//变头为体
        draw(body[tail], NoSymbol);//去尾
        turn(head, tail);//新的头尾
        draw(body[head], HeadSymbol);//画新头
    }
}
int main() {
    //获取句柄
    handle = GetStdHandle(STD_OUTPUT_HANDLE);
    //定义一个光标信息结构的对象
    CONSOLE_CURSOR_INFO cci;
    //将handle指向的窗口光标信息赋给cci
    GetConsoleCursorInfo(handle, &cci);
    //将光标隐藏
    cci.bVisible = FALSE;
    //设置handle指向窗口光标信息为cci
    SetConsoleCursorInfo(handle, &cci);
    ready();
    move();
    return 0;
}

本篇结束,下一篇我们完善键盘控制,让我们的贪吃蛇可停可动,可快可慢。文章来源地址https://www.toymoban.com/news/detail-483051.html

到了这里,关于0基础学习C++做贪吃蛇, 边玩儿边学习!(八)switch分支语句和键盘控制——自由移动的蛇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • (上) C语言中的语句分类及分支语句:if语句、switch语句介绍

    目录 前言 一、语句的分类 1. 空语句 2. 表达式语句 3. 函数调用语句 4. 复合语句 5. 控制语句 二、分支语句 1. if语句 (1) if的使用 (2) else的使用 (3) 分支中包含多条语句 (4) 嵌套if (5) 悬空else问题 2. switch语句 (1) if语句和switch语句的对比 (2) switch语句中的break (3) switch语句中的defa

    2024年01月22日
    浏览(70)
  • 【C语言步行梯】分支语句if...else、switch详谈

    🎯每日努力一点点,技术进步看得见 🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片+代码片段+网络相关题目的方式编写,欢迎订阅~~ C语言由 ; (分号)隔开的就是一条语句,举个例子↓↓↓ 生活中,我们有很多需要选择的情况。例如:你想

    2024年03月16日
    浏览(63)
  • 【C语言分支语句详解】:if,switch,让你的程序流程得心应手!

    🎥 屿小夏 : 个人主页 🔥个人专栏 : C语言详解 🌄 莫道桑榆晚,为霞尚满天! C语言中的控制语句是程序设计中不可或缺的重要组成部分。从简单的if语句到复杂的多分支结构,掌握这些语句对于编写高效、灵活的程序至关重要。本文将深入探讨C语言中控制语句的各种形

    2024年02月04日
    浏览(55)
  • 【C语言初阶】分支语句If与switch的具体用法,有这篇博客就够了

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,这里是君兮_,今天又来给大家更新0基础学习C语言中的文章啦! 今天带来的是对分支语句的详解,初学者建议先看看总集哦, 这里是链接: 【C语言初阶】万字解析,带你0基础快速入门C语言(上) 【C语言初阶】万字解析

    2024年02月11日
    浏览(62)
  • 【C++】switch 语句

    目录 1、缘起  2、笔记整理 3、if 和 switch 区别  4、总结         最近(2023-04-29)在 BiliBili 黑马程序员学习 C++  编程语言,今天学习到了 switch 语句 。以前在学习 C 语言  的时候,对这块知识点掌握的不是很好,总是遗忘。所以这次在学习 C++ 的时候,为了加强这块知

    2024年02月01日
    浏览(40)
  • 【C语言趣味教程】(10) 分支语句 Ⅱ:switch 语句 | fall-through 效应 | default 子句 | else 特性详解 | else 匹配原则 | 悬空 else 隐患

        🔗 《C语言趣味教程》👈 猛戳订阅!!! 0x00 switch 的语法 📚 介绍: switch 语句是一种多分支语句,常常用于 \\\"多分支\\\" 的情况。 用于不同条件执行不同动作,每一个 case 分支都是唯一的,从上往下逐一测试直到匹配为止。 一个标准的 switch 语句由三部分组成: case

    2024年02月03日
    浏览(53)
  • Java基础入门篇——Switch条件语句(十一)

    目录 一、switch条件语句 二、Scanner类使用 三、数据的输出 四、continue语句使用 Switch语句是一种条件语句,用于基于不同的条件值执行不同的代码块。它可以简化多个 if-else if-else 嵌套语句的结构。  Switch条件语句的基本结构: 在Switch语句中,一个表达式的值将与多个case进行

    2024年02月13日
    浏览(46)
  • 【零基础学JS - 14 】javaScript中的switch语句

    👨‍💻 作者简介:程序员半夏 , 一名全栈程序员,擅长使用各种编程语言和框架,如JavaScript、React、Node.js、Java、Python、Django、MySQL等.专注于大前端与后端的硬核干货分享,同时是一个随缘更新的UP主. 你可以在各个平台找到我! 🏆 本文收录于专栏: 零基础学JavaScript,包含Jav

    2024年02月07日
    浏览(38)
  • JS基础-分支语句

    分支语句是流程控制语句当中的一种 可以简单理解为是一种控制条件, 当达到某个条件时,执行相应的代码 IF多条件分支 例如:当 变量 a b 时, 则执行 语句块1 , 如果 a 等于 b 时,则执行语句块2 ;最后,如果 a b 时,则执行语句块3 if else 语句当中的语句块一般具有排斥作

    2024年02月09日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包