我正在制作一个需要输出自定义地图文件的关卡编辑器,以便与我将为图形库编写的源代码一起使用。
我的问题是:在决定如何构建自定义文件类型时,我需要牢记什么?另外,我如何将标准位图图像编码到我的文件(图块集)中,以便它可以全部包含在单个文件而不是两个文件中;地图文件和图块集(.bmp 文件)。
谢谢。
首先你需要设计你的文件层,你需要固定大小的数据来确定如何解码你的可变数据,例如,你读取的前四个字节可以告诉你有多少瓦片,接下来的 4 个字节可以告诉你有多少地图文件还有,在你拥有第一个文件之后,你必须定义你的文件信息,例如哪个文件和它有多少字节,然后你知道你离下一个文件条目还有多少字节等等。 .
您还可以使用结构并重载 ofstream 运算符 << 和 >> 来创建自己的文件类型,我在为《极品飞车 2》创建重播系统时自己这样做了。
struct Point4D { float x, y, z, w; };
struct Point3D { float x, y, z; };
struct Point2D { float x, y; };
struct QuatRot
{
Point4D Front;//frontvector
Point4D Right;//rightvector
Point4D Up;//upvector
};
#define NFS_MAX_VEHICLES (14)//seriously just 14.. (including the player)
struct VehicleInfo
{
//type name array offset
float unknown_01 [8]; //0x0
Point3D Pos; //0x20
float unknown_02; //0x2C
QuatRot Rotation; //0x30
Point3D unknown_03; //0x60
float unknown_04; //0x6C
Point3D Velocity; //0x70
float unknown_05; //0x7C
Point3D TurnSpeed; //0x80
float unknown_06; //0x8C
float SpeedAndBrakeAccelerator; //0x90
float unknown_07 [3]; //0x94
Point3D unknown_08; //0xA0
float unknown_09; //0xAC
Point4D unknown_10 [5]; //0xB0
float unknown_11 [20]; //0x100
float unknown_12_is_zero_when_accelerating; //0x150
//end of structure...?
};
std::ostream& operator<<(std::ostream& stream, const VehicleInfo &info);
//overload << and >> operators on "VehicleInfo" type
std::ofstream& operator<<(std::ofstream& stream, VehicleInfo &info);
std::ifstream& operator>>(std::ifstream& stream, VehicleInfo &info);
//overload << and >> operators on "FrameInfo" type
std::ofstream& operator<<(std::ofstream& stream, Recorder::FrameInfo &info);
std::ifstream& operator>>(std::ifstream& stream, Recorder::FrameInfo &info);
namespace Recorder
{
struct FrameInfo//1392 bytes / frame | max 167040 bytes @ 120 fps | 9.56 MB / min max
{
std::chrono::high_resolution_clock::duration time;
VehicleInfo Vehicle;
int Nitro;
float RPM;
float TURBO;
int CurrentGear;
KeyManager Keys[256];
};
};
std::ofstream& operator<<(std::ofstream& stream, VehicleInfo &info)
{
stream.write(reinterpret_cast<char*>(&info.unknown_01[0]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_01[1]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_01[2]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_01[3]), sizeof(float));
//...
stream.write(reinterpret_cast<char*>(&info.unknown_11[18]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_11[19]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_11[20]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_12_is_zero_when_accelerating), sizeof(float));
return stream;
}
std::ifstream& operator>>(std::ifstream& stream, VehicleInfo &info)
{
stream.read(reinterpret_cast<char*>(&info.unknown_01[0]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_01[1]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_01[2]), sizeof(float));
//.....
stream.read(reinterpret_cast<char*>(&info.unknown_11[16]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_11[17]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_11[18]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_11[19]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_11[20]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_12_is_zero_when_accelerating), sizeof(float));
return stream;
}
std::ofstream& operator<<(std::ofstream& stream, Recorder::FrameInfo &info)
{
stream.write(reinterpret_cast<char*>(&info.time), sizeof(std::chrono::high_resolution_clock::duration));
stream << info.Vehicle;
stream.write(reinterpret_cast<char*>(&info.Nitro), sizeof(int));
stream.write(reinterpret_cast<char*>(&info.RPM), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.CurrentGear), sizeof(int));
stream.write(reinterpret_cast<char*>(&info.TURBO), sizeof(int));
for(int i = 0; i < 256; ++i)
{
stream.write(reinterpret_cast<char*>(&info.Keys[i].Pressed), sizeof(bool));
stream.write(reinterpret_cast<char*>(&info.Keys[i].Released), sizeof(bool));
stream.write(reinterpret_cast<char*>(&info.Keys[i].Down), sizeof(bool));
stream.write(reinterpret_cast<char*>(&info.Keys[i].Up), sizeof(bool));
}
return stream;
}
std::ifstream& operator>>(std::ifstream& stream, Recorder::FrameInfo &info)
{
stream.read(reinterpret_cast<char*>(&info.time), sizeof(std::chrono::high_resolution_clock::duration));
stream >> info.Vehicle;
stream.read(reinterpret_cast<char*>(&info.Nitro), sizeof(int));
stream.read(reinterpret_cast<char*>(&info.RPM), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.CurrentGear), sizeof(int));
stream.read(reinterpret_cast<char*>(&info.TURBO), sizeof(int));
for(int i = 0; i < 256; ++i)
{
stream.read(reinterpret_cast<char*>(&info.Keys[i].Pressed), sizeof(bool));
stream.read(reinterpret_cast<char*>(&info.Keys[i].Released), sizeof(bool));
stream.read(reinterpret_cast<char*>(&info.Keys[i].Down), sizeof(bool));
stream.read(reinterpret_cast<char*>(&info.Keys[i].Up), sizeof(bool));
}
return stream;
}
///
std::stringstream& operator<<(std::stringstream& stream, VehicleInfo &info)
{
stream.write(reinterpret_cast<char*>(&info.unknown_01[0]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_01[1]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_01[2]), sizeof(float));
//...
stream.write(reinterpret_cast<char*>(&info.unknown_11[19]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_11[20]), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.unknown_12_is_zero_when_accelerating), sizeof(float));
return stream;
}
std::stringstream& operator>>(std::stringstream& stream, VehicleInfo &info)
{
stream.read(reinterpret_cast<char*>(&info.unknown_01[0]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_01[1]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_01[2]), sizeof(float));
//....
stream.read(reinterpret_cast<char*>(&info.unknown_11[20]), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.unknown_12_is_zero_when_accelerating), sizeof(float));
return stream;
}
std::stringstream& operator<<(std::stringstream& stream, Recorder::FrameInfo &info)
{
stream.write(reinterpret_cast<char*>(&info.time), sizeof(std::chrono::high_resolution_clock::duration));
stream << info.Vehicle;
stream.write(reinterpret_cast<char*>(&info.Nitro), sizeof(int));
stream.write(reinterpret_cast<char*>(&info.RPM), sizeof(float));
stream.write(reinterpret_cast<char*>(&info.CurrentGear), sizeof(int));
stream.write(reinterpret_cast<char*>(&info.TURBO), sizeof(int));
for(int i = 0; i < 256; ++i)
{
stream.write(reinterpret_cast<char*>(&info.Keys[i].Pressed), sizeof(bool));
stream.write(reinterpret_cast<char*>(&info.Keys[i].Released), sizeof(bool));
stream.write(reinterpret_cast<char*>(&info.Keys[i].Down), sizeof(bool));
stream.write(reinterpret_cast<char*>(&info.Keys[i].Up), sizeof(bool));
}
return stream;
}
std::stringstream& operator>>(std::stringstream& stream, Recorder::FrameInfo &info)
{
stream.read(reinterpret_cast<char*>(&info.time), sizeof(std::chrono::high_resolution_clock::duration));
stream >> info.Vehicle;
stream.read(reinterpret_cast<char*>(&info.Nitro), sizeof(int));
stream.read(reinterpret_cast<char*>(&info.RPM), sizeof(float));
stream.read(reinterpret_cast<char*>(&info.CurrentGear), sizeof(int));
stream.read(reinterpret_cast<char*>(&info.TURBO), sizeof(int));
for(int i = 0; i < 256; ++i)
{
stream.read(reinterpret_cast<char*>(&info.Keys[i].Pressed), sizeof(bool));
stream.read(reinterpret_cast<char*>(&info.Keys[i].Released), sizeof(bool));
stream.read(reinterpret_cast<char*>(&info.Keys[i].Down), sizeof(bool));
stream.read(reinterpret_cast<char*>(&info.Keys[i].Up), sizeof(bool));
}
return stream;
}