mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
Create ECS system base
This commit is contained in:
@@ -11,6 +11,8 @@ endif()
|
||||
|
||||
include(CheckCXXSymbolExists)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake_modules/")
|
||||
|
||||
@@ -233,6 +235,10 @@ set(SOURCES
|
||||
"launcher/scenery_scanner.cpp"
|
||||
|
||||
"vr/vr_interface.cpp"
|
||||
entitysystem/components/BasicComponents.h
|
||||
entitysystem/ecs.cpp
|
||||
entitysystem/ecs.h
|
||||
entitysystem/components/RenderComponents.h
|
||||
)
|
||||
|
||||
set(DEFINITIONS)
|
||||
|
||||
50
entitysystem/components/BasicComponents.h
Normal file
50
entitysystem/components/BasicComponents.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Basic components used by almost everything
|
||||
*/
|
||||
#ifndef EU07_BASICCOMPONENTS_H
|
||||
#define EU07_BASICCOMPONENTS_H
|
||||
#include "entt/entity/entity.hpp"
|
||||
#include "glm/vec3.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ECSComponent
|
||||
{
|
||||
///< summary>
|
||||
/// Basic component for storing transform of entities
|
||||
///</summary>
|
||||
struct Transform
|
||||
{
|
||||
glm::vec3 Position{0.f}; // object position
|
||||
glm::quat Rotation{1.f, 0.f, 0.f, 0.f}; // object rotation
|
||||
glm::vec3 Scale{1.f}; // object scale
|
||||
};
|
||||
|
||||
///< summary>
|
||||
/// Basic component for naming entities
|
||||
/// in future for scenery hierarchy
|
||||
///</summary>
|
||||
struct Identification
|
||||
{
|
||||
std::string Name; // object name - may contain slashes for editor hierarchy "directories"
|
||||
std::uint64_t Id{0}; // id in scene
|
||||
};
|
||||
|
||||
///< summary>
|
||||
/// Basic component for parent-child relationships between entities
|
||||
///</summary>
|
||||
struct Parent
|
||||
{
|
||||
entt::entity value{entt::null};
|
||||
};
|
||||
|
||||
///< summary>
|
||||
/// Empty component for entities that are disabled and should not be processed by systems
|
||||
///</summary>
|
||||
struct Disabled
|
||||
{
|
||||
};
|
||||
} // namespace ECSComponent
|
||||
|
||||
#endif // EU07_BASICCOMPONENTS_H
|
||||
25
entitysystem/components/RenderComponents.h
Normal file
25
entitysystem/components/RenderComponents.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef EU07_RENDERCOMPONENTS_H
|
||||
#define EU07_RENDERCOMPONENTS_H
|
||||
|
||||
namespace ECSComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Component for entities that can be rendered.
|
||||
/// </summary>
|
||||
/// <remarks>Currently empty
|
||||
/// TODO: Add component members
|
||||
/// </remarks>
|
||||
struct MeshRenderer
|
||||
{
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Component for entities that can cast shadows.
|
||||
/// </summary>
|
||||
/// <remarks>Currently empty
|
||||
/// TODO: Add component members
|
||||
/// </remarks>
|
||||
struct SpotLight{};
|
||||
|
||||
} // namespace ECSComponent
|
||||
#endif // EU07_RENDERCOMPONENTS_H
|
||||
61
entitysystem/ecs.cpp
Normal file
61
entitysystem/ecs.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Created by Hirek on 3/14/2026.
|
||||
//
|
||||
|
||||
#include "ecs.h"
|
||||
|
||||
void ECS::ClearWorld()
|
||||
{
|
||||
world_.clear();
|
||||
}
|
||||
|
||||
entt::entity ECS::CreateObject()
|
||||
{
|
||||
const auto e = world_.create();
|
||||
world_.emplace<ECSComponent::Transform>(e);
|
||||
world_.emplace<ECSComponent::Identification>(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
void ECS::DestroyObject(entt::entity Entity)
|
||||
{
|
||||
if (Entity == entt::null) // check if Entity is not null
|
||||
return;
|
||||
if (!world_.valid(Entity)) // check if exist
|
||||
return;
|
||||
world_.destroy(Entity);
|
||||
}
|
||||
|
||||
bool ECS::ValidObject(entt::entity entity) const
|
||||
{
|
||||
return entity != entt::null && world_.valid(entity);
|
||||
}
|
||||
|
||||
entt::entity ECS::FindById(std::uint64_t id)
|
||||
{
|
||||
auto view = world_.view<const ECSComponent::Identification>();
|
||||
for (auto e : view)
|
||||
{
|
||||
const auto &ident = view.get<ECSComponent::Identification>(e);
|
||||
if (ident.Id == id)
|
||||
return e;
|
||||
}
|
||||
return entt::null;
|
||||
}
|
||||
|
||||
std::vector<entt::entity> ECS::FindByName(std::string_view name)
|
||||
{
|
||||
std::vector<entt::entity> result;
|
||||
|
||||
auto view = world_.view<const ECSComponent::Identification>();
|
||||
for (auto e : view)
|
||||
{
|
||||
const auto &ident = view.get<ECSComponent::Identification>(e);
|
||||
if (ident.Name == name)
|
||||
{
|
||||
result.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
148
entitysystem/ecs.h
Normal file
148
entitysystem/ecs.h
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// Created by Hirek on 3/14/2026.
|
||||
//
|
||||
|
||||
#ifndef EU07_ECS_H
|
||||
#define EU07_ECS_H
|
||||
#include "components/BasicComponents.h"
|
||||
#include "entt/entity/registry.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
class ECS final
|
||||
{
|
||||
private:
|
||||
entt::registry world_;
|
||||
|
||||
public:
|
||||
//
|
||||
// World lifecycle
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Clears the world, removing all entities and components
|
||||
/// </summary>
|
||||
void ClearWorld();
|
||||
|
||||
//
|
||||
// Objects
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Creates new object with basic components (Transform, Identification) and returns its entity handle.
|
||||
/// </summary>
|
||||
/// <returns>Entity handle of created object</returns>
|
||||
entt::entity CreateObject();
|
||||
|
||||
/// <summary>
|
||||
/// Destroys object with it's all components
|
||||
/// </summary>
|
||||
/// <param name="Entity">Entity to be removed</param>
|
||||
void DestroyObject(entt::entity Entity);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if object with given entity handle exists in the registry
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity handle to check</param>
|
||||
/// <returns>true if object exists, false otherwise</returns>
|
||||
bool ValidObject(entt::entity entity) const;
|
||||
|
||||
//
|
||||
// Identification lookups
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Finds object with given UID. Returns null entity if not found.
|
||||
/// </summary>
|
||||
/// <param name="id">UID of object</param>
|
||||
entt::entity FindById(std::uint64_t id);
|
||||
|
||||
/// <summary>
|
||||
/// Finds objects with given name. Returns empty vector if not found.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of object</param>
|
||||
/// <remarks>May return more than 1 as many objects can have the same name</remarks>
|
||||
std::vector<entt::entity> FindByName(std::string_view name);
|
||||
|
||||
//
|
||||
// Components
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Adds component of type T to entity, forwarding provided arguments to component constructor. If component already exists, it will be replaced.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity to which component will be added</param>
|
||||
/// <param name="args">Arguments forwarded to component constructor</param>
|
||||
/// <returns>Reference to added component</returns>
|
||||
template <class T, class... Args> T &Add(entt::entity entity, Args &&...args)
|
||||
{
|
||||
return world_.emplace<T>(entity, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds component of type T to entity, forwarding provided arguments to component constructor. If component already exists, it will be replaced.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity to which component will be added</param>
|
||||
/// <returns>Reference to added component</returns>
|
||||
template <class T> T &Get(entt::entity entity)
|
||||
{
|
||||
return world_.get<T>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds component of type T to entity, forwarding provided arguments to component constructor. If component already exists, it will be replaced.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity to which component will be added</param>
|
||||
/// <returns>Reference to added component</returns>
|
||||
template <class T> const T &Get(entt::entity entity) const
|
||||
{
|
||||
return world_.get<T>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get component of type T from entity. Returns nullptr if component does not exist.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity from which component will be retrieved</param>
|
||||
/// <returns>Pointer to component if exists, nullptr otherwise</returns>
|
||||
template <class T> T *TryGet(entt::entity entity)
|
||||
{
|
||||
return world_.try_get<T>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get component of type T from entity. Returns nullptr if component does not exist.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity from which component will be retrieved</param>
|
||||
/// <returns>Pointer to component if exists, nullptr otherwise</returns>
|
||||
template <class T> const T *TryGet(entt::entity entity) const
|
||||
{
|
||||
return world_.try_get<T>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if entity has component of type T.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity to check</param>
|
||||
/// <returns>true if entity has component, false otherwise</returns>
|
||||
template <class... T> bool Has(entt::entity entity) const
|
||||
{
|
||||
return world_.all_of<T...>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes component of type T from entity. Does nothing if component does not exist.
|
||||
/// </summary> <typeparam name="T">Component type</typeparam>
|
||||
/// <param name="entity">Entity from which component will be removed</param>
|
||||
template <class... T> void Remove(entt::entity entity)
|
||||
{
|
||||
world_.remove<T...>(entity);
|
||||
}
|
||||
};
|
||||
#endif // EU07_ECS_H
|
||||
Reference in New Issue
Block a user