0基础学习C++做贪吃蛇, 边玩儿边学习!(六)结构体和while循环——各具特色的蛇

发布于:2022-11-27 ⋅ 阅读:(299) ⋅ 点赞:(0)

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

你的耐心已经被五期的学习消磨殆尽了吗?

那就看这个:

#include <iostream>
#include<conio.h>
#include <windows.h>
//初始长度
#define LENGTH 5
//输出符号
#define NoSymbol ' '
#define BodySymbol 'o'
#define HeadSymbol 'O'
using namespace std;
//窗口句柄
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) {//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++
}
//移动
void move() {
    int head = LENGTH - 1;//head和tail表示头尾所在的下标。
    int  tail = 0;
    while (1) {//while(1)恒成立,此为无限循环
        Sleep(200);//休眠200毫秒
        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;
}

以上可以直接复制粘贴编译运行,结果如下:
请添加图片描述

拿去不谢!

现在我们分析以上这个 真正实现移动 的代码。

先看预处理语句:

#include <iostream>
#include<conio.h>
#include <windows.h>
//初始长度
#define LENGTH 5
//输出符号
#define NoSymbol ' '
#define BodySymbol 'o'
#define HeadSymbol 'O'
三句#include讲过了,忘记的可以去看前几期。#define我们讲过是宏定义,就是给一段字符起一个别名,编译器会在预处理阶段将程序中相应的宏名用他所代表的内容代替。

这个叫宏定义
也就是说,之后程序中出现的Nosymbol这些,就是指上方程序中宏定义的空格符号这些。
再看后面几句。

using namespace std;
//窗口句柄
HANDLE handle;
//蛇体坐标数组
COORD body[LENGTH];

第一句,使用标准命名空间。
标准命名空间(namespace std) 是C++标准库所在的命名空间,只有使用标准命名空间,才能正确使用C++标准库里的函数。(如cout())。

命名空间是C++为了解决相同标识符的问题而引入的。暂时不必理会。

第二句:窗口句柄。
忘记的可以回顾前几期。

第三句:COORD是Windows API(Application Program Interface,应用编程接口)中定义的一种结构。表示一个字符在控制台屏幕上的坐标。

API:所谓接口就是某程序对外的门户,其他程序可以按照此程序接口的规则来获取自己想要的数据。

对接口编程:就好像你可以通过填写借记卡来从学校图书馆借到你想要的书籍一样,只要我们对接口编程,就可以获得提供接口的程序独有的信息。(比如:我们不能直接控制屏幕,但可以通过操作系统(接口提供者,屏幕控制者)提供的COORD结构来接触控制台屏幕坐标。)

COORD结构的定义如下:

typedef struct _COORD{
SHORT X;//横坐标
SHORT Y;//纵坐标
} COORD;

结构,是一种数据类型,语法如上图,声明了一个struct _COORD 的结构体类型,别称为COORD(typedef用来定义别名,在这里意为:struct _COORD 又名COORD)

如果没有typedef语句,那么我们若要定义一个COORD(坐标)型变量,语句为:
struct _COORD pos;
若有别名,可以直接写成:
COORD pos;

还搞不懂?
我们专门学习一下。

#include<iostream>
using namespace std;
//声明一个结构体类型 _snake ,并给 struct _snake 一个叫 snake 的别名。 
typedef struct _snake
{
    char HeadSymbol;//结构体第一个成员是char型的HeadSymbol
    char BodySymbol;//第二个成员
    int LENGTH;//第三个成员
}snake;
//声明结构体类型 struct food
struct food {
    char Symbol;
    short distance;
};
//用来显示snake的函数
void displaySnake(snake s) {
    cout << s.HeadSymbol;
    int i = 0;
    /*
    while循环,是一种循环结构,
    先判断()内是否成立,若成立则运行{}中代码
    {}执行一遍后继续判断()内成立与否
    循环,直至()内不成立,结束。
*/
    while (i < s.LENGTH) {
        cout << s.BodySymbol;
        i++;
    }
}
//用来显示food的函数
void displayFood(struct food f) {
    cout << f.Symbol;
    for (int i = 0;i < f.distance;i++) cout << ' ';
}

int main() {
    snake s1, s2;//定义snake(即struct _snake类型)型变量s1,s2
    /*
定义struct food型变量f1,{}内按顺序填成员的初始值,
用逗号隔开。即:f.Symbol='*';f.distance=3;
*/
    struct food f1 = { '*',3 };
    s1 = { '0','c',6 };//初始化
    s2.BodySymbol = 'o';// . 表示引用成员,可以通过点操作符直接访问成员(可以赋值,取值)
    s2.HeadSymbol = 'O';//通过点操作符引用成员变量HeadSymbol
    s2.LENGTH = s1.LENGTH;//赋值。
    displaySnake(s1);//将s1作为参数传递给displaySnake函数,开始执行此函数。
    cout <<"  ";
    displaySnake(s2);//显示s2
    cout << '\n';//输出一个换行('\n'是转义字符,char类型,表示换行)
    displayFood(f1);//显示f1
    return 0;
}
仔细阅读以上代码和注释,你将学会:
(1)结构体的声明,定义,引用,操作
(2)结构体别名之与否的区别
(3)while循环

输出如下:
在这里插入图片描述
while循环的具体内容看注释。
总之一句话:只要()内成立就一直执行{}。

以上就是本期所有内容。
下一期,我们继续分析本篇开头的 “真实运动” 代码,并学习数组。

注:以上两个源码可以直接复制粘贴编译运行。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到