Созданные ответы форума
-
АвторСообщения
-
1. Окно не реагирует ни на что т.к. в функции main нет обработчика Event’ов (или есть, но находится он после функции menu())
2. Создавать для каждого игрового состояния(меню, настройки, игра и т.д.) собственную функцию с циклом while внутри неправильно, дальше это может привести к большим проблемам. Цикл while желательно иметь один на всю игру.
Для этого лучше использовать паттерн State(состояние). Можешь загуглить полную его реализацию, я лишь вкратце опишу как он работает.
Для начала нужно создать класс Game для всей игры:
C++12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758class Game{public:Game(){// Инициализация всего, что общее для всей игры, например окно, евент//...// Можно прямо здесь инициализировать текущее состояние игрыstate = new MenuState(this);}~Game(){// То, что придется удалить, когда игра закроетсяdelete state;}// игровой циклvoid loop(){while (window.isOpen()){while (window.pollEvent(event)){// обработка событийstate->handleInput(event);switch(event.type){case sf::Event::Closed:close();return;}}// обновлениеstate->update(elapsed);// отрисовкаstate->draw(window);}}void changeState(GameState* newState){delete state;state = newState;}void close(){// закрытие игрыwindow.close();}private:sf::RenderWindow window;sf::Event event;float elapsedTime;// ...};Далее нужно создать базовый класс для состояний:
C++12345678910111213141516class GameState{GameState(Game* game){// указатель на игруthis->game = game;}virtual ~GameState() {}// чистые виртуальные методы состоянияvirtual void handleInput(sf::Event& event) = 0;virtual void update(float time) = 0;virtual void draw(sf::RenderTarget& window) = 0;protected:Game* game;};Теперь для каждого состояния игры можно делать свой класс. Покажу на примере меню:
C++123456789101112131415161718192021222324252627282930313233343536class MenuState : public GameState{public:MenuState(Game* game) : GameState(game){// Инициализация всего, что нужно конкретно для// этого состояния (текстуры, кнопки и т.д.)// ...}~MenuState() {}virtual void handleInput(sf::Event& event){// Обработка евентов, нажатий на кнопки и т.д.// ...if (/*нажата кнопка начала игры*/){// просим игру переключиться на геймплейgame->changeState(new GameProcessState(game));return; // (!)Важно сразу выходить из функции.}}virtual void update(float time){// обновление текущего состояния}virtual void draw(sf::RenderTarget& window){// отрисовка состояния}private:// текстуры, кнопки, спрайты и т.д.};И так для каждого состояния игры.
После этого функция main будет выглядеть следующим образом:
C++1234567int main(){Game game;game.loop();return 0;}Возможно, игра подтормаживает из-за того, что для каждого экземпляра “текста” выделяется его личный шрифт. В конструкторе класса текста ты предаешь шрифт как аргумент по значению, соответственно хранишь в каждом тексте копию шрифта. Так делать не обязательно, достаточно передать его по ссылке.
C++12345678910111213141516171819202122class Dam {public:float tX, tY; int size;float dy = -0.5;float lifeT = 0;bool life = true;Text t;Dam(float x, float y, String text, int size, Font& Fo){tX = x; tY = y;t.setFont(Fo);t.setCharacterSize(size);t.setString(text);}void update(float time){if (lifeT < 50) lifeT += 0.1*time;else { life = false; }t.setPosition(tX, tY);tY += dy*time;}};Ну начнем с того, что возможно ты делаешь что-то неправильно, если тебе нужен текст в отдельном списке. Ведь твоя задача так и звучит: “Нужно чтобы у каждого врага был свой текст со своим здоровьем”, а как минимум это уже значит, что текст должен быть в классе врага.
Но если вдруг возникла такая необходимость, то можно попробовать следующие варианты:- Вместо std::list использовать std::deque. В нем можно получать доступ к элементам по их номеру, а значит можно сделать так:
C++12345for(int i = 0; i < enemyArray.size(); i++){enemyArray[i].update(...);upArray[i].update(enemyArray[i].x, enemyArray[i].y...)}
Но нужно знать, что в этом массиве доступ к элементу по оператору [i] происходит долго, а значит при большом количестве врагов и текста игра начнет тормозить.
- Использовать контейнер ключ-значение, в твоем случае подойдет std::unordered_map<Entity*, Up*>. Но циклы по этому контейнеру также очень медленные.
- Хранить в каждом объекте текста указатель на его врага(или наоборот). Например:
C++1234567891011121314151617181920class Up {public:int size;bool life = true;Font f;Text t;Enemy* myEnemy;Up(int size, Font Fo, Enemy* enemy){f = Fo;t.setFont(f);t.setCharacterSize(size);myEnemy = enemy;}void update(float X, float Y, String h){t.setPosition(X, Y);t.setString(h);}};
тогда можно будет создать простой цикл:
C++12345for (upIt = upArray.begin(); upIt != upArray.end(); upIt++){Enemy* enemy = (*upIt)->myEnemy;(*upIt)->update(enemy->x, enemy->y, std::to_string(enemy->health));}Такой вариант на производительность никак не повлияет, но мало чем отличается от простого хранения текста в классе врага. И нужно подумать как присвоить тексту его врага при создании.
Дело в том, что на каждом кадре игры ты в цикле заново присваиваешь единственному(!) спрайту TextureRect, после чего сразу же его отрисовываешь. Гораздо правильнее было бы создать массив этих спрайтов, присвоить им TextureRect’ы и позицию до главного цикла while, а во время выполнения приложения просто отрисовывать каждый спрайт по очереди.
C++12345//в классе Player:private:float x, y;public:float x, y, ....Одинаковые переменные. Компилятор не может решить, каким из них присваивать значения.
А что именно ты хочешь сделать, какой должен быть результат? Потоки работают так, как должны: запускаются, выполняются, завершаются. Одновременно, лично у меня, запускается максимум 5 потоков, больше просто не успевает запуститься. А тормозит по большей части из-за Visual Studio во время отладки, т.к. она не успевает сообщать обо всех завершенных потоках. Если запустить приложение через .exe, тормозов не будет.
Попробуй перед удалением переменных, или прямо в деструкторе выполнить следующие команды:
C++12thread.wait();thread.terminate();Не уверен, что понял поставленную задачу, но предположу, что Вам нужно найти направление полета снаряда по углу поворота башни танка. Вообще решение у этой задачи довольно простое, если вспомнить тригонометрию и линейную алгебру. Рекомендую данную статью:
C++1shape.getTransform().transformPoint(shape.getPoint(i)).х // возвращает координаты точки после трансформации фигурыЕсли речь идет о чем-то наподобие интерфейса, который всегда привязан к окну, то можно сделать следующим образом:
C++12345678910void draw(sf::RenderWindow& window){window.setView(view);//устанавливаешь игровой view...//отрисовываешь игровые объектыwindow.setView(window.getDefaultView());//далее устанавливаешь стандартный view окна...//отрисовываешь интерфейс}Вообще, нет ничего плохого в том, чтобы записывать в файл сохранения все динамические объекты. Только вот в XML это вряд ли получится сделать. Записывать все придется в бинарный файл, т.к. в него можно записать не только конкретные переменные объекта, но и вообще сам объект таким, какой он есть на данный момент. Ну или группу объектов:)
Для этого придется изучить работу с бинарными файлами в C++, а это к SFML уже не относится:)
Здесь полный туториал о том, как можно рисовать различные линии и фигуры (на английском).
Для конкретно твоего случая подойдет следующий код:C++123456789101112131415//создаем массив точек, по которым будут рисоваться линии:sf::VertexArray lines(sf::Lines, 16 /*количество точек*/);//далее для каждой из точек задаем свою позицию:lines[0].position = sf::Vector2f(0,0);lines[1].position = sf::Vector2f(100,150);//и т.д.//далее для каждой точки указываем цвет(так можно создавать градиенты):lines[0].color = sf::Color::White;lines[1].color = sf::Color::Blue;//и т.д.//и в конце выводим все на экран:window.draw(lines);C++12345678910while (window.pollEvent(event)){if (event.type == sf::Event::KeyReleased) //проверка на отпускание{if (event.key.code == sf::Keyboard::Return) //указываешь кнопку{//код..}}}Переменная time (получающая время из clock) хранит в себе количество времени, проходящего между тактами процессора. Далее в цикле программы на это число умножаются все переменные, которые так или иначе зависят от прошедшего времени (dx, dy и т.д.). И как результат – одинаковая скорость работы программы как на мощных, так и на слабых компьютерах.
Если же присвоить time конкретное константное число, то на него также будут умножаться эти переменные, с той разницей, что на мощных процессорах это будет происходить в разы чаще, чем на слабых. - Вместо std::list использовать std::deque. В нем можно получать доступ к элементам по их номеру, а значит можно сделать так:
-
АвторСообщения