Préchargement des ressources avant le démarrage du jeu pour

éviter l'erreur type "ne répond pas"
This commit is contained in:
Mattéo Delabre 2016-04-10 12:27:06 +02:00
parent 13fc2e3b92
commit 6eaa4fb77f
6 changed files with 108 additions and 67 deletions

7
CMakeLists.txt vendored
View File

@ -32,8 +32,15 @@ endif()
# Recherche des librairies # Recherche des librairies
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}" ${CMAKE_MODULE_PATH})
add_executable(ptf ${SOURCES}) add_executable(ptf ${SOURCES})
find_package(SFML 2 REQUIRED system window graphics network audio) find_package(SFML 2 REQUIRED system window graphics network audio)
find_package(Boost 1.60.0 COMPONENTS system filesystem)
include_directories(${SFML_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(ptf ${SFML_LIBRARIES}) target_link_libraries(ptf ${SFML_LIBRARIES})
target_link_libraries(ptf ${Boost_LIBRARIES})
# Installation de l'exécutable # Installation de l'exécutable
install(TARGETS ptf DESTINATION bin) install(TARGETS ptf DESTINATION bin)

View File

@ -12,13 +12,12 @@
class Manager { class Manager {
private: private:
sf::RenderWindow window; sf::RenderWindow window;
ResourceManager resource_manager;
sf::Clock clock; sf::Clock clock;
sf::View default_view; sf::View default_view;
sf::String title; sf::String title;
ResourceManager resource_manager;
std::vector<sf::Event> events;
std::shared_ptr<State> state; std::shared_ptr<State> state;
std::shared_ptr<State> next_state; std::shared_ptr<State> next_state;

View File

@ -3,6 +3,7 @@
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp> #include <SFML/Audio.hpp>
#include <boost/filesystem.hpp>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <fstream> #include <fstream>
@ -16,29 +17,34 @@
*/ */
class ResourceManager { class ResourceManager {
private: private:
std::string resources_dir; bool preloaded;
boost::filesystem::path textures_path;
std::unordered_map<std::string, std::unique_ptr<sf::Texture>> textures; std::unordered_map<std::string, std::unique_ptr<sf::Texture>> textures;
boost::filesystem::path fonts_path;
std::unordered_map<std::string, std::unique_ptr<sf::Font>> fonts; std::unordered_map<std::string, std::unique_ptr<sf::Font>> fonts;
boost::filesystem::path levels_path;
boost::filesystem::path musics_path;
float music_volume; float music_volume;
sf::Music music; sf::Music music;
public: public:
ResourceManager(); ResourceManager();
~ResourceManager();
/** /**
* Récupère une image. Réutilise l'image déjà chargée * Précharge toutes les ressources préchargeables
* si elle l'a déjà é, sinon, tente de la charger */
* depuis son emplacement void preload();
/**
* Récupère une texture préchargée
*/ */
sf::Texture& getTexture(std::string name); sf::Texture& getTexture(std::string name);
/** /**
* Récupère la police demandée. Réutilise une police * Récupère une police préchargée
* déjà chargée si elle a déjà é demandée, sinon, la
* charge depuis son emplacement
*/ */
sf::Font& getFont(std::string name); sf::Font& getFont(std::string name);

View File

@ -52,6 +52,9 @@ Editor::~Editor() {}
void Editor::begin() { void Editor::begin() {
Level::begin(); Level::begin();
getResourceManager().stopMusic();
// TODO: on doit arrêter la musique car celle du
// niveau est chargée par dessous dans level.. C'est sale
getResourceManager().playMusic("editor.ogg"); getResourceManager().playMusic("editor.ogg");
getWindow().setFramerateLimit(Manager::FPS); getWindow().setFramerateLimit(Manager::FPS);
} }

View File

@ -1,13 +1,21 @@
#include <iostream>
#include "manager.hpp" #include "manager.hpp"
const unsigned int Manager::FPS = 60; const unsigned int Manager::FPS = 60;
const sf::Time Manager::FRAME_TIME = sf::seconds(1.f / Manager::FPS); const sf::Time Manager::FRAME_TIME = sf::seconds(1.f / Manager::FPS);
Manager::Manager() : window( Manager::Manager() : default_view(window.getDefaultView()),
title(sf::String(L"")), state(NULL), next_state(NULL), running(false) {
// préchargement des textures
resource_manager.preload();
// création de la fenêtre (après avoir préchargé les ressources,
// on évite ainsi tout lag pendant le traitement des événements)
window.create(
sf::VideoMode(704, 480), "Skizzle", sf::Style::Default, sf::VideoMode(704, 480), "Skizzle", sf::Style::Default,
sf::ContextSettings(0, 0, 2) sf::ContextSettings(0, 0, 2)
), default_view(window.getDefaultView()), title(sf::String(L"")), );
state(NULL), next_state(NULL), running(false) {} }
void Manager::start() { void Manager::start() {
running = true; running = true;

View File

@ -1,86 +1,104 @@
#include "resource_manager.hpp" #include "resource_manager.hpp"
#include "whereami.h" #include <iostream>
#include <cstring> #include <cstring>
// définition du séparateur de fichiers en fonction using dir_iter = boost::filesystem::directory_iterator;
// du type de système using fs_path = boost::filesystem::path;
#ifdef _WIN32
const std::string SEP = "\\";
#else
const std::string SEP = "/";
#endif
ResourceManager::ResourceManager() : music_volume(5) {
// on récupère le chemin actuel de l'exécutable pour pouvoir accéder
// au dossier des ressources qui est situé dans le même dossier
int length = wai_getExecutablePath(NULL, 0, NULL), dirname_length;
std::unique_ptr<char[]> buffer = std::unique_ptr<char[]>(new char[length + 1]);
wai_getExecutablePath(buffer.get(), length, &dirname_length);
if (length == 0) {
throw std::runtime_error("Impossible de déterminer le chemin actuel");
}
buffer.get()[length] = '\0';
std::string base_dir = std::string(buffer.get()).substr(0, dirname_length);
resources_dir = base_dir + SEP + "res" + SEP;
ResourceManager::ResourceManager() : preloaded(false), music_volume(20) {
// initialisation de la musique en bouclage et au volume par défaut // initialisation de la musique en bouclage et au volume par défaut
music.setLoop(true); music.setLoop(true);
music.setVolume(music_volume); music.setVolume(music_volume);
} }
ResourceManager::~ResourceManager() { void ResourceManager::preload() {
textures.clear(); if (preloaded) {
fonts.clear(); return;
} }
sf::Texture& ResourceManager::getTexture(std::string name) { fs_path current = boost::filesystem::current_path();
// si la texture est déjà chargée, on l'utilise directement dir_iter end;
if (textures.count(name) > 0) {
return *textures[name]; // on garde une référence aux chemins des différentes ressources
} textures_path = current / "res/textures";
fonts_path = current / "res/fonts";
levels_path = current / "res/levels";
musics_path = current / "res/musics";
// préchargement de toutes les textures
for (dir_iter it(textures_path); it != end; ++it) {
if (boost::filesystem::is_regular_file(it->path())) {
std::string full_path = boost::filesystem::canonical(it->path()).string();
std::string name = it->path().filename().string();
auto texture = std::unique_ptr<sf::Texture>(new sf::Texture); auto texture = std::unique_ptr<sf::Texture>(new sf::Texture);
std::cout << "Chargement de la texture " << name << "... ";
// tente de charger la texture dans le chemin "res/textures/name.png" if (!texture->loadFromFile(full_path)) {
if (!texture->loadFromFile(resources_dir + SEP + "textures" + SEP + name)) { std::cerr << "ERREUR!" << std::endl;
throw std::runtime_error( } else {
"Impossible de charger l'image \"" + name + "\"" std::cout << "OK!" << std::endl;
);
} }
textures[name] = std::move(texture); textures[name] = std::move(texture);
}
}
// préchargement de toutes les polices
for (dir_iter it(fonts_path); it != end; ++it) {
if (boost::filesystem::is_regular_file(it->path())) {
std::string full_path = boost::filesystem::canonical(it->path()).string();
std::string name = it->path().filename().string();
auto font = std::unique_ptr<sf::Font>(new sf::Font);
std::cout << "Chargement de la police " << name << "... ";
if (!font->loadFromFile(full_path)) {
std::cerr << "ERREUR!" << std::endl;
} else {
std::cout << "OK!" << std::endl;
}
fonts[name] = std::move(font);
}
}
preloaded = true;
}
sf::Texture& ResourceManager::getTexture(std::string name) {
if (textures.count(name) == 0) {
throw std::runtime_error(
"Impossible de charger la texture inexistante : " + name
);
}
return *textures[name]; return *textures[name];
} }
sf::Font& ResourceManager::getFont(std::string name) { sf::Font& ResourceManager::getFont(std::string name) {
// si la police est déjà chargée, on l'utilise directement if (fonts.count(name) == 0) {
if (fonts.count(name) > 0) {
return *fonts[name];
}
auto font = std::unique_ptr<sf::Font>(new sf::Font);
// tente de charger la police depuis le dossier "res/fonts"
if (!font->loadFromFile(resources_dir + SEP + "fonts" + SEP + name)) {
throw std::runtime_error( throw std::runtime_error(
"Impossible de charger la police \"" + name + "\"" "Impossible de charger la police inexistante : " + name
); );
} }
fonts[name] = std::move(font);
return *fonts[name]; return *fonts[name];
} }
std::string ResourceManager::getLevelPath(std::string name) { std::string ResourceManager::getLevelPath(std::string name) {
return resources_dir + SEP + "levels" + SEP + name; return boost::filesystem::canonical(levels_path / name).string();
} }
void ResourceManager::playMusic(std::string name) { void ResourceManager::playMusic(std::string name) {
// tente de charger la musique depuis le dossier "res/musics" // tente de charger la musique depuis le dossier "res/musics"
if (!music.openFromFile(resources_dir + SEP + "musics" + SEP + name)) { std::string full_path = boost::filesystem::canonical(musics_path / name).string();
throw std::runtime_error("Impossible de charger la musique : " + name); std::cout << "Lecture de la musique " << name << "... ";
if (!music.openFromFile(full_path)) {
std::cerr << "ERREUR!" << std::endl;
} else {
std::cout << "OK!" << std::endl;
} }
music.play(); music.play();