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))
return false;
Components.Add(t, (Component)Activator.CreateInstance(t, this));
Component component = (Component)Activator.CreateInstance(t, this);
Components.Add(t, component);
return true;
}
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"
namespace ougge {
std::ostream& operator<<(std::ostream& s, Transform& t){
s<<"{ position: {x: "<<t.position.x<<", y: "<<t.position.y;
s<<"}, rotation: "<<t.rotation;
@ -14,8 +16,7 @@ GameObject::GameObject(Mono::Object managed_obj)
GameObject::GameObject(GameObject &&o) :
object_handle(std::move(o.object_handle)),
parent(o.parent),
transform(o.transform),
components(std::move(o.components))
transform(o.transform)
{
}
@ -23,16 +24,7 @@ GameObject& GameObject::operator=(GameObject &&o){
object_handle = std::move(o.object_handle);
parent = o.parent;
transform = o.transform;
components = std::move(o.components);
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 "../Mono/Mono.hpp"
class GameObject;
namespace ougge {
class Component {
Mono::ObjectHandle object_handle;
GameObject* owner;
public:
inline Component(Mono::Object managed_obj, GameObject* owner)
: object_handle(managed_obj), owner(owner) {}
};
class GameObject;
struct Transform {
Vec2 scale = { 1, 1 };
@ -29,7 +23,7 @@ class GameObject {
Mono::ObjectHandle object_handle;
GameObject* parent;
Transform transform;
std::map<std::u16string, Component> components;
public:
/// @warning Do not use this to create objects.
/// This constructor creates null values for GameObject arrays
@ -42,10 +36,10 @@ public:
GameObject& operator=(GameObject&& o);
inline Transform& getTransform() { return transform; }
inline const Transform& getTransform() const { return transform; }
inline Mono::ObjectHandle& getObjectHandle() { return object_handle; }
inline const Mono::ObjectHandle& getObjectHandle() const { return object_handle; }
bool tryGetComponent(const std::u16string& name, Component** out_component);
bool tryAddComponent(const std::u16string& name, Component&& component);
inline GameObject* getParent() { return parent; }
inline void setParent(GameObject* p) { parent = p; }
inline Transform& getTransform() { return transform; }
};
}

View File

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

View File

@ -1,7 +1,9 @@
#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.
------------------------[construct]------------------------
@ -64,3 +66,5 @@ public:
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;
public:
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");
}
};
Method() { method_ptr = nullptr; }
/// all types must implement getClass<T>()
Method(MonoClass* target_class, const std::string& name){
@ -104,6 +81,37 @@ public:
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 {
MonoDomain* domain;
public:
RuntimeJIT(const std::string& domain_name = "MonoApp");
RuntimeJIT(const std::string& domain_name = "OuggeDomain");
RuntimeJIT(const RuntimeJIT&) = delete;
~RuntimeJIT();
inline MonoDomain* getDomain() { return domain; }
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.

View File

@ -3,66 +3,35 @@
#include <iomanip>
#include "GUI/MainWindow.hpp"
#include "Resources/Resources.hpp"
#include "Game/Scene.hpp"
#include "Game/Engine.hpp"
#include "format.hpp"
#include "UsefulException.hpp"
#include "Mono/Mono.hpp"
#include "Game/GameObjectPool.hpp"
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){
try {
Resources::init();
std::cout<<"initialized resource loader"<<std::endl;
Mono::RuntimeJIT mono;
Engine engine;
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");
u64 obj_id = 0;
auto pair = p.emplace(GameObject(mono_object_new(mono.getDomain(), gameObjectClass)));
Mono::ObjectHandle& exampleObjectHandle = pair.second.getObjectHandle();
auto gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
gameObjectCtor(exampleObjectHandle.getObject(), obj_id++, pair.first);
GameObject& exampleObj = engine.createGameObject();
std::string componentClassName = "Ougge.ExampleComponent";
if(!engine.tryCreateComponent(exampleObj, componentClassName))
throw UsefulException(format("couldn't create component '%s'", componentClassName.c_str()));
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;
auto updateCallback = [&engine](f64 deltaTime) -> void {
engine.invokeUpdate(deltaTime);
};
GUI::MainWindow w;
w.open("ougge", update);
w.open("ougge", updateCallback);
std::cout<<"created sdl window"<<std::endl;
w.startUpdateLoop();
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
///@return time from some moment in nanoseconds.
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;\
}