created Engine class

This commit is contained in:
Timerix 2025-04-24 04:50:56 +05:00
parent 366dd1214c
commit 3477b05cd8
11 changed files with 152 additions and 106 deletions

View File

@ -65,7 +65,8 @@ public class GameObject
if(Components.ContainsKey(t)) if(Components.ContainsKey(t))
return false; return false;
Components.Add(t, (Component)Activator.CreateInstance(t, this)); Component component = (Component)Activator.CreateInstance(t, this);
Components.Add(t, component);
return true; return true;
} }
private bool TryCreateComponent_internal(string fullName) private bool TryCreateComponent_internal(string fullName)

37
src/Game/Engine.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "Engine.hpp"
namespace ougge {
Engine::Engine()
: gameObjectPool(GAMEOBJECTPOOL_SIZE)
{
}
void Engine::init(){
engineManagedAssembly = mono.loadAssembly("Ougge.dll");
gameObjectClass = engineManagedAssembly->getClass("Ougge", "GameObject");
gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
gameObjectInvokeUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate");
gameObjectTryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal");
}
void Engine::invokeUpdate(f64 deltaTime){
for(auto pair : gameObjectPool){
gameObjectInvokeUpdate(pair.second.getObjectHandle().getObject(), deltaTime);
}
}
GameObject& Engine::createGameObject(){
auto pair = gameObjectPool.emplace(GameObject(mono.createObject(gameObjectClass)));
GameObject& obj = pair.second;
gameObjectCtor(obj.getObjectHandle().getObject(), obj_id++, pair.first);
return obj;
}
bool Engine::tryCreateComponent(GameObject& obj, const std::string& componentClassName){
Mono::String componentClassNameManaged = mono.createString(componentClassName);
Mono::Bool created = gameObjectTryCreateComponent(obj.getObjectHandle().getObject(), componentClassNameManaged);
return created.wide_bool;
}
}

30
src/Game/Engine.hpp Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include "../Mono/Mono.hpp"
#include "GameObjectPool.hpp"
namespace ougge {
#define GAMEOBJECTPOOL_SIZE 64*1024
class Engine {
GameObjectPool gameObjectPool;
u64 obj_id = 0;
MonoClass* gameObjectClass;
Mono::Method<void(u64, u32)> gameObjectCtor;
Mono::Method<void(f64)> gameObjectInvokeUpdate;
Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent;
public:
Mono::RuntimeJIT mono;
std::shared_ptr<Mono::Assembly> engineManagedAssembly;
Engine();
void init();
void invokeUpdate(f64 deltaTime);
GameObject& createGameObject();
bool tryCreateComponent(GameObject& obj, const std::string& componentClassName);
};
}

View File

@ -1,5 +1,7 @@
#include "GameObject.hpp" #include "GameObject.hpp"
namespace ougge {
std::ostream& operator<<(std::ostream& s, Transform& t){ std::ostream& operator<<(std::ostream& s, Transform& t){
s<<"{ position: {x: "<<t.position.x<<", y: "<<t.position.y; s<<"{ position: {x: "<<t.position.x<<", y: "<<t.position.y;
s<<"}, rotation: "<<t.rotation; s<<"}, rotation: "<<t.rotation;
@ -14,8 +16,7 @@ GameObject::GameObject(Mono::Object managed_obj)
GameObject::GameObject(GameObject &&o) : GameObject::GameObject(GameObject &&o) :
object_handle(std::move(o.object_handle)), object_handle(std::move(o.object_handle)),
parent(o.parent), parent(o.parent),
transform(o.transform), transform(o.transform)
components(std::move(o.components))
{ {
} }
@ -23,16 +24,7 @@ GameObject& GameObject::operator=(GameObject &&o){
object_handle = std::move(o.object_handle); object_handle = std::move(o.object_handle);
parent = o.parent; parent = o.parent;
transform = o.transform; transform = o.transform;
components = std::move(o.components);
return *this; return *this;
} }
bool GameObject::tryGetComponent(const std::u16string &name, Component **out_component)
{
return false;
}
bool GameObject::tryAddComponent(const std::u16string &name, Component &&component)
{
return false;
} }

View File

@ -6,15 +6,9 @@
#include "../UsefulException.hpp" #include "../UsefulException.hpp"
#include "../Mono/Mono.hpp" #include "../Mono/Mono.hpp"
class GameObject; namespace ougge {
class Component { class GameObject;
Mono::ObjectHandle object_handle;
GameObject* owner;
public:
inline Component(Mono::Object managed_obj, GameObject* owner)
: object_handle(managed_obj), owner(owner) {}
};
struct Transform { struct Transform {
Vec2 scale = { 1, 1 }; Vec2 scale = { 1, 1 };
@ -29,7 +23,7 @@ class GameObject {
Mono::ObjectHandle object_handle; Mono::ObjectHandle object_handle;
GameObject* parent; GameObject* parent;
Transform transform; Transform transform;
std::map<std::u16string, Component> components;
public: public:
/// @warning Do not use this to create objects. /// @warning Do not use this to create objects.
/// This constructor creates null values for GameObject arrays /// This constructor creates null values for GameObject arrays
@ -42,10 +36,10 @@ public:
GameObject& operator=(GameObject&& o); GameObject& operator=(GameObject&& o);
inline Transform& getTransform() { return transform; }
inline const Transform& getTransform() const { return transform; }
inline Mono::ObjectHandle& getObjectHandle() { return object_handle; } inline Mono::ObjectHandle& getObjectHandle() { return object_handle; }
inline const Mono::ObjectHandle& getObjectHandle() const { return object_handle; } inline GameObject* getParent() { return parent; }
bool tryGetComponent(const std::u16string& name, Component** out_component); inline void setParent(GameObject* p) { parent = p; }
bool tryAddComponent(const std::u16string& name, Component&& component); inline Transform& getTransform() { return transform; }
}; };
}

View File

@ -2,6 +2,8 @@
#include <bit> #include <bit>
#include <cstring> #include <cstring>
namespace ougge {
GameObjectPool::GameObjectPool(u32 size) GameObjectPool::GameObjectPool(u32 size)
{ {
useful_assert(size % 64 == 0, "size of GameObjectPool must be a multiple of 64"); useful_assert(size % 64 == 0, "size of GameObjectPool must be a multiple of 64");
@ -123,4 +125,6 @@ GameObjectPool::iterator& GameObjectPool::iterator::operator++()
{ {
index = pool->getNearestUsedIndex(index+1); index = pool->getNearestUsedIndex(index+1);
return *this; return *this;
} }
}

View File

@ -1,7 +1,9 @@
#include "GameObject.hpp" #include "GameObject.hpp"
namespace ougge {
/* /*
Fixed array stkring deleted elements indices as bits in array of u64. Fixed array that stores deleted elements indices as bits in array of u64.
Fast emplace, erase and lookup. Fast emplace, erase and lookup.
------------------------[construct]------------------------ ------------------------[construct]------------------------
@ -64,3 +66,5 @@ public:
friend class iterator; friend class iterator;
}; };
}

View File

@ -1,7 +0,0 @@
#pragma once
#include "GameObject.hpp"
class Scene {
};

View File

@ -69,30 +69,7 @@ class Method<ReturnT(ArgTypes...)>
MonoMethod* method_ptr; MonoMethod* method_ptr;
public: public:
Method() { method_ptr = nullptr; }
template<typename RT = ReturnT>
std::enable_if_t<!std::is_void<RT>::value, RT> operator()(MonoObject* class_instance, ArgTypes... args) const {
void* arg_array[] = { valueToVoidPtr(args)..., nullptr };
MonoObject* ex = nullptr;
MonoObject* result = mono_runtime_invoke(method_ptr, class_instance, arg_array, &ex);
if(ex){
//TODO: call mono_trace_set_printerr_handler from mono/mono/utils/mono-logger.h
mono_print_unhandled_exception(ex);
throw UsefulException("Some C# exception occured");
}
return valueFromMonoObject<ReturnT>(result);
};
template<typename RT = ReturnT>
std::enable_if_t<std::is_void<RT>::value, RT> operator()(MonoObject* class_instance, ArgTypes... args) const {
void* arg_array[] = { valueToVoidPtr(args)..., nullptr };
MonoObject* ex = nullptr;
mono_runtime_invoke(method_ptr, class_instance, arg_array, &ex);
if(ex){
//TODO: call mono_trace_set_printerr_handler from mono/mono/utils/mono-logger.h
mono_print_unhandled_exception(ex);
throw UsefulException("Some C# exception occured");
}
};
/// all types must implement getClass<T>() /// all types must implement getClass<T>()
Method(MonoClass* target_class, const std::string& name){ Method(MonoClass* target_class, const std::string& name){
@ -104,6 +81,37 @@ public:
name.c_str(), mono_class_get_name(target_class))); name.c_str(), mono_class_get_name(target_class)));
} }
} }
template<typename RT = ReturnT>
std::enable_if_t<!std::is_void<RT>::value, RT> operator()(MonoObject* class_instance, ArgTypes... args) const {
if(method_ptr == nullptr)
throw UsefulException("method_ptr is null");
void* arg_array[] = { valueToVoidPtr(args)..., nullptr };
MonoObject* ex = nullptr;
MonoObject* result = mono_runtime_invoke(method_ptr, class_instance, arg_array, &ex);
if(ex){
//TODO: call mono_trace_set_printerr_handler from mono/mono/utils/mono-logger.h
mono_print_unhandled_exception(ex);
throw UsefulException("Some C# exception occured");
}
return valueFromMonoObject<ReturnT>(result);
};
template<typename RT = ReturnT>
std::enable_if_t<std::is_void<RT>::value, RT> operator()(MonoObject* class_instance, ArgTypes... args) const {
if(method_ptr == nullptr)
throw UsefulException("method_ptr is null");
void* arg_array[] = { valueToVoidPtr(args)..., nullptr };
MonoObject* ex = nullptr;
mono_runtime_invoke(method_ptr, class_instance, arg_array, &ex);
if(ex){
//TODO: call mono_trace_set_printerr_handler from mono/mono/utils/mono-logger.h
mono_print_unhandled_exception(ex);
throw UsefulException("Some C# exception occured");
}
};
}; };
@ -127,12 +135,16 @@ public:
class RuntimeJIT { class RuntimeJIT {
MonoDomain* domain; MonoDomain* domain;
public: public:
RuntimeJIT(const std::string& domain_name = "MonoApp"); RuntimeJIT(const std::string& domain_name = "OuggeDomain");
RuntimeJIT(const RuntimeJIT&) = delete; RuntimeJIT(const RuntimeJIT&) = delete;
~RuntimeJIT(); ~RuntimeJIT();
inline MonoDomain* getDomain() { return domain; } inline MonoDomain* getDomain() { return domain; }
std::shared_ptr<Assembly> loadAssembly(const std::string& name); std::shared_ptr<Assembly> loadAssembly(const std::string& name);
inline Object createObject(MonoClass* klass) { return mono_object_new(domain, klass); }
inline String createString(const std::string& v) { return mono_string_new_len(domain, v.c_str(), v.size()); }
inline String createString(const char* v) { return mono_string_new(domain, v); }
}; };
/// @brief ObjectHandle can be used to store reliable reference to MonoObject. /// @brief ObjectHandle can be used to store reliable reference to MonoObject.

View File

@ -3,66 +3,35 @@
#include <iomanip> #include <iomanip>
#include "GUI/MainWindow.hpp" #include "GUI/MainWindow.hpp"
#include "Resources/Resources.hpp" #include "Resources/Resources.hpp"
#include "Game/Scene.hpp" #include "Game/Engine.hpp"
#include "format.hpp" #include "format.hpp"
#include "UsefulException.hpp" #include "UsefulException.hpp"
#include "Mono/Mono.hpp"
#include "Game/GameObjectPool.hpp"
using namespace ougge; using namespace ougge;
#define GAMEOBJECTPOOL_SIZE 64
#define optime(N, LABEL, CODE) {\
nsec_t b = getMonotonicTimeNsec();\
for(u32 i = 0; i < (u32)N; i++) {\
CODE ;\
}\
nsec_t e = getMonotonicTimeNsec();\
nsec_t t = e-b;\
std::cout<<"operation '"<<LABEL<<"' took "<<t/1e6f<<" ms"<<std::endl;\
}\
std::vector<GUI::UpdateFunc_t> updateCallbacks;
void update(f64 deltaTime){
for(auto upd : updateCallbacks){
upd(deltaTime);
}
}
int main(int argc, const char** argv){ int main(int argc, const char** argv){
try { try {
Resources::init(); Resources::init();
std::cout<<"initialized resource loader"<<std::endl; std::cout<<"initialized resource loader"<<std::endl;
Mono::RuntimeJIT mono; Engine engine;
std::cout<<"initialized mono jit runtime"<<std::endl; std::cout<<"initialized mono jit runtime"<<std::endl;
GameObjectPool p(GAMEOBJECTPOOL_SIZE); engine.init();
std::cout<<"initialized game engine"<<std::endl;
auto a = mono.loadAssembly("Ougge.dll");
MonoClass* gameObjectClass = a->getClass("Ougge", "GameObject"); GameObject& exampleObj = engine.createGameObject();
u64 obj_id = 0; std::string componentClassName = "Ougge.ExampleComponent";
auto pair = p.emplace(GameObject(mono_object_new(mono.getDomain(), gameObjectClass))); if(!engine.tryCreateComponent(exampleObj, componentClassName))
Mono::ObjectHandle& exampleObjectHandle = pair.second.getObjectHandle(); throw UsefulException(format("couldn't create component '%s'", componentClassName.c_str()));
auto gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
gameObjectCtor(exampleObjectHandle.getObject(), obj_id++, pair.first);
auto exampleObjectUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate");
updateCallbacks.push_back([&exampleObjectHandle, exampleObjectUpdate](f64 deltaTime) -> void {
exampleObjectUpdate(exampleObjectHandle.getObject(), deltaTime);
});
auto tryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal");
Mono::String componentNameManaged = mono_string_new(mono.getDomain(), "Ougge.ExampleComponent");
Mono::Bool created = tryCreateComponent(exampleObjectHandle.getObject(), componentNameManaged);
if(!created.wide_bool)
throw UsefulException("couldn't create ExampleComponent");
std::cout<<"created ExampleObject"<<std::endl; std::cout<<"created ExampleObject"<<std::endl;
auto updateCallback = [&engine](f64 deltaTime) -> void {
engine.invokeUpdate(deltaTime);
};
GUI::MainWindow w; GUI::MainWindow w;
w.open("ougge", update); w.open("ougge", updateCallback);
std::cout<<"created sdl window"<<std::endl; std::cout<<"created sdl window"<<std::endl;
w.startUpdateLoop(); w.startUpdateLoop();
std::cout<<"sdl window has been cosed"<<std::endl; std::cout<<"sdl window has been cosed"<<std::endl;

View File

@ -8,3 +8,13 @@ typedef i64 nsec_t;
/// can be used to measure delta time /// can be used to measure delta time
///@return time from some moment in nanoseconds. ///@return time from some moment in nanoseconds.
nsec_t getMonotonicTimeNsec(); nsec_t getMonotonicTimeNsec();
#define optime(N, LABEL, CODE) {\
nsec_t b = getMonotonicTimeNsec();\
for(u32 i = 0; i < (u32)N; i++) {\
CODE ;\
}\
nsec_t e = getMonotonicTimeNsec();\
nsec_t t = e-b;\
std::cout<<"operation '"<<LABEL<<"' took "<<t/1e6f<<" ms"<<std::endl;\
}