Added support for null GameObjects (loading is buggy)

This commit is contained in:
Kah Wei 2022-11-08 00:53:47 +08:00
parent 7e1a909709
commit ddd93a85f4
7 changed files with 119 additions and 38 deletions

View File

@ -256,4 +256,7 @@
Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295
Strength: 0.25
Scripts: ~
Scripts:
- Type: PickAndThrow
throwForce: [100, 200, 100]
item: 1

View File

@ -288,7 +288,7 @@ namespace SHADE
return CHANGED;
}
bool SHEditorUI::InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered)
bool SHEditorUI::InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered, bool alwaysNull)
{
ImGui::Text(label.c_str());
if (isHovered)
@ -296,7 +296,7 @@ namespace SHADE
ImGui::SameLine();
SHEntity* entity = SHEntityManager::GetEntityByID(value);
std::ostringstream oss;
if (entity)
if (!alwaysNull && entity)
{
oss << value << ": " << entity->name;
}
@ -314,6 +314,13 @@ namespace SHADE
SHDragDrop::EndTarget();
}
}
ImGui::SameLine();
if (ImGui::Button("Clear"))
{
value = MAX_EID;
changed = true;
}
return changed;
}

View File

@ -313,8 +313,12 @@ namespace SHADE
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <param name="isHovered>If set, stores the hover state of this widget.</param>
/// <param name="alwaysNull>
/// If set, the field displayed will always be blank regardless of specified
/// GameObject.
/// </param>
/// <returns>True if the value was changed.</returns>
static bool InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered = nullptr);
static bool InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered = nullptr, bool alwaysNull = false);
/// <summary>
/// Creates a combo box for enumeration input.
/// </summary>

View File

@ -290,9 +290,14 @@ namespace SHADE
{
GameObject gameObj = safe_cast<GameObject>(field->GetValue(object));
uint32_t entityId = gameObj.GetEntity();
if (SHEditorUI::InputGameObjectField(Convert::ToNative(field->Name), entityId, &isHovered))
if (SHEditorUI::InputGameObjectField(Convert::ToNative(field->Name), entityId, &isHovered, !gameObj))
{
GameObject newVal = GameObject(entityId);
if (entityId != MAX_EID)
{
// Null GameObject set
newVal = GameObject(entityId);
}
field->SetValue(object, newVal);
registerUndoAction(object, field, newVal, gameObj);
}

View File

@ -6,9 +6,9 @@
\brief Contains the definition of the functions for the GameObject managed class.
Note: This file is written in C++17/CLI.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
@ -36,10 +36,12 @@ namespace SHADE
void GameObject::Destroy(GameObject obj)
{
if (!obj.valid)
throw gcnew System::NullReferenceException("Attempted to destroy a null GameObject.");
SHEntityManager::DestroyEntity(static_cast<EntityID>(obj.GetEntity()));
}
System::Nullable<GameObject> GameObject::Find(System::String ^ name)
System::Nullable<GameObject> GameObject::Find(System::String^ name)
{
// Search the GameObjectLibrary for an Entity with the specified name
const auto ENTITY_ID = SHEntityManager::GetEntityByName(Convert::ToNative(name));
@ -50,21 +52,27 @@ namespace SHADE
return GameObject(ENTITY_ID);
}
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
System::String^ GameObject::Name::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
return Convert::ToCLI(GetNativeEntity().name);
}
}
bool GameObject::IsActiveSelf::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
return GetNativeEntity().GetActive();
}
bool GameObject::IsActiveInHierarchy::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
auto node = SHSceneManager::GetCurrentSceneGraph().GetNode(GetEntity());
if (!node)
{
@ -75,39 +83,49 @@ namespace SHADE
}
Entity GameObject::EntityId::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
return entity;
}
GameObject^ GameObject::Parent::get()
{
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
const auto* PARENT = NODE->GetParent();
return PARENT != ROOT ? gcnew GameObject(PARENT->GetEntityID()) : nullptr;
const auto* PARENT = NODE->GetParent();
return PARENT != ROOT ? gcnew GameObject(PARENT->GetEntityID()) : nullptr;
}
void GameObject::Parent::set(GameObject^ newParent)
{
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (newParent == nullptr)
SCENE_GRAPH.SetParent(entity, nullptr);
else
SCENE_GRAPH.SetParent(entity, newParent->EntityId);
if (newParent == nullptr)
SCENE_GRAPH.SetParent(entity, nullptr);
else
SCENE_GRAPH.SetParent(entity, newParent->EntityId);
}
/*---------------------------------------------------------------------------------*/
/* GameObject Property Functions */
/*---------------------------------------------------------------------------------*/
void GameObject::SetName(System::String^ name)
{
if (!valid)
throw gcnew System::NullReferenceException();
GetNativeEntity().name = Convert::ToNative(name);
}
void GameObject::SetActive(bool active)
{
if (!valid)
throw gcnew System::NullReferenceException();
GetNativeEntity().SetActive(active);
}
@ -117,63 +135,83 @@ namespace SHADE
generic <typename T>
T GameObject::AddComponent()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::AddComponent<T>(entity);
}
generic <typename T>
T GameObject::GetComponent()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::GetComponent<T>(entity);
}
generic <typename T>
T GameObject::GetComponentInChildren()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::GetComponentInChildren<T>(entity);
}
generic <typename T>
T GameObject::EnsureComponent()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::EnsureComponent<T>(entity);
}
generic <typename T>
void GameObject::RemoveComponent()
{
if (!valid)
throw gcnew System::NullReferenceException();
ECS::RemoveComponent<T>(entity);
}
/*---------------------------------------------------------------------------------*/
/* Script Access Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
T GameObject::AddScript()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::AddScript<T>(entity);
}
generic <typename T>
T GameObject::GetScript()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScript<T>(entity);
}
generic <typename T>
T GameObject::GetScriptInChildren()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScriptInChildren<T>(entity);
}
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScripts<T>(entity);
}
generic <typename T>
void GameObject::RemoveScript()
{
if (!valid)
throw gcnew System::NullReferenceException();
ScriptStore::RemoveScript<T>(entity);
}
@ -181,20 +219,24 @@ namespace SHADE
/* Constructors */
/*---------------------------------------------------------------------------------*/
GameObject::GameObject(const SHEntity& entity)
: entity { entity.GetEID() }
, children{ gcnew System::Collections::ArrayList }
: entity{ entity.GetEID() }
, children{ gcnew System::Collections::ArrayList }
, valid{ true }
{}
GameObject::GameObject(Entity entity)
: entity { entity }
, children{ gcnew System::Collections::ArrayList }
: entity{ entity }
, children{ gcnew System::Collections::ArrayList }
, valid{ true }
{}
/*---------------------------------------------------------------------------------*/
/* Getters */
/*---------------------------------------------------------------------------------*/
SHEntity& GameObject::GetNativeEntity()
{
if (!valid)
throw gcnew System::NullReferenceException();
SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity);
if (nativeEntity == nullptr)
throw gcnew System::InvalidOperationException("[GameObject] Unable to obtain native Entity for GameObject.");
@ -202,14 +244,22 @@ namespace SHADE
return *nativeEntity;
}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
GameObject::operator bool(GameObject gameObj)
{
return gameObj.valid;
}
/*---------------------------------------------------------------------------------*/
/* IEquatable */
/*---------------------------------------------------------------------------------*/
bool GameObject::Equals(GameObject other)
{
return entity == other.entity;
return (!valid && !other.valid) || entity == other.entity;
}
/*---------------------------------------------------------------------------------*/
/* Object */
/*---------------------------------------------------------------------------------*/

View File

@ -29,8 +29,8 @@ namespace SHADE
/* Class Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Lightweight object for an PlushieEngine Entity that allows for easy access
/// to Component and Script operations.
/// Lightweight object for an Entity that allows for easy access to Component and
/// Script operations.
/// </summary>
public value class GameObject : public System::IEquatable<GameObject>
{
@ -98,8 +98,8 @@ namespace SHADE
/// </summary>
property GameObject^ Parent
{
GameObject^ get();
void set(GameObject^);
GameObject^ get();
void set(GameObject^);
}
/*-----------------------------------------------------------------------------*/
@ -247,12 +247,22 @@ namespace SHADE
/// <returns>Native Entity object that this GameObject represents.</returns>
SHEntity& GetNativeEntity();
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a GameObject is valid.
/// </summary>
/// <param name="gameObj">GameObjects to check.</param>
static operator bool(GameObject gameObj);
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Entity entity;
System::Collections::ArrayList^ children;
bool valid;
public:
/*-----------------------------------------------------------------------------*/

View File

@ -171,7 +171,7 @@ namespace SHADE
else if (fieldInfo->FieldType == GameObject::typeid)
{
GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object));
fieldNode = gameObj.GetEntity();
fieldNode = gameObj ? gameObj.GetEntity() : MAX_EID;
}
else // Not any of the supported types
{
@ -250,7 +250,9 @@ namespace SHADE
}
else if (fieldInfo->FieldType == GameObject::typeid)
{
fieldInfo->SetValue(object, GameObject(node.as<uint32_t>()));
const uint32_t EID = node.as<uint32_t>();
fieldInfo->SetValue(object, EID == MAX_EID ? GameObject() : GameObject(EID));
Debug::LogError(std::to_string(EID));
}
else // Not any of the supported types
{