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
- [ ] 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.
+15 -13
View File
@@ -1,23 +1,25 @@
#include "Scene.h"
#include "Logging/Logger.h"
#include <iostream>
namespace UE
{
void Scene::SceneInit()
{
//id = currentID++;
std::cout << "Scene has been init!" << std::endl;
}
void Scene::SceneInit()
{
UE_LOG_TRACE("Scene {0} has been init!", _sceneName);
}
void Scene::SceneClean()
{
std::cout << "Scene has been cleaned!" << std::endl;
if (loaded)
{
SceneUnload();
}
}
void Scene::SceneClean()
{
UE_LOG_TRACE("Scene {0} has been Cleaned!", _sceneName);
if (loaded)
{
SceneUnload();
}
}
}
+66 -35
View File
@@ -5,7 +5,6 @@
///
/// TODO:
/// - Scene debería ser serializable y cargable desde archivos, al menos para las clases derivadas. ( o quizás no....)
///
///
union SDL_Event;
@@ -13,49 +12,81 @@ union SDL_Event;
namespace UE
{
/*
Estructura básica de una escena. Almacena los datos mínimos.
Se utilizará como clase base para las clases Scene específicas.
Esta clase será heredada por las escenas del usuario.
*/
class Scene
{
public:
/*
Estructura básica de una escena.
Se utiliza como clase base para las clases Scene específicas del Game.
Esta clase será heredada por las escenas del usuario.
*/
class Scene
{
public:
Scene(std::string name)
: _sceneName(name)
{}
Scene(std::string name)
: _sceneName(name)
{
SceneInit();
}
/* Funciones "internas" de la clase para inicialización y cierre. */
void SceneInit(); //Te calienta y prepara la casa al llegar.
void SceneClean(); //Te deja todo limpio y reluciente al salir.
~Scene()
{
SceneClean();
}
/* Funciones que habrán de sobrecargar las escenas del usuario. */
virtual void SceneLoad() { std::cout << "EMPTY SCENE CREATED" << std::endl; }
virtual void SceneRender() {}
virtual void SceneUpdate() {}
virtual void SceneHandleEvents(SDL_Event* event) {}
virtual void SceneUnload() { std::cout << "EMPTY SCENE DESCARGADA" << std::endl; }
/* Funciones "internas" de la clase para inicialización y cierre. */
void SceneInit(); //Te calienta y prepara la casa al llegar.
void SceneClean(); //Te deja todo limpio y reluciente al salir.
// ¿Esto sirve para algo?
//void loadDataFromFile(std::string path);
/*
Métodos de los estados de la escena.
Habrán de ser sobrecargardos por las escenas del usuario.
*/
//Se crean todos los objetos y se carga todo lo necesario para la escena.
virtual void SceneLoad() = 0;
/*
* 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; }
/*
* 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 std::string GetName() { return _sceneName; }
protected:
inline bool IsLoaded() { return loaded; }
//Nombre de la escena. Para identificarla en el SceneManager.
std::string _sceneName = "NullScene";
bool loaded = false;
protected:
//Almacena el ID actual, permitiendo generar un ID nuevo para cada Scene que se instancie.
//static uint16_t currentID;
std::string _sceneName;
//std::vector<Entity> _entidades;
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; }
};
}
+119 -77
View File
@@ -1,8 +1,5 @@
#include "SceneManager.h"
#include "Scene.h"
#include "SceneBuilder.h"
#include "Logging/Logger.h"
#include <iostream>
@@ -10,91 +7,136 @@
namespace UE
{
void SceneManager::InitSceneManager(SceneBuilder* sceneBuilder)
{
_sceneBuilder = sceneBuilder;
void SceneManager::InitSceneManager()
{
UE_LOG_INFO("Se ha inicializado el SceneManager.");
}
UE_LOG_INFO("Se ha inicializado el SceneManager.");
}
void SceneManager::CleanSceneManager()
{
for (auto& it : _loadedScenes)
{
Scene* sc = it.second;
sc->SceneClean();
delete sc;
}
void SceneManager::CleanSceneManager()
{
if (_currentScene != nullptr)
{
_currentScene->SceneUnload();
delete _currentScene;
}
_loadedScenes.clear();
//for (auto& it : _scenes)
//{
// Scene* sc = it.second;
// sc->SceneClean();
// delete sc;
//}
if (_currentScene != nullptr)
{
_currentScene = nullptr;
}
//_scenes.clear();
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();
}
//Cambiamos la escena activa por la nueva.
_currentScene = _loadedScenes.at(name);
}
}
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;
}
//Si todo está correcto.
//Si tenemos campo libre, pista libre, punto rojo.
//Descargamos.
_loadedScenes.at(name)->SceneUnload();
_loadedScenes.erase(name);
}
//void SceneManager::AddScene(Scene* sceneToAdd)
//{
// _scenes.insert(std::make_pair(sceneToAdd->GetName(), sceneToAdd));
// sceneToAdd->SceneInit();
// UE_LOG_INFO("Se ha a�adido la escena {0} al SceneManager.", sceneToAdd->GetName());
//}
bool SceneManager::IsSceneLoaded(std::string name)
{
//Comprobamos si existe la escena indicada.
if(_loadedScenes.find(name) != _loadedScenes.end())
{
//Si la encontramos, existe.
return true;
}
return false;
}
std::string SceneManager::GetCurrentSceneName()
{
return _currentScene->GetName();
}
//Scene* SceneManager::GetScenePtr(std::string sceneName)
//{
// if (_scenes.find(sceneName) == _scenes.end())
// {
// UE_LOG_ERROR("No se ha encontrado la escena indicada.");
// return nullptr;
// }
// return _scenes.at(sceneName);
//}
Scene* SceneManager::GetCurrentScenePtr()
{
return _currentScene;
}
std::string SceneManager::GetActiveSceneName()
{
return _currentScene->GetName();
}
//void SceneManager::LoadScene(std::string sceneName)
//{
// if (_currentScene != nullptr)
// {
// _currentScene->SceneUnload();
// delete _currentScene;
// }
// _currentScene = _scenes.at(sceneName);
// _currentScene->SceneLoad();
//}
void SceneManager::NewLoadScene(int sceneID)
{
if (_currentScene != nullptr)
{
_currentScene->SceneUnload();
delete _currentScene;
}
_currentScene = _sceneBuilder->InstanciateScene(sceneID);
_currentScene->SceneLoad();
}
void SceneManager::UpdateScene()
{
_currentScene->SceneUpdate();
}
void SceneManager::UpdateScene()
{
_currentScene->SceneUpdate();
}
}
+90 -51
View File
@@ -1,72 +1,111 @@
#pragma once
#include "Scene/Scene.h"
#include <string>
#include <vector>
#include <unordered_map>
//
// Habría que implemetar un sistema para cambiar de escena.
// La cuestión sería almecenar el ID actual o algo así.
// 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.
// 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....
//
// TODO:
// - Se podría plantear un sistema de carga asincrona para las escenas.
// - La variable "loaded" de las escenas no tiene mucha utilidad en este momento.
namespace UE
{
class Scene;
class SceneBuilder;
/* Gestiona todas escenas. Las carga, descargar y ejecuta. */
class SceneManager
{
/* Gestiona todas escenas. Las carga, descargar y ejecuta. */
class SceneManager
{
public:
/* Constructor */
SceneManager() {}
public:
void InitSceneManager(SceneBuilder* sceneBuilder);
void CleanSceneManager();
/* Constructor */
SceneManager()
{
InitSceneManager();
}
//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);
//Devuelve un ptr a la escena del ID especificado.
//Scene* GetScenePtr(std::string sceneName);
std::string GetActiveSceneName();
//Devuelve la escena activa.
inline Scene* GetActiveScenePtr() { return _currentScene; }
//Descarga la escena activa y carga la escena indicada.
//void LoadScene(std::string sceneName);
//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?
void UpdateScene();
// ¿Esto sirve para algo?
//void LoadSceneDataFromFile(std::string filePath);
~SceneManager()
{
CleanSceneManager();
}
private:
Scene* _currentScene = nullptr;
//Inicializa el ScenenManager (En caso de haber algo que iniciar.)
void InitSceneManager();
//Limpia los contenedores de Scenes y descarga las escenas cargadas.
void CleanSceneManager();
SceneBuilder* _sceneBuilder = nullptr;
/*
* 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);
//Almacenamos un ptr a las diferentes escenas disponibles.
//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;
/*
* Cambia la escena activa por la indicada.
* Si la indicada no está cargada, no hace nada.
*/
void SwitchScene(std::string name);
/*
* Carga la escena indicada.
* Cambia la escena actual por la nueva escena.
*/
void LoadAndSwitchScene(Scene* sceneToLoad);
/*
* 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 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();
private:
//Ptr a la escena que está activa en ese momento.
Scene* _currentScene = nullptr;
//Almacenamos un ptr a todas las escenas cargadas en ese momento.
//o, al menos, lo intentamos.
std::unordered_map<std::string, Scene*> _loadedScenes;
};
}
+2 -2
View File
@@ -15,7 +15,7 @@ namespace UE
public:
//-------------------
//---- Métodos ------
//---- Métodos ------
//-------------------
static void StartFrame();
@@ -36,7 +36,7 @@ namespace UE
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;
};
-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 "UberGame1.h"
#include "GameScenes.hpp"
#include "UberEngine.h"
@@ -33,7 +32,6 @@ int main(int argc, char* args[])
return 0;
}
void Init()
{
UE::Logger::InitLogger();
@@ -51,7 +49,8 @@ void Load()
//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.
//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; }
Game::GetSceneManager()->GetActiveScenePtr()->SceneHandleEvents(&eventHandler);
Game::GetSceneManager()->GetCurrentScenePtr()->SceneHandleEvents(&eventHandler);
if (eventHandler.type == SDL_QUIT)
{
_quit = true;
@@ -113,10 +112,10 @@ void Loop()
switch (eventHandler.key.keysym.sym)
{
case SDLK_1:
Game::GetSceneManager()->NewLoadScene(LasEscenas::mainMenu);
Game::GetSceneManager()->LoadAndSwitchScene(new MainScene());
break;
case SDLK_2:
Game::GetSceneManager()->NewLoadScene(LasEscenas::nivel1);
Game::GetSceneManager()->LoadAndSwitchScene(new TestScene2());
break;
default:
break;
@@ -159,7 +158,7 @@ void Loop()
Game::GetRenderer()->SetCamPosition(camPos.x, camPos.y);
}
Game::GetSceneManager()->GetActiveScenePtr()->SceneUpdate();
Game::GetSceneManager()->GetCurrentScenePtr()->SceneUpdate();
//Game::GetRenderer()->QueueDrawCall(4, DestR2, test1);
//Game::GetRenderer()->QueueDrawCall(1, DestR, background);
@@ -173,7 +172,7 @@ void Loop()
Game::GetRenderer()->NewFrame();
//Renderiza la escena.
Game::GetSceneManager()->GetActiveScenePtr()->SceneRender();
Game::GetSceneManager()->GetCurrentScenePtr()->SceneRender();
//As� podemos renderizar cosas de ImGui cuando estemos entre NewFrame y EndFrame.
bool show = true;
+4 -1
View File
@@ -23,7 +23,10 @@ class MainScene : public UE::Scene
{
public:
MainScene(std::string sceneName) : Scene(sceneName) {}
MainScene() : Scene("MainScene")
{
//_sceneName = "MainScene";
}
void SceneLoad() override
+4 -1
View File
@@ -18,7 +18,10 @@ class TestScene2 : public UE::Scene
{
public:
TestScene2(std::string sceneName) : Scene(sceneName) {}
TestScene2() : Scene("TestScene")
{
//_sceneName = "TestScene";
}
void SceneLoad() override
{
+5 -9
View File
@@ -5,9 +5,6 @@
#include "Assets/AssetManager.h"
#include "Scene/SceneManager.h"
#include "Scene/SceneBuilder.h"
#include "GameScenes.hpp"
//Sobrecarga de SceneBuilder que devuelve las escenas correctas para este juego.
//#include "GameScenes.hpp"
@@ -16,24 +13,23 @@ UE::Renderer* Game::mainRenderer;
UE::AssetManager* Game::asManager;
UE::SceneManager* Game::scManager;
GameScenes Game::_sceneBuilder;
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->InitRenderer();
UE_LOG_INFO("Renderer Created.");
//Cargamos el AssetManager
asManager = new UE::AssetManager(mainRenderer->GetSDLRenderer());
asManager->InitAssetManager();
UE_LOG_INFO("AssetManager Created.");
//Creamos el SceneBuilder de este juego.
_sceneBuilder = GameScenes();
//Cargamos el SceneManager
scManager = new UE::SceneManager();
scManager->InitSceneManager(&_sceneBuilder);
}
void Game::CleanGame()
-5
View File
@@ -5,11 +5,8 @@ namespace UE
class Renderer;
class AssetManager;
class SceneManager;
class SceneBuilder;
}
class GameScenes;
class Game
{
public:
@@ -25,6 +22,4 @@ private:
static UE::Renderer* mainRenderer;
static UE::AssetManager* asManager;
static UE::SceneManager* scManager;
static GameScenes _sceneBuilder;
};