添加 Components 和 Scene 序列化支持
- Component: 添加 Serialize/Deserialize 虚函数 - TransformComponent: 实现 Transform 数据的序列化/反序列化 - GameObject: 实现对象序列化/反序列化 - Scene: 实现 Save/Load 方法,支持场景文件保存和加载 - 测试: 添加 Save_And_Load 和 Save_ContainsGameObjectData 测试
This commit is contained in:
@@ -187,5 +187,48 @@ void GameObject::Destroy() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::Serialize(std::ostream& os) const {
|
||||
os << "name=" << m_name << ";";
|
||||
os << "active=" << (m_activeSelf ? "1" : "0") << ";";
|
||||
os << "id=" << m_id << ";";
|
||||
os << "transform=";
|
||||
m_transform->Serialize(os);
|
||||
os << ";";
|
||||
}
|
||||
|
||||
void GameObject::Deserialize(std::istream& is) {
|
||||
std::string token;
|
||||
|
||||
while (is.peek() != -1 && is.peek() != '\n' && is.peek() != '\r') {
|
||||
if (is.peek() == ';') {
|
||||
is.get();
|
||||
if (is.peek() == ';') break;
|
||||
continue;
|
||||
}
|
||||
|
||||
char key[64];
|
||||
is.get(key, 64, '=');
|
||||
if (key[0] == '\0') break;
|
||||
is.get();
|
||||
|
||||
if (strcmp(key, "name") == 0) {
|
||||
std::getline(is, m_name, ';');
|
||||
} else if (strcmp(key, "active") == 0) {
|
||||
char val;
|
||||
is.get(val);
|
||||
m_activeSelf = (val == '1');
|
||||
if (is.peek() == ';') is.get();
|
||||
} else if (strcmp(key, "id") == 0) {
|
||||
is >> m_id;
|
||||
if (is.peek() == ';') is.get();
|
||||
} else if (strcmp(key, "transform") == 0) {
|
||||
m_transform->Deserialize(is);
|
||||
if (is.peek() == ';') is.get();
|
||||
} else {
|
||||
std::getline(is, token, ';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Components
|
||||
} // namespace XCEngine
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Components/GameObject.h"
|
||||
#include "Scene/Scene.h"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Components {
|
||||
@@ -273,5 +274,47 @@ void TransformComponent::NotifyHierarchyChanged() {
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
void TransformComponent::Serialize(std::ostream& os) const {
|
||||
os << "position=" << m_localPosition.x << "," << m_localPosition.y << "," << m_localPosition.z << ";";
|
||||
os << "rotation=" << m_localRotation.x << "," << m_localRotation.y << "," << m_localRotation.z << "," << m_localRotation.w << ";";
|
||||
os << "scale=" << m_localScale.x << "," << m_localScale.y << "," << m_localScale.z << ";";
|
||||
}
|
||||
|
||||
void TransformComponent::Deserialize(std::istream& is) {
|
||||
std::string token;
|
||||
|
||||
while (std::getline(is, token, ';')) {
|
||||
if (token.empty()) continue;
|
||||
|
||||
size_t eqPos = token.find('=');
|
||||
if (eqPos == std::string::npos) continue;
|
||||
|
||||
std::string key = token.substr(0, eqPos);
|
||||
std::string value = token.substr(eqPos + 1);
|
||||
|
||||
if (key == "position") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream vs(value);
|
||||
float x, y, z;
|
||||
vs >> x >> y >> z;
|
||||
m_localPosition = Math::Vector3(x, y, z);
|
||||
} else if (key == "rotation") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream vs(value);
|
||||
float x, y, z, w;
|
||||
vs >> x >> y >> z >> w;
|
||||
m_localRotation = Math::Quaternion(x, y, z, w);
|
||||
} else if (key == "scale") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream vs(value);
|
||||
float x, y, z;
|
||||
vs >> x >> y >> z;
|
||||
m_localScale = Math::Vector3(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
} // namespace Components
|
||||
} // namespace XCEngine
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Scene/Scene.h"
|
||||
#include "Components/GameObject.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Components {
|
||||
@@ -141,11 +142,53 @@ void Scene::LateUpdate(float deltaTime) {
|
||||
}
|
||||
|
||||
void Scene::Load(const std::string& filePath) {
|
||||
std::ifstream file(filePath);
|
||||
if (!file.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_gameObjects.clear();
|
||||
m_rootGameObjects.clear();
|
||||
m_gameObjectIDs.clear();
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
std::istringstream iss(line);
|
||||
std::string token;
|
||||
std::getline(iss, token, '=');
|
||||
|
||||
if (token == "scene") {
|
||||
std::getline(iss, m_name, ';');
|
||||
} else if (token == "gameobject") {
|
||||
auto go = std::make_unique<GameObject>();
|
||||
go->Deserialize(iss);
|
||||
go->m_scene = this;
|
||||
GameObject* ptr = go.get();
|
||||
GameObject::GetGlobalRegistry()[ptr->m_id] = ptr;
|
||||
m_gameObjectIDs.insert(ptr->m_id);
|
||||
m_rootGameObjects.push_back(ptr->m_id);
|
||||
m_gameObjects.emplace(ptr->m_id, std::move(go));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::Save(const std::string& filePath) {
|
||||
std::ofstream file(filePath);
|
||||
if (!file.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
file << "# XCEngine Scene File\n";
|
||||
file << "scene=" << m_name << ";\n";
|
||||
file << "active=" << (m_active ? "1" : "0") << ";\n\n";
|
||||
|
||||
for (auto* go : GetRootGameObjects()) {
|
||||
file << "gameobject=";
|
||||
go->Serialize(file);
|
||||
file << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Components
|
||||
|
||||
Reference in New Issue
Block a user