This commit is contained in:
2025-10-06 04:18:49 +08:00
commit df2cacdb92
2784 changed files with 1280840 additions and 0 deletions

View File

@@ -0,0 +1,397 @@
#include "Asset/AnimationStruct.h"
#include "Asset/ScriptData.h"
namespace AniScriptParser
{
std::string Get_Ani_Flag(int data)
{
switch (data)
{
case 0:
return "LOOP";
case 1:
return "SHADOW";
case 3:
return "COORD";
case 7:
return "IMAGE_RATE";
case 8:
return "IMAGE_ROTATE";
case 9:
return "RGBA";
case 10:
return "INTERPOLATION";
case 11:
return "GRAPHIC_EFFECT";
case 12:
return "DELAY";
case 13:
return "DAMAGE_TYPE";
case 14:
return "DAMAGE_BOX";
case 15:
return "ATTACK_BOX";
case 16:
return "PLAY_SOUND";
case 17:
return "PRELOAD";
case 18:
return "SPECTRUM";
case 23:
return "SET_FLAG";
case 24:
return "FLIP_TYPE";
case 25:
return "LOOP_START";
case 26:
return "LOOP_END";
case 27:
return "CLIP";
case 28:
return "OPERATION";
default:
return "";
}
}
std::string Get_Ani_Effect_Type(int data)
{
switch (data)
{
case 0:
return "NONE";
case 1:
return "DODGE";
case 2:
return "LINEARDODGE";
case 3:
return "DARK";
case 4:
return "XOR";
case 5:
return "MONOCHROME";
case 6:
return "SPACEDISTORT";
default:
return "";
}
};
std::string Get_Ani_Flip_Type(int data)
{
switch (data)
{
case 1:
return "HORIZON";
case 2:
return "VERTICAL";
case 3:
return "ALL";
default:
return "";
}
};
std::string Get_Ani_Damage_Type(int data)
{
switch (data)
{
case 0:
return "NORMAL";
case 1:
return "SUPERARMOR";
case 2:
return "UNBREAKABLE";
default:
return "";
}
};
AlsInfo StructAlsInfo(ScriptData &Data)
{
AlsInfo Info;
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[use animation]")
{
std::string AniPath = Data.Get();
std::string AniKey = Data.Get();
Info.AniList[AniKey].path = Tool_toLowerCase(AniPath);
}
else if (Segment == "[none effect add]")
{
std::vector<int> AniLayer = {std::stoi(Data.Get()), std::stoi(Data.Get())};
std::string AniKey = Data.Get();
Info.AniList[AniKey].layer = AniLayer;
}
else if (Segment == "[add]")
{
std::vector<int> AniLayer = {std::stoi(Data.Get()), std::stoi(Data.Get())};
std::string AniKey = Data.Get();
Info.AniList[AniKey].layer = AniLayer;
}
}
return Info;
};
AniInfo StructAniInfo(ScriptData &Data)
{
AniInfo Info;
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[image]")
{
}
}
return Info;
};
/////////以下是读取逻辑
AniInfo StructAniInfo(Blob blob)
{
AniInfo Info;
int Frame_Max = blob.getUShort();
int Img_Count = blob.getUShort();
// Img的路径读取 存入数组
for (int i = 0; i < Img_Count; i++)
{
int Buf = blob.getInt();
std::string ImgPath = "sprite/" + blob.getString(Buf);
Info.Img_List.push_back(ImgPath);
}
// Ani头部标签数量
int Ani_H_Item_Count = blob.getUShort();
// 处理标签
for (int i = 0; i < Ani_H_Item_Count; i++)
{
int Type = blob.getUShort();
switch (Type)
{
case 0:
case 1:
{
std::string Key = AniScriptParser::Get_Ani_Flag(Type);
int Value = blob.getByte();
Info.Flag.emplace(Key, Value);
break;
}
case 3:
case 28:
{
std::string Key = AniScriptParser::Get_Ani_Flag(Type);
int Value = blob.getUShort();
Info.Flag.emplace(Key, Value);
break;
}
case 18:
{
blob.getByte();
blob.getInt();
blob.getInt();
blob.getInt();
blob.get256();
blob.get256();
blob.get256();
blob.get256();
blob.getUShort();
}
default:
break;
}
}
// 读取每一个Img
for (int i = 0; i < Frame_Max; i++)
{
AniFrame FrameObject;
// 碰撞框项目数量
int Ani_Box_Item_Count = blob.getUShort();
for (int j = 0; j < Ani_Box_Item_Count; j++)
{
int Box_Type = blob.getUShort();
std::vector<int> D_Box_b;
for (int k = 0; k < 6; k++)
{
D_Box_b.push_back(blob.getInt());
}
if (Box_Type == 15)
FrameObject.AttackBox.push_back(D_Box_b);
else
FrameObject.DamageBox.push_back(D_Box_b);
}
// 调用的第几个Img
int Index_Buf = blob.getShort();
if (Index_Buf != -1)
{
FrameObject.Img_Path = Tool_toLowerCase(Info.Img_List[Index_Buf]);
FrameObject.Img_Index = blob.getUShort();
}
else
{
FrameObject.Img_Path = "";
FrameObject.Img_Index = 0;
}
// 坐标
FrameObject.Img_Pos = VecPos{blob.getInt(), blob.getInt()};
// Img中的项目数量
int Img_Flag_Count = blob.getUShort();
for (int j = 0; j < Img_Flag_Count; j++)
{
int Img_Flag_Type = blob.getUShort();
std::string Key;
int Value;
switch (Img_Flag_Type)
{
case 0:
case 1:
case 10:
{
Key = AniScriptParser::Get_Ani_Flag(Img_Flag_Type);
Value = blob.getByte();
FrameObject.Flag.emplace(Key, Value);
break;
}
case 3:
{
Key = "COORD";
Value = blob.getUShort();
FrameObject.Flag.emplace(Key, Value);
break;
}
case 17:
{
Key = "PRELOAD";
Value = 1;
FrameObject.Flag.emplace(Key, Value);
break;
}
case 7:
{
Key = "IMAGE_RATE";
VecFPos pos{
blob.getFloat(),
blob.getFloat()};
FrameObject.Flag.emplace(Key, pos);
break;
}
case 8:
{
Key = "IMAGE_ROTATE";
float RateBuffer = blob.getFloat();
FrameObject.Flag.emplace(Key, RateBuffer);
break;
}
case 9:
{
Key = "RGBA";
std::vector<int> RGBA = {
(int)blob.get256(),
(int)blob.get256(),
(int)blob.get256(),
(int)blob.get256()};
FrameObject.Flag.emplace(Key, RGBA);
break;
}
case 11:
{
int Effect_Type = blob.getUShort();
Key = "GRAPHIC_EFFECT_" + AniScriptParser::Get_Ani_Effect_Type(Effect_Type);
std::vector<float> effect;
switch (Effect_Type)
{
case 5:
{
effect.push_back(blob.get256());
effect.push_back(blob.get256());
effect.push_back(blob.get256());
break;
}
case 6:
{
effect.push_back(blob.get256());
effect.push_back(blob.get256());
break;
}
}
FrameObject.Flag.emplace(Key, effect);
break;
}
case 12:
{
Value = blob.getInt();
FrameObject.Delay = Value;
break;
}
case 13:
{
Key = "DAMAGE_TYPE";
std::string DTYPE = AniScriptParser::Get_Ani_Damage_Type(blob.getUShort());
FrameObject.Flag.emplace(Key, DTYPE);
break;
}
case 16:
{
int SoundTempSize = blob.getInt();
Key = "PLAY_SOUND";
std::string sound = blob.getString(SoundTempSize);
FrameObject.Flag.emplace(Key, sound);
break;
}
case 23:
{
Key = "SET_FLAG";
Value = blob.getInt();
FrameObject.Flag.emplace(Key, Value);
break;
}
case 24:
{
Key = "FLIP_TYPE";
std::string FTYPEValue = AniScriptParser::Get_Ani_Flip_Type(blob.getUShort());
FrameObject.Flag.emplace(Key, FTYPEValue);
break;
}
case 25:
{
Key = "LOOP_START";
FrameObject.Flag.emplace(Key, 1);
break;
}
case 26:
{
Key = "LOOP_END";
Value = blob.getInt();
FrameObject.Flag.emplace(Key, Value);
break;
}
case 27:
{
Key = "CLIP";
std::vector<int> ClipArr{
blob.getShort(),
blob.getShort(),
blob.getShort(),
blob.getShort(),
};
FrameObject.Flag.emplace(Key, ClipArr);
break;
}
default:
break;
}
}
Info.Frame.push_back(FrameObject);
}
return Info;
}
};

View File

@@ -0,0 +1,58 @@
#pragma once
#include <vector>
#include <string>
#include <variant>
#include <unordered_map>
#include <SDL.h>
#include "Tool/Blob.hpp"
#include "Tool/Tool_String.h"
#include "Tool/Common.h"
class ScriptData;
namespace AniScriptParser
{
using AniFlag = std::variant<
int,
float,
VecPos,
VecFPos,
std::string,
std::vector<int>,
std::vector<float>>;
struct AniFrame
{
std::string Img_Path; // img路径
int Img_Index; // img索引
VecPos Img_Pos; // img位置
std::vector<std::vector<int>> AttackBox; // 攻击框
std::vector<std::vector<int>> DamageBox; // 受击框
std::unordered_map<std::string, AniFlag> Flag; // Frame特效数据
int Delay; // 延迟
};
struct AniInfo
{
std::vector<std::string> Img_List; // img列表
std::vector<AniFrame> Frame; // ani列表
std::unordered_map<std::string, AniFlag> Flag; // ani特效数据
};
struct AlsAniInfo
{
std::string path;
std::vector<int> layer;
};
struct AlsInfo
{
std::unordered_map<std::string, AlsAniInfo> AniList; // Ani列表
};
// 工具函数
std::string Get_Ani_Flag(int data);
std::string Get_Ani_Effect_Type(int data);
std::string Get_Ani_Flip_Type(int data);
std::string Get_Ani_Damage_Type(int data);
// Ani脚本的读取逻辑
AniInfo StructAniInfo(Blob blob);
AlsInfo StructAlsInfo(ScriptData &blob);
};

View File

@@ -0,0 +1,48 @@
#include "AssetManager.h"
#include "Asset/Asset_Script.h"
AssetManager::AssetManager()
{
}
AssetManager::~AssetManager()
{
}
AniScriptParser::AniInfo AssetManager::StructAniInfo(std::string path)
{
std::vector<BYTE> Data = Asset_Script::GetInstance().GetFileContentByte(path);
if (Data.size() > 0)
{
Blob blob(Data);
return AniScriptParser::StructAniInfo(blob);
}
SDL_LogError(0, "Ani加载失败 Error : %s", path.c_str());
return AniScriptParser::AniInfo();
}
AniScriptParser::AlsInfo AssetManager::StructAlsInfo(std::string path)
{
std::vector<BYTE> Data = Asset_Script::GetInstance().GetFileContentByte(path);
if (Data.size() > 0)
{
ScriptData Pvf;
Pvf.Init(Data, path);
AniScriptParser::AlsInfo Info = AniScriptParser::StructAlsInfo(Pvf);
return Info;
}
SDL_LogError(0, "Als加载失败 Error : %s", path.c_str());
return AniScriptParser::AlsInfo();
}
ScriptData AssetManager::GetScriptInfo(std::string path)
{
std::vector<BYTE> Data = Asset_Script::GetInstance().GetFileContentByte(path);
if (Data.size() > 0)
{
ScriptData Pvf;
Pvf.Init(Data, path);
return Pvf;
}
SDL_LogError(0, "Script加载失败 Error : %s", path.c_str());
return ScriptData();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "Asset/AnimationStruct.h" //Ani结构
#include "Asset/ScriptData.h"
class AssetManager
{
public:
AssetManager(const AssetManager &) = delete;
AssetManager &operator=(const AssetManager &) = delete;
AssetManager(AssetManager &&) = delete;
AssetManager &operator=(AssetManager &&) = delete;
// 全局访问点
static AssetManager &GetInstance()
{
static AssetManager instance; // 局部静态变量,保证只初始化一次
return instance;
}
private:
AssetManager(/* args */);
~AssetManager();
public:
// 构造Ani结构体
AniScriptParser::AniInfo StructAniInfo(std::string path);
AniScriptParser::AlsInfo StructAlsInfo(std::string path);
// Script读取体
ScriptData GetScriptInfo(std::string path);
};

View File

@@ -0,0 +1,246 @@
#include "Asset_ImagePack.h"
Asset_ImagePack::Asset_ImagePack()
{
}
Asset_ImagePack::~Asset_ImagePack()
{
}
void Asset_ImagePack::Init()
{
DIR *dir;
struct dirent *ent;
std::string path = "ImagePacks2/";
dir = opendir(path.c_str());
while ((ent = readdir(dir)))
{
// 跳过.和..目录
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
continue;
std::string RealPath = path + ent->d_name;
Ifstream_NPK Fs;
Fs.open(RealPath.c_str(), std::ios::in | std::ios::binary);
if (Fs.is_open())
{
std::string Header = Fs.ReadString();
// 如果是NPK
if (Header.find("NeoplePack_Bill") != std::string::npos)
{
// 读取img数量
int ImageCount = Fs.ReadInt();
// 读取头
NpkInfo *ImgList = new NpkInfo[ImageCount];
for (int i = 0; i < ImageCount; i++)
{
ImgList[i].Offset = Fs.ReadInt();
ImgList[i].Length = Fs.ReadInt();
ImgList[i].Path = Fs.ReadInfo();
}
for (int i = 0; i < ImageCount; i++)
{
IMG img;
img.imgOffset = ImgList[i].Offset;
img.imgSize = ImgList[i].Length;
img.img_index = i;
img.lpBelongsFile = ent->d_name;
img.lpImgName = ImgList[i].Path;
img.lp_lplist = NULL;
img.png_sum = 0;
map_npk.insert(make_pair(img.lpImgName, img));
}
// 销毁
delete[] ImgList;
}
}
Fs.close();
}
closedir(dir);
}
void Asset_ImagePack::ParseColor(BYTE *Tab, int Type, BYTE *SaveByte, int Offset)
{
BYTE a = 0;
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
switch (Type)
{
case 0x0e:
a = (BYTE)(Tab[1] >> 7);
r = (BYTE)((Tab[1] >> 2) & 0x1f);
g = (BYTE)((Tab[0] >> 5) | ((Tab[1] & 3) << 3));
b = (BYTE)(Tab[0] & 0x1f);
a = (BYTE)(a * 0xff);
r = (BYTE)((r << 3) | (r >> 2));
g = (BYTE)((g << 3) | (g >> 2));
b = (BYTE)((b << 3) | (b >> 2));
break;
case 0x0f:
a = (BYTE)(Tab[1] & 0xf0);
r = (BYTE)((Tab[1] & 0xf) << 4);
g = (BYTE)(Tab[0] & 0xf0);
b = (BYTE)((Tab[0] & 0xf) << 4);
break;
}
SaveByte[Offset + 0] = b;
SaveByte[Offset + 1] = g;
SaveByte[Offset + 2] = r;
SaveByte[Offset + 3] = a;
}
void Asset_ImagePack::LoadImgToMem(IMG *p)
{
std::string Path = "ImagePacks2/" + p->lpBelongsFile;
// SDL_Log("LoadImgToMem : %s", Path.c_str());
Ifstream_NPK Fs;
Fs.open(Path.c_str(), std::ios::in | std::ios::binary);
if (Fs.is_open())
{
Fs.seekg(p->imgOffset);
std::string Flag = Fs.ReadString(); // 读取Flag
if (Flag.find("Neople Img File") != std::string::npos)
{
// 索引表大小
long TableLength = Fs.ReadLong();
// img 版本 4字节
Fs.ReadInt(); // 读取版本
// img 帧数
int IndexCount = Fs.ReadInt();
// 图片数量赋值
p->png_sum = IndexCount;
// new出 Png数量的 结构体
ImgInfo *PngList = new ImgInfo[IndexCount];
for (int i = 0; i < IndexCount; i++)
{
PngList[i].Type = Fs.ReadInt();
if (PngList[i].Type == 17)
{
// 引用贴图
int frbuf = Fs.ReadInt();
// 压缩类型 用来临时存一下引用编号
PngList[i].CmpType = frbuf;
////大小
PngList[i].Size = 0;
PngList[i].Offset = PngList[i - 1].Offset + PngList[i - 1].Size;
continue;
}
// 压缩类型
PngList[i].CmpType = Fs.ReadInt();
// 宽度
PngList[i].Width = Fs.ReadInt();
// 高度
PngList[i].Height = Fs.ReadInt();
// 大小
PngList[i].Size = Fs.ReadInt();
// Xpos
PngList[i].Xpos = Fs.ReadInt();
// Ypos
PngList[i].Ypos = Fs.ReadInt();
// 帧域X
PngList[i].FrameXpos = Fs.ReadInt();
// 帧域Y
PngList[i].FrameYpos = Fs.ReadInt();
// 计算偏移
if (i == 0)
PngList[i].Offset = 0 + p->imgOffset + TableLength + 32;
else
PngList[i].Offset = PngList[i - 1].Offset + PngList[i - 1].Size;
}
for (int i = 0; i < IndexCount; i++)
{
// 引用
if (PngList[i].Type == 17)
{
// 引用编号
int YYIndex = PngList[i].CmpType;
int sizebuf = PngList[YYIndex].Width * PngList[YYIndex].Height * 4;
BYTE *bByte = new BYTE[sizebuf];
memcpy(bByte, PngList[PngList[i].CmpType].PNGdata, sizebuf);
PngList[i].PNGdata = PngList[YYIndex].PNGdata;
// 压缩类型 用来临时存一下引用编号
PngList[i].CmpType = PngList[YYIndex].CmpType;
// 宽度
PngList[i].Width = PngList[YYIndex].Width;
// 高度
PngList[i].Height = PngList[YYIndex].Height;
// 大小
PngList[i].Size = 0;
// Xpos
PngList[i].Xpos = PngList[YYIndex].Xpos;
// Ypos
PngList[i].Ypos = PngList[YYIndex].Ypos;
// 帧域X
PngList[i].FrameXpos = PngList[YYIndex].FrameXpos;
// 帧域Y
PngList[i].FrameYpos = PngList[YYIndex].FrameYpos;
continue;
}
Fs.seekg(PngList[i].Offset);
BYTE *PngData = Fs.ReadCustomSize(PngList[i].Size);
int DeSize = PngList[i].Width * PngList[i].Height * 4;
BYTE *bByte = new BYTE[DeSize];
unsigned long RealSize = DeSize;
uncompress(bByte, &RealSize, PngData, (unsigned long)PngList[i].Size);
delete[] PngData;
if (PngList[i].Type != 16)
{
int PngByteSize = DeSize * 2;
PngList[i].PNGdata = new BYTE[PngByteSize];
for (int e = 0; e < PngByteSize; e += 4)
{
BYTE NeedData[2];
memset(NeedData, 0, 2);
memcpy(NeedData, bByte + (e / 4) * 2, 2);
ParseColor(NeedData, PngList[i].Type, PngList[i].PNGdata, e);
}
delete[] bByte;
}
else
{
PngList[i].PNGdata = bByte;
}
}
p->lp_lplist = PngList;
}
else if (Flag.find("Neople Image File") != std::string::npos)
{
// LoadImgToMem2(p);
}
Fs.close();
}
}
Asset_ImagePack::IMG *Asset_ImagePack::GetIMG(std::string imgName)
{
IMG *img = NULL;
std::map<std::string, IMG>::iterator itr;
itr = map_npk.find(imgName);
if (itr == map_npk.end())
{
std::string mes = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!调用了不存在的Img : " + imgName;
SDL_Log(mes.c_str());
img = &map_npk["sprite/interface/base.img"];
}
else
{
img = &itr->second;
}
// 如果图片数组不存在 或者 图片数据不存在都要重读
if (!img->lp_lplist)
{
LoadImgToMem(img);
}
img->UseTime = SDL_GetTicks();
return img;
}

View File

@@ -0,0 +1,86 @@
#pragma once
#ifdef _SWITCH_
#include <switch.h>
#endif
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <SDL.h>
#include <map>
#include "Tool/Ifstream_NPK.h"
#include <zlib.h>
class Asset_ImagePack
{
public:
struct NpkInfo
{
int Offset;
int Length;
std::string Path;
};
// PNG结构体
struct ImgInfo
{
// 图片格式
int Type;
// 压缩类型
int CmpType;
// 宽度
int Width;
// 高度
int Height;
// 大小
int Size;
// Xpos
int Xpos;
// Ypos
int Ypos;
// 帧域X
int FrameXpos;
// 帧域Y
int FrameYpos;
// 偏移
int Offset;
// Png位图数据
BYTE *PNGdata;
};
struct IMG // npk的img的结构体
{
std::string lpImgName; // img文件的路径
int img_index; // img文件在npk文件里的序号
unsigned imgOffset;
unsigned imgSize;
std::string lpBelongsFile; // 这个img属于哪个npk文件
int png_sum; // 这个img文件有多少个 图片
ImgInfo *lp_lplist; // 图片的数组..
Uint32 UseTime = 0;
};
public:
Asset_ImagePack(const Asset_ImagePack &) = delete;
Asset_ImagePack &operator=(const Asset_ImagePack &) = delete;
Asset_ImagePack(Asset_ImagePack &&) = delete;
Asset_ImagePack &operator=(Asset_ImagePack &&) = delete;
// 全局访问点
static Asset_ImagePack &GetInstance()
{
static Asset_ImagePack instance; // 局部静态变量,保证只初始化一次
return instance;
}
public:
void Init();
void ParseColor(BYTE *Tab, int Type, BYTE *SaveByte, int Offset);
void LoadImgToMem(IMG *p);
IMG *GetIMG(std::string imgName);
private:
Asset_ImagePack(/* args */);
~Asset_ImagePack();
std::map<std::string, IMG> map_npk;
};

View File

@@ -0,0 +1,227 @@
#include "Asset/Asset_Script.h"
#include "Asset_Script.h"
void Asset_Script::Init()
{
// 读取头建立树
InitHeader();
// 读取bin文件
InitBin();
// 读取LoadString
InitLoadString();
}
void Asset_Script::Clear()
{
FileInfo.clear();
BinStringM.clear();
LoadStringM.clear();
_Data.clear();
_Data.shrink_to_fit();
}
void Asset_Script::InitHeader()
{
// 读取UUID的长度
int UUID_LENGTH = GetInt();
// UUID 读 1 - 36位 构造 UTF8 string
std::string UUID = GetString(UUID_LENGTH);
// 版本号
int Version = GetInt();
(void)Version;
// 文件路径数据的大小
int AlignedIndexHeaderSize = GetInt();
// 解密密钥
int IndexHeaderCrc = GetInt();
// 文件数量
int IndexSize = GetInt();
// 文件起始位置
int FristPos = tellg();
CrcDecode(AlignedIndexHeaderSize, IndexHeaderCrc);
int CurrPos = 0;
StartPos = AlignedIndexHeaderSize + 56;
// 建立pvf文件索引表
for (int i = 0; i < IndexSize; i++)
{
seek(FristPos + CurrPos);
int FileNumber = GetInt();
(void)FileNumber;
int FilePathLength = GetInt();
std::string FileName = tolower(GetString(FilePathLength));
int FileLength = GetInt();
int Cre32 = GetInt();
int RelativeOffset = GetInt();
if (FileLength > 0)
{
int RealFileLength = (FileLength + 3) & 4294967292;
PvfFileInfo Info;
Info.ROffset = RelativeOffset;
Info.Cr32 = Cre32;
Info.Length = RealFileLength;
Info.DecodeFlag = false;
FileInfo[FileName] = Info;
}
CurrPos += 20;
CurrPos += FilePathLength;
}
}
void Asset_Script::InitBin()
{
if (FileInfo.count("stringtable.bin") == 0)
{
SDL_LogError(0, "stringtable.bin文件不存在");
return;
}
PvfFileInfo BinInfo = FileInfo["stringtable.bin"];
seek(StartPos + BinInfo.ROffset);
CrcDecode(BinInfo.Length, BinInfo.Cr32);
seek(StartPos + BinInfo.ROffset);
int FileHPos = tellg();
int Count = GetInt();
int CurrentIndex = 0;
for (int i = 0; i < Count; i++)
{
seek(FileHPos + CurrentIndex * 4 + 4);
int StartPos = GetInt();
int EndPos = GetInt();
int Len = EndPos - StartPos;
seek(FileHPos + StartPos + 4);
std::string Str = GetString(Len);
BinStringM[CurrentIndex] = Str;
CurrentIndex++;
}
}
void Asset_Script::InitLoadString()
{
if (FileInfo.count("n_string.lst") == 0)
{
SDL_LogError(0, "n_string.lst文件不存在");
}
PvfFileInfo Info = FileInfo["n_string.lst"];
seek(StartPos + Info.ROffset);
CrcDecode(Info.Length, Info.Cr32);
seek(StartPos + Info.ROffset);
int FileHPos = tellg();
int Flag = GetShort();
(void)Flag;
int i = 2;
while (i < Info.Length)
{
if ((Info.Length - i) >= 10)
{
seek(FileHPos + i + 6);
int FindKey = GetInt();
std::string Key = GetBinString(FindKey);
std::string Type = tolower(Key.substr(0, Key.find("/")));
if (Key.length() > 0)
{
PvfFileInfo *FileInfo = GetFileInfo(Key);
if (FileInfo == nullptr)
continue;
seek(StartPos + FileInfo->ROffset);
CrcDecode(FileInfo->Length, FileInfo->Cr32);
seek(StartPos + FileInfo->ROffset);
std::string Str = GetStringNormal(FileInfo->Length);
std::vector<std::string> StrArr = split(Str, "\n");
for (auto it = StrArr.begin(); it != StrArr.end(); ++it)
{
std::string strobj = *it;
if (strobj.find(">") != std::string::npos)
{
std::vector<std::string> strobjarr = split(strobj, ">");
if (strobjarr.size() > 1)
{
LoadStringM[Type][strobjarr[0]] = strobjarr[1];
}
}
}
}
}
else
break;
i += 10;
}
}
std::string Asset_Script::GetBinString(int Key)
{
if (BinStringM.count(Key))
return BinStringM[Key];
return "";
}
std::string Asset_Script::GetLoadString(std::string Type, std::string Key)
{
if (LoadStringM.count(Type) && LoadStringM[Type].count(Key))
return LoadStringM[Type][Key];
return "";
}
Asset_Script::PvfFileInfo *Asset_Script::GetFileInfo(std::string path)
{
path = tolower(path);
if (FileInfo.count(path))
return &FileInfo[path];
return nullptr;
}
std::string Asset_Script::GetFileContent(std::string path)
{
if (FileInfo.count(path))
{
seek(StartPos + FileInfo[path].ROffset);
if (FileInfo[path].DecodeFlag == false)
{
CrcDecode(FileInfo[path].Length, FileInfo[path].Cr32);
seek(StartPos + FileInfo[path].ROffset);
FileInfo[path].DecodeFlag = true;
}
char *blobp = new char[FileInfo[path].Length];
read((char *)blobp, FileInfo[path].Length);
std::string Str(blobp, FileInfo[path].Length);
delete[] blobp;
return Str;
}
return std::string();
}
char *Asset_Script::GetFileContentChar(std::string path)
{
if (FileInfo.count(path))
{
seek(StartPos + FileInfo[path].ROffset);
if (FileInfo[path].DecodeFlag == false)
{
CrcDecode(FileInfo[path].Length, FileInfo[path].Cr32);
seek(StartPos + FileInfo[path].ROffset);
FileInfo[path].DecodeFlag = true;
}
char *blobp = new char[FileInfo[path].Length];
read((char *)blobp, FileInfo[path].Length);
return blobp;
}
return nullptr;
}
std::vector<BYTE> Asset_Script::GetFileContentByte(std::string path)
{
if (FileInfo.count(path))
{
seek(StartPos + FileInfo[path].ROffset);
if (FileInfo[path].DecodeFlag == false)
{
CrcDecode(FileInfo[path].Length, FileInfo[path].Cr32);
seek(StartPos + FileInfo[path].ROffset);
FileInfo[path].DecodeFlag = true;
}
std::vector<BYTE> blobp(FileInfo[path].Length);
read((char *)blobp.data(), FileInfo[path].Length);
return blobp;
}
return std::vector<BYTE>();
}

View File

@@ -0,0 +1,60 @@
#pragma once
#ifdef _SWITCH_
#include <switch.h>
#endif
#include <stdio.h>
#include <string>
#include <dirent.h>
#include <SDL.h>
#include <map>
#include "Tool/Ifstream_PVF.h"
class Asset_Script : public Ifstream_PVF
{
public:
struct PvfFileInfo
{
int ROffset;
int Cr32;
int Length;
bool DecodeFlag = false;
};
private:
Asset_Script(const std::string filename = "Script.pvf") : Ifstream_PVF(filename) {};
~Asset_Script() = default;
int StartPos = 0;
std::map<std::string, PvfFileInfo> FileInfo;
std::map<int, std::string> BinStringM;
std::map<std::string, std::map<std::string, std::string>> LoadStringM;
public:
Asset_Script(const Asset_Script &) = delete;
Asset_Script &operator=(const Asset_Script &) = delete;
Asset_Script(Asset_Script &&) = delete;
Asset_Script &operator=(Asset_Script &&) = delete;
// 全局访问点
static Asset_Script &GetInstance()
{
static Asset_Script instance; // 局部静态变量,保证只初始化一次
return instance;
}
public:
void Init();
void InitHeader();
void InitBin();
void InitLoadString();
void Clear();
public:
std::string GetBinString(int Key);
std::string GetLoadString(std::string Type, std::string Key);
PvfFileInfo *GetFileInfo(std::string path);
std::string GetFileContent(std::string path); // 获取文件内容
char* GetFileContentChar(std::string path); // 获取文件内容
std::vector<BYTE> GetFileContentByte(std::string path); // 获取文件内容
};

105
source/Asset/ScriptData.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include "ScriptData.h"
#include "Tool/Tool_String.h"
#include "Asset/Asset_Script.h"
ScriptData::ScriptData()
{
}
ScriptData::~ScriptData()
{
}
void ScriptData::Init(std::vector<BYTE> Data, std::string FilePath)
{
std::string ASA = "";
for (size_t i = 0; i < Data.size(); i++)
{
ASA += std::to_string((int)Data[i]);
ASA += ",";
}
if (Data.size() < 7)
return;
IO = std::make_shared<Blob>(Data);
filepath = FilePath;
filetype = Tool_toLowerCase(FilePath.substr(0, FilePath.find_first_of("/")));
filesize = Data.size();
}
std::string ScriptData::Get()
{
if (!IO)
return "";
if (_CurI < filesize && filesize - _CurI >= 5)
{
std::string Ret = UnpackData();
_CurI += 5;
return Ret;
}
return "_nop_";
}
void ScriptData::Back()
{
if (_CurI >= 5)
_CurI -= 5;
}
bool ScriptData::IsEnd()
{
return (_CurI >= filesize || filesize - _CurI < 5);
}
std::string ScriptData::UnpackData()
{
IO->setOffset(_CurI);
int currentByte = (int)(IO->getByte());
int after = IO->getInt();
switch (currentByte)
{
case 9:
{
BYTE NewcurrentByte = IO->getByte(); // 内容指示位
(void)NewcurrentByte;
int Newafter = IO->getInt();
std::string Buf = Asset_Script::GetInstance().GetBinString(Newafter);
if (Buf.empty())
Buf = "";
else
Buf = Asset_Script::GetInstance().GetLoadString(filetype, Buf);
return Buf;
}
case 10:
{
std::string Buf = Asset_Script::GetInstance().GetBinString(after);
if (Buf.empty())
Buf = "";
else
Buf = Asset_Script::GetInstance().GetLoadString(filetype, Buf);
return Buf;
}
case 2:
{
IO->setOffset(IO->getOffset() - 4);
int ret = IO->getInt();
return std::to_string(ret);
}
case 4:
{
float Bbuf;
std::memcpy(&Bbuf, &after, sizeof(float));
return std::to_string(Bbuf);
}
case 6:
case 8:
case 7:
case 5:
{
return Asset_Script::GetInstance().GetBinString(after);
}
default:
return "";
}
}

25
source/Asset/ScriptData.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include "Tool/Blob.hpp"
#include <memory>
class ScriptData
{
using BYTE = unsigned char;
private:
std::shared_ptr<Blob> IO;
public:
ScriptData();
~ScriptData();
std::string filepath;
std::string filetype;
int filesize;
int _CurI = 2;
void Init(std::vector<BYTE> Data, std::string FilePath);
std::string Get();
void Back();
bool IsEnd();
std::string UnpackData();
};

223
source/EngineCore/Game.cpp Normal file
View File

@@ -0,0 +1,223 @@
#include "Game.h"
#include "squirrel/SquirrelEx.h"
#include "EngineFrame/Component/Sprite.h"
#include "EngineFrame/Actor/Actor.h"
#include "EngineFrame/Component/Text.h"
#include "EngineFrame/Actor/Debug_Actor.h"
Game::Game()
{
}
Game::~Game()
{
Clear();
}
void Game::Init(std::function<void()> CallBack)
{
// 计算帧时间
m_frameTime = 1000 / m_fps;
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
SDL_JoystickEventState(SDL_ENABLE);
SDL_JoystickOpen(0);
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not initialize! Error: %s\n", SDL_GetError());
m_isRunning = false;
}
m_window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_W, Screen_H, SDL_WINDOW_SHOWN);
if (m_window == nullptr)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Window! Error: %s\n", SDL_GetError());
m_isRunning = false;
}
// 打开所有检测到的控制器
int numControllers = SDL_NumJoysticks();
for (int i = 0; i < numControllers; i++)
{
if (SDL_IsGameController(i))
{
SDL_GameController *controller = SDL_GameControllerOpen(i);
if (controller)
{
SDL_Log("成功打开控制器: %s", SDL_GameControllerName(controller));
}
else
{
SDL_Log("无法打开控制器 %d! SDL错误: %s", i, SDL_GetError());
}
}
}
// 创建渲染器
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);
if (m_renderer == nullptr)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Renderer! Error: %s\n", SDL_GetError());
m_isRunning = false;
}
// 启用渲染器的混合功能(必须,否则纹理混合模式无效)
SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_BLEND);
IMG_Init(IMG_INIT_PNG);
// 初始化SDL_mixer支持OGG格式
// 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError());
m_isRunning = false;
}
// 初始化 TTF
if (TTF_Init() == -1)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "TTF 初始化失败TTF_Error: %s\n", TTF_GetError());
m_isRunning = false;
}
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
// 构造调试对象
m_DebugInfoActor = new Debug_Actor();
CallBack();
}
void Game::Run()
{
while (m_isRunning)
{
u32 frameStart = SDL_GetTicks(); // 帧开始时间
SDL_Event m_event;
HandleEvents(&m_event);
Update(m_deltaTime); // 注意这里使用的是上一帧的deltaTime合理见说明
Render();
// 帧率统计(保持不变)
m_frameCount++;
u32 currentTime = SDL_GetTicks();
if (currentTime - m_lastFpsPrintTime >= 1000)
{
u32 fps = m_frameCount;
if (m_DebugInfoActor)
m_DebugInfoActor->FPS = fps;
m_lastFpsPrintTime = currentTime;
m_frameCount = 0;
}
// 计算实际总帧时间(关键修改)
u32 diff = SDL_GetTicks() - frameStart; // 处理耗时
if (diff < m_frameTime)
{
SDL_Delay(m_frameTime - diff); // 尝试延迟补全
}
// 延迟后,重新计算从帧开始到现在的总时间(包含可能的延迟误差)
u32 actualFrameTime = SDL_GetTicks() - frameStart;
m_deltaTime = actualFrameTime / 1000.0f; // 用实际总时间更新deltaTime
}
}
void Game::HandleEvents(SDL_Event *e)
{
while (SDL_PollEvent(e))
{
if (e->type == SDL_QUIT)
{
m_isRunning = false;
SDL_Log("Game Exit1");
}
else if (e->type == SDL_JOYBUTTONDOWN)
{
if (e->jbutton.button == JOY_PLUS)
{
m_isRunning = false;
SDL_Log("Game Exit2");
}
}
// 处理屏幕按下事件
else if (e->type == SDL_FINGERDOWN)
{
// 触发双击事件
SDL_Log("退出程序");
m_isRunning = false;
SDL_Log("Game Exit3");
}
if (m_scene != nullptr)
m_scene->HandleEvents(e);
if (m_uiScene != nullptr)
m_uiScene->HandleEvents(e);
}
}
void Game::Update(float deltaTime)
{
if (m_scene != nullptr)
m_scene->Update(deltaTime);
if (m_uiScene != nullptr)
m_uiScene->Update(deltaTime);
// 调试信息
if (m_DebugInfoActor != nullptr)
{
m_DebugInfoActor->Update(deltaTime);
m_DebugInfoActor->RenderCount = RenderCount;
}
RenderCount = 0;
}
void Game::Render()
{
SDL_RenderClear(m_renderer);
if (m_scene != nullptr)
m_scene->Render();
if (m_uiScene != nullptr)
m_uiScene->Render();
if (m_DebugInfoActor != nullptr)
m_DebugInfoActor->Render();
SDL_RenderPresent(m_renderer);
}
void Game::Clear()
{
if (m_scene != nullptr)
{
m_scene->Exit();
}
m_scene = nullptr;
if (m_uiScene != nullptr)
{
m_uiScene->Exit();
}
m_uiScene = nullptr;
m_DebugInfoActor = nullptr;
IMG_Quit();
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
void Game::ChangeScene(RefPtr<Scene> scene)
{
if (m_scene != nullptr)
{
m_scene->Exit();
}
m_scene = scene;
m_scene->Enter();
}
void Game::ChangeUIScene(RefPtr<Scene> scene)
{
if (m_uiScene != nullptr)
{
m_uiScene->Exit();
}
m_uiScene = scene;
m_uiScene->Enter();
}
SDL_Renderer *Game::GetRenderer()
{
return m_renderer;
}

94
source/EngineCore/Game.h Normal file
View File

@@ -0,0 +1,94 @@
#pragma once
#include "EngineFrame/Scene/Scene.h"
#include "Tool/RefPtr.h"
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <SDL_ttf.h>
#include <memory>
#include <functional>
// some switch buttons
#define JOY_A 0
#define JOY_B 1
#define JOY_X 2
#define JOY_Y 3
#define JOY_PLUS 10
#define JOY_MINUS 11
#define JOY_LEFT 12
#define JOY_UP 13
#define JOY_RIGHT 14
#define JOY_DOWN 15
class Debug_Actor;
class Game
{
#ifndef __SWITCH__
typedef Uint32 u32;
#endif
public:
// 删除拷贝构造和赋值运算符,确保无法复制
Game(const Game &) = delete;
Game &operator=(const Game &) = delete;
// 移动构造和赋值也删除,避免意外转移
Game(Game &&) = delete;
Game &operator=(Game &&) = delete;
// 全局访问点
static Game &GetInstance()
{
static Game instance; // 局部静态变量,保证只初始化一次
return instance;
}
void Init(std::function<void()> CallBack);
void Run();
void HandleEvents(SDL_Event *e);
void Update(float deltaTime);
void Render();
void Clear();
// 切换场景
void ChangeScene(RefPtr<Scene> scene);
// 设定UI层场景对象
void ChangeUIScene(RefPtr<Scene> scene);
SDL_Renderer *GetRenderer();
uint32_t RenderCount = 0;
private:
// 构造函数和析构函数设为私有,防止外部创建和销毁
Game();
~Game();
// 游戏是否运行
bool m_isRunning = true;
// 窗口
SDL_Window *m_window;
// 渲染器
SDL_Renderer *m_renderer;
// 游戏层场景
RefPtr<Scene> m_scene;
// UI层场景
RefPtr<Scene> m_uiScene;
// 帧数
int m_fps = 10000;
u32 m_frameTime;
float m_deltaTime;
// 新增:帧率统计变量
u32 m_frameCount; // 每秒内的帧数计数器
u32 m_lastFpsPrintTime; // 上一次输出帧率的时间(毫秒,基于 SDL_GetTicks()
// 调试信息Actor
RefPtr<Debug_Actor> m_DebugInfoActor;
public:
// 屏幕宽高
int Screen_W = 1280;
int Screen_H = 720;
};

View File

@@ -0,0 +1,27 @@
#include "Actor.h"
#include "EngineFrame/Scene/Scene.h"
#include "EngineFrame/Component/RenderBase.h"
#include <algorithm>
Actor::Actor()
{
Init();
}
void Actor::Init()
{
addTag(Tag::ACTOR);
addTag(Tag::RENDER);
addTag(Tag::TRANSFORM);
addTag(Tag::UPDATE);
}
void Actor::AddComponent(RefPtr<Component> Component)
{
BaseNode::AddChild(Component);
}
void Actor::RemoveComponent(RefPtr<Component> Component)
{
BaseNode::RemoveChild(Component);
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "EngineFrame/Base/BaseNode.h"
#include "EngineFrame/Component/Component.h"
#include "Tool/IntrusiveList.hpp"
class Scene;
/**
* @brief Actor类继承自Actor_base类
*
* Actor类是一个基础的游戏对象类可以添加到场景中
*/
class Actor : public BaseNode
{
public:
Actor();
public:
void Init() override;
void AddComponent(RefPtr<Component> Component);
void RemoveComponent(RefPtr<Component> Component);
// void AddChild(RefPtr<Actor> child);
// void RemoveChild(RefPtr<Actor> child);
};

View File

@@ -0,0 +1,155 @@
#include "Debug_Actor.h"
#include "EngineCore/Game.h"
#include <string>
Debug_Actor::Debug_Actor()
{
m_debugFont = TTF_OpenFont("Fonts/GasinamuNew.ttf", 16);
if (m_debugFont == nullptr)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load debug font: %s", TTF_GetError());
}
FPS_Text = new Text("Current FPS:", m_debugFont, SDL_Color{255, 255, 255, 255});
DT_Text = new Text("DeltaTime :", m_debugFont, SDL_Color{255, 255, 255, 255});
RC_Text = new Text("Render Calls:", m_debugFont, SDL_Color{255, 255, 255, 255});
if (FPS_Text != nullptr)
{
SDL_Point Pos{26, 26};
FPS_Text->SetPos(Pos);
this->AddComponent(FPS_Text);
}
if (DT_Text != nullptr)
{
SDL_Point Pos{26, 46};
DT_Text->SetPos(Pos);
this->AddComponent(DT_Text);
}
if (RC_Text != nullptr)
{
SDL_Point Pos{26, 66};
RC_Text->SetPos(Pos);
this->AddComponent(RC_Text);
}
}
Debug_Actor::~Debug_Actor()
{
if (m_debugFont != nullptr)
{
TTF_CloseFont(m_debugFont);
m_debugFont = nullptr;
}
}
void Debug_Actor::Update(float deltaTime)
{
Actor::Update(deltaTime);
if (FPS_Text != nullptr)
{
std::string fpsText = "Current FPS: " + std::to_string(FPS);
FPS_Text->SetText(fpsText);
std::string dtText = "DeltaTime: " + std::to_string((int)(deltaTime * 1000));
DT_Text->SetText(dtText);
std::string rcText = "Render Calls: " + std::to_string(RenderCount);
RC_Text->SetText(rcText);
}
}
void Debug_Actor::Render()
{
if (FPS_Text != nullptr)
{
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
if (renderer != nullptr)
{
SDL_Point textPos = FPS_Text->Pos;
SDL_Point textSize = FPS_Text->Size;
int bgX = textPos.x - padding;
int bgY = textPos.y - padding;
int bgWidth = textSize.x + padding * 2;
int bgHeight = textSize.y + padding * 2 * 4;
DrawRoundedRect(renderer, bgX, bgY, bgWidth, bgHeight, cornerRadius, bgColor);
}
}
Actor::Render();
}
void Debug_Actor::DrawRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h, int radius, SDL_Color color)
{
if (renderer == nullptr)
return;
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawLine(renderer, x + radius, y, x + w - radius, y);
SDL_RenderDrawLine(renderer, x + radius, y + h, x + w - radius, y + h);
SDL_RenderDrawLine(renderer, x, y + radius, x, y + h - radius);
SDL_RenderDrawLine(renderer, x + w, y + radius, x + w, y + h - radius);
const int segments = 16;
for (int i = 0; i < segments; i++)
{
float t1 = static_cast<float>(i) / segments;
float t2 = static_cast<float>(i + 1) / segments;
float angle1 = M_PI * (1.0f - t1);
float angle2 = M_PI * (1.0f - t2);
SDL_RenderDrawLineF(
renderer,
x + radius + cos(angle1) * radius, y + radius + sin(angle1) * radius,
x + radius + cos(angle2) * radius, y + radius + sin(angle2) * radius);
angle1 = 2 * M_PI - t1 * M_PI_2;
angle2 = 2 * M_PI - t2 * M_PI_2;
SDL_RenderDrawLineF(
renderer,
x + w - radius + cos(angle1) * radius, y + radius + sin(angle1) * radius,
x + w - radius + cos(angle2) * radius, y + radius + sin(angle2) * radius);
angle1 = t1 * M_PI_2;
angle2 = t2 * M_PI_2;
SDL_RenderDrawLineF(
renderer,
x + w - radius + cos(angle1) * radius, y + h - radius + sin(angle1) * radius,
x + w - radius + cos(angle2) * radius, y + h - radius + sin(angle2) * radius);
angle1 = M_PI_2 + t1 * M_PI_2;
angle2 = M_PI_2 + t2 * M_PI_2;
SDL_RenderDrawLineF(
renderer,
x + radius + cos(angle1) * radius, y + h - radius + sin(angle1) * radius,
x + radius + cos(angle2) * radius, y + h - radius + sin(angle2) * radius);
}
for (int dy = 0; dy < h; dy++)
{
int leftIndent = 0;
int rightIndent = 0;
if (dy < radius)
{
float ratio = 1.0f - static_cast<float>(dy) / radius;
leftIndent = rightIndent = static_cast<int>(radius * (1.0f - sqrt(1.0f - ratio * ratio)));
}
else if (dy > h - radius)
{
float ratio = static_cast<float>(dy - (h - radius)) / radius;
leftIndent = rightIndent = static_cast<int>(radius * (1.0f - sqrt(1.0f - ratio * ratio)));
}
SDL_RenderDrawLine(
renderer,
x + leftIndent, y + dy,
x + w - rightIndent, y + dy);
}
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
#include "EngineFrame/Component/Text.h"
#include <SDL_ttf.h>
#include <cstdint>
class Debug_Actor : public Actor
{
private:
TTF_Font *m_debugFont;
RefPtr<Text> FPS_Text;
RefPtr<Text> DT_Text;
RefPtr<Text> RC_Text;
public:
Debug_Actor();
~Debug_Actor() override;
void Update(float deltaTime) override;
void Render() override;
uint32_t FPS = 0;
uint32_t RenderCount = 0;
SDL_Color bgColor = {0, 0, 0, 90};
int cornerRadius = 4;
int padding = 12;
#ifdef __SWITCH__
double M_PI = 3.14159265358979323846;
double M_PI_2 = 1.57079632679489661923;
#endif
private:
void DrawRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h, int radius, SDL_Color color);
};

View File

@@ -0,0 +1,303 @@
#include "BaseNode.h"
void BaseNode::Init()
{
}
void BaseNode::HandleEvents(SDL_Event *e)
{
// 如果有子节点并含有事件标签,则处理事件
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
if (child->hasTag(Tag::ACTOR) || child->hasTag(Tag::HANDEL_EVENT))
child->HandleEvents(e);
child = child->GetNext();
}
}
void BaseNode::Update(float deltaTime)
{
// 如果有回调函数,则调用回调函数
if (cb_update_)
{
cb_update_(deltaTime);
}
// 如果有子节点并含有刷新标签,则更新子节点
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
if (child->hasTag(Tag::UPDATE))
child->Update(deltaTime);
child = child->GetNext();
}
}
void BaseNode::Render()
{
// 如果有子节点并含有渲染标签,则渲染子节点
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
if (child->hasTag(Tag::RENDER))
child->Render();
child = child->GetNext();
}
}
void BaseNode::Clear()
{
}
void BaseNode::SetCallbackOnUpdate(const UpdateCallback &cb)
{
cb_update_ = cb;
}
void BaseNode::SetChildIterationTransform()
{
TransformT n_transform;
n_transform.position = transform.position + transformIter.position;
n_transform.scale = transform.scale * transformIter.scale;
n_transform.rotation = transform.rotation + transformIter.rotation;
// 如果有子节点并含有transform标签则设置其位置
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
if (child->hasTag(Tag::TRANSFORM))
child->SetIterationTransform(n_transform);
child = child->GetNext();
}
}
void BaseNode::CalcRenderInfo()
{
}
void BaseNode::SetName(std::string name)
{
m_Name = name;
}
std::string BaseNode::GetName()
{
return m_Name;
}
int BaseNode::GetRenderZOrder()
{
return m_RenderZOrder;
}
void BaseNode::SetRenderZOrder(int zOrder)
{
m_RenderZOrder = zOrder;
}
void BaseNode::Reorder()
{
if (m_Parent)
{
RefPtr<BaseNode> me = this;
m_Parent->m_BaseNodes.Remove(me);
RefPtr<BaseNode> sibling = m_Parent->m_BaseNodes.GetLast();
if (sibling && sibling->GetRenderZOrder() > m_RenderZOrder)
{
sibling = sibling->GetPrev();
while (sibling)
{
if (sibling->GetRenderZOrder() <= m_RenderZOrder)
break;
sibling = sibling->GetPrev();
}
}
if (sibling)
{
m_Parent->m_BaseNodes.InsertAfter(me, sibling);
}
else
{
m_Parent->m_BaseNodes.PushFront(me);
}
}
}
void BaseNode::AddChild(RefPtr<BaseNode> child)
{
m_BaseNodes.PushBack(child);
child->OnAdded(this);
// 如果是需要渲染的子对象
if (child->hasTag(Tag::RENDER))
{
// 重新排序
child->Reorder();
// 如果组件有transform标签则设置其位置
if (child->hasTag(Tag::TRANSFORM))
{
TransformT n_transform;
n_transform.position = transform.position + transformIter.position;
n_transform.scale = transform.scale * transformIter.scale;
n_transform.rotation = transform.rotation + transformIter.rotation;
child->SetIterationTransform(n_transform);
}
}
}
void BaseNode::RemoveChild(RefPtr<BaseNode> child)
{
child->m_Parent = nullptr;
m_BaseNodes.Remove(child);
}
void BaseNode::OnAdded(BaseNode *node)
{
m_Parent = node;
}
void BaseNode::SetIterationTransform(TransformT n_transform)
{
if (n_transform == transformIter)
return;
transformIter = n_transform;
CalcRenderInfo();
SetChildIterationTransform();
}
TransformT BaseNode::GetIterationTransform()
{
return transformIter;
}
void BaseNode::SetTransform(TransformT n_transform)
{
if (n_transform == transform)
return;
transform = n_transform;
CalcRenderInfo();
SetChildIterationTransform();
}
TransformT BaseNode::GetTransform()
{
return transform;
}
void BaseNode::SetPos(VecFPos pos)
{
if (pos == this->transform.position)
return;
this->transform.position = pos;
CalcRenderInfo();
SetChildIterationTransform();
}
VecFPos BaseNode::GetPos()
{
return this->transform.position;
}
void BaseNode::SetScale(VecFPos scale)
{
if (scale == this->transform.scale)
return;
this->transform.scale = scale;
CalcRenderInfo();
SetChildIterationTransform();
}
VecFPos BaseNode::GetScale()
{
return this->transform.scale;
}
void BaseNode::SetRotation(float angle)
{
if (angle == this->transform.rotation)
return;
this->transform.rotation = angle;
CalcRenderInfo();
SetChildIterationTransform();
}
float BaseNode::GetRotation()
{
return this->transform.rotation;
}
void BaseNode::SetAnchor(VecFPos anchor)
{
if (anchor == this->Anchor)
return;
Anchor.x = anchor.x;
Anchor.y = anchor.y;
}
VecFPos BaseNode::GetAnchor()
{
VecFPos P;
P.x = Anchor.x;
P.y = Anchor.y;
return P;
}
void BaseNode::SetSize(VecSize size)
{
this->Size = size;
}
VecSize BaseNode::GetSize()
{
return this->Size;
}
void BaseNode::SetVisible(bool visible)
{
this->Visible = visible;
}
bool BaseNode::GetVisible()
{
return this->Visible;
}
void BaseNode::SetIterationPos(VecFPos pos)
{
if (pos == this->transformIter.position)
return;
this->transformIter.position = pos;
CalcRenderInfo();
SetChildIterationTransform();
}
VecFPos BaseNode::GetIterationPos()
{
return this->transformIter.position;
}
void BaseNode::SetIterationScale(VecFPos scale)
{
if (scale == this->transformIter.scale)
return;
this->transformIter.scale = scale;
CalcRenderInfo();
SetChildIterationTransform();
}
VecFPos BaseNode::GetIterationScale()
{
return this->transformIter.scale;
}
void BaseNode::SetIterationRotation(float angle)
{
if (angle == this->transformIter.rotation)
return;
this->transformIter.rotation = angle;
CalcRenderInfo();
SetChildIterationTransform();
}
float BaseNode::GetIterationRotation()
{
return this->transformIter.rotation;
}

View File

@@ -0,0 +1,124 @@
#pragma once
#include <functional>
#include <SDL.h>
#include <string>
#include "Tool/RefObject.h"
#include "Tool/RefPtr.h"
#include "Tool/IntrusiveList.hpp"
#include "Tool/TagGed.h"
#include "Tool/TransformT.h"
class BaseNode : public RefObject, public TagGed, protected IntrusiveListValue<RefPtr<BaseNode>>
{
public:
typedef std::function<void(float deltaTime)> UpdateCallback;
using IntrusiveListValue<RefPtr<BaseNode>>::GetNext;
using IntrusiveListValue<RefPtr<BaseNode>>::GetPrev;
public:
// 更新时的回调函数
UpdateCallback cb_update_;
// 节点名称
std::string m_Name;
// 子节点列表
IntrusiveList<RefPtr<BaseNode>> m_BaseNodes;
// 指向父对象的指针
BaseNode *m_Parent = nullptr;
// 渲染层级
int m_RenderZOrder = 0;
// 二维仿射变换
TransformT transform;
// 迭代的二维仿射变换
TransformT transformIter;
// 锚点
VecFPos Anchor = {0.f, 0.f};
// 大小
VecSize Size = {0, 0};
// 是否显示
bool Visible = true;
// 计算渲染信息Flag (为了保证每帧只计算一次)
bool CalcRenderInfoFlag = true;
public:
BaseNode(/* args */) = default;
~BaseNode() = default;
public:
virtual void Init();
virtual void HandleEvents(SDL_Event *e);
virtual void Update(float deltaTime);
virtual void Render();
virtual void Clear();
/// \~chinese
/// @brief 设置更新时的回调函数
void SetCallbackOnUpdate(const UpdateCallback &cb);
void SetChildIterationTransform();
// 计算渲染信息
virtual void CalcRenderInfo();
// 设置名字
void SetName(std::string name);
// 获取名字
std::string GetName();
// 设置渲染层级
int GetRenderZOrder();
// 获取渲染层级
void SetRenderZOrder(int zOrder);
// 重新排序
void Reorder();
// 添加子对象
virtual void AddChild(RefPtr<BaseNode> child);
// 移除子对象
void RemoveChild(RefPtr<BaseNode> child);
// 被添加时
virtual void OnAdded(BaseNode *node);
// 设置迭代的二维仿射变换
void SetIterationTransform(TransformT transform);
// 获取迭代的二维仿射变换
TransformT GetIterationTransform();
// 设置二维仿射变换
void SetTransform(TransformT transform);
// 获取二维仿射变换
TransformT GetTransform();
// 设置迭代的坐标
virtual void SetIterationPos(VecFPos pos);
// 获取迭代的坐标
VecFPos GetIterationPos();
// 设置迭代的缩放
virtual void SetIterationScale(VecFPos scale);
// 获取迭代的缩放
VecFPos GetIterationScale();
// 设置迭代的旋转角度
virtual void SetIterationRotation(float angle);
// 获取迭代的旋转角度
float GetIterationRotation();
// 设置坐标
virtual void SetPos(VecFPos pos);
// 获取坐标
VecFPos GetPos();
// 设置缩放
virtual void SetScale(VecFPos scale);
// 获取缩放
VecFPos GetScale();
// 设置旋转角度
virtual void SetRotation(float angle);
// 获取旋转角度
float GetRotation();
// 设置中心点
virtual void SetAnchor(VecFPos anchor);
// 获取中心点
VecFPos GetAnchor();
// 设置大小
virtual void SetSize(VecSize size);
// 获取大小
VecSize GetSize();
// 设置是否显示
void SetVisible(bool visible);
// 获取是否显示
bool GetVisible();
};

View File

@@ -0,0 +1,309 @@
#include "Animation.h"
#include "Asset/AssetManager.h"
#include "Asset/Asset_Script.h"
#include "Tool/Math.h"
#include "EngineFrame/Actor/Actor.h"
Animation::Animation()
{
}
Animation::Animation(std::string AniPath)
{
Init(AniPath);
}
Animation::Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions, Animation::ReplaceData data)
{
this->AdditionalOptions = AdditionalOptions;
this->AdditionalOptionsData = data;
Init(AniPath);
}
Animation::~Animation()
{
}
void Animation::Init(std::string AniPath)
{
Actor::Init();
AniScriptParser::AniInfo Info = AssetManager::GetInstance().StructAniInfo(AniPath);
this->AniPath = AniPath;
this->AnimationFlag = Info.Flag;
this->FrameArr = Info.Frame;
for (size_t i = 0; i < this->FrameArr.size(); i++)
{
AniScriptParser::AniFrame FrameObj = this->FrameArr[i];
RefPtr<Sprite> SpriteObj = nullptr;
if (!FrameObj.Img_Path.empty())
{
if (AdditionalOptions)
{
FrameObj.Img_Path = AdditionalOptions(FrameObj.Img_Path, this->AdditionalOptionsData);
}
SpriteObj = new Sprite(FrameObj.Img_Path, FrameObj.Img_Index);
SpriteObj->SetAnchor(VecFPos(0.5f, 0.5f));
SpriteObj->SetPos(VecFPos(FrameObj.Img_Pos.x, FrameObj.Img_Pos.y));
SpriteObj->SetVisible(false);
}
else
{
SpriteObj = new Sprite();
SpriteObj->SetVisible(false);
SDL_Log("Animation::Init() SpriteObj is nullptr");
}
SpriteArr.push_back(SpriteObj);
AddChild(SpriteObj);
}
// 初始化完毕 如果是第一次初始化 而非重新构造 设置大小为第0帧大小否则天空 地板等依靠大小的初始化会有问题
if (CurrentIndexT == 0)
SetSize(SpriteArr[0]->GetSize());
// 记录总帧数
TotalFrameIndex = FrameArr.size();
// TODO 染色
// 判断是否有Als
if (Asset_Script::GetInstance().GetFileInfo(AniPath + ".als"))
{
AniScriptParser::AlsInfo Info = AssetManager::GetInstance().StructAlsInfo(AniPath + ".als");
if (Info.AniList.size() > 0)
{
std::string Dir = AniPath.substr(0, AniPath.find_last_of("/") + 1);
for (auto &Ani : Info.AniList)
{
RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path);
AlsAniObj->SetRenderZOrder(Ani.second.layer[1]);
AddChild(AlsAniObj);
}
}
}
FlushFrame(0);
}
void Animation::HandleEvents(SDL_Event *e)
{
}
void Animation::Update(float deltaTime)
{
// 可用性检查
if (IsUsability && Visible)
{
float dt_ms = deltaTime * 1000.0f;
// 累加当前帧时间
CurrentIndexT += dt_ms;
// 插值模式判断
InterpolationLogic();
// 循环处理:只要当前时间超过帧延迟,就切换帧(支持一次跳过多帧)
while (CurrentIndexT >= NextFrameDelay)
{
CurrentIndexT -= NextFrameDelay;
// 如果当前帧小于总帧数就切换
if (CurrentFrameIndex < (TotalFrameIndex - 1))
{
FlushFrame(CurrentFrameIndex + 1);
}
// 说明播放完毕了
else
{
// 如果有循环
if (AnimationFlag.count("LOOP"))
{
FlushFrame(0);
}
// 没有循环触发状态机回调
else
{
// 将不再可用
IsUsability = false;
if (EndCallback)
EndCallback();
break;
}
}
}
Actor::Update(deltaTime);
}
}
void Animation::Render()
{
if (!Visible)
return;
Actor::Render();
}
void Animation::OnAdded(BaseNode *node)
{
Actor::OnAdded(node);
FlushFrame(0);
}
void Animation::Clear()
{
}
void Animation::FlushFrame(int Index)
{
// 关闭旧帧显示
if (CurrentFrame)
CurrentFrame->SetVisible(false);
// 同步当前帧编号
CurrentFrameIndex = Index;
// 当前帧更换为本帧
CurrentFrame = SpriteArr[CurrentFrameIndex];
// 开启新帧显示
CurrentFrame->SetVisible(true);
// 如果是整体染色 则直接使用染色帧
// if (DyeAllFlag) CurrentFrame = DyeFrameList[CurrentFrameIndex];
AniScriptParser::AniFrame FrameInfo = FrameArr[CurrentFrameIndex];
// 设置下帧延迟
NextFrameDelay = FrameInfo.Delay;
std::unordered_map<std::string, AniScriptParser::AniFlag> FlagBuf = FrameInfo.Flag;
// 关键帧
if (FlagBuf.count("SET_FLAG"))
{
if (ChangeFrameCallback)
ChangeFrameCallback(std::get<int>(FlagBuf["SET_FLAG"]));
}
// 播放音效
if (FlagBuf.count("PLAY_SOUND"))
{
// TODO 还没有做音效的播放
}
// 缩放
if (FlagBuf.count("IMAGE_RATE"))
{
VecFPos Rate = std::get<VecFPos>(FlagBuf["IMAGE_RATE"]);
CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f});
CurrentFrame->SetScale(VecFPos{Rate.x, Rate.y});
}
// 线性减淡
if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE"))
{
CurrentFrame->SetBlendMode(SDL_BLENDMODE_ADD);
}
// 旋转
if (FlagBuf.count("IMAGE_ROTATE"))
{
CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f});
CurrentFrame->SetRotation(std::get<float>(FlagBuf["IMAGE_ROTATE"]));
}
// 染色
// if (!DyeAllFlag)
// 插值模式
if (FlagBuf.count("INTERPOLATION"))
{
// 初始化插值数据
if (InterpolationFlag.size() == 0)
{
// 旧插值数据
InterpolationFlag.push_back(FrameArr[CurrentFrameIndex]);
// 新插值数据
InterpolationFlag.push_back(FrameArr[CurrentFrameIndex + 1]);
}
}
else
{
if (InterpolationFlag.size() > 0)
{
InterpolationFlag.clear();
}
}
// 如果有描边
if (IsOutline)
{
}
// Ani的大小同步为精灵帧对象的大小
SetSize(CurrentFrame->GetSize());
// 裁切 //TODO
}
void Animation::Reset()
{
IsUsability = true;
CurrentIndexT = 0;
FlushFrame(0);
}
AniScriptParser::AniFrame Animation::GetCurrentFrameInfo()
{
return FrameArr[CurrentFrameIndex];
}
void Animation::SetFrameIndex(int Index)
{
FlushFrame(Index);
CurrentIndexT = 0;
}
void Animation::InterpolationLogic()
{
if (InterpolationFlag.size() == 0)
return;
// 插值倍率
float InterRate = Math::getUniformVelocity(0, 100, CurrentIndexT, NextFrameDelay) / 100.0f;
AniScriptParser::AniFrame OldData = InterpolationFlag[0];
AniScriptParser::AniFrame NewData = InterpolationFlag[1];
// RGBA插值
{
std::vector<int> OldRgbaData = {255, 255, 255, 250};
std::vector<int> NewRgbaData = {255, 255, 255, 250};
if (OldData.Flag.count("RGBA"))
OldRgbaData = std::get<std::vector<int>>(OldData.Flag["RGBA"]);
if (NewData.Flag.count("RGBA"))
NewRgbaData = std::get<std::vector<int>>(NewData.Flag["RGBA"]);
std::vector<int> RgbaData = {
(int)(OldRgbaData[0] + (NewRgbaData[0] - OldRgbaData[0]) * InterRate),
(int)(OldRgbaData[1] + (NewRgbaData[1] - OldRgbaData[1]) * InterRate),
(int)(OldRgbaData[2] + (NewRgbaData[2] - OldRgbaData[2]) * InterRate),
(int)(OldRgbaData[3] + (NewRgbaData[3] - OldRgbaData[3]) * InterRate)};
// TODO 染色 和 透明度还没弄
}
// 坐标
{
VecFPos PosData = {
(OldData.Img_Pos.x + (NewData.Img_Pos.x - OldData.Img_Pos.x) * InterRate),
(OldData.Img_Pos.y + (NewData.Img_Pos.y - OldData.Img_Pos.y) * InterRate)};
CurrentFrame->SetPos(PosData);
}
// 缩放
{
VecFPos OldRateData = {1.0f, 1.0f};
VecFPos NewRateData = {1.0f, 1.0f};
if (OldData.Flag.count("IMAGE_RATE"))
{
OldRateData = std::get<VecFPos>(OldData.Flag["IMAGE_RATE"]);
}
if (NewData.Flag.count("IMAGE_RATE"))
{
NewRateData = std::get<VecFPos>(NewData.Flag["IMAGE_RATE"]);
}
VecFPos RateData = {
OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate,
OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate};
CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f});
CurrentFrame->SetScale(RateData);
}
// 旋转
{
float OldAngleData = 0.0;
float NewAngleData = 0.0;
if (OldData.Flag.count("IMAGE_ROTATE"))
{
OldAngleData = std::get<float>(OldData.Flag["IMAGE_ROTATE"]);
}
if (NewData.Flag.count("IMAGE_ROTATE"))
{
NewAngleData = std::get<float>(NewData.Flag["IMAGE_ROTATE"]);
}
CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate);
}
}

View File

@@ -0,0 +1,95 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
#include "EngineFrame/Component/Sprite.h"
#include "Asset/AnimationStruct.h"
#include <functional>
#include <tuple>
#include <utility>
class Animation : public Actor
{
public:
struct ReplaceData
{
int Param1;
int Param2;
ReplaceData() : Param1(0), Param2(0) {}
ReplaceData(int _Param1, int _Param2) : Param1(_Param1), Param2(_Param2) {}
};
public:
Animation(/* args */);
Animation(std::string AniPath);
Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions, Animation::ReplaceData);
~Animation();
void Init(std::string AniPath);
void HandleEvents(SDL_Event *e) override;
void Update(float deltaTime) override;
void Render() override;
void OnAdded(BaseNode *node) override;
void Clear() override;
public:
void FlushFrame(int Index);
void Reset();
AniScriptParser::AniFrame GetCurrentFrameInfo();
void SetFrameIndex(int Index);
void InterpolationLogic();
// TODO SetOutline
// TODO SetDye
// TODO SetCrop
public:
// Ani是否可用
bool IsUsability = true;
// 当前帧数
int CurrentFrameIndex = 0;
// 总帧数
int TotalFrameIndex = 0;
// 当前帧时间
float CurrentIndexT = 0;
// 当前帧
RefPtr<Sprite> CurrentFrame = nullptr;
// 下帧延迟
float NextFrameDelay = 9999999;
// 染色Flag
bool DyeingFlag = false;
// 插值模式
std::vector<AniScriptParser::AniFrame> InterpolationFlag;
// 关键帧回调
std::function<void(int)> ChangeFrameCallback;
// 结束回调
std::function<void()> EndCallback;
// Ani的标签
std::unordered_map<std::string, AniScriptParser::AniFlag> AnimationFlag;
// 帧对象数组
std::vector<AniScriptParser::AniFrame> FrameArr;
// 图片精灵帧对象
std::vector<RefPtr<Sprite>> SpriteArr;
// Ani类型
std::string Type = "normal";
// Ani路径
std::string AniPath;
// 是否描边
bool IsOutline = false;
// // 描边颜色
// OutlineColor = null;
// // 描边对象List
// OutlineList = null;
// // 当前描边对象
// CurrentOutline = null;
// // 染色颜色
// DyeColor = null;
// // 染色帧List
// DyeFrameList = null;
// // 整体染色
// DyeAllFlag = false;
// // 裁切数据
// CropRect = null;
// 附加选项
std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions;
Animation::ReplaceData AdditionalOptionsData;
};

View File

@@ -0,0 +1,7 @@
#include "Component.h"
#include "EngineFrame/Actor/Actor.h"
void Component::Init()
{
addTag(Tag::COMPONENT);
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "EngineFrame/Base/BaseNode.h"
#include <SDL.h>
class Actor;
class Component : public BaseNode
{
public:
void Init() override;
};

View File

@@ -0,0 +1,86 @@
#include "RenderBase.h"
#include "EngineFrame/Actor/Actor.h"
RenderBase::RenderBase()
{
}
RenderBase::~RenderBase()
{
}
void RenderBase::CalcRenderInfo()
{
this->CalcRenderInfoFlag = true;
}
void RenderBase::Init()
{
Component::Init();
// 标记该组件需要渲染和更新
addTag(Tag::RENDER);
addTag(Tag::UPDATE);
addTag(Tag::TRANSFORM);
// 计算渲染信息
CalcRenderInfo();
}
void RenderBase::Update(float deltaTime)
{
if (!Visible)
return;
Component::Update(deltaTime);
}
void RenderBase::Render()
{
if (!Visible)
return;
Component::Render();
}
void RenderBase::SetIterationPos(VecFPos pos)
{
Component::SetIterationPos(pos);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetIterationScale(VecFPos scale)
{
Component::SetIterationScale(scale);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetIterationRotation(float angle)
{
if (!Visible)
return;
Component::SetIterationRotation(angle);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetPos(VecFPos pos)
{
Component::SetPos(pos);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetScale(VecFPos scale)
{
Component::SetScale(scale);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetRotation(float angle)
{
Component::SetRotation(angle);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetAnchor(VecFPos anchor)
{
Component::SetAnchor(anchor);
CalcRenderInfo(); // 更新渲染信息
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include "EngineFrame/Component/Component.h"
#include "Tool/TransformT.h"
class RenderBase : public Component
{
public:
struct RenderGuidanceInfo
{
SDL_Rect rect;
float rotation;
SDL_RendererFlip flip = SDL_FLIP_NONE;
VecPos AnchorPos;
bool Visible = true;
bool IsInScreen;
};
public:
RenderBase(/* args */);
~RenderBase();
public:
void Init() override;
void Update(float deltaTime) override;
void Render() override;
public:
public:
// 设置迭代的坐标
void SetIterationPos(VecFPos pos) override;
// 设置迭代的缩放
void SetIterationScale(VecFPos scale) override;
// 设置迭代的旋转角度
void SetIterationRotation(float angle) override;
// 设置坐标
void SetPos(VecFPos pos) override;
// 设置缩放
void SetScale(VecFPos scale) override;
// 设置旋转角度
void SetRotation(float angle) override;
// 设置中心点
void SetAnchor(VecFPos anchor) override;
// 计算渲染信息
void CalcRenderInfo() override;
};

View File

@@ -0,0 +1,159 @@
#include "Sprite.h"
#include "EngineCore/Game.h"
#include "Text.h"
Sprite::Sprite()
{
}
Sprite::Sprite(std::string imgPath, int Index)
{
this->imgPath = imgPath;
this->Index = Index;
m_texture = new Texture(imgPath, Index);
Init();
CalcRenderInfoLogic(); // 第一次计算
}
Sprite::Sprite(std::string PngPath)
{
m_texture = new Texture(PngPath);
Init();
CalcRenderInfoLogic(); // 第一次计算
}
Sprite::~Sprite()
{
}
RefPtr<Texture> Sprite::GetTexture()
{
return m_texture;
}
void Sprite::SetIterationPos(VecFPos pos)
{
RenderBase::SetIterationPos(pos);
CalcRenderInfo();
}
void Sprite::HandleEvents(SDL_Event *e)
{
}
void Sprite::Update(float deltaTime)
{
if (CalcRenderInfoFlag && Visible)
CalcRenderInfoLogic();
}
void Sprite::CalcRenderInfoLogic()
{
// 计算缩放因子和翻转状态
float scaleX = transformIter.scale.x * transform.scale.x;
float scaleY = transformIter.scale.y * transform.scale.y;
// X轴和Y轴上是否翻转的标志
bool flipX = scaleX < 0;
bool flipY = scaleY < 0;
_RenderGuidanceInfo.flip = SDL_FLIP_NONE;
// 更新翻转状态
if (flipX)
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_HORIZONTAL | _RenderGuidanceInfo.flip);
if (flipY)
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
int texturePosX = flipX ? -(m_texture->TextureSize.width + m_texture->TexturePos.x) + SDL_abs(transform.position.x * 2) : m_texture->TexturePos.x;
int texturePosY = flipY ? -(m_texture->TextureSize.height + m_texture->TexturePos.y) + SDL_abs(transform.position.y * 2) : m_texture->TexturePos.y;
// 先计算Img坐标与精灵坐标合成后的真实坐标
int RealPosX = transform.position.x + texturePosX;
int RealPosY = transform.position.y + texturePosY;
// 计算在世界中的位置
int baseX = transformIter.position.x + RealPosX;
int baseY = transformIter.position.y + RealPosY;
// 获取当前帧的原始尺寸
int frameWidth = m_texture->TextureSize.width;
int frameHeight = m_texture->TextureSize.height;
// 原始锚点偏移(基于帧尺寸)
int origAnchorOffsetX = static_cast<int>(frameWidth * Anchor.x);
int origAnchorOffsetY = static_cast<int>(frameHeight * Anchor.y);
// 缩放的绝对值
float absScaleX = SDL_abs(scaleX);
float absScaleY = SDL_abs(scaleY);
// 缩放后的尺寸
int scaledWidth = static_cast<int>(frameWidth * absScaleX);
int scaledHeight = static_cast<int>(frameHeight * absScaleY);
// 缩放后的锚点偏移
int scaledAnchorOffsetX = static_cast<int>(origAnchorOffsetX * absScaleX);
int scaledAnchorOffsetY = static_cast<int>(origAnchorOffsetY * absScaleY);
// 计算缩放后的锚点偏移与原锚点偏移的差值
int scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
int scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
int Xpos = baseX + scaleOffsetX;
int Ypos = baseY + scaleOffsetY;
// 更新渲染信息
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
// 屏幕内检测
int screenWidth = Game::GetInstance().Screen_W;
int screenHeight = Game::GetInstance().Screen_H;
bool isInScreen = (Xpos + scaledWidth >= 0 && Xpos <= screenWidth && Ypos + scaledHeight >= 0 && Ypos <= screenHeight);
_RenderGuidanceInfo.IsInScreen = isInScreen;
this->Size = {scaledWidth, scaledHeight};
_RenderGuidanceInfo.rotation = transformIter.rotation + transform.rotation;
CalcRenderInfoFlag = false;
}
void Sprite::Render()
{
if (!Visible)
return;
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
if (!m_texture)
return;
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
{
if (_RenderGuidanceInfo.rotation != 0.f || _RenderGuidanceInfo.flip != SDL_FLIP_NONE)
{
SDL_Point AnchorPos = _RenderGuidanceInfo.AnchorPos;
SDL_RenderCopyEx(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
}
else
{
SDL_RenderCopy(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect);
// // 设置绘制颜色
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128);
// // 绘制填充矩形
// SDL_RenderFillRect(renderer, &_RenderGuidanceInfo.rect);
}
Game::GetInstance().RenderCount++;
}
}
void Sprite::Clear()
{
}
void Sprite::SetBlendMode(SDL_BlendMode blendMode)
{
if (GetBlendMode() != blendMode)
m_texture->SetBlendMode(blendMode);
}
SDL_BlendMode Sprite::GetBlendMode()
{
return m_texture->GetBlendMode();
}

View File

@@ -0,0 +1,77 @@
#pragma once
#include <string>
#include "Asset/Asset_ImagePack.h"
#include "EngineFrame/Component/RenderBase.h"
#include "EngineFrame/Render/Texture.h"
class Game;
/**
* @brief Sprite类继承自Component类用于表示游戏中的精灵组件
*/
class Sprite : public RenderBase
{
protected:
/* data */
RefPtr<Texture> m_texture = nullptr;
public:
/**
* @brief Sprite类的默认构造函数
*/
Sprite(/* args */);
/**
* @brief Sprite类的带参数构造函数
* @param imgPath 纹理图片路径
* @param Index 索引值
*/
Sprite(std::string imgPath, int Index);
/**
* @brief Sprite类的带参数构造函数
* @param imgPath 纹理图片文件路径
*/
Sprite(std::string PngPath);
/**
* @brief Sprite类的析构函数
*/
~Sprite();
/**
* @brief 处理事件
* @param e SDL事件指针
*/
void HandleEvents(SDL_Event *e) override;
/**
* @brief 更新组件状态
* @param deltaTime 时间增量
*/
void Update(float deltaTime) override;
/**
* @brief 渲染组件
* @param deltaTime 时间增量
*/
void Render() override;
/**
* @brief 清理组件资源
*/
void Clear() override;
/**
* @brief 获取纹理
* @return SDL_Texture* 纹理指针
*/
RefPtr<Texture> GetTexture();
void SetIterationPos(VecFPos pos) override;
public:
RenderGuidanceInfo _RenderGuidanceInfo;
std::string imgPath;
int Index;
public:
// 计算渲染信息
void CalcRenderInfoLogic();
// 设置混合模式
void SetBlendMode(SDL_BlendMode blendMode);
// 获取混合模式
SDL_BlendMode GetBlendMode();
};

View File

@@ -0,0 +1,207 @@
#include "EngineFrame/Component/Text.h"
#include "Text.h"
#include "EngineCore/Game.h"
Text::Text()
{
}
Text::Text(std::string Str, TTF_Font *font, SDL_Color color)
{
m_text = Str;
m_font = font;
m_text_color = color;
Init(Str, font, color);
}
Text::Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
{
m_text = Str;
m_font = font;
m_text_color = textColor;
m_stroke_color = strokeColor;
m_stroke_size = strokeSize;
Init(Str, font, textColor, strokeColor, strokeSize);
}
Text::~Text()
{
}
void Text::Init(std::string Str, TTF_Font *font, SDL_Color color)
{
// 标记该组件需要渲染和更新
addTag(Tag::RENDER);
addTag(Tag::UPDATE);
// TTF_SetFontOutline(font, 1);
// 先渲染为表面
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), color);
if (!textSurface)
{
SDL_LogError(0, "文字渲染为表面失败TTF_Error:%s", TTF_GetError());
}
// 再将表面转换为纹理
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
m_texture = SDL_CreateTextureFromSurface(renderer, textSurface);
if (!m_texture)
{
SDL_LogError(0, "表面转换为纹理失败SDL_Error:%s", SDL_GetError());
}
// 设置纹理过滤模式为最近邻,避免缩放模糊
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeNearest);
Size.x = textSurface->w;
Size.y = textSurface->h;
TextureSize.x = textSurface->w;
TextureSize.y = textSurface->h;
// 释放表面
SDL_FreeSurface(textSurface);
}
void Text::Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
{
// 先保存原始字体的轮廓设置
int originalOutline = TTF_GetFontOutline(font);
// 设置字体轮廓大小(描边宽度)
TTF_SetFontOutline(font, strokeSize);
// 渲染描边(使用描边颜色)
SDL_Surface *strokeSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), strokeColor);
if (!strokeSurface)
{
SDL_LogError(0, "描边渲染为表面失败TTF_Error:%s", TTF_GetError());
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
return;
}
// 恢复字体轮廓设置,用于渲染文字本身
TTF_SetFontOutline(font, 0);
// 渲染文字本身(使用文字颜色)
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), textColor);
if (!textSurface)
{
SDL_LogError(0, "文字渲染为表面失败TTF_Error:%s", TTF_GetError());
SDL_FreeSurface(strokeSurface);
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
return;
}
// 创建一个合并描边和文字的表面
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
// 计算最终纹理大小(描边会增加额外尺寸)
int finalWidth = strokeSurface->w;
int finalHeight = strokeSurface->h;
// 创建一个临时表面用于合并描边和文字
SDL_Surface *finalSurface = SDL_CreateRGBSurfaceWithFormat(
0, finalWidth, finalHeight, 32, SDL_PIXELFORMAT_RGBA32);
if (!finalSurface)
{
SDL_LogError(0, "创建最终表面失败SDL_Error:%s", SDL_GetError());
SDL_FreeSurface(textSurface);
SDL_FreeSurface(strokeSurface);
TTF_SetFontOutline(font, originalOutline);
return;
}
// 将描边绘制到最终表面
SDL_Rect strokeRect = {0, 0, strokeSurface->w, strokeSurface->h};
SDL_BlitSurface(strokeSurface, nullptr, finalSurface, &strokeRect);
// 计算文字在描边中间的位置
SDL_Rect textRect = {
strokeSize, // X偏移描边宽度
strokeSize, // Y偏移描边宽度
textSurface->w,
textSurface->h};
SDL_BlitSurface(textSurface, nullptr, finalSurface, &textRect);
// 将合并后的表面转换为纹理
m_texture = SDL_CreateTextureFromSurface(renderer, finalSurface);
if (!m_texture)
{
SDL_LogError(0, "表面转换为纹理失败SDL_Error:%s", SDL_GetError());
}
// 设置尺寸信息
Size.x = finalSurface->w;
Size.y = finalSurface->h;
TextureSize.x = finalSurface->w;
TextureSize.y = finalSurface->h;
// 释放所有临时表面
SDL_FreeSurface(textSurface);
SDL_FreeSurface(strokeSurface);
SDL_FreeSurface(finalSurface);
// 恢复字体原始轮廓设置
TTF_SetFontOutline(font, originalOutline);
}
void Text::HandleEvents(SDL_Event *e)
{
}
void Text::Update(float deltaTime)
{
}
void Text::Render()
{
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
if (!renderer || !m_texture)
return;
SDL_Rect dstrect = {Pos.x, Pos.y, Size.x, Size.y};
SDL_RenderCopy(renderer, m_texture, NULL, &dstrect);
}
void Text::Clear()
{
}
void Text::SetPos(SDL_Point pos)
{
Pos = pos;
}
SDL_Point Text::GetPos()
{
return Pos;
}
void Text::SetText(std::string Str)
{
if (Str == m_text)
return;
if (!m_font)
{
SDL_LogError(0, "SetText失败字体指针为空");
return;
}
// 如果有原纹理先删除原纹理
if (m_texture)
{
SDL_DestroyTexture(m_texture);
m_texture = nullptr; // 置空指针
}
m_text = Str;
// 根据是否有描边选择对应的Init方法
if (m_stroke_size > 0)
{
Init(Str, m_font, m_text_color, m_stroke_color, m_stroke_size);
}
else
{
Init(Str, m_font, m_text_color);
}
}
std::string Text::GetText()
{
return m_text;
}

View File

@@ -0,0 +1,59 @@
#pragma once
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include "EngineFrame/Component/Component.h"
class Game;
class Text : public Component
{
private:
/* data */
SDL_Texture *m_texture = nullptr;
public:
Text(/* args */);
Text(std::string Str, TTF_Font *font, SDL_Color color);
Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
~Text();
// 显式引入基类的Init方法避免隐藏
using Component::Init;
void Init(std::string Str, TTF_Font *font, SDL_Color color);
void Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
void HandleEvents(SDL_Event *e) override;
void Update(float deltaTime) override;
void Render() override;
void Clear() override;
SDL_Texture *GetTexture();
public:
// 组件标签
Tag m_tag = Tag::RENDER | Tag::UPDATE; // 标记该组件需要渲染和更新
std::string m_text;
TTF_Font *m_font;
SDL_Color m_text_color;
SDL_Color m_stroke_color;
int m_stroke_size = 0;
SDL_Point Pos = {0, 0}; // 位置坐标
SDL_Point TextureSize = {0, 0}; // 纹理大小
SDL_Point Size = {0, 0}; // 大小
SDL_Point Anchor = {0, 0}; // 中心点
float Angle = 0.0f; // 旋转角度
SDL_RendererFlip flip = SDL_FLIP_NONE; // 翻转
public:
// 设置坐标
void SetPos(SDL_Point pos);
// 设置文本
void SetText(std::string Str);
// 获取坐标
SDL_Point GetPos();
// 获取文本
std::string GetText();
};

View File

@@ -0,0 +1,83 @@
#include "EngineFrame/Render/Texture.h"
#include "Asset/Asset_ImagePack.h"
#include "EngineCore/Game.h"
#include "Texture.h"
Texture::Texture()
{
}
Texture::Texture(std::string PngPath)
{
SDL_Surface *surface = IMG_Load(PngPath.c_str());
if (!surface)
{
SDL_Log("无法加载图片: %s", SDL_GetError());
return;
}
m_texture = SDL_CreateTextureFromSurface(Game::GetInstance().GetRenderer(), surface);
if (!m_texture)
{
SDL_Log("无法创建纹理: %s", SDL_GetError());
SDL_FreeSurface(surface); // 记得释放surface
return;
}
this->TextureSize.width = surface->w;
this->TextureSize.height = surface->h;
this->TextureFramepos.width = surface->w;
this->TextureFramepos.height = surface->h;
SDL_FreeSurface(surface);
}
Texture::Texture(std::string imgPath, int Index)
{
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath);
if (Info->lpImgName == "sprite/interface/base.img")
return;
Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index];
m_texture = SDL_CreateTexture(
Game::GetInstance().GetRenderer(),
SDL_PIXELFORMAT_ARGB8888, // 匹配RGBA数据格式
SDL_TEXTUREACCESS_STREAMING,
Buf.Width, Buf.Height);
if (!m_texture)
{
SDL_Log("纹理创建失败: %s", SDL_GetError());
}
int pitch = Buf.Width * 4;
SDL_UpdateTexture(m_texture, NULL, Buf.PNGdata, pitch);
SDL_SetTextureBlendMode(m_texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeBest);
this->TexturePos.x = Buf.Xpos;
this->TexturePos.y = Buf.Ypos;
this->TextureSize.width = Buf.Width;
this->TextureSize.height = Buf.Height;
this->TextureFramepos.width = Buf.FrameXpos;
this->TextureFramepos.height = Buf.FrameYpos;
}
Texture::~Texture()
{
SDL_DestroyTexture(m_texture);
}
SDL_Texture *Texture::GetTexture()
{
return m_texture;
}
void Texture::SetBlendMode(SDL_BlendMode blendMode)
{
SDL_SetTextureBlendMode(m_texture, blendMode);
}
SDL_BlendMode Texture::GetBlendMode()
{
SDL_BlendMode blendMode;
SDL_GetTextureBlendMode(m_texture, &blendMode);
return blendMode;
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <SDL.h>
#include <string>
#include "Tool/RefPtr.h"
#include "Tool/RefObject.h"
class Texture : public RefObject
{
private:
SDL_Texture *m_texture = nullptr;
public:
VecSize TextureSize = {0, 0}; // 纹理大小
VecPos TexturePos = {0, 0}; // 纹理位置
VecSize TextureFramepos = {0, 0}; // 帧域宽高
public:
Texture(/* args */);
Texture(std::string PngPath);
Texture(std::string imgPath, int Index);
~Texture();
public:
void SetBlendMode(SDL_BlendMode blendMode);
// 获取混合模式
SDL_BlendMode GetBlendMode();
SDL_Texture *GetTexture(); // 获取纹理
};

View File

@@ -0,0 +1,22 @@
#include "Scene.h"
#include "EngineFrame/Scene/Scene.h"
#include <algorithm>
Scene::Scene()
{
Init();
}
void Scene::Enter()
{
}
void Scene::Init()
{
BaseNode::Init();
addTag(Tag::SCENE);
}
void Scene::Exit()
{
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "EngineFrame/Base/BaseNode.h"
class Scene : public BaseNode
{
public:
Scene();
virtual void Enter();
virtual void Exit();
void Init();
};

61
source/Tool/Allocator.cpp Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (c) 2016-2018 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "Tool/Allocator.h"
namespace memory
{
MemoryAllocator *current_allocator_ = nullptr;
MemoryAllocator *GetGlobalAllocator()
{
class GlobalAllocator : public MemoryAllocator
{
public:
virtual void *Alloc(size_t size) override
{
return ::operator new(size);
}
virtual void Free(void *ptr) override
{
::operator delete(ptr);
}
};
static GlobalAllocator global_allocator;
return &global_allocator;
}
MemoryAllocator *GetAllocator()
{
if (!current_allocator_)
{
current_allocator_ = GetGlobalAllocator();
}
return current_allocator_;
}
void SetAllocator(MemoryAllocator *allocator)
{
current_allocator_ = allocator;
}
} // namespace memory

151
source/Tool/Allocator.h Normal file
View File

@@ -0,0 +1,151 @@
#pragma once
#include <limits>
#include <cstddef>
#include <utility>
namespace memory
{
/// \~chinese
/// @brief 内存分配器
class MemoryAllocator
{
public:
/// \~chinese
/// @brief 申请内存
virtual void *Alloc(size_t size) = 0;
/// \~chinese
/// @brief 释放内存
virtual void Free(void *ptr) = 0;
};
/// \~chinese
/// @brief 获取当前内存分配器
MemoryAllocator *GetAllocator();
/// \~chinese
/// @brief 设置当前内存分配器
void SetAllocator(MemoryAllocator *allocator);
/// \~chinese
/// @brief 使用当前内存分配器分配内存
inline void *Alloc(size_t size)
{
return memory::GetAllocator()->Alloc(size);
}
/// \~chinese
/// @brief 使用当前内存分配器释放内存
inline void Free(void *ptr)
{
memory::GetAllocator()->Free(ptr);
}
} // namespace memory
/// \~chinese
/// @brief 分配器
template <typename _Ty>
class Allocator
{
public:
typedef _Ty value_type;
typedef _Ty *pointer;
typedef const _Ty *const_pointer;
typedef _Ty &reference;
typedef const _Ty &const_reference;
using size_type = size_t;
using difference_type = ptrdiff_t;
template <class _Other>
struct rebind
{
using other = Allocator<_Other>;
};
Allocator() noexcept {}
Allocator(const Allocator &) noexcept = default;
template <class _Other>
Allocator(const Allocator<_Other> &) noexcept
{
}
inline _Ty *allocate(size_t count)
{
if (count > 0)
{
return static_cast<_Ty *>(memory::Alloc(sizeof(_Ty) * count));
}
return nullptr;
}
inline void *allocate(size_t count, const void *)
{
return allocate(count);
}
inline void deallocate(void *ptr, size_t count)
{
memory::Free(ptr /*, sizeof(_Ty) * count */);
}
template <typename _UTy, typename... _Args>
inline void construct(_UTy *const ptr, _Args &&...args)
{
::new (const_cast<void *>(static_cast<const volatile void *>(ptr))) _Ty(std::forward<_Args>(args)...);
}
template <typename _UTy>
inline void destroy(_UTy *ptr)
{
ptr->~_UTy();
}
size_t max_size() const noexcept
{
return std::numeric_limits<size_t>::max() / sizeof(_Ty);
}
_Ty *address(_Ty &val) const noexcept
{
return std::addressof(val);
}
const _Ty *address(const _Ty &val) const noexcept
{
return std::addressof(val);
}
};
// Allocator<void>
template <>
class Allocator<void>
{
public:
using value_type = void;
typedef void *pointer;
typedef const void *const_pointer;
using size_type = size_t;
using difference_type = ptrdiff_t;
template <class _Other>
struct rebind
{
using other = Allocator<_Other>;
};
};
template <class _Ty, class _Other>
bool operator==(const Allocator<_Ty> &, const Allocator<_Other> &) noexcept
{
return true;
}
template <class _Ty, class _Other>
bool operator!=(const Allocator<_Ty> &, const Allocator<_Other> &) noexcept
{
return false;
}

137
source/Tool/Blob.hpp Normal file
View File

@@ -0,0 +1,137 @@
#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <stdexcept>
#include <algorithm>
class Blob
{
using BYTE = unsigned char;
private:
const std::vector<BYTE> m_blob;
size_t m_offset;
// 检查是否有足够的剩余字节
void checkSize(size_t required) const
{
if (m_offset + required > m_blob.size())
{
throw std::out_of_range("Insufficient data in blob");
}
}
public:
// 构造函数,接受一个字节向量的引用
Blob(const std::vector<BYTE> blob) : m_blob(blob), m_offset(0) {}
// 重置解析偏移量
void reset() { m_offset = 0; }
// 获取当前偏移量
size_t getOffset() const { return m_offset; }
// 设置偏移量
void setOffset(size_t offset)
{
if (offset > m_blob.size())
{
throw std::out_of_range("Offset out of range");
}
m_offset = offset;
}
// 获取剩余字节数
size_t remaining() const { return m_blob.size() - m_offset; }
// 读取一个T类型的数据适用于基本类型
template <typename T>
T get()
{
checkSize(sizeof(T));
T value;
std::copy(m_blob.begin() + m_offset,
m_blob.begin() + m_offset + sizeof(T),
reinterpret_cast<BYTE *>(&value));
m_offset += sizeof(T);
return value;
}
// 读取int类型
int32_t getInt() { return get<int32_t>(); }
// 读取无符号int类型
uint32_t getUInt() { return get<uint32_t>(); }
// 读取short类型
int16_t getShort() { return get<int16_t>(); }
// 读取无符号short类型
uint16_t getUShort() { return get<uint16_t>(); }
// 读取float类型
float getFloat() { return get<float>(); }
// 读取double类型
double getDouble() { return get<double>(); }
BYTE getByte() { return get<BYTE>(); }
float get256()
{
BYTE buf = get<BYTE>();
return static_cast<float>(buf);
}
// 读取指定长度的字符串
std::string getString(size_t length)
{
checkSize(length);
std::string str(reinterpret_cast<const char *>(m_blob.data() + m_offset), length);
m_offset += length;
return str;
}
// 读取以null结尾的字符串
std::string getNullTerminatedString()
{
size_t length = 0;
size_t pos = m_offset;
// 查找null终止符
while (pos < m_blob.size() && m_blob[pos] != '\0')
{
pos++;
length++;
}
// 确保找到了终止符
if (pos >= m_blob.size())
{
throw std::runtime_error("Null-terminated string not found");
}
// 读取字符串(不包含终止符)
std::string str(reinterpret_cast<const char *>(m_blob.data() + m_offset), length);
m_offset = pos + 1; // 跳过终止符
return str;
}
// 读取指定数量的字节
std::vector<BYTE> getBytes(size_t count)
{
checkSize(count);
std::vector<BYTE> bytes(m_blob.begin() + m_offset, m_blob.begin() + m_offset + count);
m_offset += count;
return bytes;
}
};

262
source/Tool/Common.h Normal file
View File

@@ -0,0 +1,262 @@
#pragma once
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <cstddef>
#include <SDL.h>
#ifdef __SWITCH__
#include <switch/types.h>
#else
#include <cmath>
#endif
/// \~chinese
/// @brief 不可拷贝对象
class Noncopyable
{
protected:
Noncopyable() = default;
private:
Noncopyable(const Noncopyable &) = delete;
Noncopyable &operator=(const Noncopyable &) = delete;
};
// 整数坐标向量
typedef struct VecPos
{
int x;
int y;
// 构造函数,方便初始化
VecPos(int x_ = 0, int y_ = 0) : x(x_), y(y_) {}
// 定义到 SDL_Point 的转换运算符
operator SDL_Point() const
{
return {x, y}; // 直接返回包含 x、y 的 SDL_Point
}
// 转换为SDL_Point指针的运算符用于指针场景
operator const SDL_Point *() const
{
// 注意:这里返回的是指向当前对象的指针,需确保对象生命周期有效
return reinterpret_cast<const SDL_Point *>(this);
}
// 加法运算符重载:两个 VecPos 相加
VecPos operator+(const VecPos &other) const
{
return VecPos(x + other.x, y + other.y);
}
// 减法运算符重载:两个 VecPos 相减
VecPos operator-(const VecPos &other) const
{
return VecPos(x - other.x, y - other.y);
}
// 等于运算符重载:判断两个 VecPos 是否相等
bool operator==(const VecPos &other) const
{
return x == other.x && y == other.y;
}
// 复合赋值加法:当前对象加上另一个 VecPos
VecPos &operator+=(const VecPos &other)
{
x += other.x;
y += other.y;
return *this;
}
// 复合赋值减法:当前对象减去另一个 VecPos
VecPos &operator-=(const VecPos &other)
{
x -= other.x;
y -= other.y;
return *this;
}
} VecPos;
// 浮点数坐标向量
typedef struct VecFPos
{
float x;
float y;
// 构造函数,方便初始化
VecFPos(float x_ = 0.0f, float y_ = 0.0f) : x(x_), y(y_) {}
VecFPos(int x_, int y_ = 0) : x(static_cast<float>(x_)), y(static_cast<float>(y_)) {}
// 定义到 SDL_FPoint 的转换运算符
operator SDL_FPoint() const
{
return {x, y}; // 直接返回包含 x、y 的 SDL_Point
}
// 加法运算符重载:两个 VecFPos 相加
VecFPos operator+(const VecFPos &other) const
{
return VecFPos(x + other.x, y + other.y);
}
// 减法运算符重载:两个 VecFPos 相减
VecFPos operator-(const VecFPos &other) const
{
return VecFPos(x - other.x, y - other.y);
}
// 乘法运算符重载:两个 VecFPos 相乘
VecFPos operator*(const VecFPos &other) const
{
return VecFPos(x * other.x, y * other.y);
}
// 等于运算符重载:判断两个 VecFPos 是否相等
// 注意:浮点数比较需要考虑精度问题
bool operator==(const VecFPos &other) const
{
// 使用一个小的epsilon值来比较浮点数
const float epsilon = 0.0001f;
return (fabs(x - other.x) < epsilon) && (fabs(y - other.y) < epsilon);
}
// 复合赋值加法:当前对象加上另一个 VecFPos
VecFPos &operator+=(const VecFPos &other)
{
x += other.x;
y += other.y;
return *this;
}
// 复合赋值减法:当前对象减去另一个 VecFPos
VecFPos &operator-=(const VecFPos &other)
{
x -= other.x;
y -= other.y;
return *this;
}
} VecFPos;
// 尺寸向量
typedef struct VecSize
{
int width;
int height;
// 构造函数,方便初始化
VecSize(int width_ = 0, int height_ = 0) : width(width_), height(height_) {}
// 加法运算符重载:两个 VecSize 相加
VecSize operator+(const VecSize &other) const
{
return VecSize(width + other.width, height + other.height);
}
// 减法运算符重载:两个 VecSize 相减
VecSize operator-(const VecSize &other) const
{
return VecSize(width - other.width, height - other.height);
}
// 等于运算符重载:判断两个 VecSize 是否相等
bool operator==(const VecSize &other) const
{
return width == other.width && height == other.height;
}
// 复合赋值加法:当前对象加上另一个 VecSize
VecSize &operator+=(const VecSize &other)
{
width += other.width;
height += other.height;
return *this;
}
// 复合赋值减法:当前对象减去另一个 VecSize
VecSize &operator-=(const VecSize &other)
{
width -= other.width;
height -= other.height;
return *this;
}
} VecSize;
typedef struct VecPos3
{
int x;
int y;
int z;
VecPos3(int x_ = 0, int y_ = 0, int z_ = 0) : x(x_), y(y_), z(z_) {}
VecPos3 operator+(const VecPos3 &other) const
{
return VecPos3(x + other.x, y + other.y, z + other.z);
}
VecPos3 operator-(const VecPos3 &other) const
{
return VecPos3(x - other.x, y - other.y, z - other.z);
}
bool operator==(const VecPos3 &other) const
{
return x == other.x && y == other.y && z == other.z;
}
} VecPos3;
typedef struct VecFPos3
{
float x;
float y;
float z;
VecFPos3(float x_ = 0, float y_ = 0, float z_ = 0) : x(x_), y(y_), z(z_) {}
VecFPos3 operator+(const VecFPos3 &other) const
{
return VecFPos3(x + other.x, y + other.y, z + other.z);
}
VecFPos3 operator-(const VecFPos3 &other) const
{
return VecFPos3(x - other.x, y - other.y, z - other.z);
}
bool operator==(const VecFPos3 &other) const
{
return x == other.x && y == other.y && z == other.z;
}
} VecFPos3;
typedef struct VecSpeed3
{
float x;
float y;
float z;
VecSpeed3(float x_ = 0, float y_ = 0, float z_ = 0) : x(x_), y(y_), z(z_) {}
VecSpeed3 operator+(const VecSpeed3 &other) const
{
return VecSpeed3(x + other.x, y + other.y, z + other.z);
}
VecSpeed3 operator-(const VecSpeed3 &other) const
{
return VecSpeed3(x - other.x, y - other.y, z - other.z);
}
bool operator==(const VecSpeed3 &other) const
{
return x == other.x && y == other.y && z == other.z;
}
} VecSpeed3;

View File

@@ -0,0 +1,86 @@
#include "Ifstream_NPK.h"
// 密钥初始化
Ifstream_NPK::Ifstream_NPK() : Key{112, 117, 99, 104, 105, 107, 111, 110, 64, 110, 101, 111, 112, 108, 101, 32, 100, 117, 110, 103, 101, 111, 110, 32, 97, 110, 100, 32, 102, 105, 103, 104, 116, 101, 114, 32, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 0}
{
// 构造函数体可以为空
}
// char* 转整数
int Ifstream_NPK::CharToInt(char *Str)
{
return *(int *)Str;
}
// char* 转Long
long Ifstream_NPK::CharToLong(char *Str)
{
return *(long long *)Str;
}
// 读整数
int Ifstream_NPK::ReadInt()
{
char *CountBuffer = new char[4];
for (int i = 0; i < 4; i++)
{
this->get(CountBuffer[i]);
}
int Count = CharToInt(CountBuffer);
delete[] CountBuffer;
return Count;
}
// 读字符串
std::string Ifstream_NPK::ReadString()
{
char *CharBuffer = new char[1024];
this->get(CharBuffer, 1024, '\0');
std::string Str = CharBuffer;
delete[] CharBuffer;
this->seekg(1, std::ios::cur);
return Str;
}
// 读取信息
std::string Ifstream_NPK::ReadInfo()
{
char *CharBuffer = new char[256];
char var;
int i = 0;
while (i < 256)
{
this->get(var);
CharBuffer[i] = var ^ Key[i];
++i;
}
std::string Str = CharBuffer;
delete[] CharBuffer;
return Str;
}
// 读LONG
int Ifstream_NPK::ReadLong()
{
char *CountBuffer = new char[8];
for (int i = 0; i < 8; i++)
{
this->get(CountBuffer[i]);
}
long Count = CharToLong(CountBuffer);
delete[] CountBuffer;
return Count;
}
// 读指定长度数据
BYTE *Ifstream_NPK::ReadCustomSize(int Size)
{
BYTE *CharBuffer = new BYTE[Size];
for (int j = 0; j < Size; j++)
{
char var;
this->get(var);
CharBuffer[j] = var;
}
return CharBuffer;
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <fstream>
#include <string>
typedef unsigned char BYTE;
class Ifstream_NPK : public std::ifstream
{
private:
const BYTE Key[256];
public:
// 构造函数
Ifstream_NPK();
// char* 转整数
int CharToInt(char *Str);
// char* 转Long
long CharToLong(char *Str);
// 读整数
int ReadInt();
// 读字符串
std::string ReadString();
// 读取信息
std::string ReadInfo();
// 读LONG
int ReadLong();
// 读指定长度数据
BYTE *ReadCustomSize(int Size);
};

View File

@@ -0,0 +1,35 @@
#include "Ifstream_PVF.h"
Ifstream_PVF::Ifstream_PVF(std::string fileName)
{
std::ifstream file(fileName, std::ios::binary | std::ios::in);
if (file.is_open())
{
// 获取文件大小
file.seekg(0, std::ios::end);
std::streamsize length = file.tellg();
file.seekg(0, std::ios::beg);
if (length > 0)
{
// 直接调整vector大小并读取数据
_Data.resize(static_cast<size_t>(length));
if (file.read(_Data.data(), length))
{
}
else
{
_Data.clear();
}
}
file.close();
}
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "无法打开文件: %s", fileName.c_str());
}
}
Ifstream_PVF::~Ifstream_PVF()
{
// vector会自动释放内存无需手动操作
}

170
source/Tool/Ifstream_PVF.h Normal file
View File

@@ -0,0 +1,170 @@
#pragma once
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <SDL.h>
#include <algorithm>
#include "Tool/Tool_String.h"
typedef unsigned char BYTE;
// 定义宏用于注册获取不同类型值的函数
#define REGISTER_GET_FUNCTION(Type, FunctionName) \
Type Get##FunctionName() \
{ \
char buffer[sizeof(Type)]; \
read(buffer, sizeof(Type)); \
Type result; \
std::memcpy(&result, buffer, sizeof(Type)); \
return result; \
}
class Ifstream_PVF
{
public:
// 使用vector存储数据替代char*
std::vector<char> _Data;
// 当前位置
int _CurPos = 0;
// 上一次读取的实际大小
int _LastReadSize = 0;
public:
Ifstream_PVF(std::string fileName);
~Ifstream_PVF();
public:
int tellg()
{
return _CurPos;
}
// 获取数据大小
int size() const
{
return static_cast<int>(_Data.size());
}
void read(char *ptr, int size)
{
// 使用vector的size()作为最大长度
if ((size + _CurPos) > static_cast<int>(_Data.size()))
{
size = static_cast<int>(_Data.size()) - _CurPos;
}
memcpy(ptr, _Data.data() + _CurPos, size);
_CurPos += size;
_LastReadSize = size;
}
int gcount()
{
return _LastReadSize;
}
void seek(int _jidx)
{
// 确保不会越界
_CurPos = std::clamp(_jidx, 0, static_cast<int>(_Data.size()));
}
public:
unsigned int charPtrToInt(const char *bytes)
{
unsigned int result;
std::memcpy(&result, bytes, sizeof(int));
return result;
}
void CrcDecode(const int Length, const int crc32)
{
int num = 0x81A79011;
int originalPos = tellg(); // 保存初始位置
for (int i = 0; i < Length; i += 4)
{
int Pos = tellg();
char buffer[4];
read(buffer, 4);
unsigned int anInt = charPtrToInt(buffer);
unsigned int val = (anInt ^ num ^ crc32);
unsigned int jiemi = (val >> 6) | ((val << (32 - 6)) & 0xFFFFFFFF);
// 使用vector的data()获取数据指针
if (Pos + 3 < static_cast<int>(_Data.size()))
{
_Data[Pos] = ((jiemi >> 0) & 0xFF);
_Data[Pos + 1] = ((jiemi >> 8) & 0xFF);
_Data[Pos + 2] = ((jiemi >> 16) & 0xFF);
_Data[Pos + 3] = ((jiemi >> 24) & 0xFF);
}
}
// 重置读取位置,因为解码过程中移动了指针
seek(originalPos + Length); // 移动到解码后的位置
}
std::string tolower(std::string str)
{
for (size_t i = 0; i < str.length(); ++i)
{
str[i] = std::tolower(str[i]);
}
return str;
}
std::vector<std::string> split(const std::string &str, const std::string &delimiter)
{
std::vector<std::string> tokens;
size_t pos = 0;
size_t found;
while ((found = str.find(delimiter, pos)) != std::string::npos)
{
tokens.push_back(str.substr(pos, found - pos));
pos = found + delimiter.length();
}
tokens.push_back(str.substr(pos));
return tokens;
}
public:
REGISTER_GET_FUNCTION(int, Int);
REGISTER_GET_FUNCTION(short, Short);
REGISTER_GET_FUNCTION(unsigned short, UShort);
std::string GetString(const int size)
{
if (size <= 0)
return "";
// 确保不会读取超出范围的数据
int readSize = std::min(size, static_cast<int>(_Data.size()) - _CurPos);
std::string result(_Data.data() + _CurPos, readSize);
_CurPos += readSize;
_LastReadSize = readSize;
if (readSize != size)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "未能成功读取指定字节数的数据!");
}
return (result);
}
std::string GetStringNormal(const int size)
{
// 与GetString实现相同可根据实际需求区分
if (size <= 0)
return "";
int readSize = std::min(size, static_cast<int>(_Data.size()) - _CurPos);
std::string result(_Data.data() + _CurPos, readSize);
_CurPos += readSize;
_LastReadSize = readSize;
if (readSize != size)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "未能成功读取指定字节数的数据!");
}
return result;
}
};

View File

@@ -0,0 +1,459 @@
#pragma once
#include <type_traits>
#include <iterator>
#include <stdexcept>
/// \~chinese
/// @brief 侵入式链表
template <typename _PtrTy>
class IntrusiveList
{
public:
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
using pointer = value_type *;
using reference = value_type &;
IntrusiveList()
: first_(), last_()
{
}
~IntrusiveList()
{
Clear();
}
/// \~chinese
/// @brief 获取首元素
const value_type &GetFirst() const
{
return first_;
}
/// \~chinese
/// @brief 获取首元素
value_type &GetFirst()
{
return first_;
}
/// \~chinese
/// @brief 获取尾元素
const value_type &GetLast() const
{
return last_;
}
/// \~chinese
/// @brief 获取尾元素
value_type &GetLast()
{
return last_;
}
/// \~chinese
/// @brief 链表是否为空
inline bool IsEmpty() const
{
return first_ == nullptr;
}
/// \~chinese
/// @brief 在链表尾部添加对象
void PushBack(reference child)
{
if (child->GetPrev())
child->GetPrev()->GetNext() = child->GetNext();
if (child->GetNext())
child->GetNext()->GetPrev() = child->GetPrev();
child->GetPrev() = last_;
child->GetNext() = nullptr;
if (first_)
{
last_->GetNext() = child;
}
else
{
first_ = child;
}
last_ = child;
}
/// \~chinese
/// @brief 在链表头部添加对象
void PushFront(reference child)
{
if (child->GetPrev())
child->GetPrev()->GetNext() = child->GetNext();
if (child->GetNext())
child->GetNext()->GetPrev() = child->GetPrev();
child->GetPrev() = nullptr;
child->GetNext() = first_;
if (first_)
{
first_->GetPrev() = child;
}
else
{
last_ = child;
}
first_ = child;
}
/// \~chinese
/// @brief 在链表的对象前插入新对象
void InsertBefore(reference child, reference before)
{
if (child->GetPrev())
child->GetPrev()->GetNext() = child->GetNext();
if (child->GetNext())
child->GetNext()->GetPrev() = child->GetPrev();
if (before->GetPrev())
before->GetPrev()->GetNext() = child;
else
first_ = child;
child->GetPrev() = before->GetPrev();
child->GetNext() = before;
before->GetPrev() = child;
}
/// \~chinese
/// @brief 在链表的对象后插入新对象
void InsertAfter(reference child, reference after)
{
if (child->GetPrev())
child->GetPrev()->GetNext() = child->GetNext();
if (child->GetNext())
child->GetNext()->GetPrev() = child->GetPrev();
if (after->GetNext())
after->GetNext()->GetPrev() = child;
else
last_ = child;
child->GetNext() = after->GetNext();
child->GetPrev() = after;
after->GetNext() = child;
}
/// \~chinese
/// @brief 移除对象
void Remove(reference child)
{
if (child->GetNext())
{
child->GetNext()->GetPrev() = child->GetPrev();
}
else
{
last_ = child->GetPrev();
}
if (child->GetPrev())
{
child->GetPrev()->GetNext() = child->GetNext();
}
else
{
first_ = child->GetNext();
}
child->GetPrev() = nullptr;
child->GetNext() = nullptr;
}
/// \~chinese
/// @brief 清空所有对象
void Clear()
{
value_type p = first_;
while (p)
{
value_type tmp = p;
p = p->GetNext();
if (tmp)
{
tmp->GetNext() = nullptr;
tmp->GetPrev() = nullptr;
}
}
first_ = nullptr;
last_ = nullptr;
}
/// \~chinese
/// @brief 检查链表是否有效
bool CheckValid()
{
if (!first_)
return true;
int pos = 0;
value_type p = first_;
value_type tmp = p;
do
{
tmp = p;
p = p->GetNext();
++pos;
if (p)
{
if (p->GetPrev() != tmp)
return false;
}
else
{
if (tmp != last_)
return false;
}
} while (p);
return true;
}
public:
template <typename _IterPtrTy>
struct Iterator
{
using iterator_category = std::bidirectional_iterator_tag;
using value_type = _IterPtrTy;
using pointer = _IterPtrTy *;
using reference = _IterPtrTy &;
using difference_type = ptrdiff_t;
inline Iterator(value_type ptr = nullptr, bool is_end = false)
: base_(ptr), is_end_(is_end)
{
}
inline reference operator*() const
{
return const_cast<reference>(base_);
}
inline pointer operator->() const
{
return std::pointer_traits<pointer>::pointer_to(**this);
}
inline Iterator &operator++()
{
value_type next = base_->GetNext();
if (next)
base_ = next;
else
is_end_ = true;
return (*this);
}
inline Iterator operator++(int)
{
Iterator old = (*this);
++(*this);
return old;
}
inline Iterator &operator--()
{
if (is_end_)
is_end_ = false;
else
base_ = base_->GetPrev();
return (*this);
}
inline Iterator operator--(int)
{
Iterator old = (*this);
--(*this);
return old;
}
inline bool operator==(const Iterator &other) const
{
return base_ == other.base_ && is_end_ == other.is_end_;
}
inline bool operator!=(const Iterator &other) const
{
return !(*this == other);
}
inline operator bool() const
{
return base_ != nullptr && !is_end_;
}
private:
bool is_end_;
typename std::remove_const<value_type>::type base_;
};
public:
using iterator = Iterator<value_type>;
using const_iterator = Iterator<const value_type>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
inline iterator begin()
{
return iterator(first_, first_ == nullptr);
}
inline const_iterator begin() const
{
return const_iterator(first_, first_ == nullptr);
}
inline const_iterator cbegin() const
{
return begin();
}
inline iterator end()
{
return iterator(last_, true);
}
inline const_iterator end() const
{
return const_iterator(last_, true);
}
inline const_iterator cend() const
{
return end();
}
inline reverse_iterator rbegin()
{
return reverse_iterator(end());
}
inline const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}
inline const_reverse_iterator crbegin() const
{
return rbegin();
}
inline reverse_iterator rend()
{
return reverse_iterator(begin());
}
inline const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}
inline const_reverse_iterator crend() const
{
return rend();
}
inline value_type &front()
{
if (IsEmpty())
throw std::out_of_range("front() called on empty list");
return first_;
}
inline const value_type &front() const
{
if (IsEmpty())
throw std::out_of_range("front() called on empty list");
return first_;
}
inline value_type &back()
{
if (IsEmpty())
throw std::out_of_range("back() called on empty list");
return last_;
}
inline const value_type &back() const
{
if (IsEmpty())
throw std::out_of_range("back() called on empty list");
return last_;
}
private:
value_type first_;
value_type last_;
};
/// \~chinese
/// @brief 侵入式链表元素
template <typename _PtrTy>
class IntrusiveListValue
{
public:
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
using reference = value_type &;
using pointer = value_type *;
IntrusiveListValue()
: prev_(nullptr), next_(nullptr)
{
}
IntrusiveListValue(value_type rhs)
: prev_(nullptr), next_(nullptr)
{
if (rhs)
{
prev_ = rhs->GetPrev();
next_ = rhs->GetNext();
}
}
/// \~chinese
/// @brief 获取前一元素
const value_type &GetPrev() const
{
return prev_;
}
/// \~chinese
/// @brief 获取前一元素
value_type &GetPrev()
{
return prev_;
}
/// \~chinese
/// @brief 获取下一元素
const value_type &GetNext() const
{
return next_;
}
/// \~chinese
/// @brief 获取下一元素
value_type &GetNext()
{
return next_;
}
private:
value_type prev_;
value_type next_;
friend class IntrusiveList<_PtrTy>;
};

110
source/Tool/Logger.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "Logger.h"
Logger::Logger()
: m_logFile(nullptr)
, m_initialized(false)
, m_originalCallback(nullptr)
, m_originalUserdata(nullptr)
{
}
Logger::~Logger()
{
Close();
}
bool Logger::Init()
{
if (m_initialized) {
return true;
}
// 获取当前工作目录
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) == nullptr) {
return false;
}
// 构建日志文件路径
std::string logPath = std::string(cwd) + "/log.txt";
// 打开日志文件(追加模式)
m_logFile = fopen(logPath.c_str(), "a");
if (!m_logFile) {
return false;
}
// 保存原始的SDL日志回调
SDL_LogGetOutputFunction(&m_originalCallback, &m_originalUserdata);
// 设置自定义的SDL日志回调
SDL_LogSetOutputFunction(SDLLogCallback, this);
m_initialized = true;
// 使用SDL_Log写入初始化信息这会同时输出到文件和原始目标
SDL_Log("Logger initialized successfully - Log file: %s", logPath.c_str());
return true;
}
void Logger::Close()
{
if (m_initialized) {
if (m_logFile) {
SDL_Log("Logger shutting down");
fflush(m_logFile);
fclose(m_logFile);
m_logFile = nullptr;
}
// 恢复原始的SDL日志回调
if (m_originalCallback) {
SDL_LogSetOutputFunction(m_originalCallback, m_originalUserdata);
}
m_initialized = false;
}
}
void Logger::SDLLogCallback(void* userdata, int category, SDL_LogPriority priority, const char* message)
{
Logger* logger = static_cast<Logger*>(userdata);
// 首先调用原始回调(保持控制台输出等功能)
if (logger->m_originalCallback) {
logger->m_originalCallback(logger->m_originalUserdata, category, priority, message);
}
// 然后写入到日志文件
if (logger->m_initialized && logger->m_logFile) {
std::string timestamp = logger->GetCurrentTime();
const char* priorityStr = "UNKNOWN";
switch (priority) {
case SDL_LOG_PRIORITY_VERBOSE: priorityStr = "VERBOSE"; break;
case SDL_LOG_PRIORITY_DEBUG: priorityStr = "DEBUG"; break;
case SDL_LOG_PRIORITY_INFO: priorityStr = "INFO"; break;
case SDL_LOG_PRIORITY_WARN: priorityStr = "WARN"; break;
case SDL_LOG_PRIORITY_ERROR: priorityStr = "ERROR"; break;
case SDL_LOG_PRIORITY_CRITICAL: priorityStr = "CRITICAL"; break;
default: break;
}
fprintf(logger->m_logFile, "[%s][%s] %s\n", timestamp.c_str(), priorityStr, message);
fflush(logger->m_logFile);
}
}
std::string Logger::GetCurrentTime()
{
time_t rawTime;
struct tm* timeInfo;
char buffer[80];
time(&rawTime);
timeInfo = localtime(&rawTime);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo);
return std::string(buffer);
}

52
source/Tool/Logger.h Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#ifdef _SWITCH_
#include <switch.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <string>
#include <SDL.h>
#include <vector>
#include <time.h>
class Logger
{
public:
Logger(const Logger &) = delete;
Logger &operator=(const Logger &) = delete;
Logger(Logger &&) = delete;
Logger &operator=(Logger &&) = delete;
// 全局访问点
static Logger &GetInstance()
{
static Logger instance;
return instance;
}
public:
// 初始化函数 - 重定向SDL_Log到日志文件
bool Init();
// 关闭日志
void Close();
private:
Logger();
~Logger();
// SDL日志回调函数 - 将日志同时输出到文件和原始输出
static void SDLLogCallback(void* userdata, int category, SDL_LogPriority priority, const char* message);
// 获取当前时间字符串
std::string GetCurrentTime();
private:
FILE* m_logFile;
bool m_initialized;
SDL_LogOutputFunction m_originalCallback;
void* m_originalUserdata;
};

282
source/Tool/Math.h Normal file
View File

@@ -0,0 +1,282 @@
#pragma once
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <stdexcept>
class Math
{
private:
/* data */
public:
Math(/* args */) = default;
~Math() = default;
public:
static void InitRandomSeed()
{
static bool seeded = false;
if (!seeded)
{
srand(static_cast<unsigned int>(time(nullptr)));
seeded = true;
}
}
// 1. 获取X轴方向0目标在左侧1目标在右侧
static int getDirectionToTargetX(float objX, float x)
{
return (objX > x) ? 0 : 1;
}
// 2. 生成[Min, Max]范围内的随机整数(左闭右闭)
static int Rand(int Min, int Max)
{
InitRandomSeed(); // 确保随机数种子已初始化
if (Min > Max)
{
throw std::invalid_argument("Rand: Min must be less than or equal to Max");
}
// 计算随机数范围:(Max - Min + 1)个可能值
int range = Max - Min + 1;
// rand()返回[0, RAND_MAX],通过取模和偏移实现范围映射
return Min + (rand() % range);
}
// 3. 从数组中随机获取一个元素(支持任意可索引容器)
template <typename T>
static T GetRandomElementFromArray(const std::vector<T> &arr)
{
if (arr.empty())
{
throw std::invalid_argument("GetRandomElementFromArray: Array is empty");
}
int randomIndex = Rand(0, static_cast<int>(arr.size()) - 1);
return arr[randomIndex];
}
// 5. 根据方向计算偏移后的X坐标
static float GetDistancePos(float startX, int direction, float offsetX)
{
return (direction == 0) ? (startX - offsetX) : (startX + offsetX);
}
// 6. 通过两点坐标计算旋转角度(预留实现,需根据具体需求补充)
static float getRorateAngleByCurrentPos(float x1, float y1, float z1, float x2, float y2, float z2)
{
// 示例实现计算X-Z平面内的角度可根据需求调整为3D角度
float dx = x2 - x1;
float dz = z2 - z1;
// atan2(dz, dx)返回与X轴正方向的夹角弧度范围[-π, π]
return std::atan2(dz, dx);
}
// 8. 标准抛物线计算y = a(x - c/2)² + b开口向下
static float sq_Parabola(float x, float b, float c)
{
if (c == 0)
{
throw std::invalid_argument("sq_Parabola: c cannot be zero");
}
// 计算抛物线系数a确保顶点在x=c/2y=b
float a = (-4.0f * b) / (c * c);
return a * (x - c / 2.0f) * (x - c / 2.0f) + b;
}
// 9. 计算2D平面两点距离Y轴权重0.29,用于透视校正)
static float Get2D_Distance(float x1, float y1, float x2, float y2)
{
float offsetX = x1 - x2;
float offsetY = (y1 - y2) * 0.29f;
// 勾股定理计算距离
return std::sqrt(offsetX * offsetX + offsetY * offsetY);
}
// 10. 判断角度是否在[startA, endA]形成的锐角范围内(角度单位:度)
static bool CheckAngleIsInArea(float judge, float startA, float endA)
{
// 步骤1将角度标准化到[0, 360)范围
auto normalizeAngle = [](float angle)
{
angle = std::fmod(angle, 360.0f);
return (angle < 0) ? (angle + 360.0f) : angle;
};
startA = normalizeAngle(startA);
endA = normalizeAngle(endA);
judge = normalizeAngle(judge);
// 特殊情况范围跨0度如startA=350°endA=10°
if (startA > 270.0f && startA < 360.0f && endA > 0.0f && endA < 90.0f)
{
return (judge >= startA && judge <= 360.0f) || (judge >= 0.0f && judge <= endA);
}
// 普通情况范围不跨0度
else
{
// 处理startA > endA的正常范围如startA=30°endA=60°
if (startA > endA)
{
std::swap(startA, endA);
}
return (judge >= startA && judge <= endA);
}
}
// 11. 弧度转角度
static float toDegree(float radian)
{
return radian * 57.2957795f; // 180/π ≈ 57.2957795
}
// 12. 角度转弧度
static float toRadian(float degree)
{
return degree * 0.0174532925f; // π/180 ≈ 0.0174532925
}
// 13. 判断点是否在立方体内(立方体由对角点定义)
static bool pointIsInCubeArea(float px, float py, float pz,
float startX, float startY, float startZ,
float endX, float endY, float endZ)
{
// 计算立方体中心点和半边长
float cubeCenterX = (startX + endX) / 2.0f;
float cubeXLen = std::fabs(startX - endX) / 2.0f;
float cubeCenterY = (startY + endY) / 2.0f;
float cubeYLen = std::fabs(startY - endY) / 2.0f;
float cubeCenterZ = (startZ + endZ) / 2.0f;
float cubeZLen = std::fabs(startZ - endZ) / 2.0f;
// 点到各轴中心点的距离 ≤ 半边长 → 在立方体内
return (std::fabs(px - cubeCenterX) <= cubeXLen + 1e-6f) &&
(std::fabs(py - cubeCenterY) <= cubeYLen + 1e-6f) &&
(std::fabs(pz - cubeCenterZ) <= cubeZLen + 1e-6f);
}
// 14. 立方体与立方体碰撞检测(基于顶点和中心点判断)
static bool CubeAndCubeCollection(float c1StartX, float c1StartY, float c1StartZ,
float c1EndX, float c1EndY, float c1EndZ,
float c2StartX, float c2StartY, float c2StartZ,
float c2EndX, float c2EndY, float c2EndZ)
{
// 优化说明原Squirrel代码判断过多冗余点此处保留核心顶点+中心点判断
const std::vector<std::tuple<float, float, float>> c1Points = {
// 立方体1的8个顶点
{c1StartX, c1StartY, c1StartZ},
{c1EndX, c1StartY, c1StartZ},
{c1StartX, c1EndY, c1StartZ},
{c1EndX, c1EndY, c1StartZ},
{c1StartX, c1StartY, c1EndZ},
{c1EndX, c1StartY, c1EndZ},
{c1StartX, c1EndY, c1EndZ},
{c1EndX, c1EndY, c1EndZ},
// 立方体1的中心点
{(c1StartX + c1EndX) / 2, (c1StartY + c1EndY) / 2, (c1StartZ + c1EndZ) / 2}};
const std::vector<std::tuple<float, float, float>> c2Points = {
// 立方体2的8个顶点
{c2StartX, c2StartY, c2StartZ},
{c2EndX, c2StartY, c2StartZ},
{c2StartX, c2EndY, c2StartZ},
{c2EndX, c2EndY, c2StartZ},
{c2StartX, c2StartY, c2EndZ},
{c2EndX, c2StartY, c2EndZ},
{c2StartX, c2EndY, c2EndZ},
{c2EndX, c2EndY, c2EndZ},
// 立方体2的中心点
{(c2StartX + c2EndX) / 2, (c2StartY + c2EndY) / 2, (c2StartZ + c2EndZ) / 2}};
// 检查立方体1的点是否在立方体2内
for (const auto &[x, y, z] : c1Points)
{
if (pointIsInCubeArea(x, y, z, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
{
return true;
}
}
// 检查立方体2的点是否在立方体1内
for (const auto &[x, y, z] : c2Points)
{
if (pointIsInCubeArea(x, y, z, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
{
return true;
}
}
return false;
}
// 15. 计算三角形面积(叉乘法,避免开方,效率更高)
static float get3PointArea(float x1, float y1, float x2, float y2, float x3, float y3)
{
// 面积公式0.5 * |x1(y2-y3) + x2(y3-y1) + x3(y1-y2)|
return 0.5f * std::fabs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
}
// 16. 计算四边形面积(拆分为两个三角形面积之和)
static float get4PointArea(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
{
// 四边形拆分为:(x1,y1)-(x2,y2)-(x3,y3) 和 (x2,y2)-(x3,y3)-(x4,y4)
float area1 = get3PointArea(x1, y1, x2, y2, x3, y3);
float area2 = get3PointArea(x2, y2, x3, y3, x4, y4);
return area1 + area2;
}
// 17. 判断点是否在四边形内(面积比较法,要求四边形顶点按顺序排列)
static bool pointIsIn4PointArea(float px, float py,
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4)
{
const float eps = 10.0f; // 容差原Squirrel代码定义为10.0
float totalArea = get4PointArea(x1, y1, x2, y2, x3, y3, x4, y4);
// 点与四边形各边组成的4个三角形面积之和
float sumArea = get3PointArea(x1, y1, x2, y2, px, py) +
get3PointArea(x2, y2, x3, y3, px, py) +
get3PointArea(x3, y3, x4, y4, px, py) +
get3PointArea(x4, y4, x1, y1, px, py);
// 面积差在容差范围内 → 点在四边形内
return std::fabs(totalArea - sumArea) < eps;
}
// 18. 判断点是否在矩形内(矩形由坐标数组定义,格式:[x, y, width, height]
static bool PointIsInSquare(float x1, float y1, const std::vector<float> &SquareArr)
{
if (SquareArr.size() != 4)
{
throw std::invalid_argument("PointIsInSquare: SquareArr must have 4 elements (x, y, width, height)");
}
float sqX = SquareArr[0];
float sqY = SquareArr[1];
float sqWidth = SquareArr[2];
float sqHeight = SquareArr[3];
// 点的X在[sqX, sqX+width]Y在[sqY, sqY+height] → 在矩形内
return (x1 >= sqX - 1e-6f) && (x1 <= sqX + sqWidth + 1e-6f) &&
(y1 >= sqY - 1e-6f) && (y1 <= sqY + sqHeight + 1e-6f);
}
static float getUniformVelocity(float sv, float ev, float currentRate, float maxRate)
{
// 避免除零错误
if (maxRate <= 0.0f)
{
throw std::invalid_argument("maxRate must be greater than 0");
}
// 计算当前进度比例0.0到1.0之间)
float rate = currentRate / maxRate;
// 限制比例在[0, 1]范围内,避免超出边界
rate = std::clamp(rate, 0.0f, 1.0f);
// 计算变化量并返回当前值
float varyValue = ev - sv;
return sv + varyValue * rate;
}
};

257
source/Tool/RefBasePtr.hpp Normal file
View File

@@ -0,0 +1,257 @@
// Copyright (c) 2016-2018 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include <utility>
#include <type_traits>
#include "Tool/Common.h"
/**
* \~chinese
* @brief 引用计数智能指针
*/
template <typename _Ty, typename _RefPolicy>
class RefBasePtr : protected _RefPolicy
{
public:
using value_type = _Ty;
using pointer_type = _Ty *;
using const_pointer_type = const _Ty *;
using reference_type = _Ty &;
using const_reference_type = const _Ty &;
RefBasePtr() noexcept
: ptr_(nullptr)
{
}
RefBasePtr(std::nullptr_t) noexcept
: ptr_(nullptr)
{
}
RefBasePtr(pointer_type p)
: ptr_(p)
{
_RefPolicy::Retain(ptr_);
}
RefBasePtr(const RefBasePtr &other)
: ptr_(other.ptr_)
{
_RefPolicy::Retain(ptr_);
}
RefBasePtr(RefBasePtr &&other) noexcept
: ptr_(nullptr)
{
Swap(other);
}
~RefBasePtr()
{
Tidy();
}
template <typename _UTy, typename std::enable_if<std::is_convertible<_UTy *, _Ty *>::value, int>::type = 0>
RefBasePtr(const RefBasePtr<_UTy, _RefPolicy> &other)
{
ptr_ = dynamic_cast<pointer_type>(other.Get());
_RefPolicy::Retain(ptr_);
}
inline pointer_type Get() const noexcept
{
return ptr_;
}
inline pointer_type *GetAddressOfAndRelease()
{
Tidy();
return &ptr_;
}
inline void Reset(pointer_type ptr = nullptr)
{
if (ptr)
RefBasePtr(ptr).Swap(*this);
else
Tidy();
}
inline void Swap(RefBasePtr &other) noexcept
{
std::swap(ptr_, other.ptr_);
}
inline pointer_type operator->()
{
return ptr_;
}
inline const_pointer_type operator->() const
{
return ptr_;
}
inline reference_type operator*()
{
return *ptr_;
}
inline const_reference_type operator*() const
{
return *ptr_;
}
inline pointer_type *operator&()
{
return this->GetAddressOfAndRelease();
}
inline operator bool() const noexcept
{
return ptr_ != nullptr;
}
inline bool operator!() const noexcept
{
return ptr_ == 0;
}
inline RefBasePtr &operator=(const RefBasePtr &other)
{
if (other.ptr_ != ptr_)
RefBasePtr(other).Swap(*this);
return (*this);
}
inline RefBasePtr &operator=(RefBasePtr &&other) noexcept
{
if (other.ptr_ != ptr_)
other.Swap(*this);
return (*this);
}
inline RefBasePtr &operator=(pointer_type p)
{
if (p != ptr_)
RefBasePtr(p).Swap(*this);
return (*this);
}
template <typename _UTy, typename std::enable_if<std::is_convertible<_UTy *, _Ty *>::value, int>::type = 0>
inline RefBasePtr &operator=(const RefBasePtr<_UTy, _RefPolicy> &other)
{
if (other.Get() != ptr_)
RefBasePtr(dynamic_cast<pointer_type>(other.Get())).Swap(*this);
return (*this);
}
inline RefBasePtr &operator=(std::nullptr_t)
{
Tidy();
return *this;
}
private:
void Tidy()
{
_RefPolicy::Release(ptr_);
ptr_ = nullptr;
}
private:
pointer_type ptr_;
};
template <class _Ty, class _UTy, class _RefPolicy>
inline bool operator==(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_UTy, _RefPolicy> &rhs) noexcept
{
return lhs.Get() == rhs.Get();
}
template <class _Ty, class _RefPolicy>
inline bool operator==(const RefBasePtr<_Ty, _RefPolicy> &lhs, _Ty *rhs) noexcept
{
return lhs.Get() == rhs;
}
template <class _Ty, class _RefPolicy>
inline bool operator==(_Ty *lhs, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
{
return lhs == rhs.Get();
}
template <class _Ty, class _RefPolicy>
inline bool operator==(const RefBasePtr<_Ty, _RefPolicy> &lhs, std::nullptr_t) noexcept
{
return !static_cast<bool>(lhs);
}
template <class _Ty, class _RefPolicy>
inline bool operator==(std::nullptr_t, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
{
return !static_cast<bool>(rhs);
}
template <class _Ty, class _UTy, class _RefPolicy>
inline bool operator!=(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_UTy, _RefPolicy> &rhs) noexcept
{
return !(lhs == rhs);
}
template <class _Ty, class _RefPolicy>
inline bool operator!=(const RefBasePtr<_Ty, _RefPolicy> &lhs, _Ty *rhs) noexcept
{
return lhs.Get() != rhs;
}
template <class _Ty, class _RefPolicy>
inline bool operator!=(_Ty *lhs, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
{
return lhs != rhs.Get();
}
template <class _Ty, class _RefPolicy>
inline bool operator!=(const RefBasePtr<_Ty, _RefPolicy> &lhs, std::nullptr_t) noexcept
{
return static_cast<bool>(lhs);
}
template <class _Ty, class _RefPolicy>
inline bool operator!=(std::nullptr_t, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
{
return static_cast<bool>(rhs);
}
template <class _Ty, class _UTy, class _RefPolicy>
inline bool operator<(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_UTy, _RefPolicy> &rhs) noexcept
{
return lhs.Get() < rhs.Get();
}
// template class cannot specialize std::swap,
// so implement a swap function in kiwano namespace
template <class _Ty, class _RefPolicy>
inline void swap(RefBasePtr<_Ty, _RefPolicy> &lhs, RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
{
lhs.Swap(rhs);
}

86
source/Tool/RefObject.cpp Normal file
View File

@@ -0,0 +1,86 @@
#include "Tool/RefObject.h"
RefObject::RefObject()
: ref_count_(0) // 修正新创建对象引用计数应为1
{
}
RefObject::~RefObject() {}
void RefObject::Retain()
{
// 修正使用fetch_add确保原子操作
ref_count_.fetch_add(1, std::memory_order_relaxed);
}
void RefObject::Release()
{
// 修正使用fetch_sub确保原子操作并检查结果
if (ref_count_.fetch_sub(1, std::memory_order_acq_rel) == 1)
{
delete this;
}
}
uint32_t RefObject::GetRefCount() const
{
return ref_count_.load(std::memory_order_relaxed);
}
void *RefObject::operator new(size_t size)
{
void *ptr = memory::Alloc(size);
if (!ptr)
{
throw std::bad_alloc();
}
return ptr;
}
void RefObject::operator delete(void *ptr)
{
if (ptr) // 增加空指针检查
{
memory::Free(ptr);
}
}
// 修正添加noexcept说明符与声明一致
void *RefObject::operator new(size_t size, std::nothrow_t const &) noexcept
{
try
{
return memory::Alloc(size);
}
catch (...)
{
return nullptr;
}
}
// 修正添加noexcept说明符与声明一致
void RefObject::operator delete(void *ptr, std::nothrow_t const &) noexcept
{
if (ptr) // 增加空指针检查
{
try
{
memory::Free(ptr);
}
catch (...)
{
// 忽略异常符合noexcept语义
}
}
}
// 修正添加noexcept说明符与声明一致
void *RefObject::operator new(size_t size, void *ptr) noexcept
{
return ::operator new(size, ptr);
}
void RefObject::operator delete(void *ptr, void *place) noexcept
{
::operator delete(ptr, place);
}

45
source/Tool/RefObject.h Normal file
View File

@@ -0,0 +1,45 @@
#pragma once
#include "Tool/Common.h"
#include "Tool/Allocator.h"
#include <atomic>
/**
* \~chinese
* @brief 引用计数器
*/
class RefObject : protected Noncopyable
{
public:
/// \~chinese
/// @brief 增加引用计数
void Retain();
/// \~chinese
/// @brief 减少引用计数
void Release();
/// \~chinese
/// @brief 获取引用计数
uint32_t GetRefCount() const;
static void *operator new(size_t size);
static void operator delete(void *ptr);
static void *operator new(size_t size, std::nothrow_t const &) noexcept;
static void operator delete(void *ptr, std::nothrow_t const &) noexcept;
static void *operator new(size_t size, void *ptr) noexcept;
static void operator delete(void *ptr, void *place) noexcept;
virtual ~RefObject();
protected:
RefObject();
private:
std::atomic<uint32_t> ref_count_;
};

63
source/Tool/RefPtr.h Normal file
View File

@@ -0,0 +1,63 @@
// Copyright (c) 2016-2018 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include "Tool/RefObject.h"
#include "Tool/RefBasePtr.hpp"
/// \~chinese
/// @brief 默认的智能指针引用计数策略
struct DefaultRefPtrPolicy
{
inline void Retain(RefObject *ptr)
{
if (ptr)
ptr->Retain();
}
inline void Release(RefObject *ptr)
{
if (ptr)
ptr->Release();
}
};
/// \~chinese
/// @brief 引用计数对象智能指针
template <typename _Ty>
using RefPtr = RefBasePtr<_Ty, DefaultRefPtrPolicy>;
/// \~chinese
/// @brief 构造引用计数对象智能指针
template <typename _Ty, typename... _Args>
inline RefPtr<_Ty> MakePtr(_Args &&...args)
{
static_assert(std::is_base_of<RefObject, _Ty>::value, "_Ty must be derived from RefObject");
return RefPtr<_Ty>(new _Ty(std::forward<_Args>(args)...));
}
/// \~chinese
/// @brief 构造引用计数对象智能指针
template <typename _Ty>
inline RefPtr<_Ty> MakePtr(_Ty *ptr)
{
static_assert(std::is_base_of<RefObject, _Ty>::value, "_Ty must be derived from RefObject");
return RefPtr<_Ty>(ptr);
}

67
source/Tool/TagGed.h Normal file
View File

@@ -0,0 +1,67 @@
#pragma once
#include <type_traits>
#include <cstdint>
enum class Tag
{
NONE = 0, // 无标签
SCENE = 1 << 0, // 场景标签
ACTOR = 1 << 1, // 角色标签
COMPONENT = 1 << 2, // 组件标签
UPDATE = 1 << 3, // 更新标签
RENDER = 1 << 4, // 渲染标签
TRANSFORM = 1 << 5, // 变换标签
HANDEL_EVENT = 1 << 6, // 事件处理标签
};
constexpr Tag operator|(Tag a, Tag b)
{
using Underlying = std::underlying_type_t<Tag>;
return static_cast<Tag>(static_cast<Underlying>(a) | static_cast<Underlying>(b));
}
constexpr Tag operator&(Tag a, Tag b)
{
using Underlying = std::underlying_type_t<Tag>;
return static_cast<Tag>(static_cast<Underlying>(a) & static_cast<Underlying>(b));
}
class TagGed
{
private:
uint64_t m_tags;
public:
TagGed(Tag initialTag = Tag::NONE)
: m_tags(static_cast<uint64_t>(initialTag)) {}
// 添加标签
void addTag(Tag tag)
{
if (!hasTag(tag))
m_tags |= static_cast<uint64_t>(tag);
}
// 移除标签
void removeTag(Tag tag)
{
if (hasTag(tag))
m_tags &= ~static_cast<uint64_t>(tag);
}
// 判断是否包含指定标签
bool hasTag(Tag tag) const
{
return (m_tags & static_cast<uint64_t>(tag)) != 0;
}
// 判断是否包含所有指定标签
bool hasAllTags(Tag tags) const
{
return (m_tags & static_cast<uint64_t>(tags)) == static_cast<uint64_t>(tags);
}
// 清除所有标签
void clearTags()
{
m_tags = 0;
}
};

View File

@@ -0,0 +1,96 @@
#include "ThreadPool.h"
#include <stdexcept>
#include <cstdio>
// 获取单例实例
ThreadPool &ThreadPool::GetInstance()
{
static ThreadPool instance(3); // 固定3个工作线程
return instance;
}
ThreadPool::~ThreadPool()
{
shutdown();
}
void ThreadPool::shutdown()
{
printf("ThreadPool destroyed\n");
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
// 清空所有线程的任务队列
for (auto &queue : threadTasks)
{
// 使用swap技巧清空队列
std::queue<std::function<void()>> empty;
std::swap(queue, empty);
}
}
// 通知所有线程
for (auto &cond : threadConditions)
cond->notify_all();
for (std::thread &worker : workers)
if (worker.joinable())
worker.join();
// 释放条件变量
for (auto &cond : threadConditions)
delete cond;
}
// 获取线程池大小
size_t ThreadPool::size() const
{
return workers.size();
}
// 获取指定线程的负载(待处理任务数)
size_t ThreadPool::getThreadLoad(int threadId) const
{
if (threadId < 0 || threadId >= static_cast<int>(workers.size()))
throw std::runtime_error("Invalid thread ID");
std::unique_lock<std::mutex> lock(queue_mutex);
return threadTasks.at(threadId).size();
}
// 私有构造函数实现
ThreadPool::ThreadPool(size_t numThreads) : stop(false)
{
// 为每个线程创建任务队列
threadTasks.resize(numThreads);
// 为每个线程创建条件变量
for (size_t i = 0; i < numThreads; ++i)
{
threadConditions.push_back(new std::condition_variable());
}
for (size_t i = 0; i < numThreads; ++i)
{
workers.emplace_back([this, i]
{
while(true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->threadConditions[i]->wait(lock, [this, i] {
return this->stop || !this->threadTasks[i].empty();
});
if(this->stop && this->threadTasks[i].empty())
return;
task = std::move(this->threadTasks[i].front());
this->threadTasks[i].pop();
}
task();
} });
}
}

80
source/Tool/ThreadPool.h Normal file
View File

@@ -0,0 +1,80 @@
#pragma once
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <memory>
#include <map>
#include <stdexcept>
class ThreadPool
{
public:
// 获取单例实例
static ThreadPool &GetInstance();
// 删除拷贝构造函数和赋值运算符
ThreadPool(const ThreadPool &) = delete;
ThreadPool &operator=(const ThreadPool &) = delete;
// 向指定线程添加任务
template <class F, class... Args>
void enqueueToThread(int threadId, F &&f, Args &&...args)
{
if (threadId < 0 || threadId >= static_cast<int>(workers.size()))
throw std::runtime_error("Invalid thread ID");
{
std::unique_lock<std::mutex> lock(queue_mutex);
// 不允许在停止后添加新任务
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
// 将任务添加到指定线程的队列
threadTasks[threadId].emplace([=]() mutable
{ std::invoke(f, args...); });
}
// 通知指定线程
threadConditions[threadId]->notify_one();
}
// 向任意线程添加任务(负载均衡)
template <class F, class... Args>
void enqueue(F &&f, Args &&...args)
{
// 使用轮询方式选择线程
static std::atomic<int> nextThreadId(0);
int threadId = nextThreadId.load();
nextThreadId = (nextThreadId + 1) % workers.size();
enqueueToThread(threadId, std::forward<F>(f), std::forward<Args>(args)...);
}
~ThreadPool();
void shutdown();
// 获取线程池大小
size_t size() const;
// 获取指定线程的负载(待处理任务数)
size_t getThreadLoad(int threadId) const;
private:
// 私有构造函数
ThreadPool(size_t numThreads);
private:
std::vector<std::thread> workers;
std::vector<std::queue<std::function<void()>>> threadTasks; // 每个线程有自己的任务队列
mutable std::mutex queue_mutex;
std::vector<std::condition_variable *> threadConditions; // 使用指针存储条件变量
std::atomic<bool> stop;
};

View File

@@ -0,0 +1,82 @@
#include "Tool/Tool_Network.h"
// // 定义内存管理结构体
// struct MemoryStruct
// {
// char *memory;
// size_t size;
// };
// size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp)
// {
// size_t realsize = size * nmemb;
// struct MemoryStruct *mem = (struct MemoryStruct *)userp;
// void *ptr = realloc(mem->memory, mem->size + realsize + 1);
// if (!ptr)
// {
// return 0;
// }
// mem->memory = (char *)ptr;
// memcpy(&(mem->memory[mem->size]), contents, realsize);
// mem->size += realsize;
// mem->memory[mem->size] = '\0';
// return realsize;
// }
// int http_get(const char *url, char **response, size_t *response_size)
// {
// CURL *curl;
// CURLcode res;
// struct MemoryStruct chunk;
// // 初始化内存结构
// chunk.memory = (char *)malloc(1);
// chunk.size = 0;
// if (!chunk.memory)
// {
// return -1;
// }
// curl = curl_easy_init();
// if (curl)
// {
// curl_easy_setopt(curl, CURLOPT_URL, url);
// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
// // 允许重定向
// curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
// // 执行请求
// res = curl_easy_perform(curl);
// // 检查HTTP状态码
// long response_code;
// curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
// if (res != CURLE_OK)
// {
// free(chunk.memory);
// *response = NULL;
// *response_size = 0;
// curl_easy_cleanup(curl);
// return -1;
// }
// // 返回结果
// *response = chunk.memory;
// *response_size = chunk.size;
// curl_easy_cleanup(curl);
// return 0;
// }
// free(chunk.memory);
// *response = NULL;
// *response_size = 0;
// return -1;
// }

View File

@@ -0,0 +1,16 @@
#pragma once
#ifdef _SWITCH_
#include <switch.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Tool/Logger.h"
// // 回调函数
// size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp);
// // HTTP GET请求函数
// int http_get(const char *url, char **response, size_t *response_size);

View File

@@ -0,0 +1,88 @@
#include "Tool/Tool_String.h"
#include <SDL2/SDL.h>
#include <memory>
#include <stdexcept>
#include <vector>
#include <iconv.h>
#include <regex>
#include "Tool_String.h"
std::string Tool_toLowerCase(const std::string &str)
{
std::string result = str;
// 使用transform算法遍历字符串并转换为小写
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c)
{ return std::tolower(c); });
return result;
}
// GBK 转 UTF-8基于 SDL2 的 SDL_iconv
std::string Tool_Gbk2Utf8(const std::string &gbk_str)
{
iconv_t cd = iconv_open("UTF-8", "GBK");
if (cd == (iconv_t)-1)
{
throw std::runtime_error("Failed to open iconv conversion descriptor");
}
size_t in_bytes_left = gbk_str.size();
char *in_buf = const_cast<char *>(gbk_str.data());
// 分配输出缓冲区GBK转UTF-8后长度最多可能增长到原长的3倍
size_t out_bytes_left = gbk_str.size() * 3 + 1;
std::string utf8_str(out_bytes_left, '\0');
char *out_buf = &utf8_str[0];
// 执行转换
size_t result = iconv(cd, &in_buf, &in_bytes_left, &out_buf, &out_bytes_left);
iconv_close(cd);
if (result == (size_t)-1)
{
throw std::runtime_error("Conversion failed!");
}
// 调整字符串大小以去除未使用的空间
utf8_str.resize(utf8_str.size() - out_bytes_left);
return utf8_str;
}
std::string Tool_RegRealPath(const std::string &Path)
{
// 检查路径中是否包含"../"
if (Path.find("../") == std::string::npos)
{
return Path;
}
// 正则表达式:匹配形如"xxx/../"的模式
// [^/]+ 匹配非斜杠的字符序列(表示目录名)
// /../ 匹配"/../"
std::regex pattern("[^/]+/\\.\\./");
std::string processedPath = Path;
std::smatch match;
// 循环处理所有匹配的模式
while (std::regex_search(processedPath, match, pattern))
{
// 替换匹配到的部分(删除"xxx/../"
processedPath = std::regex_replace(processedPath, pattern, "", std::regex_constants::format_first_only);
}
return processedPath;
}
std::string Tool_TruncatePath(const std::string &path)
{
// 查找最后一个 '/' 的位置
size_t lastSlashPos = path.find_last_of('/');
// 如果找到了 '/',返回从开始到该位置(包含)的子串
if (lastSlashPos != std::string::npos)
{
return path.substr(0, lastSlashPos + 1); // +1 是为了包含 '/' 本身
}
// 如果没有找到 '/',返回原字符串(或根据需求返回空)
return path;
}

12
source/Tool/Tool_String.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <cctype>
#include <algorithm>
std::string Tool_toLowerCase(const std::string &str);
std::string Tool_Gbk2Utf8(const std::string &gbk_str);
std::string Tool_RegRealPath(const std::string &Path);
std::string Tool_TruncatePath(const std::string &path);

View File

@@ -0,0 +1,52 @@
#include "TransformT.h"
TransformT::TransformT()
: rotation(0.f), position(), scale(1.f, 1.f)
{
}
bool TransformT::IsFast() const
{
return scale.x == 1.f && scale.y == 1.f && rotation == 0.f;
}
bool TransformT::operator==(const TransformT &rhs) const
{
return position == rhs.position && rotation == rhs.rotation && scale == rhs.scale;
}
// -------------------------- 加法运算符实现 --------------------------
TransformT TransformT::operator+(const TransformT &rhs) const
{
TransformT result;
result.rotation = this->rotation + rhs.rotation;
result.position = this->position + rhs.position;
result.scale = this->scale + rhs.scale;
return result;
}
TransformT TransformT::operator-(const TransformT &rhs) const
{
TransformT result;
result.rotation = this->rotation - rhs.rotation;
result.position = this->position - rhs.position;
result.scale = this->scale - rhs.scale;
return result;
}
// -------------------------- 复合赋值运算符实现 --------------------------
TransformT &TransformT::operator+=(const TransformT &rhs)
{
this->rotation += rhs.rotation;
this->position += rhs.position;
this->scale += rhs.scale;
return *this;
}
TransformT &TransformT::operator-=(const TransformT &rhs)
{
this->rotation -= rhs.rotation;
this->position -= rhs.position;
this->scale -= rhs.scale;
return *this;
}

25
source/Tool/TransformT.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include "Tool/Common.h"
/**
* \~chinese
* @brief 二维放射变换
*/
class TransformT
{
public:
float rotation; ///< 旋转
VecFPos position; ///< 坐标
VecFPos scale; ///< 缩放
public:
TransformT();
bool IsFast() const;
bool operator==(const TransformT &rhs) const;
TransformT operator+(const TransformT &rhs) const;
TransformT operator-(const TransformT &rhs) const;
TransformT &operator+=(const TransformT &rhs);
TransformT &operator-=(const TransformT &rhs);
};

View File

@@ -0,0 +1,210 @@
#include "squirrel/SquirrelEx.h"
#include <dirent.h>
#include <string>
#include <fstream>
#include "SquirrelEx.h"
#include "Asset/Asset_Script.h"
SquirrelEx::SquirrelEx()
{
}
SquirrelEx::~SquirrelEx()
{
}
void SquirrelEx::printfunc(HSQUIRRELVM v, const SQChar *s, ...)
{
va_list vl;
va_start(vl, s);
int len = vsnprintf(NULL, 0, (const char *)s, vl);
if (len <= 0)
{
va_end(vl);
return;
}
char *buf = (char *)malloc(len + 1);
if (!buf)
{
va_end(vl);
return;
}
va_end(vl);
va_start(vl, s);
vsnprintf(buf, len + 1, (const char *)s, vl);
va_end(vl);
SDL_Log("%s", buf);
va_end(vl);
}
void SquirrelEx::errorfunc(HSQUIRRELVM v, const SQChar *s, ...)
{
va_list vl;
va_start(vl, s);
int len = vsnprintf(NULL, 0, (const char *)s, vl);
if (len <= 0)
{
va_end(vl);
return;
}
char *buf = (char *)malloc(len + 1);
if (!buf)
{
va_end(vl);
return;
}
va_end(vl);
va_start(vl, s);
vsnprintf(buf, len + 1, (const char *)s, vl);
va_end(vl);
SDL_LogError(0, "%s", buf);
va_end(vl);
}
bool SquirrelEx::Compilebuffer(std::string Path, std::string Code)
{
if (v == nullptr)
{
SDL_Log("松鼠虚拟机未初始化!");
return false;
}
if (sq_compilebuffer(v, Code.c_str(), Code.length(), Path.c_str(), SQTrue) >= 0)
{
sq_pushroottable(v);
sq_call(v, 1, SQFalse, SQTrue);
sq_pop(v, 1);
return true;
}
return false;
}
void SquirrelEx::Init()
{
v = sq_open(1024); // 栈大小1024
sqstd_seterrorhandlers(v);
sq_pushroottable(v);
sqstd_register_bloblib(v);
sqstd_register_iolib(v);
sqstd_register_systemlib(v);
sqstd_register_mathlib(v);
sqstd_register_stringlib(v);
sq_setprintfunc(v, printfunc, errorfunc);
// 加载脚本
LoadLocalScript();
}
void SquirrelEx::RequestNetScript(std::string Ip, std::string Port)
{
// char *response = NULL;
// size_t response_size = 0;
// std::string url = "http://" + Ip + ":" + Port + "/get/getadvertisement?key=Files"; // 确保协议正确
// int result = http_get(url.c_str(), &response, &response_size);
// if (result == 0 && response != NULL && response_size > 0)
// {
// std::string response_str(response, response_size);
// free(response); // 释放内存
// nlohmann::json ex1 = nlohmann::json::parse(response_str);
// for (const auto &[key, value] : ex1.items())
// {
// std::string key_str = key;
// std::string value_str = value;
// bool Flag = Compilebuffer(key_str, value_str);
// if (!Flag)
// {
// SDL_Log("Squirrel Compilebuffer Error! FileName: %s", key_str.c_str());
// }
// }
// }
// else
// {
// if (response)
// free(response);
// }
}
void SquirrelEx::LoadLocalScript()
{
std::vector<std::string> lines;
std::ifstream file("sqr/SquirrelFileConfig.cfg");
if (file.is_open())
{
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
file.close();
}
else
{
SDL_LogError(0, "配置文件未找到,请检查项目目录 sqr/SquirrelFileConfig.cfg 文件是否存在");
}
for (const auto &line : lines)
{
std::string clean_line = line;
// 移除换行符和回车符
clean_line.erase(std::remove(clean_line.begin(), clean_line.end(), '\n'), clean_line.end());
clean_line.erase(std::remove(clean_line.begin(), clean_line.end(), '\r'), clean_line.end());
if (line.find(".nut") == std::string::npos)
continue;
std::string RegistPath = "sqr/" + clean_line;
if (!SQ_SUCCEEDED(sqstd_dofile(v, (SQChar *)(RegistPath.c_str()), SQFalse, SQTrue)))
{
SDL_LogError(0, "脚本文件未找到,请检查项目目录 %s 文件是否存在", RegistPath.c_str());
}
{
// std::ifstream F;
// F.open((RegistPath).c_str(), std::ios::in | std::ios::binary);
// if (F.is_open())
// {
// std::stringstream ContentStringStream;
// ContentStringStream << F.rdbuf();
// std::string ContentString(ContentStringStream.str());
// std::string RealContentString = ContentString;
// if (RealContentString.length() > 0)
// {
// if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar *)(RealContentString.c_str()), RealContentString.length(), (SQChar *)(RegistPath.c_str()), true)))
// {
// sq_pushroottable(v);
// sq_call(v, 1, 1, 1);
// sq_pop(v, 1);
// }
// }
// }
// else
// {
// SDL_LogError(0, "脚本文件未找到,请检查项目目录 %s 文件是否存在", RegistPath.c_str());
// }
// F.close();
}
}
}
void SquirrelEx::Run()
{
// 载入main函数
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("main"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{ // gets the field 'foo' from the global table
sq_pushroottable(v); // push the 'this' (in this case is the global table)
sq_call(v, 1, SQFalse, SQTrue); // calls the function
}
sq_settop(v, top); // restores the original stack size
}
void SquirrelEx::Clean()
{
sq_close(v);
v = nullptr;
}
HSQUIRRELVM SquirrelEx::GetSquirrelVM()
{
return v;
}

View File

@@ -0,0 +1,64 @@
#pragma once
#include <string>
#include <squirrel.h> // Squirrel核心头文件
#include <sqstdio.h> // Squirrel标准IO库
#include <sqstdaux.h> // 新增:包含 sqstd_seterrorhandlers 等辅助函数
#include <sqstdblob.h> // 新增:包含 sqstd_register_bloblib 函数
#include <sqstdsystem.h> // 新增:包含 sqstd_register_systemlib 函数
#include <sqstdmath.h> // 新增:包含 sqstd_register_mathlib 函数
#include <sqstdstring.h> // 新增:包含 sqstd_register_stringlib 函数
#include <stdarg.h>
#include <json.hpp>
#include "Tool/Tool_Network.h"
#ifdef SQUNICODE
#define scvprintf vfwprintf
#else
#define scvprintf vfprintf
#endif
class SquirrelEx
{
public:
SquirrelEx(const SquirrelEx &) = delete;
SquirrelEx &operator=(const SquirrelEx &) = delete;
SquirrelEx(SquirrelEx &&) = delete;
SquirrelEx &operator=(SquirrelEx &&) = delete;
// 全局访问点
static SquirrelEx &GetInstance()
{
static SquirrelEx instance; // 局部静态变量,保证只初始化一次
return instance;
}
// 打印控制台
static void printfunc(HSQUIRRELVM v, const SQChar *s, ...);
// 错误打印控制台
static void errorfunc(HSQUIRRELVM v, const SQChar *s, ...);
// 从字符串编译Sqr脚本
bool Compilebuffer(std::string Path, std::string Code);
public:
// 初始化
void Init();
// 请求网络脚本
void RequestNetScript(std::string Ip, std::string Port);
// 加载本地脚本
void LoadLocalScript();
// 运行
void Run();
// 清理
void Clean();
// 获取SquirrelVM
HSQUIRRELVM GetSquirrelVM();
private:
SquirrelEx(/* args */);
~SquirrelEx();
HSQUIRRELVM v = nullptr;
};