【发布时间】:2017-06-23 10:17:03
【问题描述】:
我正在使用 C++ 中的 SFML 制作游戏。我想将精灵的创建分离到一个单独的函数中,以减少运行函数(包含游戏循环的函数)中的混乱。
我创建了一个名为 AssetHolder 的结构,以 std::map<std::string, resource_type> 的形式保存各种资源,如纹理、声音等。考虑下面的代码 sn-ps。
assetHolder.h
#include<SFML/Graphics.hpp>
#include<map>
#include<string>
struct AssetHolder {
std::map<std::string, sf::Texture*> textures;
//Other resources I may add in future.
};
menuScene.cpp:
#include"menuScene.h"
namespace menuScene {
std::map<std::string, sf::Sprite> sprites;
void load(AssetHolder &assets) {
sprites["background"].setTexture(*assets.textures["menuBackgroundTex"]);
}
void render(sf::RenderWindow &window) {
window.clear(sf::Color::Magenta);
window.draw(sprites["background"]);
window.display();
}
Scene run(sf::RenderWindow &window) {
while(true) {
sf::Event event;
while(window.pollEvent(event)) {
if(event.type == sf::Event::Closed) {
return Scene::Null;
}
}
render(window);
}
}
}
游戏.cpp
#include"game.h"
namespace game {
sf::RenderWindow window;
AssetHolder assets;
Scene currentScene = Scene::Menu;
void init() {
window.create(sf::VideoMode(640, 360), "Platformer");
window.setFramerateLimit(60);
sf::Texture menuBackgroundTex;
menuBackgroundTex.loadFromFile("assets/images/menuBackgroundTex.png");
menuBackgroundTex.setRepeated(true);
assets.textures["menuBackgroundTex"] = &menuBackgroundTex;
menuScene::load(assets);
}
void loop() {
while(window.isOpen()) {
switch(currentScene) {
case Scene::Menu: {
currentScene = menuScene::run(window);
break;
}
case Scene::Play: {
currentScene = playScene::run(window);
break;
}
case Scene::Exit: {
currentScene = exitScene::run(window);
break;
}
case Scene::Null: {
window.close();
break;
}
}
}
}
}
在我的主函数中,我只是调用game::init() 和game::loop()。
但是当我运行这段代码时,它不起作用。程序不会崩溃。它只是显示一个白色矩形来代替精灵。我猜是因为加载功能结束后,数据被删除了。
那我怎样才能正确地做到这一点呢?
PS:如果你想知道什么是 Scene 以及我为什么要返回它; Scene 是一个枚举,表示可能的场景/游戏状态。一个场景中的run函数返回下一个场景。
【问题讨论】:
-
你必须调用你的加载函数,就像你调用你的渲染函数一样。在你的游戏循环之前添加
load(assets)。 -
@OutOfBound 我在另一个文件中调用它:game.cpp。我会把它添加到问题中。
-
您将场景命名空间而不是继承类是否有某些特定原因?这样你就可以在构造函数和析构函数中添加资源加载/销毁,并使用一个通用接口来定义它们。
-
@Mario 好点。我没有想到。我使用命名空间的原因是这里有很多答案建议使用命名空间而不是“静态”类。我的场景不需要多个实例。因此,使用静态成员或使用命名空间创建类是唯一的选择。我认为这一定是一种好的做法。非常感谢您的帮助! :)
-
仅仅因为你不需要一个类的多个实例并不意味着所有的方法都应该是静态的。事实上,这很可能是一个迹象,它不应该是。定义一个只包含成员并且只有实例的类是非常常见的,因为类的资源可以由构造函数和析构函数很好地处理。如果你想在你的程序中添加另一个实例,你可以这样做,而不需要对你的代码库进行任何重大更改。
标签: c++ sfml code-organization