feat: add reflection
This commit is contained in:
@@ -14,8 +14,7 @@ public:
|
||||
void Start() override;
|
||||
void Update(float dt) override;
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
void Open() { m_IsOpen = true; }
|
||||
|
||||
@@ -17,9 +17,8 @@ public:
|
||||
void Start() override;
|
||||
void Interact(GameObject& interactor) override;
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ResolveReferences(const ObjectMap& objects) override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
void OnFieldsEdited() override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
[[nodiscard]] std::size_t GetColorIndex() const { return m_ColorIndex; }
|
||||
@@ -35,7 +34,6 @@ public:
|
||||
private:
|
||||
void ApplyColor();
|
||||
void ActivateTargets(GameObject& interactor);
|
||||
void DrawTargetsInspector();
|
||||
|
||||
std::size_t m_ColorIndex{0};
|
||||
int m_PressCount{0};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Serialization/GlmJson.h>
|
||||
#include <destrum/Serialization/Reflect.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
@@ -58,24 +58,13 @@ void Door::ApplyPosition()
|
||||
GetGameObject()->GetTransform().SetLocalPosition(m_ClosedPosition + GetOffsetFor(m_OpenAmount));
|
||||
}
|
||||
|
||||
nlohmann::json Door::Serialize() const
|
||||
void Door::Reflect(FieldVisitor& v)
|
||||
{
|
||||
return {
|
||||
{"openOffset", m_OpenOffset},
|
||||
{"openDuration", m_OpenDuration},
|
||||
{"toggleable", m_Toggleable},
|
||||
{"open", m_IsOpen},
|
||||
{"openAmount", m_OpenAmount},
|
||||
};
|
||||
}
|
||||
|
||||
void Door::Deserialize(const nlohmann::json& data)
|
||||
{
|
||||
m_OpenOffset = data.value("openOffset", m_OpenOffset);
|
||||
m_OpenDuration = std::max(data.value("openDuration", m_OpenDuration), 0.0f);
|
||||
m_Toggleable = data.value("toggleable", m_Toggleable);
|
||||
m_IsOpen = data.value("open", m_IsOpen);
|
||||
m_OpenAmount = std::clamp(data.value("openAmount", m_OpenAmount), 0.0f, 1.0f);
|
||||
v.Field("openOffset", m_OpenOffset, {.speed = 0.05f});
|
||||
v.Field("openDuration", m_OpenDuration, {.speed = 0.05f, .min = 0.0, .format = "%.2f s"});
|
||||
v.Field("toggleable", m_Toggleable);
|
||||
v.Field("open", m_IsOpen, {.hidden = true});
|
||||
v.Field("openAmount", m_OpenAmount, {.min = 0.0, .max = 1.0, .hidden = true});
|
||||
}
|
||||
|
||||
void Door::ImGuiInspector()
|
||||
@@ -85,7 +74,5 @@ void Door::ImGuiInspector()
|
||||
Toggle();
|
||||
}
|
||||
|
||||
ImGui::DragFloat3("Open Offset", &m_OpenOffset.x, 0.05f);
|
||||
ImGui::DragFloat("Open Duration", &m_OpenDuration, 0.05f, 0.0f, 10.0f, "%.2f s");
|
||||
ImGui::Checkbox("Toggleable", &m_Toggleable);
|
||||
Activatable::ImGuiInspector();
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
#include <destrum/Graphics/Renderer.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/Serialization/Reflect.h>
|
||||
#include <destrum/Util/GameState.h>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
@@ -108,93 +108,28 @@ void InteractableButton::ApplyColor()
|
||||
renderer.updateMaterialGPU(meshRenderer->GetMaterialID());
|
||||
}
|
||||
|
||||
nlohmann::json InteractableButton::Serialize() const
|
||||
void InteractableButton::Reflect(FieldVisitor& v)
|
||||
{
|
||||
return {
|
||||
{"colorIndex", m_ColorIndex},
|
||||
{"cycleColors", m_CycleColors},
|
||||
{"pressCount", m_PressCount},
|
||||
{"targets", m_Targets},
|
||||
};
|
||||
v.Field("colorIndex", m_ColorIndex, {.max = static_cast<double>(ButtonColors.size() - 1)});
|
||||
v.Field("cycleColors", m_CycleColors);
|
||||
v.Field("pressCount", m_PressCount, {.readOnly = true});
|
||||
v.Field("targets", m_Targets, {.filter = [this](const GameObject& object) {
|
||||
return &object != GetGameObject() && object.GetComponent<Activatable>() != nullptr;
|
||||
}});
|
||||
}
|
||||
|
||||
void InteractableButton::Deserialize(const nlohmann::json& data)
|
||||
void InteractableButton::OnFieldsEdited()
|
||||
{
|
||||
m_ColorIndex = data.value("colorIndex", m_ColorIndex) % ButtonColors.size();
|
||||
m_CycleColors = data.value("cycleColors", m_CycleColors);
|
||||
m_PressCount = data.value("pressCount", m_PressCount);
|
||||
m_Targets = data.value("targets", std::vector<ObjectRef>{});
|
||||
}
|
||||
|
||||
void InteractableButton::ResolveReferences(const ObjectMap& objects)
|
||||
{
|
||||
std::erase_if(m_Targets, [&](ObjectRef& target) {
|
||||
const ObjectId fileId = target.GetId();
|
||||
if (!target.Resolve(objects)) {
|
||||
spdlog::warn("{} targets object {} which is not in the scene file, dropping it", GetGameObject()->GetName(), fileId);
|
||||
return true;
|
||||
}
|
||||
return !target.IsSet();
|
||||
});
|
||||
if (m_CycleColors) {
|
||||
ApplyColor();
|
||||
}
|
||||
}
|
||||
|
||||
void InteractableButton::ImGuiInspector()
|
||||
{
|
||||
ImGui::Text("Presses: %d", m_PressCount);
|
||||
if (ImGui::Button("Press")) {
|
||||
Interact(*GetGameObject());
|
||||
}
|
||||
if (ImGui::Checkbox("Cycle Colors", &m_CycleColors) && m_CycleColors) {
|
||||
ApplyColor();
|
||||
}
|
||||
|
||||
DrawTargetsInspector();
|
||||
}
|
||||
|
||||
void InteractableButton::DrawTargetsInspector()
|
||||
{
|
||||
ImGui::SeparatorText("Targets");
|
||||
|
||||
const Scene* scene = GetGameObject()->GetScene();
|
||||
if (scene == nullptr) {
|
||||
ImGui::TextDisabled("Not in a scene");
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<ObjectId> targetToRemove;
|
||||
for (const ObjectRef& targetRef : m_Targets) {
|
||||
const ObjectId targetId = targetRef.GetId();
|
||||
const GameObject* target = targetRef.Get(*scene);
|
||||
ImGui::PushID(static_cast<int>(targetId));
|
||||
if (ImGui::SmallButton("x")) {
|
||||
targetToRemove = targetId;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (target != nullptr) {
|
||||
ImGui::TextUnformatted(target->GetName().c_str());
|
||||
} else {
|
||||
ImGui::TextDisabled("Missing object %llu", static_cast<unsigned long long>(targetId));
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
if (targetToRemove) {
|
||||
RemoveTarget(*targetToRemove);
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("##AddTarget", "Add target...")) {
|
||||
for (const auto& object : scene->GetObjects()) {
|
||||
const bool alreadyTargeted = object != nullptr &&
|
||||
std::ranges::find(m_Targets, ObjectRef(*object)) != m_Targets.end();
|
||||
if (object == nullptr || object.get() == GetGameObject() || alreadyTargeted ||
|
||||
object->GetComponent<Activatable>() == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ImGui::PushID(static_cast<int>(object->GetId()));
|
||||
if (ImGui::Selectable(object->GetName().c_str())) {
|
||||
AddTarget(*object);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
Interactable::ImGuiInspector();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user