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}
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

@ -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));
@ -56,15 +58,21 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
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,10 +83,14 @@ namespace SHADE
}
Entity GameObject::EntityId::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
return entity;
}
GameObject^ GameObject::Parent::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
@ -91,6 +103,8 @@ namespace SHADE
}
void GameObject::Parent::set(GameObject^ newParent)
{
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (newParent == nullptr)
@ -104,10 +118,14 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
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,30 +135,40 @@ 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);
}
@ -150,30 +178,40 @@ namespace SHADE
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,13 +219,15 @@ namespace SHADE
/* Constructors */
/*---------------------------------------------------------------------------------*/
GameObject::GameObject(const SHEntity& entity)
: entity { entity.GetEID() }
: entity{ entity.GetEID() }
, children{ gcnew System::Collections::ArrayList }
, valid{ true }
{}
GameObject::GameObject(Entity entity)
: entity { entity }
: entity{ entity }
, children{ gcnew System::Collections::ArrayList }
, valid{ true }
{}
/*---------------------------------------------------------------------------------*/
@ -195,6 +235,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
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,12 +244,20 @@ 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;
}
/*---------------------------------------------------------------------------------*/

View File

@ -29,8 +29,9 @@ 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.
/// Can be set to a invalid/null GameObject by default construction.
/// </summary>
public value class GameObject : public System::IEquatable<GameObject>
{
@ -247,12 +248,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,8 @@ 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));
}
else // Not any of the supported types
{