快板帧率问题
Allegro framerate issue
所以我最近在使用 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 class 最终充当一个成熟的 GameState 管理器(目前它只支持一个 GameState),我希望 Game class 的 init 函数调用每个 GameState 的自己的个人初始化功能。显然,这意味着在调用 Game 的 init 函数之前注册每个 GameState,所以我将 main 函数更改为如下所示:
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 毫秒,即使游戏 class 报告帧速率仍设置为 60fps。为了调试此问题,我对 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 毫秒。似乎这个问题只发生在我创建一个新的 GameState 后调用 init 时,所以我查看了 PlayState class 的构造函数和 Game class 的 init 函数,看看我是否能找到一些东西那会导致这种行为,但我仍然无法找到原因。您可以在下面找到上述两个功能:
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 的渲染函数中注释掉所有渲染调用,游戏会以正确的帧速率运行,但显然这不是一个可行的解决方案。我将 post 下面的渲染函数。目前效率不是很高(每帧都创建新的 sprite 对象),但这并不能解释为什么如果在创建 PlayState 实例之前调用 Game.init() 就可以完美地工作。
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());
}
谁能看出我可能遇到此问题的任何原因?我已经研究了几个小时了,我这辈子都想不通。
我发现了问题。来自 Allegro 5 文档:
Unless you set the ALLEGRO_MEMORY_BITMAP flag, the bitmap is created for the current display. Blitting to another display may be slow.
我试图在创建显示之前创建位图,因此导致性能不佳。设置 ALLEGRO_MEMORY_BITMAP 标志可显着提高帧速率,但每帧仍需要大约 100ms-200ms。我想这只是 Allegro 的一个弱点,我需要从现在开始考虑。
所以我最近在使用 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 class 最终充当一个成熟的 GameState 管理器(目前它只支持一个 GameState),我希望 Game class 的 init 函数调用每个 GameState 的自己的个人初始化功能。显然,这意味着在调用 Game 的 init 函数之前注册每个 GameState,所以我将 main 函数更改为如下所示:
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 毫秒,即使游戏 class 报告帧速率仍设置为 60fps。为了调试此问题,我对 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 毫秒。似乎这个问题只发生在我创建一个新的 GameState 后调用 init 时,所以我查看了 PlayState class 的构造函数和 Game class 的 init 函数,看看我是否能找到一些东西那会导致这种行为,但我仍然无法找到原因。您可以在下面找到上述两个功能:
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 的渲染函数中注释掉所有渲染调用,游戏会以正确的帧速率运行,但显然这不是一个可行的解决方案。我将 post 下面的渲染函数。目前效率不是很高(每帧都创建新的 sprite 对象),但这并不能解释为什么如果在创建 PlayState 实例之前调用 Game.init() 就可以完美地工作。
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());
}
谁能看出我可能遇到此问题的任何原因?我已经研究了几个小时了,我这辈子都想不通。
我发现了问题。来自 Allegro 5 文档:
Unless you set the ALLEGRO_MEMORY_BITMAP flag, the bitmap is created for the current display. Blitting to another display may be slow.
我试图在创建显示之前创建位图,因此导致性能不佳。设置 ALLEGRO_MEMORY_BITMAP 标志可显着提高帧速率,但每帧仍需要大约 100ms-200ms。我想这只是 Allegro 的一个弱点,我需要从现在开始考虑。