难度预警!!!
一些结构体 的碎碎念

在之之前我们的结构体中,我们在里面写了成员函数,这样其实是错误的。我们之前是迫于无奈必须要用函数。
通常来说不允许这样使用,只让你使用成员变量。


在class 中 成员变量是隐藏的,不让你直接访问,通常要通过成员函数get set 方法 来访问。在大一新手村的时候我们早已滚瓜烂熟了。
矩形碰撞函数
我们一样用头文件来实现这个功能 名字就起做MyRect

-> 相当于 (*p). 解引用访问
映射 map
数据结构
线 树 图
真正的数据结构其实只有线,树其实是一种算法,使用的时候都是搭配一些高阶算法使用。
图是牵扯到架构 和 设计 方向的,网络地图等等东西,这玩意效率不高 最好不超过32个。
unity3d 用的碰撞检测用的是有序图,最多添加32个 多了不能添加了。
线性结构有很多经典的算法 图结构算法太多了,每个问题都有自己的算法
之后我们还要复习新手村学的 链表 线性表

map
树形结构 红黑树
迭代器 iterator
打包两个东西 随意组合两个数据 而且能容纳不同类型

定义一个类型的数据 我们称为bmpmap
这里面包含一些函数
find() 查找键值对

这里的 iterator 也是官方提供的 我们取名叫 it
键值对
pair<数据类型1,数据类型2>(数据1,数据2)

.insert()

这样就能在 我们的bmp map中存储我们的数据

在demo5的基础上改进
我们用一点面向对象的思想,我们最早的draw1.0版本 是编码一个图素,后来我们又改进成了2.0版本,也就是给定坐标和宽高,现在我们想进一步改进。
先定义一个 矩形结构体,这个矩形为了编程方便,并没有使用 四个角,而是给出了四条直线围成的矩形,方便后续编程。
struct MYRECT
MyRect.h

然后实现对应方法:
MyRect.cpp

这两个 一个是碰撞检测前面我们讲过了
一个是设置矩形 这里我们只需要 给定左上角坐标 矩形的宽和高 就可以设置好一个矩形,并且转换为 四个边的坐标,四个边的坐标更容易编程。
struct BMP
BMP 是 Bitmap(位图)的缩写,代表一种无损的栅格图像文件格式。该格式由微软开发,最初用于 Windows 操作系统存储图像数据。由于它以像素矩阵(位图)形式保存图像信息,因此得名"位图文件格式"(Bitmap File)。
- PNG:支持无损压缩,文件更小且透明通道。
- JPEG:有损压缩,适合照片但牺牲部分画质。
- BMP 的局限性:因未压缩导致占用空间大,现代应用逐渐减少。
这里我们是用控制台模拟的BMP。
我们在 GameDraw.h 中重新定义了一个结构体 BMP
这里我们把它的对应方法全部放在了GAMEDRAW里面,为了模拟结构体的正确用法。

BMP 只有宽高 和对应容量 这里的BMP是搭配使用的我们 我们继续改进OBJ这个 结构体 来进行管理。
struct OBJ
1.0 版本


在1.0版本中 我们只能绘制单一的图素 而且只能是长方形 这个功能就很积累 今天我们升级一下。

在OBJ2.0 中我们 把tis 和 w,h 这个东西换成了 cosnt cahr* key
这是什么呢?
这就是 拿来放 BMP 用的,当然 这里还没有 把BMP 和key 配合使用起来。
我们在上面的内容里介绍过的map 红黑树 就是用在这里
bool AddBmp(const char* key, BMP bmp);
我们已经知道 在OBJ里 图素被替换成了 const char* key 也就是一个字符串
这里我们是用来存放 bmp的索引的,那么怎么将 key字符串 和 bmp 绑定起来呢?
于是我们在 GameDraw.cpp 里面 性写了一个方法 bool AddBmp(const char* key, BMP bmp);

这个方法很贱单,使用的时候 传入一个 OBJ里的字符串key 和 一个创建好大小的BMP
先判断是否为空字符串
然后 我们用map 搞一个迭代器 std::map<const char*, BMP>::iterator it;
这个迭代器 是 const char* 和 结构体BMP 的组合类型。
注意这里使用map需要加头文件 #include <map>

我们提前在 GAMEDRAW 结构体中 创建出 bmpmap 红黑树对象
然后记住这个用法 就是 it用来接收 是否找到东西
it = bmpmap.find(key);
这里的返回值 我们并不关心 可以这样理解 it 就是指向这个bmpmap 的一个特殊的指针
这里可以存放返回的结果。
如果找到了 就可以指向 这个键值对
如果 it == bmpmap.end();
那就添加不了
就说明已经迭代到了最后一个 还是没有,就是没有 就可以添加上 这个键值对
添加的时候是这样使用的
首先 我们要知道怎么手动创造一个键值对
std::pair<const char*, BMP>(key, bmp)
然后把这个键值对添加到 bmpmap中 使用的是 insert方法
bmpmap.insert(std::pair<const char*, BMP>(key, bmp));、
完整的代码时这样的
cpp
bool GAMEDRAW::AddBmp(const char* key, BMP bmp)
{
if (key == 0)
return false;
//用key 直接查找 是否有数据
std::map<const char*, BMP>::iterator it;
it = bmpmap.find(key);
if (it != bmpmap.end())
return false;
bmpmap.insert(std::pair<const char*, BMP>(key, bmp));
return true;
}
bool Draw(const char* key, int x ,int y);
要知道 我们之前的draw 函数1.0 是画一个图素 2.0 是在一个矩形范围内画一个图素
这里 的3.0 是画一个bmp

这是我们2.0 的draw 函数
现在 我们直接改成 画BMP
那就是给 key ,x,y 就可以
首先 key 为空 , key中找不到BMP都直接返回false,记住只要找map里的东西 都要创建迭代器

接着 才是我们的 draw 功能
首先 我们怎么拿到这个 BMP呢? 很简单迭代器的第一个元素叫first 第二个元素叫 second
直接用指针 来指向这个 BMP 然后就拿到了

我们用 p -> 就可以拿到 BMP的 w,h 还有 _map[100]
然后进行绘制 这里注意 的是 只有 _map[i] 不等于0才绘制 这样在没有东西的地方 相当于BMP就透明了

这里自己 实现一下就好了
源.cpp
这里有变化的是 BMP我们要创建一下
几个量我们都初始化然后赋值就可以了

这里我们用了一个 {} 作用是释放内存。
效果完成!

附上工程源码:
MyRect.h
cpp
#pragma once
struct MYRECT {
int left, top, right, bottom;
bool Sollider(const MYRECT& other);
bool Set(int x, int y, int w, int h);
};
MyRect.cpp
cpp
#include "MyRect.h"
bool MYRECT::Sollider(const MYRECT& other)
{
if(right < other.left || left > other.right || bottom < other.top || top > other.bottom)
return false;
return true;
}
bool MYRECT::Set(int x, int y, int w, int h)
{
left = x;
top = y;
right = x + w - 1;
bottom = y + h -1;
return true;
}
GameDraw.h
cpp
#pragma once
#include <map>
using namespace std;
struct BMP {
int w, h;
char _map[100];
};
struct GameDraw {
int _max_w,_max_h;
int _w, _h;
int client[32 * 256];
char print[(15 * 2 + 1)*16 +1];
char _ts[128];
int _tslen;
int ww = 70, wh = 16;
int cx = 0, cy = 0, cw = 15, ch = 16;
map<const char*, BMP> bmp_map;
void init();//初始化各个数据
bool SetTs(const char* ts);//设置图素
bool SetSize(int w, int h);//设置窗口大小
void Begin();//把窗口大小中的client清零
void Draw(const char* key,int x,int y);//给client 编码画图
void End();//把client中的数据显示到窗口上
bool AddBmp(const char* key,BMP bmp);
};
GameDraw.cpp
cpp
#include "GameDraw.h"
#include <iostream>
#include <map>
void GameDraw::init()
{
_max_w = 256;
_max_h = 32;
_ts[0] = " "[0];
_ts[1] = " "[1];
_tslen = 0;
}
bool GameDraw::SetTs(const char* ts)
{
if (ts == nullptr) {
return false;
}
int i = 0;
while (1) {
if (ts[i] == '\0' || ts[i + 1] == '\0') {
break;
}
_tslen++;
_ts[_tslen * 2] = ts[i++];
_ts[_tslen * 2 + 1] = ts[i++];
}
return true;
}
bool GameDraw::SetSize(int w, int h)
{
if (w<1 || h<1 || w> _max_w || h> _max_h) {
return false;
}
_w = w;
_h = h;
return true;
}
void GameDraw::Begin()
{
for (int i = 0; i < _h; i++) {
for (int j = 0; j < _w; j++) {
client[i * _w + j] = 0;
}
}
}
void GameDraw::Draw(const char* key, int x, int y)
{
////第一个 左上角的定位点在地图中就行,其他的出界就不画
//
//for (int i = 0; i < h; i++) {
// for (int j = 0; j < w; j++) {
// if (x >= 0 && x < _w && y >= 0 && y < _h) {
// client[y * _w + x] = tsi;
// x++;
// }
// }
// y++;
// x -= w;
//}
if (key == nullptr)
return;
map<const char*, BMP>::iterator it;
it = bmp_map.find(key);
if (it == bmp_map.end())
return;
BMP bmp = it->second;
for (int i = 0; i < bmp.h; i++) {
for (int j = 0; j < bmp.w; j++) {
if (bmp._map[j + i * bmp.w] != 0)
client[y * _w + x] = bmp._map[j + i * bmp.w];
x++;
}
y++;
x -= bmp.w;
}
}
void GameDraw::End()
{
int pos = cx + cy * _w;
int size = 0;
for (int i = 0; i < ch; i++) {
for (int j = 0; j < cw; j++) {
if (client[pos + i * _w + j] == 0) {
print[size++] = _ts[client[pos + i * _w + j] ];
}
else {
print[size++] = _ts[client[pos + i * _w + j] * 2];
print[size++] = _ts[client[pos + i * _w + j] * 2 + 1];
}
}
print[size++] = '\n';
}
print[size] = 0;
system("cls");
std::cout << print;
}
bool GameDraw::AddBmp(const char* key, BMP bmp)
{
if (key == nullptr)
return false;
map<const char*, BMP>::iterator it;
it = bmp_map.find(key);
if (it == bmp_map.end()) {
bmp_map.insert(pair<const char*, BMP>(key, bmp));
return true;
}
else
return true;
}
源.cpp
cpp
#include <iostream>
#include"GameDraw.h"
#include<windows.h>
using namespace std;
struct OBJ {
int x, y;
/*int tsi;*/
const char* key;
};
void main() {
GameDraw gd;
OBJ hero = {0,0,"tank"};
{
BMP bmp_temp;
bmp_temp.w = 3;
bmp_temp.h = 3;
int temp_map[9] = {
0,2,0,
5,4,5,
5,0,5,
};
for (int i = 0; i < 9; i++) {
bmp_temp._map[i] = temp_map[i];
}
gd.AddBmp("tank", bmp_temp);
}
{
BMP bmp_temp;
bmp_temp.w = 4;
bmp_temp.h = 5;
int temp_map[20] = {
5,5,5,5,
5,5,5,5,
0,5,5,0,
0,5,5,0,
0,5,5,0,
};
for (int i = 0; i < 20; i++) {
bmp_temp._map[i] = temp_map[i];
}
gd.AddBmp("pipe", bmp_temp);
}
/*OBJ hero = { 0,0,1,1,3 };
OBJ ground = { 0,15,70,1,5 };
OBJ brick1 = { 11,5,4,2,5 };
OBJ brick2 = { 24,6,4,9,5 };*/
while (1) {
gd.init();
gd.SetSize(70,16);
gd.Begin();
gd.SetTs("〓▲★●■");
gd.Draw("tank",hero.x,hero.y);
for (int i = 1; i <= 3; i++) {
gd.Draw("pipe",i*15,11);
}
/*gd.Draw(hero.x, hero.y, hero.w, hero.h, hero.tsi);
gd.Draw(ground.x, ground.y, ground.w, ground.h, ground.tsi);
gd.Draw(brick1.x, brick1.y, brick1.w, brick1.h, brick1.tsi);
gd.Draw(brick2.x, brick2.y, brick2.w, brick2.h, brick2.tsi);*/
Sleep(30);
gd.End();
if (GetAsyncKeyState('W')) {
hero.y -= 1;
}
if (GetAsyncKeyState('S')) {
hero.y += 1;
}
if (GetAsyncKeyState('A')) {
hero.x -= 1;
}
if (GetAsyncKeyState('D')) {
hero.x += 1;
}
//卷轴
gd.cx = hero.x - gd.cw/2;
gd.cy = hero.y - gd.ch/2;
if (gd.cx < 0) gd.cx = 0;
if (gd.cy < 0) gd.cy = 0;
if (gd.cx + gd.cw > gd.ww) gd.cx = gd.ww - gd.cw;
if (gd.cy + gd.ch > gd.wh) gd.cy = gd.wh - gd.ch;
}
Sleep(30);
}