GameObjects can now be marked as invalid #181

Merged
Pycorax merged 3 commits from SP3-6-c-scripting into main 2022-11-08 13:52:08 +08:00
7 changed files with 119 additions and 38 deletions

View File

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

View File

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

View File

@ -313,8 +313,12 @@ namespace SHADE
/// <param name="label">Label used to identify this widget.</param> /// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</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="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> /// <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> /// <summary>
/// Creates a combo box for enumeration input. /// Creates a combo box for enumeration input.
/// </summary> /// </summary>

View File

@ -290,9 +290,14 @@ namespace SHADE
{ {
GameObject gameObj = safe_cast<GameObject>(field->GetValue(object)); GameObject gameObj = safe_cast<GameObject>(field->GetValue(object));
uint32_t entityId = gameObj.GetEntity(); 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); GameObject newVal = GameObject(entityId);
if (entityId != MAX_EID)
{
// Null GameObject set
newVal = GameObject(entityId);
}
field->SetValue(object, newVal); field->SetValue(object, newVal);
registerUndoAction(object, field, newVal, gameObj); registerUndoAction(object, field, newVal, gameObj);
} }

View File

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

View File

@ -29,8 +29,9 @@ namespace SHADE
/* Class Definitions */ /* Class Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Lightweight object for an PlushieEngine Entity that allows for easy access /// Lightweight object for an Entity that allows for easy access to Component and
/// to Component and Script operations. /// Script operations.
/// Can be set to a invalid/null GameObject by default construction.
/// </summary> /// </summary>
public value class GameObject : public System::IEquatable<GameObject> public value class GameObject : public System::IEquatable<GameObject>
{ {
@ -98,8 +99,8 @@ namespace SHADE
/// </summary> /// </summary>
property GameObject^ Parent property GameObject^ Parent
{ {
GameObject^ get(); GameObject^ get();
void set(GameObject^); void set(GameObject^);
} }
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -247,12 +248,22 @@ namespace SHADE
/// <returns>Native Entity object that this GameObject represents.</returns> /// <returns>Native Entity object that this GameObject represents.</returns>
SHEntity& GetNativeEntity(); 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: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Entity entity; Entity entity;
System::Collections::ArrayList^ children; System::Collections::ArrayList^ children;
bool valid;
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -171,7 +171,7 @@ namespace SHADE
else if (fieldInfo->FieldType == GameObject::typeid) else if (fieldInfo->FieldType == GameObject::typeid)
{ {
GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object)); GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object));
fieldNode = gameObj.GetEntity(); fieldNode = gameObj ? gameObj.GetEntity() : MAX_EID;
} }
else // Not any of the supported types else // Not any of the supported types
{ {
@ -250,7 +250,8 @@ namespace SHADE
} }
else if (fieldInfo->FieldType == GameObject::typeid) 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));
} }
else // Not any of the supported types else // Not any of the supported types
{ {