From 834d57ea32275459014d3863373db5e63086d612 Mon Sep 17 00:00:00 2001 From: h4570 Date: Sun, 31 Jul 2022 11:52:49 +0200 Subject: [PATCH] demo memory leak fix --- demo/inc/state/state_manager.hpp | 52 ++++++++++++++++--- demo/inc/states/game/game_state.hpp | 40 ++++++++++++++ demo/inc/states/intro/intro_state.hpp | 1 + .../intro/states/intro_press_key_state.hpp | 4 +- demo/src/demo_game.cpp | 16 ++++-- demo/src/states/game/game_state.cpp | 50 ++++++++++++++++++ demo/src/states/intro/intro_state.cpp | 26 ++++++++-- .../intro/states/intro_press_key_state.cpp | 49 ++++++++++------- .../intro/states/intro_ps2dev_state.cpp | 27 ++++++---- .../states/intro/states/intro_tyra_state.cpp | 39 ++++++++------ 10 files changed, 242 insertions(+), 62 deletions(-) create mode 100644 demo/inc/states/game/game_state.hpp create mode 100644 demo/src/states/game/game_state.cpp diff --git a/demo/inc/state/state_manager.hpp b/demo/inc/state/state_manager.hpp index 028c903..18ad797 100644 --- a/demo/inc/state/state_manager.hpp +++ b/demo/inc/state/state_manager.hpp @@ -19,21 +19,57 @@ namespace Demo { template class StateManager { public: - StateManager(const StateTypeT& initialState) { + StateManager(const StateTypeT& t_initialState, + const StateTypeT& t_exitState) { stateInitialized = false; - currentState = initialState; + currentState = t_initialState; + exitState = t_exitState; } - ~StateManager() { - for (auto& state : states) { - delete state; - } - } + ~StateManager() { freeAll(); } const StateTypeT& getCurrentState() const { return currentState; } + const StateTypeT& getExitState() const { return exitState; } + + bool finished() const { return currentState == exitState; } + + std::vector*>* getAll() { return &states; } + + State* get(const StateTypeT& stateType) { + for (auto& state : states) { + if (state->getState() == stateType) { + return state; + } + } + return nullptr; + } + void add(State* state) { states.push_back(state); } + /** remove (without free) */ + void remove(const State* state) { + states.erase(std::remove(states.begin(), states.end(), state), + states.end()); + } + + /** free and remove */ + void free(const State* state) { + auto* found = get(state); + if (!found) return; + + remove(found); + delete found; + } + + /** free and remove all */ + void freeAll() { + for (auto& state : states) { + delete state; + } + states.clear(); + } + void update() { for (auto& state : states) { if (state->getState() == currentState) { @@ -57,7 +93,7 @@ class StateManager { private: bool stateInitialized; std::vector*> states; - StateTypeT currentState; + StateTypeT currentState, exitState; }; } // namespace Demo diff --git a/demo/inc/states/game/game_state.hpp b/demo/inc/states/game/game_state.hpp new file mode 100644 index 0000000..8a64f17 --- /dev/null +++ b/demo/inc/states/game/game_state.hpp @@ -0,0 +1,40 @@ +/* +# ______ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licenced under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "state/global_state_type.hpp" + +namespace Demo { + +class GameState : public State { + public: + GameState(Engine* t_engine); + ~GameState(); + + const GlobalStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + void update(); + + /** @return Next game state */ + GlobalStateType onFinish(); + + private: + GlobalStateType state; + bool _wantFinish; + bool initialized; +}; + +} // namespace Demo diff --git a/demo/inc/states/intro/intro_state.hpp b/demo/inc/states/intro/intro_state.hpp index d8b4136..88d2f47 100644 --- a/demo/inc/states/intro/intro_state.hpp +++ b/demo/inc/states/intro/intro_state.hpp @@ -36,6 +36,7 @@ class IntroState : public State { private: GlobalStateType state; bool _wantFinish; + bool initialized; StateManager stateManager; }; diff --git a/demo/inc/states/intro/states/intro_press_key_state.hpp b/demo/inc/states/intro/states/intro_press_key_state.hpp index 49581ff..ffdba5a 100644 --- a/demo/inc/states/intro/states/intro_press_key_state.hpp +++ b/demo/inc/states/intro/states/intro_press_key_state.hpp @@ -33,11 +33,11 @@ class IntroPressKeyState : public State { void onStart(); - void update(); - /** @return Next game state */ IntroStateType onFinish(); + void update(); + private: void renderFiller(); void updateMap(); diff --git a/demo/src/demo_game.cpp b/demo/src/demo_game.cpp index 01a9d8f..532c20f 100644 --- a/demo/src/demo_game.cpp +++ b/demo/src/demo_game.cpp @@ -10,14 +10,24 @@ #include "demo_game.hpp" #include "states/intro/intro_state.hpp" +#include "states/game/game_state.hpp" namespace Demo { DemoGame::DemoGame(Engine* t_engine) - : engine(t_engine), stateManager(STATE_INTRO) {} + : engine(t_engine), stateManager(STATE_INTRO, STATE_EXIT) {} DemoGame::~DemoGame() {} -void DemoGame::init() { stateManager.add(new IntroState(engine)); } -void DemoGame::loop() { stateManager.update(); } +void DemoGame::init() { + stateManager.add(new IntroState(engine)); + stateManager.add(new GameState(engine)); +} +void DemoGame::loop() { + stateManager.update(); + + if (stateManager.finished()) { + exit(0); + } +} } // namespace Demo diff --git a/demo/src/states/game/game_state.cpp b/demo/src/states/game/game_state.cpp new file mode 100644 index 0000000..805f613 --- /dev/null +++ b/demo/src/states/game/game_state.cpp @@ -0,0 +1,50 @@ +/* +# ______ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licenced under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/game_state.hpp" +#include "file/file_utils.hpp" +#include "thread/threading.hpp" +#include "debug/debug.hpp" + +using Tyra::FileUtils; +using Tyra::Threading; + +namespace Demo { + +GameState::GameState(Engine* t_engine) : State(t_engine) { + state = STATE_GAME; + _wantFinish = false; + initialized = false; +} + +GameState::~GameState() {} + +void GameState::onStart() { + TYRA_LOG("Game. RAM: ", engine->info.getAvailableRAM(), "MB"); + + engine->audio.stopSong(); + initialized = true; +} + +GlobalStateType GameState::onFinish() { + if (!initialized) return STATE_EXIT; + + initialized = false; + + return STATE_EXIT; +} + +void GameState::update() { + engine->renderer.beginFrame(); + Threading::switchThread(); + engine->renderer.endFrame(); +} + +} // namespace Demo diff --git a/demo/src/states/intro/intro_state.cpp b/demo/src/states/intro/intro_state.cpp index 0deadd8..063dc2c 100644 --- a/demo/src/states/intro/intro_state.cpp +++ b/demo/src/states/intro/intro_state.cpp @@ -21,26 +21,44 @@ using Tyra::FileUtils; namespace Demo { IntroState::IntroState(Engine* t_engine) - : State(t_engine), stateManager(STATE_PS2DEV) { + : State(t_engine), stateManager(STATE_PS2DEV, STATE_INTRO_END) { state = STATE_INTRO; _wantFinish = false; + initialized = false; } IntroState::~IntroState() {} void IntroState::onStart() { + TYRA_LOG("Intro. RAM: ", engine->info.getAvailableRAM(), "MB"); + engine->audio.loadSong(FileUtils::fromCwd("intro/intro.wav")); engine->audio.setSongLoop(false); engine->audio.setSongVolume(80); - engine->audio.playSong(); + // engine->audio.playSong(); stateManager.add(new IntroPs2DevState(engine)); stateManager.add(new IntroTyraState(engine)); stateManager.add(new IntroPressKeyState(engine)); + + initialized = true; } -void IntroState::update() { stateManager.update(); } +GlobalStateType IntroState::onFinish() { + if (!initialized) return STATE_GAME; -GlobalStateType IntroState::onFinish() { return STATE_EXIT; } + stateManager.freeAll(); + + initialized = false; + return STATE_GAME; +} + +void IntroState::update() { + stateManager.update(); + + if (stateManager.finished()) { + _wantFinish = true; + } +} } // namespace Demo diff --git a/demo/src/states/intro/states/intro_press_key_state.cpp b/demo/src/states/intro/states/intro_press_key_state.cpp index 8b146e7..aec2346 100644 --- a/demo/src/states/intro/states/intro_press_key_state.cpp +++ b/demo/src/states/intro/states/intro_press_key_state.cpp @@ -37,26 +37,11 @@ IntroPressKeyState::IntroPressKeyState(Engine* t_engine) fillersOffset = -512.0F; } -IntroPressKeyState::~IntroPressKeyState() { - if (!initialized) return; - - for (u8 i = 0; i < mapRows; i++) - for (u8 j = 0; j < mapCols; j++) { - engine->renderer.core.texture.repository.free(mapTextures[i][j]->getId()); - delete mapSprites[i][j]; - } - - engine->renderer.core.texture.repository.free(fillerTexture->getId()); - delete fillerSprite; - - engine->renderer.core.texture.repository.free(logoTexture->getId()); - delete logoSprite; - - engine->renderer.core.texture.repository.free(pressKeyTexture->getId()); - delete pressKeySprite; -} +IntroPressKeyState::~IntroPressKeyState() {} void IntroPressKeyState::onStart() { + TYRA_LOG("Intro - presskey. RAM: ", engine->info.getAvailableRAM(), "MB"); + for (u8 i = 0; i < mapRows; i++) { for (u8 j = 0; j < mapCols; j++) { mapSprites[i][j] = new Sprite; @@ -104,6 +89,28 @@ void IntroPressKeyState::onStart() { initialized = true; } +IntroStateType IntroPressKeyState::onFinish() { + if (!initialized) return STATE_INTRO_END; + + for (u8 i = 0; i < mapRows; i++) + for (u8 j = 0; j < mapCols; j++) { + engine->renderer.core.texture.repository.free(mapTextures[i][j]->getId()); + delete mapSprites[i][j]; + } + + engine->renderer.core.texture.repository.free(fillerTexture->getId()); + delete fillerSprite; + + engine->renderer.core.texture.repository.free(logoTexture->getId()); + delete logoSprite; + + engine->renderer.core.texture.repository.free(pressKeyTexture->getId()); + delete pressKeySprite; + + initialized = false; + return STATE_INTRO_END; +} + void IntroPressKeyState::update() { engine->renderer.beginFrame(); @@ -116,6 +123,10 @@ void IntroPressKeyState::update() { mapDirection = 0; } + if (engine->pad.getClicked().Cross) { + _wantFinish = true; + } + const float offset = 0.1F; if (mapDirection == 0) { mapPosition += offset; @@ -172,8 +183,6 @@ void IntroPressKeyState::update() { engine->renderer.endFrame(); } -IntroStateType IntroPressKeyState::onFinish() { return STATE_INTRO_END; } - void IntroPressKeyState::renderFiller() { fillerSprite->position.x = -1.0F + fillersOffset; engine->renderer.renderer2D.render(fillerSprite); diff --git a/demo/src/states/intro/states/intro_ps2dev_state.cpp b/demo/src/states/intro/states/intro_ps2dev_state.cpp index dcdacd4..606ff9d 100644 --- a/demo/src/states/intro/states/intro_ps2dev_state.cpp +++ b/demo/src/states/intro/states/intro_ps2dev_state.cpp @@ -30,17 +30,12 @@ IntroPs2DevState::IntroPs2DevState(Engine* t_engine) : State(t_engine) { fadeoutActivated = false; } -IntroPs2DevState::~IntroPs2DevState() { - if (!initialized) return; - - delete sprite; - engine->renderer.core.texture.repository.free(texture->getId()); -} +IntroPs2DevState::~IntroPs2DevState() {} void IntroPs2DevState::onStart() { - const auto& settings = engine->renderer.core.getSettings(); + TYRA_LOG("Intro - ps2dev. RAM: ", engine->info.getAvailableRAM(), "MB"); - TYRA_LOG("Init!"); + const auto& settings = engine->renderer.core.getSettings(); initialDelayTimer.prime(); @@ -57,11 +52,25 @@ void IntroPs2DevState::onStart() { initialized = true; } +IntroStateType IntroPs2DevState::onFinish() { + if (!initialized) return STATE_TYRA; + + delete sprite; + engine->renderer.core.texture.repository.free(texture->getId()); + + initialized = false; + return STATE_TYRA; +} + void IntroPs2DevState::update() { engine->renderer.beginFrame(); if (initialDelayTimer.getTimeDelta() >= 60000) initialDelayElapsed = true; + if (engine->pad.getClicked().Cross) { + _wantFinish = true; + } + frameSkipper++; if (frameSkipper > 3) { frameSkipper = 0; @@ -94,6 +103,4 @@ void IntroPs2DevState::update() { engine->renderer.endFrame(); } -IntroStateType IntroPs2DevState::onFinish() { return STATE_TYRA; } - } // namespace Demo diff --git a/demo/src/states/intro/states/intro_tyra_state.cpp b/demo/src/states/intro/states/intro_tyra_state.cpp index f2650d8..70cca78 100644 --- a/demo/src/states/intro/states/intro_tyra_state.cpp +++ b/demo/src/states/intro/states/intro_tyra_state.cpp @@ -32,21 +32,11 @@ IntroTyraState::IntroTyraState(Engine* t_engine) : State(t_engine) { frameSkipper = 0; } -IntroTyraState::~IntroTyraState() { - if (!initialized) return; - - engine->renderer.core.texture.repository.free(tyraTexture->getId()); - engine->renderer.core.texture.repository.free(bgTexture->getId()); - engine->renderer.core.texture.repository.free(bg2Texture->getId()); - engine->renderer.core.texture.repository.free(fillerTexture->getId()); - - delete tyraSprite; - delete bgSprite; - delete bg2Sprite; - delete fillerSprite; -} +IntroTyraState::~IntroTyraState() {} void IntroTyraState::onStart() { + TYRA_LOG("Intro - tyra. RAM: ", engine->info.getAvailableRAM(), "MB"); + const auto& settings = engine->renderer.core.getSettings(); initialDelayTimer.prime(); @@ -90,6 +80,23 @@ void IntroTyraState::onStart() { initialized = true; } +IntroStateType IntroTyraState::onFinish() { + if (!initialized) return STATE_PRESS_KEY; + + engine->renderer.core.texture.repository.free(tyraTexture->getId()); + engine->renderer.core.texture.repository.free(bgTexture->getId()); + engine->renderer.core.texture.repository.free(bg2Texture->getId()); + engine->renderer.core.texture.repository.free(fillerTexture->getId()); + + delete tyraSprite; + delete bgSprite; + delete bg2Sprite; + delete fillerSprite; + + initialized = false; + return STATE_PRESS_KEY; +} + void IntroTyraState::update() { engine->renderer.beginFrame(); @@ -100,6 +107,10 @@ void IntroTyraState::update() { frameSkipper = 0; } + if (engine->pad.getClicked().Cross) { + _wantFinish = true; + } + const float slideUpMaxPost = -128.0F; if (initialDelayElapsed) { @@ -170,6 +181,4 @@ void IntroTyraState::renderFillers() { engine->renderer.renderer2D.render(fillerSprite); } -IntroStateType IntroTyraState::onFinish() { return STATE_PRESS_KEY; } - } // namespace Demo