原书中GameEngine的代码有两处bug,源代码分别为:
void GameEngine::CleanupSprites() { // Delete and remove the sprites in the sprite vector vector<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++) { delete (*siSprite); m_vSprites.erase(siSprite); siSprite--; } }
void GameEngine::UpdateSprites() { // Check to see if the sprite vector needs to grow if (m_vSprites.size() >= (m_vSprites.capacity() / 2)) m_vSprites.reserve(m_vSprites.capacity() * 2); // Update the sprites in the sprite vector RECT rcOldSpritePos; SPRITEACTION saSpriteAction; vector<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++) { // Save the old sprite position in case we need to restore it rcOldSpritePos = (*siSprite)->GetPosition(); // Update the sprite saSpriteAction = (*siSprite)->Update(); // Handle the SA_KILL sprite action if (saSpriteAction & SA_KILL) { // Notify the game that the sprite is dying SpriteDying(*siSprite); delete (*siSprite); m_vSprites.erase(siSprite); siSprite--; continue; } // See if the sprite collided with any others if (CheckSpriteCollision(*siSprite)) // Restore the old sprite position (*siSprite)->SetPosition(rcOldSpritePos); } }
这两段代码在VC6编译器能正常运行,但在VS2008以后的编译器编译之后运行时产生错误,分别修正如下:
void GameEngine::CleanupSprites() { // Delete and remove the sprites in the sprite vector vector<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++) { delete (*siSprite);//注意这里 } m_vSprites.clear();//注意这里 } //================================================= //或 void GameEngine::CleanupSprites() { // Delete and remove the sprites in the sprite vector vector<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)//注意这里 { delete (*siSprite); siSprite = m_vSprites.erase(siSprite); //注意这里 } } //=====================================================
void GameEngine::UpdateSprites() { // Check to see if the sprite vector needs to grow if (m_vSprites.size() >= (m_vSprites.capacity() / 2)) { m_vSprites.reserve(m_vSprites.capacity() * 2); } // Update the sprites in the sprite vector RECT rcOldSpritePos; SPRITEACTION saSpriteAction; vector<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)//注意这里 { // Save the old sprite position in case we need to restore it rcOldSpritePos = (*siSprite)->GetPosition(); // Update the sprite saSpriteAction = (*siSprite)->Update(); // Handle the SA_KILL sprite action if (saSpriteAction & SA_KILL) { // Notify the game that the sprite is dying SpriteDying(*siSprite); delete (*siSprite); //siSprite--; siSprite = m_vSprites.erase(siSprite); //注意这里 continue; } // See if the sprite collided with any others if (CheckSpriteCollision(*siSprite)) { // Restore the old sprite position (*siSprite)->SetPosition(rcOldSpritePos); } siSprite++;//注意这里 } }
分析:vector.erase(p)之后,所有指向p所指的内存的迭代器全部失效,但是它的返回值是指向下一个元素的迭代器。以前的编译器之所以能够成功运行,应该是之前的标准并不清晰或者编译器内部实现的问题,VS2008之后严格按照标准来之后就出现运行时错误。
PS :
《BEGINNING GAME PROGRAMMING》 中还有个问题:程序要是换用了修改了BMP图像资源,结果是图像不能正常显示变黑的了。
http://blog.csdn.net/dkink/article/details/2310564 给出了解决办法,但还有点小问题,下面给出原因和改正办法。
这里作者忽略了一个小小的问题,...........无压缩BMP文件的
pBitmapInfo->bmiHeader.biSizeImage 里面的值不一定是图像的真实大小,可能是0或者随意的值。 所以需要重新计算,在Bitmap.cpp里面,Bitmap类的 两个Create函数的下面这个位置添加计算biSizeImage的代码。
// Store the width and height of the bitmap
BITMAPINFO* pBitmapInfo = (BITMAPINFO*)pBitmapImage;
m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;
// 计算biSizeImage填充回去,是增加的代码
//注意这里
int lineByte=(m_iWidth*pBitmapInfo->bmiHeader.biBitCount/8+3)/4*4; //位图每行占多少个字节
pBitmapInfo->bmiHeader.biSizeImage = m_iHeight*lineByte;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Get a handle to the bitmap and copy the image bits
PBYTE pBitmapBits;
m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
(PVOID*)&pBitmapBits, NULL, 0);
参考资料:
1.C++Primer中文版(第四版)P282~283
2.http://www.cplusplus.com/forum/beginner/47420/
3.http://blog.csdn.net/dkink/article/details/2330905
4.http://blog.csdn.net/vhshiwen/article/details/4808867
5.http://www.cnblogs.com/buxianghe/archive/2012/06/25/2560713.html