feat: add prefabs
This commit is contained in:
@@ -9,7 +9,9 @@
|
||||
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||
#include <destrum/Graphics/Managers/Renderer2D.h>
|
||||
#include <destrum/Input/InputManager.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/Serialization/PrefabSerializer.h>
|
||||
#include <destrum/Serialization/SceneSerializer.h>
|
||||
|
||||
#include <components/FirstPersonController.h>
|
||||
@@ -120,6 +122,20 @@ void LightKeeper::drawDebugMenuBar()
|
||||
saveCurrentScene();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::TextDisabled("Prefab");
|
||||
|
||||
ImGui::SetNextItemWidth(320.0f);
|
||||
ImGui::InputText("Prefab path", prefabPath, sizeof(prefabPath));
|
||||
|
||||
const bool hasSelection = SceneManager::GetInstance().GetCurrentScene().GetSelectedObject() != nullptr;
|
||||
if (ImGui::MenuItem("Save Selected as Prefab", nullptr, false, hasSelection)) {
|
||||
saveSelectedPrefab();
|
||||
}
|
||||
if (ImGui::MenuItem("Instantiate Prefab")) {
|
||||
instantiatePrefab();
|
||||
}
|
||||
|
||||
if (!sceneStatus.empty()) {
|
||||
ImGui::Separator();
|
||||
ImGui::TextWrapped("%s", sceneStatus.c_str());
|
||||
@@ -270,6 +286,43 @@ void LightKeeper::saveCurrentScene()
|
||||
}
|
||||
}
|
||||
|
||||
void LightKeeper::saveSelectedPrefab()
|
||||
{
|
||||
try {
|
||||
const GameObject* selected = SceneManager::GetInstance().GetCurrentScene().GetSelectedObject();
|
||||
if (selected == nullptr) {
|
||||
sceneStatus = "Select an object to save as a prefab";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto path = ResolveScenePath(prefabPath, m_params.exeDir);
|
||||
const auto parent = path.parent_path();
|
||||
if (!parent.empty()) {
|
||||
std::filesystem::create_directories(parent);
|
||||
}
|
||||
|
||||
sceneStatus = PrefabSerializer::Save(*selected, path)
|
||||
? "Saved prefab \"" + selected->GetName() + "\" to " + path.string()
|
||||
: "Failed to save prefab to " + path.string();
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"Prefab save failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void LightKeeper::instantiatePrefab()
|
||||
{
|
||||
try {
|
||||
const auto path = ResolveScenePath(prefabPath, m_params.exeDir);
|
||||
const GameObject* instance = PrefabSerializer::Instantiate(
|
||||
SceneManager::GetInstance().GetCurrentScene(), path.string());
|
||||
sceneStatus = instance != nullptr
|
||||
? "Instantiated \"" + instance->GetName() + "\" from " + path.string()
|
||||
: "Failed to instantiate prefab " + path.string();
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"Prefab instantiate failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void LightKeeper::loadScene()
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
// The visible ground plane is at y = -1
|
||||
@@ -268,11 +269,12 @@ namespace {
|
||||
float top;
|
||||
};
|
||||
|
||||
void CreateWall(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources, const std::string& name,
|
||||
std::vector<GameObject*> CreateWall(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources, const std::string& name,
|
||||
const glm::vec3& floorCenter, float length, float height, bool alongX, MaterialID materialID,
|
||||
const std::optional<WallOpening>& opening = std::nullopt)
|
||||
{
|
||||
constexpr float thickness = 0.3f;
|
||||
std::vector<GameObject*> pieces;
|
||||
|
||||
const auto createPiece = [&](const std::string& suffix, float from, float to, float bottom, float top)
|
||||
{
|
||||
@@ -285,13 +287,14 @@ namespace {
|
||||
const glm::vec3 size = alongX
|
||||
? glm::vec3{to - from, top - bottom, thickness}
|
||||
: glm::vec3{thickness, top - bottom, to - from};
|
||||
CreateBox(scene, gfxDevice, resources, name + suffix, center, size, materialID, RigidbodyType::Static);
|
||||
pieces.push_back(
|
||||
CreateBox(scene, gfxDevice, resources, name + suffix, center, size, materialID, RigidbodyType::Static));
|
||||
};
|
||||
|
||||
const float halfLength = length * 0.5f;
|
||||
if (!opening) {
|
||||
createPiece("", -halfLength, halfLength, 0.0f, height);
|
||||
return;
|
||||
return pieces;
|
||||
}
|
||||
|
||||
const float openingStart = opening->offset - opening->width * 0.5f;
|
||||
@@ -300,6 +303,7 @@ namespace {
|
||||
createPiece("_Right", openingEnd, halfLength, 0.0f, height);
|
||||
createPiece("_Below", openingStart, openingEnd, 0.0f, opening->bottom);
|
||||
createPiece("_Above", openingStart, openingEnd, opening->top, height);
|
||||
return pieces;
|
||||
}
|
||||
|
||||
GameObject* CreateCeilingLight(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources,
|
||||
@@ -336,26 +340,40 @@ namespace {
|
||||
constexpr float doorOffset = -1.5f;
|
||||
constexpr float doorWidth = 1.2f;
|
||||
|
||||
CreateBox(scene, gfxDevice, resources, "House_Floor", center + glm::vec3{0.0f, 0.03f, 0.0f},
|
||||
{width, 0.06f, depth}, floorMaterial, RigidbodyType::Static);
|
||||
GameObject* house = scene.CreateGameObject("House");
|
||||
house->GetTransform().SetWorldPosition(center);
|
||||
const auto addToHouse = [&](GameObject* object)
|
||||
{
|
||||
object->GetTransform().SetParent(&house->GetTransform(), true);
|
||||
};
|
||||
const auto addWallToHouse = [&](const std::vector<GameObject*>& pieces)
|
||||
{
|
||||
for (GameObject* piece : pieces) {
|
||||
addToHouse(piece);
|
||||
}
|
||||
};
|
||||
|
||||
CreateWall(scene, gfxDevice, resources, "House_FrontWall", center + glm::vec3{0.0f, 0.0f, depth * 0.5f},
|
||||
width + 0.3f, wallHeight, true, wallMaterial,
|
||||
WallOpening{.offset = doorOffset, .width = doorWidth, .bottom = 0.0f, .top = 2.2f});
|
||||
CreateWall(scene, gfxDevice, resources, "House_BackWall", center - glm::vec3{0.0f, 0.0f, depth * 0.5f},
|
||||
width + 0.3f, wallHeight, true, wallMaterial,
|
||||
WallOpening{.offset = 1.5f, .width = 1.4f, .bottom = 1.0f, .top = 2.0f});
|
||||
CreateWall(scene, gfxDevice, resources, "House_LeftWall", center - glm::vec3{width * 0.5f, 0.0f, 0.0f},
|
||||
depth - 0.3f, wallHeight, false, wallMaterial);
|
||||
CreateWall(scene, gfxDevice, resources, "House_RightWall", center + glm::vec3{width * 0.5f, 0.0f, 0.0f},
|
||||
depth - 0.3f, wallHeight, false, wallMaterial,
|
||||
WallOpening{.offset = 0.0f, .width = 1.6f, .bottom = 1.0f, .top = 2.0f});
|
||||
addToHouse(CreateBox(scene, gfxDevice, resources, "House_Floor", center + glm::vec3{0.0f, 0.03f, 0.0f},
|
||||
{width, 0.06f, depth}, floorMaterial, RigidbodyType::Static));
|
||||
|
||||
CreateBox(scene, gfxDevice, resources, "House_Roof", center + glm::vec3{0.0f, wallHeight + 0.15f, 0.0f},
|
||||
{width + 0.8f, 0.3f, depth + 0.8f}, roofMaterial, RigidbodyType::Static);
|
||||
addWallToHouse(CreateWall(scene, gfxDevice, resources, "House_FrontWall", center + glm::vec3{0.0f, 0.0f, depth * 0.5f},
|
||||
width + 0.3f, wallHeight, true, wallMaterial,
|
||||
WallOpening{.offset = doorOffset, .width = doorWidth, .bottom = 0.0f, .top = 2.2f}));
|
||||
addWallToHouse(CreateWall(scene, gfxDevice, resources, "House_BackWall", center - glm::vec3{0.0f, 0.0f, depth * 0.5f},
|
||||
width + 0.3f, wallHeight, true, wallMaterial,
|
||||
WallOpening{.offset = 1.5f, .width = 1.4f, .bottom = 1.0f, .top = 2.0f}));
|
||||
addWallToHouse(CreateWall(scene, gfxDevice, resources, "House_LeftWall", center - glm::vec3{width * 0.5f, 0.0f, 0.0f},
|
||||
depth - 0.3f, wallHeight, false, wallMaterial));
|
||||
addWallToHouse(CreateWall(scene, gfxDevice, resources, "House_RightWall", center + glm::vec3{width * 0.5f, 0.0f, 0.0f},
|
||||
depth - 0.3f, wallHeight, false, wallMaterial,
|
||||
WallOpening{.offset = 0.0f, .width = 1.6f, .bottom = 1.0f, .top = 2.0f}));
|
||||
|
||||
const GameObject* ceilingLight =
|
||||
addToHouse(CreateBox(scene, gfxDevice, resources, "House_Roof", center + glm::vec3{0.0f, wallHeight + 0.15f, 0.0f},
|
||||
{width + 0.8f, 0.3f, depth + 0.8f}, roofMaterial, RigidbodyType::Static));
|
||||
|
||||
GameObject* ceilingLight =
|
||||
CreateCeilingLight(scene, gfxDevice, resources, center + glm::vec3{0.0f, wallHeight - 0.06f, 0.0f});
|
||||
addToHouse(ceilingLight);
|
||||
|
||||
// Inside, next to the door
|
||||
Material switchMaterial = Material::SimpleColor(glm::vec3{0.9f}, "LightSwitchMaterial");
|
||||
@@ -369,6 +387,7 @@ namespace {
|
||||
auto* switchButton = lightSwitch->AddComponent<InteractableButton>();
|
||||
switchButton->SetCycleColors(false);
|
||||
switchButton->AddTarget(*ceilingLight);
|
||||
addToHouse(lightSwitch);
|
||||
|
||||
GameObject* sofa = ModelSpawner::SpawnStaticModel(
|
||||
scene, gfxDevice, resources, "game://sofa.glb", StaticModelOptions(),
|
||||
@@ -377,6 +396,7 @@ namespace {
|
||||
sofa->GetTransform().SetWorldPosition({-3.7, -1, -17.5});
|
||||
sofa->GetTransform().SetWorldRotation({180, 0, 180});
|
||||
sofa->GetTransform().SetWorldScale({3, 3, 3});
|
||||
addToHouse(sofa);
|
||||
}
|
||||
|
||||
void CreateFlightHelmet(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
|
||||
Reference in New Issue
Block a user