堆 动态内存 超级玛丽demo7
之前我们加入了BMP 里面有个量
这里我们 最开始写的400感觉有点大 写了100,假如我们的地图很大 10000往上,要画一个地面,那就完蛋了,BMP 要10000*10000,定义其他东西的时候 比如一个坦克 才3*3.
这时候堆就帮我们解决问题了。
终于学到堆了 前面提到了无数次 填坑了也算是,这玩意大一新手村大部分人还真就 只知道 勉强能看懂 不怎么用。
动态 静态 热 冷
运行时可以改变大小叫做热 或者 叫动态
运行时候不能改变 叫做 冷 或者 静态
我们总听说 热更新 动态内存 等词汇 就是这样来的
热更新
其实很早以前 我们玩的游戏 还可以冷更新
自己从官网 去 下载更新包放在指定位置
现在冷跟新 基本上 都是先打开游戏 然后提示你 有新版本可以更新,甚至可以一边运行一边更新,甚至一边玩一边更新。
以后我们汇重点学习 热更新知识,才开始填 堆 的坑,又挖一个新坑位。
堆
用多少内存 开多少内存。
假如我们想定义一个 int buf[999999999999999999999]
肯定报错!!!
数组的内存在栈区,这个区域只有1MB,而且公用。
但是这里的公用 是每个线程都有 1MB
堆理论无限大小 只有内存 的物理大小限制。
malloc
这玩意 大一新手村天天用,当时书上写的是动态内存 其实就是堆内存。
int a;
int *p;
p = (int*)malloc(a);
a代表 字节个数 新手村的时候 书上写的是 个数*sizeof()
开辟了 a个字节 但是不知道是什么类型的数据,默认为void*
强转 计算机在识别内存的时候 才会按四字节 读取 然后 把2进制 按照整数的规则处理
[]的作用 数组的名字其实存放的是首地址 a[10]
a[0] 就是跳0次 然后 解引用
这就比 (*) 多了一个跳字节的功能
这里我们 malloc开内存的时候
int len;
int *p = (int*)malloc(sizeof(int)*len);
free(p);
配合刚刚我们说的 就可以
p[0] p[1] p[2] 直接访问了
非常方便
free
释放地址中 开辟的所有内存 然后指针存的地址为空
指针的作用 随着 多态 函数 堆 的学习 含金量一直上升 这就是c++的魅力
记住 堆内存用多少开多少 不能开100个字节 只用50字节。
free的时候是全部释放,不用完也会浪费。
内存泄漏 100字节 在程序中再也用不了了。
土话 叫这个堆为 野堆
内存
大部分人大一新手村的时候这玩意就大概知道 没搞明白过
生命周期 读 写 特点
栈 定义---函数结束 可读 可写 1mb
堆 malloc---free 可读 可写 理论上无线大,理论上永久存在
常量 只读不可写
静态 程序开始--程序结束 可读可 永久性内存 直到程序结束之后才释放
栈内存 和 静态内存
常量
下面代码哪里出错了?
p是形参,要二级指针 才能操作a
指令内存区 储存函数命令(代码)
下面这个代码有两个指令
没有被接收的变量 就是在缓存中 不在内存中
有了堆 我们就可以改进之前的 struct BMP
之前那里的_map 放一个 char* 用来放 一个malloc 出来的地址就可以了。
还有一个可以改进的地方,因为在真实的游戏开发中 这个BMP资源有时候分辨率高,开销很大
以这里为例子,我们定义一个 坦克 图标 来当作我们的英雄
每次我们在 添加 使用AddBmp的时候 就是直接把这个 东西直接传进去 ,虽然我们使用了{}来释放了这个资源,但是函数中 编译又会重新在函数中创建一个 BMP的形参,来操作 然后函数里面
又有函数 insert 来弄这个Bmp 当作形参,导致一个图片要造成好几次的 内存开销。
我们可以 直接传入这个堆内存的 地址,这样每次都只 增加四字节的开销。
这里有点把我自己绕晕了
在 map中放数据的时候 进行的是解引用,意思是已经解引用存储在了 map中 才释放我们在 main函数定义的临时变量map。
而节约内存开销 我倒是理解对了,豆包是这样回答我的:
ai真的太厉害了!!!!有了ai之后 真的是学习编程的超级利器!!!!
有了堆之后 我们直接铺上地面 当作图片 搞个大图
项目源码:
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;
};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,const 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)
{////第一个 左上角的定位点在地图中就行,其他的出界就不画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,const 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,};bmp_temp._map = (char*)malloc(sizeof(char) * 9);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,};bmp_temp._map = (char*)malloc(sizeof(char) * 20);for (int i = 0; i < 20; i++) {bmp_temp._map[i] = temp_map[i];}gd.AddBmp("pipe", &bmp_temp);/*free(bmp_temp._map);bmp_temp._map = NULL;*/}{BMP bmp_temp;bmp_temp.w = 70;bmp_temp.h = 2;int temp_map[140];for (int i = 0; i < bmp_temp.h; i++) {for (int j = 0; j < bmp_temp.w; j++) {if((i * bmp_temp.w + j)%2 == 0)temp_map[i*bmp_temp.w + j] = 5;elsetemp_map[i*bmp_temp.w + j] = 4;}}bmp_temp._map = (char*)malloc(sizeof(char) * 140);for (int i = 0; i < 140; i++) {bmp_temp._map[i] = temp_map[i];}gd.AddBmp("ground", &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*20,9);}gd.Draw("ground",0,14);/*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);
}