矩阵结构体 图片绘制 超级玛丽demo6
难度预警!!!
一些结构体 的碎碎念
在之之前我们的结构体中,我们在里面写了成员函数,这样其实是错误的。我们之前是迫于无奈必须要用函数。
通常来说不允许这样使用,只让你使用成员变量。
在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));、
完整的代码时这样的
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
#pragma oncestruct MYRECT {int left, top, right, bottom;bool Sollider(const MYRECT& other);bool Set(int x, int y, int w, int h);
};
MyRect.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
#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
#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;}elsereturn true;
}
源.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);
}