[C++][SFML 2.2] 奇怪的性能问题 - 移动鼠标会降低 CPU 使用率
[C++][SFML 2.2] Strange Performance Issues - Moving Mouse Lowers CPU Usage
在过去两周左右的时间里,我一直致力于制作 2D 地图编辑器,但我 运行 遇到了一个非常奇怪的问题。当我试图优化我的代码时,例如,通过为真正应该是函数的函数创建函数,我做了一些让我的 CPU 使用率达到顶峰的事情。我已经尝试注释掉我认为最有可能是罪魁祸首(滚动、渲染、其他计算)的不同代码部分,但无济于事。我认为问题可能只是试图从不同的函数中调用事物,但为了尽可能模块化,我真的很喜欢这个功能。
自从我将其与文件进行比较以来,我所做的另一项重大更改是我将所有变量移植到外部 CPP 文件中,因为将变量设置为全局变量使其更易于从在不同的功能中。这可能是一个非常简单的问题,但我一辈子都无法理解为什么会这样。
使用原始代码,我得到大约 2-3% CPU 的使用率。使用新代码,我得到大约 20-35%,但是,如果我移动鼠标,它会下降到大约 6-8%。
tl;dr:在尝试使用函数优化我的代码后,我以某种方式降低了我的性能,并发现了一个奇怪的怪癖,即移动鼠标会大大减少 CPU 使用率。 .
//Most variables are declared in an external file
void editorLoop()
{
/***************************/
//See what user wants to do
/***************************/
std::cout << "Would you like to [O]pen a file, make [N]ew one, or [E]xit?\n";
std::cin >> openOrNewFile;
/************************/
//Create a new file
/***********************/
if (openOrNewFile == 'n' || openOrNewFile == 'N')
{
createMap();
}
/***********************/
//Quit the program
/**********************/
else if (openOrNewFile == 'e' || openOrNewFile == 'E')
{
return;
}
/************************/
//Open an existing file
/***********************/
else if (openOrNewFile == 'o' || openOrNewFile == 'O')
{
openMap();
}
/**********************/
//Invalid input
/*********************/
else
{
std::cout << "Please enter a valid input!\n";
main();
}
/***********************/
//Create the Window
/***********************/
sf::RenderWindow gameWindow(sf::VideoMode(screenSizeX, screenSizeY, mapTileSize), "Game");
//Artificially cap FPS to keep memory and CPU usage low
gameWindow.setFramerateLimit(60);
//view1's size is defined externally, same size as the gameWindow, though
view1.setCenter(screenSizeX / 2, screenSizeY / 2 + mapTileSize);
//Load GUI Elements
//I've found that trying to load these inside the setGUIElements function leads to the
//texture memory to be deleted, so I'm left with white spaces
sf::Texture guiElements;
if (!guiElements.loadFromFile("Resources/guiElements.png"))
{
std::cout << "Error loading guiElements.png\n";
}
sf::Font arial;
if (!arial.loadFromFile("Resources/arial.ttf"))
{
std::cout << "Error loading arial.tff\n";
}
setGUIElements();
activeTileSprite.setTexture(tileTexture);
upArrowX.setTexture(guiElements);
downArrowX.setTexture(guiElements);
upArrowY.setTexture(guiElements);
downArrowY.setTexture(guiElements);
saveButton.setTexture(guiElements);
editBoxX.setFont(arial);
editBoxY.setFont(arial);
//Selector Rectangle
sf::RectangleShape Selected(sf::Vector2f(mapTileSize, mapTileSize));
Selected.setFillColor(sf::Color(0,0,0,0));
Selected.setOutlineThickness(2);
Selected.setOutlineColor(sf::Color(255,0,0));
Selected.setPosition(-1000,-1000);
//Set up toolbox string values
tempXTileValue = std::to_string((_ULonglong)xTileValue);
tempYTileValue = std::to_string((_ULonglong)yTileValue);
while (gameWindow.isOpen())
{
/************************************/
//Mouse Input Defined Here
/***********************************/
//Get mouse position relative to the window
sf::Vector2f mousePositionGlobal = gameWindow.mapPixelToCoords(sf::Mouse::getPosition(gameWindow));
sf::Vector2i mousePositionLocal = sf::Mouse::getPosition(gameWindow);
sf::Event event;
while (gameWindow.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
gameWindow.close();
}
if (event.type == sf::Event::MouseButtonReleased)
{
if (event.key.code == sf::Mouse::Left)
{
std::cout << "Global Mouse Position:\n" << "X: " << mousePositionGlobal.x << " Y: " << mousePositionGlobal.y << "\n\n";
std::cout << "Local Mouse Position:\n" << "X: " << mousePositionLocal.x << " Y: " << mousePositionLocal.y << "\n\n";
int mouseX = mousePositionGlobal.x;
int mouseY = mousePositionGlobal.y;
//Move the selector rectangle to where the mouse clicked
if ((mouseX >= 0) && (mouseY >= 0))
{
if (mousePositionLocal.x > 900 && mousePositionLocal.x < 1100 && mousePositionLocal.y > 30 && mousePositionLocal.y < 286)
{
}
else
{
Selected.setPosition((mouseX/32)*32, (mouseY/32)*32);
/*****************************************/
//These lines define what tile to be placed
//NOTE: map[][]'s first [] is the Y axis, and the second [] is the X axis!!
/*****************************************/
map[mouseY/32*32/32][mouseX/32*32/32].x = yTileValue;
map[mouseY/32*32/32][mouseX/32*32/32].y = xTileValue;
}
}
/********************/
//Toolbox stuff
/********************/
//This can probably be written better ...
//Up Arrow X
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && (mousePositionLocal.y > screenSizeY * 0.096) && (mousePositionLocal.y < screenSizeY * 0.096 + 32))
{
if (xTileValue < 10)
{
xTileValue ++;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
else
{
xTileValue = 0;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
}
//Down Arrow X
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && mousePositionLocal.y > 98 && mousePositionLocal.y < 130)
{
if (xTileValue > 0)
{
xTileValue --;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
else
{
xTileValue = 10;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
}
//Up Arrow Y
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && mousePositionLocal.y > 148 && mousePositionLocal.y < 180)
{
if (yTileValue < 10)
{
yTileValue ++;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
else
{
yTileValue = 0;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
}
//Down Arrow Y
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && mousePositionLocal.y > 188 && mousePositionLocal.y < 220)
{
if (yTileValue > 0)
{
yTileValue --;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
else
{
yTileValue = 10;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
}
//Save Button
if (mousePositionLocal.x > screenSizeX * 0.886 && mousePositionLocal.x < screenSizeX * 0.886 + 32 && mousePositionLocal.y > screenSizeY * 0.414 - 32 && mousePositionLocal.y < screenSizeY * 0.414)
{
saveMap();
}
}
if (event.key.code == sf::Mouse::Right)
{
Selected.setPosition(-1000, - 1000);
}
}
if (event.type == sf::Event::KeyReleased)
{
if (event.key.code == sf::Keyboard::X)
{
showToolBox = !showToolBox;
}
}
//View Managing
viewCenter = view1.getCenter();
viewSize = view1.getSize();
/*************************/
//Scrolling
/************************/
if ((mousePositionLocal.x > screenSizeX * 0.83) && (mousePositionLocal.x < screenSizeX) && (mousePositionLocal.y > mapTileSize) && (mousePositionLocal.y < screenSizeY * 0.43) && (showToolBox == true))
{
enableScroll = false;
}
else
{
enableScroll = true;
}
if ((mousePositionLocal.y < screenSizeY * 0.1) && (enableScroll == true))
{
//If the view would leave the map by scrolling; don't scroll
if (viewCenter.y < mapTileSize * 10.7)
{
}
else
{
scroll(0,-scrollSpeed);
}
}
if ((mousePositionLocal.y > screenSizeY * 0.9) && (enableScroll == true))
{
if (viewCenter.y > ((mapSizeY * mapTileSize)) - (mapTileSize * 9))
{
}
else
{
scroll(0,scrollSpeed);
}
}
if (mousePositionLocal.x < screenSizeX * 0.1 && enableScroll == true)
{
if (viewCenter.x < (mapTileSize * 17))
{
}
else
{
scroll(-scrollSpeed,0);
}
}
if ((mousePositionLocal.x > screenSizeX * 0.9) && enableScroll == true)
{
if (viewCenter.x > (mapSizeX * mapTileSize) - (mapTileSize * 17))
{
}
else
{
scroll(scrollSpeed,0);
}
}
//Clear buffer
gameWindow.clear();
//The view has to be set in the draw function
//for a reason that is not yet clear to me.
gameWindow.setView(view1);
//Add stuff to new buffer
//Y loop
for (int i = 0; i < map.size(); i++)
{
//X loop
for (int j = 0; j < map[i].size(); j++)
{
if ((map[i][j].x != -1) && (map[i][j].y != -1))
{
tiles.setPosition(j * mapTileSize, i * mapTileSize);
tiles.setTextureRect(sf::IntRect(map[i][j].x * mapTileSize, map[i][j].y * mapTileSize, mapTileSize, mapTileSize));
gameWindow.draw(tiles);
}
}
}
//Draw the Selector rectangle
gameWindow.draw(Selected);
if (showToolBox == true)
{
activeTileSprite.setTextureRect(sf::IntRect(mapTileSize*yTileValue, mapTileSize*xTileValue, mapTileSize, mapTileSize));
//Draw toolbox
gameWindow.draw(toolbarBox);
gameWindow.draw(activeTileSprite);
gameWindow.draw(upArrowX);
gameWindow.draw(downArrowX);
gameWindow.draw(upArrowY);
gameWindow.draw(downArrowY);
//Update the strings for X and Y here
//Otherwise, it doesn't work for some reason
editBoxX.setString("Y: " + tempXTileValue);
editBoxY.setString("X: " + tempYTileValue);
gameWindow.draw(editBoxX);
gameWindow.draw(editBoxY);
gameWindow.draw(saveButton);
}
//Render buffer
gameWindow.display();
}
}
openfile.close();
return;
}
如果我需要添加(或删除)任何信息,请告诉我。
我已经四处查看但找不到任何类似的问题,所以希望我没有遗漏任何东西,并正确解释了我的问题。
再次感谢,
helpMeLearnC++
P.S。我应该提一下,我不是一个完全的初学者,但我也不是超级高级。
P.S.S.在尝试了 Selbie 的建议之后,我注意到,相当矛盾的是,除非鼠标移动,否则我的游戏不会更新......现在我想知道为什么这会比鼠标不动时产生更好的性能......(或代码我用过没有正常工作)。
P.S.S.S.在进一步修改代码之后,我发现了我认为的预期:当鼠标移动时,gameWindow.pollEvent() 优先于 while(gameWindow.isOpen()) 循环,后者执行绘图很可能是什么扼杀了我的表现。现在的问题是处理这个问题的最佳方法是什么。
P.S.S.S.S.对于那些好奇的人,假设我检查 FPS 的方法是正确的,我每秒渲染大约 27,000 帧(我的测试非常小,所以虽然我认为它看起来有点高,但我不会完全抹黑它)。
通过将 mousePositionGlobal 和 mousePositionLocal 移动到 pollEvent 循环中,我能够将性能从大约 20-35% 降低到大约 8-15%,并在剩下的过程中下降(大约 3% ) 当鼠标移动时。所以,取得了进展,但我仍然不确定是什么原因导致了差异......由于 FPS 已经上升到大约 35,000,我将假设我的计算代码是错误的。还有其他建议吗?
我敢打赌你的 CPU 是四核的。您看到的 CPU 百分比来自 Windows 任务管理器(或来自使用 Windows 性能计数器的其他应用程序)。我怀疑这是因为你有一个单线程游戏循环,它不停地运行,帧之间没有休眠。因此,您的“20-35%”CPU 实际上是您的程序在您的芯片上占用了一个完整的内核。这是任何想要以可能的最高帧速率渲染的游戏循环的典型特征。
我怀疑在您的显卡上,"moving the mouse" 也会产生与其他 windowed 游戏类似的性能特征。当您移动鼠标时,Windows 图形获得比游戏 window 更高的优先级并暂停游戏循环的渲染。因此,当鼠标四处移动时,您的代码仍然是 运行,但帧速率要低得多。由于图形系统必须处理游戏外的绘图请求,.draw() 或 .display() 调用被阻止 window。因此,您的游戏循环块和使用更少 CPU.
我的建议是在您的游戏中添加帧速率计数器 window。显示最后一秒累积的帧数的东西(需要一些额外的整数变量、时间函数和一些除法来计算帧速率)。我猜你会看到当鼠标移动时帧速率计数器变慢。
另外,在互联网上搜索 "code profiling tool"。 Visual Studio 的某些版本内置了 on。它们应该在您的代码花费大部分时间的地方。
一个简单的游戏循环,您不想在其中运行 CPU 可能类似于:
time last_render = now();
while( app_is_running ) {
Event e;
// eat all events. Ideally, more important than rendering,
// and should take only a little bit of time:
while ( get_event(&e) ) {
process_event(e); // <- note, does not render, should be **cheap**
}
// frame limit code:
while (now()-last_render < frame_limit) {
Event e;
if (wait_for_event(&e, (frame_limit-delta)/2))
process_event(e);
}
last_render = now(); // stamp before rendering
render(); // also includes other game state updates.
}
现在,sfml 似乎缺少 wait_for_event(Event*, timeout)
功能。这意味着你不能 "go to sleep while still responding to events"。因此,休眠要么使您的事件处理无响应,要么您必须对其进行管理,要么您需要多个线程。
我们可以建立一个线程安全队列,创建一个线程,其工作是 waitForEvent
并让它填充一个我们可以等待的队列,然后在队列上休眠和超时(基本上解决什么问题似乎是 sfml 缺陷)。
或者我们可以轮询和跟踪 CPU。离我远点 phone!
或者我们可以忍受 1 帧的用户输入响应延迟(我认为这是不可接受的)。
我不是游戏开发者,所以对这个建议持怀疑态度。
在过去两周左右的时间里,我一直致力于制作 2D 地图编辑器,但我 运行 遇到了一个非常奇怪的问题。当我试图优化我的代码时,例如,通过为真正应该是函数的函数创建函数,我做了一些让我的 CPU 使用率达到顶峰的事情。我已经尝试注释掉我认为最有可能是罪魁祸首(滚动、渲染、其他计算)的不同代码部分,但无济于事。我认为问题可能只是试图从不同的函数中调用事物,但为了尽可能模块化,我真的很喜欢这个功能。
自从我将其与文件进行比较以来,我所做的另一项重大更改是我将所有变量移植到外部 CPP 文件中,因为将变量设置为全局变量使其更易于从在不同的功能中。这可能是一个非常简单的问题,但我一辈子都无法理解为什么会这样。
使用原始代码,我得到大约 2-3% CPU 的使用率。使用新代码,我得到大约 20-35%,但是,如果我移动鼠标,它会下降到大约 6-8%。
tl;dr:在尝试使用函数优化我的代码后,我以某种方式降低了我的性能,并发现了一个奇怪的怪癖,即移动鼠标会大大减少 CPU 使用率。 .
//Most variables are declared in an external file
void editorLoop()
{
/***************************/
//See what user wants to do
/***************************/
std::cout << "Would you like to [O]pen a file, make [N]ew one, or [E]xit?\n";
std::cin >> openOrNewFile;
/************************/
//Create a new file
/***********************/
if (openOrNewFile == 'n' || openOrNewFile == 'N')
{
createMap();
}
/***********************/
//Quit the program
/**********************/
else if (openOrNewFile == 'e' || openOrNewFile == 'E')
{
return;
}
/************************/
//Open an existing file
/***********************/
else if (openOrNewFile == 'o' || openOrNewFile == 'O')
{
openMap();
}
/**********************/
//Invalid input
/*********************/
else
{
std::cout << "Please enter a valid input!\n";
main();
}
/***********************/
//Create the Window
/***********************/
sf::RenderWindow gameWindow(sf::VideoMode(screenSizeX, screenSizeY, mapTileSize), "Game");
//Artificially cap FPS to keep memory and CPU usage low
gameWindow.setFramerateLimit(60);
//view1's size is defined externally, same size as the gameWindow, though
view1.setCenter(screenSizeX / 2, screenSizeY / 2 + mapTileSize);
//Load GUI Elements
//I've found that trying to load these inside the setGUIElements function leads to the
//texture memory to be deleted, so I'm left with white spaces
sf::Texture guiElements;
if (!guiElements.loadFromFile("Resources/guiElements.png"))
{
std::cout << "Error loading guiElements.png\n";
}
sf::Font arial;
if (!arial.loadFromFile("Resources/arial.ttf"))
{
std::cout << "Error loading arial.tff\n";
}
setGUIElements();
activeTileSprite.setTexture(tileTexture);
upArrowX.setTexture(guiElements);
downArrowX.setTexture(guiElements);
upArrowY.setTexture(guiElements);
downArrowY.setTexture(guiElements);
saveButton.setTexture(guiElements);
editBoxX.setFont(arial);
editBoxY.setFont(arial);
//Selector Rectangle
sf::RectangleShape Selected(sf::Vector2f(mapTileSize, mapTileSize));
Selected.setFillColor(sf::Color(0,0,0,0));
Selected.setOutlineThickness(2);
Selected.setOutlineColor(sf::Color(255,0,0));
Selected.setPosition(-1000,-1000);
//Set up toolbox string values
tempXTileValue = std::to_string((_ULonglong)xTileValue);
tempYTileValue = std::to_string((_ULonglong)yTileValue);
while (gameWindow.isOpen())
{
/************************************/
//Mouse Input Defined Here
/***********************************/
//Get mouse position relative to the window
sf::Vector2f mousePositionGlobal = gameWindow.mapPixelToCoords(sf::Mouse::getPosition(gameWindow));
sf::Vector2i mousePositionLocal = sf::Mouse::getPosition(gameWindow);
sf::Event event;
while (gameWindow.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
gameWindow.close();
}
if (event.type == sf::Event::MouseButtonReleased)
{
if (event.key.code == sf::Mouse::Left)
{
std::cout << "Global Mouse Position:\n" << "X: " << mousePositionGlobal.x << " Y: " << mousePositionGlobal.y << "\n\n";
std::cout << "Local Mouse Position:\n" << "X: " << mousePositionLocal.x << " Y: " << mousePositionLocal.y << "\n\n";
int mouseX = mousePositionGlobal.x;
int mouseY = mousePositionGlobal.y;
//Move the selector rectangle to where the mouse clicked
if ((mouseX >= 0) && (mouseY >= 0))
{
if (mousePositionLocal.x > 900 && mousePositionLocal.x < 1100 && mousePositionLocal.y > 30 && mousePositionLocal.y < 286)
{
}
else
{
Selected.setPosition((mouseX/32)*32, (mouseY/32)*32);
/*****************************************/
//These lines define what tile to be placed
//NOTE: map[][]'s first [] is the Y axis, and the second [] is the X axis!!
/*****************************************/
map[mouseY/32*32/32][mouseX/32*32/32].x = yTileValue;
map[mouseY/32*32/32][mouseX/32*32/32].y = xTileValue;
}
}
/********************/
//Toolbox stuff
/********************/
//This can probably be written better ...
//Up Arrow X
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && (mousePositionLocal.y > screenSizeY * 0.096) && (mousePositionLocal.y < screenSizeY * 0.096 + 32))
{
if (xTileValue < 10)
{
xTileValue ++;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
else
{
xTileValue = 0;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
}
//Down Arrow X
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && mousePositionLocal.y > 98 && mousePositionLocal.y < 130)
{
if (xTileValue > 0)
{
xTileValue --;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
else
{
xTileValue = 10;
std::cout << xTileValue << std::endl;
tempXTileValue = std::to_string((_ULonglong)xTileValue);
}
}
//Up Arrow Y
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && mousePositionLocal.y > 148 && mousePositionLocal.y < 180)
{
if (yTileValue < 10)
{
yTileValue ++;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
else
{
yTileValue = 0;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
}
//Down Arrow Y
if ((mousePositionLocal.x > screenSizeX * 0.95) && (mousePositionLocal.x < screenSizeX * 0.95 + 32) && mousePositionLocal.y > 188 && mousePositionLocal.y < 220)
{
if (yTileValue > 0)
{
yTileValue --;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
else
{
yTileValue = 10;
std::cout << yTileValue << std::endl;
tempYTileValue = std::to_string((_ULonglong)yTileValue);
}
}
//Save Button
if (mousePositionLocal.x > screenSizeX * 0.886 && mousePositionLocal.x < screenSizeX * 0.886 + 32 && mousePositionLocal.y > screenSizeY * 0.414 - 32 && mousePositionLocal.y < screenSizeY * 0.414)
{
saveMap();
}
}
if (event.key.code == sf::Mouse::Right)
{
Selected.setPosition(-1000, - 1000);
}
}
if (event.type == sf::Event::KeyReleased)
{
if (event.key.code == sf::Keyboard::X)
{
showToolBox = !showToolBox;
}
}
//View Managing
viewCenter = view1.getCenter();
viewSize = view1.getSize();
/*************************/
//Scrolling
/************************/
if ((mousePositionLocal.x > screenSizeX * 0.83) && (mousePositionLocal.x < screenSizeX) && (mousePositionLocal.y > mapTileSize) && (mousePositionLocal.y < screenSizeY * 0.43) && (showToolBox == true))
{
enableScroll = false;
}
else
{
enableScroll = true;
}
if ((mousePositionLocal.y < screenSizeY * 0.1) && (enableScroll == true))
{
//If the view would leave the map by scrolling; don't scroll
if (viewCenter.y < mapTileSize * 10.7)
{
}
else
{
scroll(0,-scrollSpeed);
}
}
if ((mousePositionLocal.y > screenSizeY * 0.9) && (enableScroll == true))
{
if (viewCenter.y > ((mapSizeY * mapTileSize)) - (mapTileSize * 9))
{
}
else
{
scroll(0,scrollSpeed);
}
}
if (mousePositionLocal.x < screenSizeX * 0.1 && enableScroll == true)
{
if (viewCenter.x < (mapTileSize * 17))
{
}
else
{
scroll(-scrollSpeed,0);
}
}
if ((mousePositionLocal.x > screenSizeX * 0.9) && enableScroll == true)
{
if (viewCenter.x > (mapSizeX * mapTileSize) - (mapTileSize * 17))
{
}
else
{
scroll(scrollSpeed,0);
}
}
//Clear buffer
gameWindow.clear();
//The view has to be set in the draw function
//for a reason that is not yet clear to me.
gameWindow.setView(view1);
//Add stuff to new buffer
//Y loop
for (int i = 0; i < map.size(); i++)
{
//X loop
for (int j = 0; j < map[i].size(); j++)
{
if ((map[i][j].x != -1) && (map[i][j].y != -1))
{
tiles.setPosition(j * mapTileSize, i * mapTileSize);
tiles.setTextureRect(sf::IntRect(map[i][j].x * mapTileSize, map[i][j].y * mapTileSize, mapTileSize, mapTileSize));
gameWindow.draw(tiles);
}
}
}
//Draw the Selector rectangle
gameWindow.draw(Selected);
if (showToolBox == true)
{
activeTileSprite.setTextureRect(sf::IntRect(mapTileSize*yTileValue, mapTileSize*xTileValue, mapTileSize, mapTileSize));
//Draw toolbox
gameWindow.draw(toolbarBox);
gameWindow.draw(activeTileSprite);
gameWindow.draw(upArrowX);
gameWindow.draw(downArrowX);
gameWindow.draw(upArrowY);
gameWindow.draw(downArrowY);
//Update the strings for X and Y here
//Otherwise, it doesn't work for some reason
editBoxX.setString("Y: " + tempXTileValue);
editBoxY.setString("X: " + tempYTileValue);
gameWindow.draw(editBoxX);
gameWindow.draw(editBoxY);
gameWindow.draw(saveButton);
}
//Render buffer
gameWindow.display();
}
}
openfile.close();
return;
}
如果我需要添加(或删除)任何信息,请告诉我。
我已经四处查看但找不到任何类似的问题,所以希望我没有遗漏任何东西,并正确解释了我的问题。
再次感谢,
helpMeLearnC++
P.S。我应该提一下,我不是一个完全的初学者,但我也不是超级高级。
P.S.S.在尝试了 Selbie 的建议之后,我注意到,相当矛盾的是,除非鼠标移动,否则我的游戏不会更新......现在我想知道为什么这会比鼠标不动时产生更好的性能......(或代码我用过没有正常工作)。
P.S.S.S.在进一步修改代码之后,我发现了我认为的预期:当鼠标移动时,gameWindow.pollEvent() 优先于 while(gameWindow.isOpen()) 循环,后者执行绘图很可能是什么扼杀了我的表现。现在的问题是处理这个问题的最佳方法是什么。
P.S.S.S.S.对于那些好奇的人,假设我检查 FPS 的方法是正确的,我每秒渲染大约 27,000 帧(我的测试非常小,所以虽然我认为它看起来有点高,但我不会完全抹黑它)。
通过将 mousePositionGlobal 和 mousePositionLocal 移动到 pollEvent 循环中,我能够将性能从大约 20-35% 降低到大约 8-15%,并在剩下的过程中下降(大约 3% ) 当鼠标移动时。所以,取得了进展,但我仍然不确定是什么原因导致了差异......由于 FPS 已经上升到大约 35,000,我将假设我的计算代码是错误的。还有其他建议吗?
我敢打赌你的 CPU 是四核的。您看到的 CPU 百分比来自 Windows 任务管理器(或来自使用 Windows 性能计数器的其他应用程序)。我怀疑这是因为你有一个单线程游戏循环,它不停地运行,帧之间没有休眠。因此,您的“20-35%”CPU 实际上是您的程序在您的芯片上占用了一个完整的内核。这是任何想要以可能的最高帧速率渲染的游戏循环的典型特征。
我怀疑在您的显卡上,"moving the mouse" 也会产生与其他 windowed 游戏类似的性能特征。当您移动鼠标时,Windows 图形获得比游戏 window 更高的优先级并暂停游戏循环的渲染。因此,当鼠标四处移动时,您的代码仍然是 运行,但帧速率要低得多。由于图形系统必须处理游戏外的绘图请求,.draw() 或 .display() 调用被阻止 window。因此,您的游戏循环块和使用更少 CPU.
我的建议是在您的游戏中添加帧速率计数器 window。显示最后一秒累积的帧数的东西(需要一些额外的整数变量、时间函数和一些除法来计算帧速率)。我猜你会看到当鼠标移动时帧速率计数器变慢。
另外,在互联网上搜索 "code profiling tool"。 Visual Studio 的某些版本内置了 on。它们应该在您的代码花费大部分时间的地方。
一个简单的游戏循环,您不想在其中运行 CPU 可能类似于:
time last_render = now();
while( app_is_running ) {
Event e;
// eat all events. Ideally, more important than rendering,
// and should take only a little bit of time:
while ( get_event(&e) ) {
process_event(e); // <- note, does not render, should be **cheap**
}
// frame limit code:
while (now()-last_render < frame_limit) {
Event e;
if (wait_for_event(&e, (frame_limit-delta)/2))
process_event(e);
}
last_render = now(); // stamp before rendering
render(); // also includes other game state updates.
}
现在,sfml 似乎缺少 wait_for_event(Event*, timeout)
功能。这意味着你不能 "go to sleep while still responding to events"。因此,休眠要么使您的事件处理无响应,要么您必须对其进行管理,要么您需要多个线程。
我们可以建立一个线程安全队列,创建一个线程,其工作是 waitForEvent
并让它填充一个我们可以等待的队列,然后在队列上休眠和超时(基本上解决什么问题似乎是 sfml 缺陷)。
或者我们可以轮询和跟踪 CPU。离我远点 phone!
或者我们可以忍受 1 帧的用户输入响应延迟(我认为这是不可接受的)。
我不是游戏开发者,所以对这个建议持怀疑态度。