Allegro частота кадров
Так что у меня недавно были проблемы с Аллегро. Я понятия не имею, что вызывает это, но я постараюсь подробно описать проблему ниже, как могу.
В моей основной функции у меня есть что-то вроде этого:
int main()
{
Game *game = new Game();
game->init(800, 600, 60); //width, height, framerate
PlayState *playState = new PlayState(); //extends abstract class GameState
game->setDefaultState(playState);
game->startGame();
gMemoryTracker.reportAllocations(cout);
system("pause");
return 0;
}
Это работает нормально, и печать прошедшего времени в конце каждого кадра показывает около 16,7 мс на кадр. Однако, поскольку я хотел бы, чтобы класс Game в конечном итоге выступал в качестве полноценного диспетчера GameState (в настоящее время он поддерживает только один GameState), я хотел бы, чтобы функция init класса Game вызывала собственную функцию init каждого GameState. Очевидно, это будет означать регистрацию каждого GameState перед вызовом функции инициализации Game, поэтому я изменил основную функцию, чтобы она выглядела следующим образом:
int main()
{
Game *game = new Game();
//this is where the call to init used to be
PlayState *playState = new PlayState();
game->setDefaultState(playState);
game->init(800, 600, 60); //now this is called after we create a GameState and set it as default
game->startGame();
gMemoryTracker.reportAllocations(cout);
system("pause");
return 0;
}
Проблема заключается в том, что теперь для рендеринга каждого кадра требуется около 1100 мс, хотя класс Game сообщает, что частота кадров все еще установлена на 60 кадров в секунду. В попытке отладить эту проблему я сделал одно последнее изменение в main:
int main()
{
Game *game = new Game();
PlayState *playState = new PlayState();
game->init(800, 600, 60); //now init is being called after we create a new GameState, but before we set it as default
game->setDefaultState(playState);
game->startGame();
gMemoryTracker.reportAllocations(cout);
system("pause");
return 0;
}
Но это приводит к той же проблеме, что и раньше, с каждым кадром для рендеринга требуется около 1100 мс. Кажется, что эта проблема возникает, только когда я вызываю init после создания нового GameState, поэтому я посмотрел на конструктор класса PlayState и функцию init класса Game, чтобы посмотреть, смогу ли я найти что-то, что могло бы вызвать такое поведение, но я до сих пор не удалось найти причину. Вы можете найти две вышеупомянутые функции ниже:
bool Game::init(int width, int height, float frameRate)
{
mFrameRate = frameRate;
bool result = mpGraphics->init(width, height); //initialize the graphics system
//this calls the init function for the default GameState. commented-out for debugging purposes
//result = result && mpDefaultState->init();
return result; //were all inits successful?
}
PlayState::PlayState() : GameState("play_state")
{
//create required graphics buffers and fonts
bgBuffer = new GraphicsBuffer(DISPLAY_SIZE.getX(), DISPLAY_SIZE.getY());
woodsBuffer = new GraphicsBuffer(ASSET_PATH + "Woods.png");
smurfBuffer = new GraphicsBuffer(ASSET_PATH + "smurf_sprites.png");
font = new Font(ASSET_PATH + "cour.ttf", 12);
smurfAnimation = new Animation(60, true); //create new animation for smurf walk cycle. args are animation framerate (must be <= game framerate) and loop animation
//load sprites from spritesheet
for (int y = 0; y < (int)SPRITE_SHEET_SIZE.getY() / (int)SPRITE_SIZE.getY(); y++)
{
for (int x = 0; x < (int)SPRITE_SHEET_SIZE.getX() / (int)SPRITE_SIZE.getX(); x++)
{
//there was already a class named Rectangle, so i had to get creative
UnequalSquare uSquare(x * (int)SPRITE_SIZE.getX(), y * (int)SPRITE_SIZE.getY(), (int)SPRITE_SIZE.getX(), (int)SPRITE_SIZE.getY());
smurfAnimation->addSprite(Sprite(*smurfBuffer, uSquare));
}
}
}
Также я заметил, что игра запускается с правильной частотой кадров, если я закомментирую все вызовы рендеринга в функции рендеринга PlayState, но, очевидно, это нереальное решение. Я опубликую функцию рендера ниже. На данный момент он не очень эффективен (создание новых спрайтовых объектов в каждом кадре), но это не объясняет, почему он работает идеально, если Game.init() вызывается перед созданием экземпляра PlayState.
void PlayState::render(GraphicsSystem* graphics, const Timer& frameTimer)
{
// Create background
Sprite bgSprite(*bgBuffer);
graphics->fill(*bgBuffer, Color(255, 0, 0));
// Create image
Sprite woodsSprite(*woodsBuffer);
Vector2D woodsLocation((DISPLAY_SIZE.getX() - (woodsSprite.getWidth() * WOODS_SCALE)) / 2.0, (DISPLAY_SIZE.getY() - (woodsSprite.getHeight() * WOODS_SCALE)) / 2.0);
// Draw Text
int fontWidth = font->getTextWidth(TEXT_STRING);
int fontHeight = font->getFontHeight();
for (int i = 0; i <= DISPLAY_SIZE.getY() / fontHeight; i++)
{
for (int j = 0; j <= DISPLAY_SIZE.getX() / fontWidth; j++)
{
graphics->drawText(*bgBuffer, Vector2D(j * fontWidth, i * fontHeight), TEXT_STRING, *font, Color());
}
}
//update the animation
smurfAnimation->update();
// Draw sprites to backbuffer
graphics->drawSpriteToBackbuffer(gZeroVector2D, bgSprite);
graphics->drawSpriteToBackbuffer(woodsLocation, woodsSprite, WOODS_SCALE);
graphics->drawSpriteToBackbuffer(gZeroVector2D, smurfAnimation->getCurrentSprite());
}
Может кто-нибудь увидеть какие-либо причины, почему я мог испытывать эту проблему? Я был в этом в течение нескольких часов, и я не могу понять это для моей жизни.
1 ответ
Я нашел проблему. Из документации Allegro 5:
Если вы не установите флаг ALLEGRO_MEMORY_BITMAP, растровое изображение создается для текущего отображения. Перемотка на другой дисплей может быть медленной.
Я пытался создать растровые изображения до того, как создал дисплей, что привело к снижению производительности. Установка флага ALLEGRO_MEMORY_BITMAP значительно улучшает частоту кадров, но она по-прежнему занимает около 100-200 мс на кадр. Я полагаю, что это всего лишь слабость Аллегро, которую я должен буду учитывать с этого момента.