SFML и C++ Уроки \ Разработка игр › Форумы › Логика игр › Генераторы рун теряются в действиях
В этой теме 4 ответа, 1 участник, последнее обновление Heisenberg 7 года/лет, 8 мес. назад.
-
АвторСообщения
-
Написал систему генерации бонуснах рун, которые появляются в генераторах случайным образом. Но где-то теряется логика условий, и они перестают их генерировать.
Ещё если немного подождать, то начинает просидать fps, до тех пор пока не поднимешь хотябы одну руну.C++123456789101112131415161718192021222324252627282930#pragma once#include"Rectangle.h"#include"Hero.h"class Rune : public Rectangle{private:int bonusExperience;int bonusDamage;int bonusGold;int bonusHeal;int bonusEnergy;float bonusHaste;bool isCanTake;sf::String type;public:int getBonusExperience();int getBonusDamage();int getBonusGold();float getBonusHaste();bool getCanTake();void setCanTake(bool _state);Rune(sf::String _file, float _width, float _height, float _x, float _y, sf::String _type);~Rune(void);};C++123456789101112131415161718192021222324252627282930313233343536373839404142#include "Rune.h"Rune::Rune(sf::String _file, float _width, float _height, float _x, float _y, sf::String _type): Rectangle(_file, _width, _height, _x, _y){type = _type;bonusDamage = 0, bonusExperience = 0, bonusHaste = 0, bonusGold = 0, bonusHeal = 0, bonusEnergy = 0;if(type == "Experience") bonusExperience = 25;if(type == "Haste") bonusHaste = 0.2;if(type == "Heal") bonusHeal = 100;if(type == "Energy") bonusEnergy = 50;if(type == "Damage") bonusDamage = 5;if(type == "Gold") bonusGold = 25;rect.setTextureRect(sf::IntRect(0,0,256,256));isCanTake = false;}bool Rune::getCanTake() {return isCanTake;}void Rune::setCanTake(bool _isCanTake) {isCanTake = _isCanTake;}int Rune::getBonusExperience() {return bonusExperience;}int Rune::getBonusDamage() {return bonusDamage;}int Rune::getBonusGold() {return bonusGold;}float Rune::getBonusHaste() {return bonusHaste;}Rune::~Rune(void){}C++1234567891011121314151617181920212223242526272829#pragma once#include"Rectangle.h"#include"Hero.h"#include"Rune.h"class Distributor : public Rectangle{private:float speedDistr;float speedRune;float rotate;float moveX, moveY;float moveRange;float timer;int count;int typeGen;enum DIRECTION { LEFT, UP, RIGHT, DOWN } direction;std::vector<Rune*> rune;std::vector<Rune*>::iterator it;enum STATE { FLYUP, MOVEPOINT, FLYDOWN, GENERATION } state;public:Distributor(sf::String _file, float _width, float _height, float _x, float _y);void Update(float _time, sf::RenderWindow *_wnd, Hero &_hero);virtual ~Distributor(void);};C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147#include "Distributor.h"Distributor::Distributor(sf::String _file, float _width, float _height, float _x, float _y): Rectangle (_file, _width, _height, _x, _y){speedDistr = 0.2;speedRune = 0.25;rotate = -0.35;moveX = 0, moveY = 0;moveRange = 0;typeGen = 0;timer = 0;count = 0;state = GENERATION;rune.reserve(100);}void Distributor::Update(float _time, sf::RenderWindow *_wnd, Hero &_hero) {// Меняет направление раздатчиковif(y <= -936) if(x > 1000 || x < -1000){ y = -936; direction = UP; }if(y >= 936) if(x > 1000 || x < -1000){ y = 936; direction = DOWN; }if(x <= -936) if(y > 1000 || y < -1000){ x = -936; direction = RIGHT; }if(x >= 936) if(y > 1000 || y < -1000){ x = 936; direction = LEFT; }// Движение раздатчиковswitch(direction){case DOWN: y -= speedDistr * _time; break;case UP: y += speedDistr * _time; break;case LEFT: x -= speedDistr * _time; break;case RIGHT: x += speedDistr * _time; break;}_wnd->draw(rect);rect.rotate(rotate *_time);rect.setPosition(x,y);switch(state){case GENERATION : // Если руна не создана, то создаём еёif(timer <= 5000) {if(count < 20)timer += _time;}else{typeGen = rand()%100+1;if(typeGen > 0 && typeGen < 60) rune.push_back(new Rune("ExperienceRune.png", 32, 32, x, y, "Experience"));if(typeGen > 60 && typeGen < 70) rune.push_back(new Rune("HasteRune.png", 32, 32, x, y, "Haste"));if(typeGen > 70 && typeGen < 80) rune.push_back(new Rune("HealRune.png", 32, 32, x, y, "Heal"));if(typeGen > 80 && typeGen < 90) rune.push_back(new Rune("EnergyRune.png", 32, 32, x, y, "Energy"));if(typeGen > 90 && typeGen < 95) rune.push_back(new Rune("DamageRune.png", 32, 32, x, y, "Damage"));if(typeGen > 95 && typeGen < 100) rune.push_back(new Rune("GoldRune.png", 32, 32, x, y, "Gold"));timer = 0;count++;state = FLYUP;std::printf("Count = %d\n", count);}break;case FLYUP : // После создания руны поднимаем её в воздух (увеличиваем размер и увеличиваем прозрачность)for(it = rune.begin(); it != rune.end(); it++){Rune *r = *it;if(!r->getCanTake()){if(r->getScaleX() < 2.0) {r->setScale(sf::Vector2f(r->getScaleX() + 0.001 * _time, r->getScaleY() + 0.001 * _time));r->setColor(255,255,255, 255 - (100 * r->getScaleX()));}// Как достигли нужной высотыelse {moveX = rand()%1900-950; moveY = rand()%1900-950;moveRange = sqrt((moveX - r->getPositionX())*(moveX - r->getPositionX())+ (moveY - r->getPositionY())*(moveY - r->getPositionY()));r->setScale(sf::Vector2f(2.0,2.0));state = MOVEPOINT;}}if(!r->getCanTake())r->setPosition(x,y);}break;case MOVEPOINT : // После того как подняли руну в воздух и выбрали точку, двигаем еёif (moveRange > 2){for(it = rune.begin(); it != rune.end(); it++) {Rune *r = *it;if(!r->getCanTake()){moveRange = sqrt(( moveX - r->getPositionX() ) * ( moveX - r->getPositionX() )+( moveY - r->getPositionY() ) * ( moveY - r->getPositionY() ));r->setPosition( r->getPositionX() + (speedRune * _time) * ( moveX - r->getPositionX() ) / moveRange,r->getPositionY() + (speedRune * _time) * ( moveY - r->getPositionY() ) / moveRange);}}}else state = FLYDOWN;break;case FLYDOWN :for(it = rune.begin(); it != rune.end(); it++){Rune *r = *it;if(!r->getCanTake()){if(r->getScaleX() > 1.0) {r->setScale(sf::Vector2f(r->getScaleX() - 0.001 * _time, r->getScaleY() - 0.001 * _time));r->setColor(255,255,255, 255 - (100 * r->getScaleX()));}// Как достигли нужной высотыelse {r->setScale(sf::Vector2f(1.0,1.0));r->setColor(255,255,255, 255);state = GENERATION;r->setCanTake(true);}}}break;}for(it = rune.begin(); it != rune.end();){Rune *r = *it;if(r->getCanTake()) r->Rotate(-0.1*_time);else r->Rotate(0.025*_time);r->setTextureRect(sf::IntRect(0,0,256,256));_wnd->draw(r->getPoly());r->setTextureRect(sf::IntRect(256,0,256,256));_wnd->draw(r->getPoly());if(r->getRect().intersects(_hero.getRect()) && r->getCanTake() && _hero.getAlive()){count--;std::printf("Count = %d\n", count);it = rune.erase(it); delete r;}else it++;}}C++12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667#include<SFML/Graphics.hpp>#include<list>#include<vector>#include"BackgroundLines.h"#include"Hero.h"#include"Sprint.h"#include"Distributor.h"int main(){//Инициализация линий заднего фонаstd::list<BackgroundLines*> linesList; std::list<BackgroundLines*>::iterator linesIter;for(int i = 0; i != 11; i++) linesList.push_back( new BackgroundLines("", true, 1, 2001, i*200, 0, 0,0,0));for(int j = 0; j != 11; j++) linesList.push_back( new BackgroundLines("", false, 2001, 1, 0, j*200, 0,0,0));//Инициализация раздатчиков рунstd::list<Distributor*> distrList; std::list<Distributor*>::iterator distrIter;distrList.push_back(new Distributor("Distributor.png", 128, 128, -1064, -936));distrList.push_back(new Distributor("Distributor.png", 128, 128, 936, -1064));distrList.push_back(new Distributor("Distributor.png", 128, 128, 1064, 936));distrList.push_back(new Distributor("Distributor.png", 128, 128, -936, 1064));//Инициализация героевHero hero("Hero.png", 64, 64, 0, 0, 0.1, 10, 25, 15, 0.5, 0.25);Sprint sprint;sf::View camera;sf::Clock clock;sf::RenderWindow window(sf::VideoMode(800, 600), "The Game", sf::Style::None, sf::ContextSettings(32,0,8,2,0));camera.reset(sf::FloatRect(0, 0, 800, 600));srand(::time(0));while(window.isOpen()){float time = clock.getElapsedTime().asMicroseconds();clock.restart();time /= 1000;sf::Event Event;while (window.pollEvent(Event)){if (Event.type == sf::Event::Closed)window.close();if ( Event.type == sf::Event::KeyPressed){if ( Event.key.code == sf::Keyboard::Escape ) window.close();}hero.UpdateEvent(&Event);sprint.UpdateEvent(&hero, &Event);}window.clear();camera.setCenter( hero.getPositionX(), hero.getPositionY() );for(linesIter = linesList.begin(); linesIter != linesList.end(); linesIter++)(*linesIter)->Update(&window, time, &hero);hero.UpdateTime(time, &window);sprint.UpdateTime(&hero, time);for(distrIter = distrList.begin(); distrIter != distrList.end(); distrIter++) {(*distrIter)->Update(time, &window, hero);}window.setView(camera);window.display();}return 0;}Проблема решена на половину, теперь всё работает как и задумано, но FPS всё ещё падает. Игра буквально начинает дёргаться.
Проблема заключалась в том, что генераторы (Класс Distributor) обрабатывали сразу все существующие руны, из которых брали значения применяемые в условиях, тем самым теряя собственную логику переставали подчиняться.
Решил путём перевода из list в vector, для доступности контроля последнего созданного объекта (Руны)
Rune *r = rune.back()А так-же во избежании последующего бага с обращением к несуществующему адресу памяти добавил защитные условия if(!rune.empty) которое проверяет на пустоту вектора.
Может кто знает почему падает FPS? Ведь у меня стоит лимит на создание рун по 20 шт. на каждый генератор * 4. Это совсем немного, ранее я запускал программу с 300 элементами, ничего подобного не встречалось.
И как убрать микрозадержку при создании новой руны, которая возникает каждый раз когда создаётся новый элемент вектора.
Пробовал заранее выделять память под объекты rune.reserve(20), но это не помогло.
Самый необъяснимый факт, если поднять одну любую руну, то лаги на время пропадают.
Избавился от микрозадержки при создании нового объекта рун.
Ошибка была в загрузке новой текстуры каждый раз при создании.
Избавился от этого путём однократной загрузки файла и передачей ссылки в качестве аргумента конструктору. Мой косяк.Но FPS со временем продолжает падать
даже комментировал подозрительные действия, такие как проверка на столкновения героя с руной и её отображение.Всё, я решил весь список своих проблем.
Заметки на будущее для вас.Никогда не используйте внутри цикла метод:
C++1setTextureRect(sf::IntRect(left,top,width,height));Это напрягает процессор. Используйте эту функцию только по надобности.
Если вы используете std::vector, или std::list, и вам нужно обратиться к последнему созданному элементу отдельно, не проходя по всем элементам. Используйте волшебные методы этих инструментов:
Назначаем указатель на последний объект списка, который мы сможем обработать не затрагивая остальные элементы.
C++1YouClass *ptr = YouList.back();Но есть одна важная вещь, о которой вам стоит помнить.
Используя этот метод вам нужно дополнительное условие:C++1if(!YouList.empty())Это условие поможет избежать обращение к пустому списку, иначе вылетит ошибка с обращением к несуществующему адресу памяти.
Ещё одно правило, которое следует выполнять, это загружать не более одной текстуры на все <<одноподобные>> объекты. Иначе ресурсы компьютера могут не осилить вашу 2D игру.
Что уж там о GTA V говорить…
Загруженную текстуру можно передавать в качестве аргумента в виде ссылки.Выше в теме я сказал что заменил std::list на std::vector, чтобы обратиться к последнему элементу. Знайте – std::list тоже так умеет.
Выполняя ряд этих правил ваша игра будет летать, а не ползать
Спасибо за внимание и помощь 😀
Если кому интересно, можете протестировать и сказать у кого как работает.
Распакуйте архив, запустите debug.exe -
АвторСообщения
Для ответа в этой теме необходимо авторизоваться.