Nuevo sistema de Escenas.

Nos quitamos del medio la cosa rara del SceneBuilder.
Simplificamos la estructura y la hacemos más o menos segura.
This commit is contained in:
2022-08-11 12:57:40 +02:00
parent ce1886d3db
commit b2d6a31275
14 changed files with 316 additions and 269 deletions
+3
View File
@@ -39,3 +39,6 @@ Repositorio principal de UberEngine. Sin mucho más.
### JSON / AssetManager ### JSON / AssetManager
- [ ] Crear un sistema sencillo (un método o algo común para todas las veces que sea necesario) para añadir seguridad al parse y uso de los JSON. De tal forma que se devuelva el error por consola pero no salten exepciones ni mierdas. - [ ] Crear un sistema sencillo (un método o algo común para todas las veces que sea necesario) para añadir seguridad al parse y uso de los JSON. De tal forma que se devuelva el error por consola pero no salten exepciones ni mierdas.
### Sistema de Escenas.
- [ ] Revisar los métodos para carga/descarga y de cambio de escenas. Creo que se pueden estructurar mejor.
+5 -3
View File
@@ -1,5 +1,7 @@
#include "Scene.h" #include "Scene.h"
#include "Logging/Logger.h"
#include <iostream> #include <iostream>
namespace UE namespace UE
@@ -7,13 +9,13 @@ namespace UE
void Scene::SceneInit() void Scene::SceneInit()
{ {
//id = currentID++; UE_LOG_TRACE("Scene {0} has been init!", _sceneName);
std::cout << "Scene has been init!" << std::endl;
} }
void Scene::SceneClean() void Scene::SceneClean()
{ {
std::cout << "Scene has been cleaned!" << std::endl; UE_LOG_TRACE("Scene {0} has been Cleaned!", _sceneName);
if (loaded) if (loaded)
{ {
SceneUnload(); SceneUnload();
+49 -18
View File
@@ -5,7 +5,6 @@
/// ///
/// TODO: /// TODO:
/// - Scene debería ser serializable y cargable desde archivos, al menos para las clases derivadas. ( o quizás no....)
/// ///
/// ///
union SDL_Event; union SDL_Event;
@@ -14,9 +13,9 @@ namespace UE
{ {
/* /*
Estructura básica de una escena. Almacena los datos mínimos. Estructura básica de una escena.
Se utilizará como clase base para las clases Scene específicas. Se utiliza como clase base para las clases Scene específicas del Game.
Esta clase será heredada por las escenas del usuario. Esta clase será heredada por las escenas del usuario.
*/ */
class Scene class Scene
{ {
@@ -24,35 +23,67 @@ namespace UE
Scene(std::string name) Scene(std::string name)
: _sceneName(name) : _sceneName(name)
{} {
SceneInit();
}
/* Funciones "internas" de la clase para inicialización y cierre. */ ~Scene()
{
SceneClean();
}
/* Funciones "internas" de la clase para inicialización y cierre. */
void SceneInit(); //Te calienta y prepara la casa al llegar. void SceneInit(); //Te calienta y prepara la casa al llegar.
void SceneClean(); //Te deja todo limpio y reluciente al salir. void SceneClean(); //Te deja todo limpio y reluciente al salir.
/*
Métodos de los estados de la escena.
Habrán de ser sobrecargardos por las escenas del usuario.
*/
/* Funciones que habrán de sobrecargar las escenas del usuario. */ //Se crean todos los objetos y se carga todo lo necesario para la escena.
virtual void SceneLoad() { std::cout << "EMPTY SCENE CREATED" << std::endl; } virtual void SceneLoad() = 0;
virtual void SceneRender() {}
virtual void SceneUpdate() {}
virtual void SceneHandleEvents(SDL_Event* event) {}
virtual void SceneUnload() { std::cout << "EMPTY SCENE DESCARGADA" << std::endl; }
// ¿Esto sirve para algo? /*
//void loadDataFromFile(std::string path); * Render de los objetos de la escena.
* Se ejecuta en cada frame.
*/
virtual void SceneRender() = 0;
/*
* Update para los objetos de la escena.
* Utilizado para las físicas y otros componentes similares.
* Se ejecuta en cada frame.
*/
virtual void SceneUpdate() = 0;
/*
* Gestor de eventos para la escena.
* Utilizado para capturar los eventos que necesita la escena.
*/
virtual void SceneHandleEvents(SDL_Event* event) = 0;
/*
* Descarga y limpia todos los elementos de la escena.
* Utilizado también para guardado o lo que sea conveniente.
*/
virtual void SceneUnload() = 0;
//Obtener el nombre de la escena.
inline std::string GetName() { return _sceneName; } inline std::string GetName() { return _sceneName; }
/*
* Permite comprobar si la escena está cargada o no.
* TODO: Útil si queremos hacer carga asincrona o similar. Al menos para assets o algo.
*/
inline bool IsLoaded() { return loaded; } inline bool IsLoaded() { return loaded; }
protected: protected:
//Almacena el ID actual, permitiendo generar un ID nuevo para cada Scene que se instancie.
//static uint16_t currentID;
std::string _sceneName; //Nombre de la escena. Para identificarla en el SceneManager.
//std::vector<Entity> _entidades; std::string _sceneName = "NullScene";
bool loaded = false; bool loaded = false;
-18
View File
@@ -1,18 +0,0 @@
#pragma once
namespace UE
{
class Scene;
/*
Será sobrecargado por el juego, de tal forma que cuando se le pida crear una escena, sepa qué objeto crear.
*/
class SceneBuilder
{
public:
virtual inline Scene* InstanciateScene(int sceneID) { return nullptr; }
};
}
+101 -59
View File
@@ -1,8 +1,5 @@
#include "SceneManager.h" #include "SceneManager.h"
#include "Scene.h"
#include "SceneBuilder.h"
#include "Logging/Logger.h" #include "Logging/Logger.h"
#include <iostream> #include <iostream>
@@ -10,86 +7,131 @@
namespace UE namespace UE
{ {
void SceneManager::InitSceneManager(SceneBuilder* sceneBuilder) void SceneManager::InitSceneManager()
{ {
_sceneBuilder = sceneBuilder;
UE_LOG_INFO("Se ha inicializado el SceneManager."); UE_LOG_INFO("Se ha inicializado el SceneManager.");
} }
void SceneManager::CleanSceneManager() void SceneManager::CleanSceneManager()
{ {
for (auto& it : _loadedScenes)
{
Scene* sc = it.second;
sc->SceneClean();
delete sc;
}
_loadedScenes.clear();
if (_currentScene != nullptr) if (_currentScene != nullptr)
{
_currentScene = nullptr;
}
UE_LOG_INFO("El ScenenManager se ha descargado correctamente.");
}
void SceneManager::LoadScene(Scene* sceneToLoad)
{
std::string name = sceneToLoad->GetName();
//Comprobamos si la escena ya está cargada en la lista.
if(IsSceneLoaded(name))
{
//Si lo está, la descargamos para volverla a cargar.
//En caso de no estar activa, claro está.
UnloadScene(name);
}
//Cargamos la escena en cuestión.
sceneToLoad->SceneLoad();
//Añadimos la escena a la lista de escenas cargadas.
_loadedScenes.insert(std::make_pair(name, sceneToLoad));
}
void SceneManager::LoadAndSwitchScene(Scene* sceneToLoad)
{
LoadScene(sceneToLoad);
SwitchScene(sceneToLoad->GetName());
}
void SceneManager::SwitchScene(std::string name)
{
//Comprobamos si existe la escena indicada.
if(!IsSceneLoaded(name))
{
UE_LOG_WARN("SceneManager: Scene {0}, No se puede cambiar de escena. No está cargada.", name);
return;
}
//Cambiamos la escena actual por la indicada.
_currentScene = _loadedScenes.at(name);
}
void SceneManager::SwitchAndUnloadScene(std::string name)
{
//Comprobamos si existe la escena indicada.
if(!IsSceneLoaded(name))
{
UE_LOG_WARN("SceneManager: Scene {0}, No se puede cambiar de escena. No está cargada.", name);
return;
}
//Descargamos la escena anterior en caso de haberla.
if(_currentScene != nullptr && IsSceneLoaded(_currentScene->GetName()))
{ {
_currentScene->SceneUnload(); _currentScene->SceneUnload();
delete _currentScene;
} }
//for (auto& it : _scenes) //Cambiamos la escena activa por la nueva.
//{ _currentScene = _loadedScenes.at(name);
// Scene* sc = it.second;
// sc->SceneClean();
// delete sc;
//}
//_scenes.clear();
} }
void SceneManager::UnloadScene(std::string name)
{
//Comprobamos si existe la escena indicada.
if(!IsSceneLoaded(name))
{
UE_LOG_WARN("SceneManager: Scene {0}, no se puede descargar. No está cargada.", name);
return;
}
//Comprobamos si se trata de la escena actual.
if(GetCurrentSceneName() == name)
{
//No hacemos nada, no se puede recargar la escena actual así como así.
UE_LOG_WARN("SceneManager: Scene {0}, no se puede descargar. Es la escena actual.", name);
return;
}
//void SceneManager::AddScene(Scene* sceneToAdd) //Si todo está correcto.
//{ //Si tenemos campo libre, pista libre, punto rojo.
// _scenes.insert(std::make_pair(sceneToAdd->GetName(), sceneToAdd)); //Descargamos.
// sceneToAdd->SceneInit(); _loadedScenes.at(name)->SceneUnload();
_loadedScenes.erase(name);
// UE_LOG_INFO("Se ha a�adido la escena {0} al SceneManager.", sceneToAdd->GetName()); }
//}
bool SceneManager::IsSceneLoaded(std::string name)
//Scene* SceneManager::GetScenePtr(std::string sceneName) {
//{ //Comprobamos si existe la escena indicada.
// if (_scenes.find(sceneName) == _scenes.end()) if(_loadedScenes.find(name) != _loadedScenes.end())
// { {
// UE_LOG_ERROR("No se ha encontrado la escena indicada."); //Si la encontramos, existe.
// return nullptr; return true;
// } }
// return _scenes.at(sceneName); return false;
//} }
std::string SceneManager::GetCurrentSceneName()
std::string SceneManager::GetActiveSceneName()
{ {
return _currentScene->GetName(); return _currentScene->GetName();
} }
//void SceneManager::LoadScene(std::string sceneName) Scene* SceneManager::GetCurrentScenePtr()
//{
// if (_currentScene != nullptr)
// {
// _currentScene->SceneUnload();
// delete _currentScene;
// }
// _currentScene = _scenes.at(sceneName);
// _currentScene->SceneLoad();
//}
void SceneManager::NewLoadScene(int sceneID)
{ {
if (_currentScene != nullptr) return _currentScene;
{
_currentScene->SceneUnload();
delete _currentScene;
}
_currentScene = _sceneBuilder->InstanciateScene(sceneID);
_currentScene->SceneLoad();
} }
void SceneManager::UpdateScene() void SceneManager::UpdateScene()
+77 -38
View File
@@ -1,71 +1,110 @@
#pragma once #pragma once
#include "Scene/Scene.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
// //
// Habría que implemetar un sistema para cambiar de escena. // TODO:
// La cuestión sería almecenar el ID actual o algo así. // - Se podría plantear un sistema de carga asincrona para las escenas.
// Las escenas que no están cargadas se pueden mantener construidas en el vector, pues el espacio que ocupan en memoria debería ser mínimo. // - La variable "loaded" de las escenas no tiene mucha utilidad en este momento.
// Cuando cargas una escena, se descarga la anterior mediante Scene.unload y se carga la nueva con Scene.Load. De esta forma,
// si cada escena gestiona bien sus recursos en la carga y descarga, no debería generar ningún problema y no ocupar espacio cuando esté descargada.
// Quizás se puede añadir una opción para mantener cargada una escena o algo.
//
// Quizás es innecesaria la ID interna de la escena....
//
namespace UE namespace UE
{ {
class Scene;
class SceneBuilder;
/* Gestiona todas escenas. Las carga, descargar y ejecuta. */ /* Gestiona todas escenas. Las carga, descargar y ejecuta. */
class SceneManager class SceneManager
{ {
public: public:
/* Constructor */
SceneManager() {}
void InitSceneManager(SceneBuilder* sceneBuilder); /* Constructor */
SceneManager()
{
InitSceneManager();
}
~SceneManager()
{
CleanSceneManager();
}
//Inicializa el ScenenManager (En caso de haber algo que iniciar.)
void InitSceneManager();
//Limpia los contenedores de Scenes y descarga las escenas cargadas.
void CleanSceneManager(); void CleanSceneManager();
//Añade una escena a la lista y retorna su ID. Son Ptrs, por lo que poco importa donde los almacenamos. /*
//void AddScene(Scene* sceneToAdd); * Carga una nueva escena.
* Se almacena en la lista de escenas cargadas.
* Para cambiar de escena, usar SwitchScene();
* Si la escena ya estuvise cargada, se descargará la anterior y se cargará la nueva.
*/
void LoadScene(Scene* sceneToLoad);
//Devuelve un ptr a la escena del ID especificado. /*
//Scene* GetScenePtr(std::string sceneName); * Cambia la escena activa por la indicada.
std::string GetActiveSceneName(); * Si la indicada no está cargada, no hace nada.
*/
void SwitchScene(std::string name);
//Devuelve la escena activa. /*
inline Scene* GetActiveScenePtr() { return _currentScene; } * Carga la escena indicada.
* Cambia la escena actual por la nueva escena.
*/
void LoadAndSwitchScene(Scene* sceneToLoad);
//Descarga la escena activa y carga la escena indicada. /*
//void LoadScene(std::string sceneName); * Cambia la escena activa por la indicada.
* Descarga completamente la escena activa anterior.
* Si la escena indicada no está cargarda, no hace nada.
* Si no hay una escena activa, no la descarga.
*/
void SwitchAndUnloadScene(std::string name);
//Descarga la escena activa y carga la escena indicada. Para ello llama al builder que tiene y este le devuelve un ptr a la nueva escena.
void NewLoadScene(int sceneID);
//Pasa el Update a la escena actual. /*
//¿Necesita hacer algo más? * Descarga la escena con el nombre indicado.
* Si la escena no está en la lista, no hace nada.
*/
void UnloadScene(std::string name);
/*
* Comprueba si la escena indicada está en la lista de escenas cargadas.
* Retorna true si está cargada, false si no.
*/
bool IsSceneLoaded(std::string name);
/*
* Devuelve el nombre de la escena activa.
*/
std::string GetCurrentSceneName();
/*
* Devuelve el ptr de la escena activa.
*/
Scene* GetCurrentScenePtr();
/*
* Update para la escena activa.
* Se ha de llamar en cada frame para pasar el update a la escena activa.
* TODO: No se usa... O añadimos para las otras fases o quitamos esta.
*/
void UpdateScene(); void UpdateScene();
// ¿Esto sirve para algo?
//void LoadSceneDataFromFile(std::string filePath);
private: private:
//Ptr a la escena que está activa en ese momento.
Scene* _currentScene = nullptr; Scene* _currentScene = nullptr;
SceneBuilder* _sceneBuilder = nullptr; //Almacenamos un ptr a todas las escenas cargadas en ese momento.
//o, al menos, lo intentamos.
//Almacenamos un ptr a las diferentes escenas disponibles. std::unordered_map<std::string, Scene*> _loadedScenes;
//Otra opción es trabajar con Templates para instanciar la clase pretinente sin necesidad de almacenar nada.
//De cualquier forma, son ptr en el Stack y deberían de eliminar todo al hacer scene.Unload().
//std::unordered_map<std::string, Scene*> _scenes;
//std::vector<Scene*> _scenes;
}; };
+2 -2
View File
@@ -15,7 +15,7 @@ namespace UE
public: public:
//------------------- //-------------------
//---- Métodos ------ //---- Métodos ------
//------------------- //-------------------
static void StartFrame(); static void StartFrame();
@@ -36,7 +36,7 @@ namespace UE
static const int FPS = 60; static const int FPS = 60;
//Milisegundos que tiene que tener un frame para poder hacer el número de FPS por segundo. //Milisegundos que tiene que tener un frame para poder hacer el número de FPS por segundo.
static const int MS_PER_FRAME = 1000 / FPS; static const int MS_PER_FRAME = 1000 / FPS;
}; };
-48
View File
@@ -1,48 +0,0 @@
#pragma once
#include "Scene/SceneBuilder.h"
#include "Scene/Scene.h"
#include "Scenes/MainScene.hpp"
#include "Scenes/TestScene2.hpp"
//#include "Logging\Logger.h"
enum LasEscenas
{
mainMenu = 0, nivel1
};
class GameScenes : public UE::SceneBuilder
{
public:
GameScenes()
{
}
UE::Scene* InstanciateScene(int sceneID) override
{
switch (sceneID)
{
case LasEscenas::mainMenu:
{
UE::Scene* sc = new MainScene("Main");
return sc;
break;
}
case LasEscenas::nivel1:
{
UE::Scene* sc = new TestScene2("Test2");
return sc;
break;
}
default:
return nullptr;
break;
}
}
};
+7 -8
View File
@@ -7,7 +7,6 @@
#include <ImGui/imgui_impl_opengl3.h> #include <ImGui/imgui_impl_opengl3.h>
#include "UberGame1.h" #include "UberGame1.h"
#include "GameScenes.hpp"
#include "UberEngine.h" #include "UberEngine.h"
@@ -33,7 +32,6 @@ int main(int argc, char* args[])
return 0; return 0;
} }
void Init() void Init()
{ {
UE::Logger::InitLogger(); UE::Logger::InitLogger();
@@ -51,7 +49,8 @@ void Load()
//Cargamos la escena que queramos tras tener todos los Assets pertinentes cargados. //Cargamos la escena que queramos tras tener todos los Assets pertinentes cargados.
//Si la escena contiene su propio AssetManager y los carga ella misma, no ser� necesario. //Si la escena contiene su propio AssetManager y los carga ella misma, no ser� necesario.
//Game::GetSceneManager()->LoadScene("Main"); //Game::GetSceneManager()->LoadScene("Main");
Game::GetSceneManager()->NewLoadScene(LasEscenas::mainMenu); Game::GetSceneManager()->LoadScene(new MainScene());
Game::GetSceneManager()->SwitchScene("MainScene");
} }
@@ -98,7 +97,7 @@ void Loop()
if (io.WantCaptureMouse) { continue; } if (io.WantCaptureMouse) { continue; }
Game::GetSceneManager()->GetActiveScenePtr()->SceneHandleEvents(&eventHandler); Game::GetSceneManager()->GetCurrentScenePtr()->SceneHandleEvents(&eventHandler);
if (eventHandler.type == SDL_QUIT) if (eventHandler.type == SDL_QUIT)
{ {
_quit = true; _quit = true;
@@ -113,10 +112,10 @@ void Loop()
switch (eventHandler.key.keysym.sym) switch (eventHandler.key.keysym.sym)
{ {
case SDLK_1: case SDLK_1:
Game::GetSceneManager()->NewLoadScene(LasEscenas::mainMenu); Game::GetSceneManager()->LoadAndSwitchScene(new MainScene());
break; break;
case SDLK_2: case SDLK_2:
Game::GetSceneManager()->NewLoadScene(LasEscenas::nivel1); Game::GetSceneManager()->LoadAndSwitchScene(new TestScene2());
break; break;
default: default:
break; break;
@@ -159,7 +158,7 @@ void Loop()
Game::GetRenderer()->SetCamPosition(camPos.x, camPos.y); Game::GetRenderer()->SetCamPosition(camPos.x, camPos.y);
} }
Game::GetSceneManager()->GetActiveScenePtr()->SceneUpdate(); Game::GetSceneManager()->GetCurrentScenePtr()->SceneUpdate();
//Game::GetRenderer()->QueueDrawCall(4, DestR2, test1); //Game::GetRenderer()->QueueDrawCall(4, DestR2, test1);
//Game::GetRenderer()->QueueDrawCall(1, DestR, background); //Game::GetRenderer()->QueueDrawCall(1, DestR, background);
@@ -173,7 +172,7 @@ void Loop()
Game::GetRenderer()->NewFrame(); Game::GetRenderer()->NewFrame();
//Renderiza la escena. //Renderiza la escena.
Game::GetSceneManager()->GetActiveScenePtr()->SceneRender(); Game::GetSceneManager()->GetCurrentScenePtr()->SceneRender();
//As� podemos renderizar cosas de ImGui cuando estemos entre NewFrame y EndFrame. //As� podemos renderizar cosas de ImGui cuando estemos entre NewFrame y EndFrame.
bool show = true; bool show = true;
+4 -1
View File
@@ -23,7 +23,10 @@ class MainScene : public UE::Scene
{ {
public: public:
MainScene(std::string sceneName) : Scene(sceneName) {} MainScene() : Scene("MainScene")
{
//_sceneName = "MainScene";
}
void SceneLoad() override void SceneLoad() override
+4 -1
View File
@@ -18,7 +18,10 @@ class TestScene2 : public UE::Scene
{ {
public: public:
TestScene2(std::string sceneName) : Scene(sceneName) {} TestScene2() : Scene("TestScene")
{
//_sceneName = "TestScene";
}
void SceneLoad() override void SceneLoad() override
{ {
+5 -9
View File
@@ -5,9 +5,6 @@
#include "Assets/AssetManager.h" #include "Assets/AssetManager.h"
#include "Scene/SceneManager.h" #include "Scene/SceneManager.h"
#include "Scene/SceneBuilder.h"
#include "GameScenes.hpp"
//Sobrecarga de SceneBuilder que devuelve las escenas correctas para este juego. //Sobrecarga de SceneBuilder que devuelve las escenas correctas para este juego.
//#include "GameScenes.hpp" //#include "GameScenes.hpp"
@@ -16,24 +13,23 @@ UE::Renderer* Game::mainRenderer;
UE::AssetManager* Game::asManager; UE::AssetManager* Game::asManager;
UE::SceneManager* Game::scManager; UE::SceneManager* Game::scManager;
GameScenes Game::_sceneBuilder;
void Game::InitGame() void Game::InitGame()
{ {
//Cargamos el Renderer.
//Hay que implementar un sistema de flags o
// una struct de configuración para la inicialización del renderer.
mainRenderer = new UE::Renderer(640, 480, 5); mainRenderer = new UE::Renderer(640, 480, 5);
mainRenderer->InitRenderer(); mainRenderer->InitRenderer();
UE_LOG_INFO("Renderer Created."); UE_LOG_INFO("Renderer Created.");
//Cargamos el AssetManager
asManager = new UE::AssetManager(mainRenderer->GetSDLRenderer()); asManager = new UE::AssetManager(mainRenderer->GetSDLRenderer());
asManager->InitAssetManager(); asManager->InitAssetManager();
UE_LOG_INFO("AssetManager Created."); UE_LOG_INFO("AssetManager Created.");
//Creamos el SceneBuilder de este juego. //Cargamos el SceneManager
_sceneBuilder = GameScenes();
scManager = new UE::SceneManager(); scManager = new UE::SceneManager();
scManager->InitSceneManager(&_sceneBuilder);
} }
void Game::CleanGame() void Game::CleanGame()
-5
View File
@@ -5,11 +5,8 @@ namespace UE
class Renderer; class Renderer;
class AssetManager; class AssetManager;
class SceneManager; class SceneManager;
class SceneBuilder;
} }
class GameScenes;
class Game class Game
{ {
public: public:
@@ -25,6 +22,4 @@ private:
static UE::Renderer* mainRenderer; static UE::Renderer* mainRenderer;
static UE::AssetManager* asManager; static UE::AssetManager* asManager;
static UE::SceneManager* scManager; static UE::SceneManager* scManager;
static GameScenes _sceneBuilder;
}; };