SFML и C++ Уроки \ Разработка игр › Форумы › SFML Graphics › при перетаскивании окна пропадают монстры и игрок › Ответ в теме: при перетаскивании окна пропадают монстры и игрок
Для избегания таких вещей делают перемещение обьектов привязанно не ко времени, а к некому игровому тику который срабатывает каждый интервал времени.
Для привязки всего к тику придётся переписывать половину кода. Для себя я набросал два класса которые отвечают за подобную механику обновления обьектов. Можешь спокойно использовать и модифицировать их как хочешь. Учти что:
1. Твой код должен содержатся в классе – наследнике от State и в int main() должна быть обьявлена конструкция:
IApp app(window);
app.run(new ИмяНовогоКлассаState(&window))
2. onHandle(sf::Event event) будет вызыватся на каждый ивент содержащийся в пуле окна
3. onUpdate(sf::Time delta) и onDraw(sf::RenderWindow window) не всегда будут вызыватся одновременно за один цикл (если отрисовка займёт слишком много времени следующее обновление будет вызвано столько раз, сколько излишнего времени заняла отрисовка и наоборот, если отрисовка проходит быстрее чем временной шаг то будет снова вызыватся отрисовка пока не пройдт времени больше чем временной шаг).
Ну, думаю и ежу понятно что код инициализации должен быть в конструкторе класса, логика в onUpdate а отрисовка в onDraw. Если нужно перехватить вводимый игроком текст или ещё что-то связаное с sf::Event – ловим в onHandle.
Узлы, добавленые в addNode(Node * node), будут иметь приоритет заданый переменной Z и всегда приоритет ниже Parent(Т.е. класса в котором он был добавлен)
Ну и собственно классы(Разбиты на хидеры и .cpp, как и положено). Кстати, если сможешь понять как можно использовать класс-узел (Node) это сильно сможет облегчить тебе жизнь в дальнейшем програмировании игры (В частности при помощи этого класса можно спокойно отрисовывать спрайты слоями, т.е. вначале то что должно быть на заднем плане, дальше на главном а после то что должно быть поверх главного плана)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
//IApp.h #ifndef IAPP_H #define IAPP_H #include <vector> #include <SFML/Graphics.hpp> class State;//Forward declaration of State так как присутствует рекурсивное объявление /// \brief This class manages the different states of the game. class IApp { public: IApp(sf::RenderWindow& window); ~IApp(); /// \brief Runs the director with the passed state as starting state void run(State* state); /// \brief Replaces the current state void replaceState(State* state); /// \brief Push a new state on top of the stack void pushState(State* state); /// \brief Pop the top state void popState(); /// \brief The timestep for the update function void setTimestep(sf::Time timestep); private: void draw(sf::RenderWindow* window); void handle(const sf::Event& event); void update(); void doPop(); bool running; bool shouldPop; std::vector<State*> states; sf::RenderWindow& window; sf::Time accumulator; sf::Time timestep; sf::Clock frameClock; }; #endif // IAPP_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
//IApp.cpp #include "IApp.h" #include "State.h" #include <iostream> //#include <tmx/Log.h> //using namespace tmx; IApp::IApp(sf::RenderWindow& window) : window(window), running(false), shouldPop(false), timestep(sf::milliseconds(20)), accumulator(sf::Time::Zero) { } IApp::~IApp() { //LOG("deleting app", Logger::Type::Info); for(auto itr = states.begin(); itr != states.end(); itr++) delete (*itr); states.clear(); } void IApp::run(State* state) { pushState(state); running = true; sf::Event event; frameClock.restart(); while(running) { if(!shouldPop) { //handle while(window.pollEvent(event)) { handle(event); } //update accumulator += frameClock.getElapsedTime(); while(accumulator >= timestep) { update(); accumulator -= timestep; } frameClock.restart(); //draw window.clear(); draw(&window); window.display(); } else { doPop(); frameClock.restart(); } } } void IApp::setTimestep(sf::Time timestep) { this->timestep = timestep; } void IApp::replaceState(State* state) { //LOG("replacing state", Logger::Type::Info); //LOG("states: " + states.size(),Logger::Type::Info); popState(); // store and init the new state state->setDirector(this); state->setWindow(&window); states.insert(states.end() - 1, state); LOG("states: " + states.size(), Logger::Type::Info); } void IApp::pushState(State* state) { //LOG("Pushing state", Logger::Type::Info); //LOG("states: " + states.size(), Logger::Type::Info); state->setDirector(this); state->setWindow(&window); // pause current state if ( !states.empty() ) states.back()->pause(); // store and init the new state states.push_back(state); //LOG("states: " + states.size(), Logger::Type::Info); } void IApp::doPop() { //LOG("Popping state", Logger::Type::Info); //LOG("states: " + states.size(), Logger::Type::Info); shouldPop = false; // cleanup the current state if ( !states.empty() ) { //LOG("deleting state", Logger::Type::Info); delete states.back(); //LOG("state deleted", Logger::Type::Info); states.pop_back(); } // resume previous state if ( !states.empty() ) states.back()->resume(); else { running = false; window.close(); } //LOG("states: " + states.size(), Logger::Type::Info); } void IApp::popState() { shouldPop = true; } void IApp::handle(const sf::Event& event) { if(!states.empty()) states.back()->handle(event); } void IApp::update() { if(!states.empty()) states.back()->update(timestep); } void IApp::draw(sf::RenderWindow* window) { if(!states.empty()) states.back()->draw(window); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//State.h #ifndef STATE_H #define STATE_H #include "IApp.h" //#include "ResourceManager.h" #include "Node.h" /// \brief The base class for states that can be added to a director class State : public Node { friend class IApp; public: /// \brief Constructor State(); virtual ~State(){}; /// \brief Called when another state is pushed on top of the stack. virtual void pause(){}; /// \brief Called when the state becomes the top of the stack. virtual void resume(){}; protected: IApp* app; void setApp(IApp* app); private: }; #endif // STATE_H |
1 2 3 4 5 6 7 8 9 10 11 12 |
//State.cpp #include "State.h" State::State() : Node("State") { setZ(-1000); } void State::setApp(IApp* app) { this->app= app; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
//Node.h #ifndef NODE_H #define NODE_H #include <SFML/Graphics.hpp> class Node { public: Node(const std::string& name = "Node"); virtual ~Node(); std::string getName(); void setName(const std::string& name); void draw(sf::RenderWindow* window); void update(sf::Time delta); void handle(const sf::Event& event); void addNode(Node* node); void removeNode(Node* node); void setWindow(sf::RenderWindow* window); int getZ() const; void setZ(int z); Node* getParent(); void setParent(Node* parentnode); std::vector<Node*>& getChildren(); protected: virtual void onDraw(sf::RenderWindow* window){} virtual void onUpdate(sf::Time delta){} virtual void onHandle(const sf::Event& event){} virtual void onWindowSet(){} Node* parent; sf::RenderWindow* window; private: std::vector<Node*> children; std::string name; int z; }; #endif // NODE_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
//Node.cpp #include "Node.h" #include <algorithm> //#include <tmx/Log.h> //using namespace tmx; bool sortByZValue(const Node* a, const Node* b) { return (a->getZ() < b->getZ()); } Node::Node(const std::string& name) : name(name), parent(NULL), z(0), window(NULL) { //ctor } Node::~Node() { for(Node* node : children) { //LOG("deleting node: " + node->getName(),Logger::Type::Info); delete node; } } std::string Node::getName() { return name; } void Node::setName(const std::string& name) { this->name = name; } void Node::setZ(int z) { this->z = z; } int Node::getZ() const { return z; } void Node::setWindow(sf::RenderWindow* window) { this->window = window; for(Node* node : children) node->setWindow(window); onWindowSet(); } void Node::draw(sf::RenderWindow* window) { onDraw(window); for(Node* node : children) node->draw(window); } void Node::update(sf::Time delta) { onUpdate(delta); for(Node* node : children) node->update(delta); } void Node::handle(const sf::Event& event) { onHandle(event); for(Node* node : children) node->handle(event); } void Node::addNode(Node* node) { node->setParent(this); node->setWindow(window); children.push_back(node); std::sort(begin(children), end(children), sortByZValue); } void Node::removeNode(Node* node) { for(auto itr = children.begin(); itr != children.end(); itr++) { if(node == (*itr)) { children.erase(itr); return; } } } Node* Node::getParent() { return parent; } void Node::setParent(Node* parentnode) { parent = parentnode; } std::vector<Node*>& Node::getChildren() { return children; } |