http://www.programming2dgames.com/chapter5.htm
示例一:Planet
真正示例的开始,首先是载入2张图片
1.Graphics添加了2个方法
loadTexture和drawSprite
loadTexture方法得到一个IRECT3DTEXTURE9接口
//============================================================================= // Load the texture into default D3D memory (normal texture use) // For internal engine use only. Use the TextureManager class to load game textures. // Pre: filename is name of texture file. // transcolor is transparent color // Post: width and height = size of texture // texture points to texture // Returns HRESULT //============================================================================= HRESULT Graphics::loadTexture(const char *filename, COLOR_ARGB transcolor, UINT &width, UINT &height, LP_TEXTURE &texture) { // The struct for reading file info D3DXIMAGE_INFO info; result = E_FAIL; try{ if(filename == NULL) { texture = NULL; return D3DERR_INVALIDCALL; } // Get width and height from file result = D3DXGetImageInfoFromFile(filename, &info); if (result != D3D_OK) return result; width = info.Width; height = info.Height; // Create the new texture by loading from file result = D3DXCreateTextureFromFileEx( device3d, //3D device filename, //image filename info.Width, //texture width info.Height, //texture height 1, //mip-map levels (1 for no chain) 0, //usage D3DFMT_UNKNOWN, //surface format (default) D3DPOOL_DEFAULT, //memory class for the texture D3DX_DEFAULT, //image filter D3DX_DEFAULT, //mip filter transcolor, //color key for transparency &info, //bitmap file info (from loaded file) NULL, //color palette &texture ); //destination texture } catch(...) { throw(GameError(gameErrorNS::FATAL_ERROR, "Error in Graphics::loadTexture")); } return result; }
drawSprite方法则是画精灵元素
//============================================================================= // Draw the sprite described in SpriteData structure // Color is optional, it is applied like a filter, WHITE is default (no change) // Pre : sprite->Begin() is called // Post: sprite->End() is called // spriteData.rect defines the portion of spriteData.texture to draw // spriteData.rect.right must be right edge + 1 // spriteData.rect.bottom must be bottom edge + 1 //============================================================================= void Graphics::drawSprite(const SpriteData &spriteData, COLOR_ARGB color) { if(spriteData.texture == NULL) // if no texture return; // Find center of sprite D3DXVECTOR2 spriteCenter=D3DXVECTOR2((float)(spriteData.width/2*spriteData.scale), (float)(spriteData.height/2*spriteData.scale)); // Screen position of the sprite D3DXVECTOR2 translate=D3DXVECTOR2((float)spriteData.x,(float)spriteData.y); // Scaling X,Y D3DXVECTOR2 scaling(spriteData.scale,spriteData.scale); if (spriteData.flipHorizontal) // if flip horizontal { scaling.x *= -1; // negative X scale to flip // Get center of flipped image. spriteCenter.x -= (float)(spriteData.width*spriteData.scale); // Flip occurs around left edge, translate right to put // Flipped image in same location as original. translate.x += (float)(spriteData.width*spriteData.scale); } if (spriteData.flipVertical) // if flip vertical { scaling.y *= -1; // negative Y scale to flip // Get center of flipped image spriteCenter.y -= (float)(spriteData.height*spriteData.scale); // Flip occurs around top edge, translate down to put // Flipped image in same location as original. translate.y += (float)(spriteData.height*spriteData.scale); } // Create a matrix to rotate, scale and position our sprite D3DXMATRIX matrix; D3DXMatrixTransformation2D( &matrix, // the matrix NULL, // keep origin at top left when scaling 0.0f, // no scaling rotation &scaling, // scale amount &spriteCenter, // rotation center (float)(spriteData.angle), // rotation angle &translate); // X,Y location // Tell the sprite about the matrix "Hello Neo" sprite->SetTransform(&matrix); // Draw the sprite sprite->Draw(spriteData.texture,&spriteData.rect,NULL,NULL,color); }
2.Texture的2个包装类
TextureManager(依赖loadTexture)用于载入一个IRECT3DTEXTURE9对象,Image类(依赖drawSprite)用于获取TextureManager的IRECT3DTEXTURE9对象并进行绘制
TextureManager
//============================================================================= // Loads the texture file from disk. // Post: returns true if successful, false if failed //============================================================================= bool TextureManager::initialize(Graphics *g, const char *f) { try{ graphics = g; // the graphics object file = f; // the texture file hr = graphics->loadTexture(file, TRANSCOLOR, width, height, texture); if (FAILED(hr)) { SAFE_RELEASE(texture); return false; } } catch(...) {return false;} initialized = true; // set true when successfully initialized return true; }
Image
//============================================================================= // Draw this image using the specified SpriteData. // The current SpriteData.rect is used to select the texture. // Pre : spriteBegin() is called // Post: spriteEnd() is called //============================================================================= void Image::draw(SpriteData sd, COLOR_ARGB color) { if (!visible || graphics == NULL) return; sd.rect = spriteData.rect; // use this Images rect to select texture sd.texture = textureManager->getTexture(); // get fresh texture incase onReset() was called if(color == graphicsNS::FILTER) // if draw with filter graphics->drawSprite(sd, colorFilter); // use colorFilter else graphics->drawSprite(sd, color); // use color as filter }
Spacewar载入图片
1.initialize
//============================================================================= // Initializes the game // Throws GameError on error //============================================================================= void Spacewar::initialize(HWND hwnd) { Game::initialize(hwnd); // throws GameError // nebula texture if (!nebulaTexture.initialize(graphics,NEBULA_IMAGE)) throw(GameError(gameErrorNS::FATAL_ERROR, "Error initializing nebula texture")); // planet texture if (!planetTexture.initialize(graphics,PLANET_IMAGE)) throw(GameError(gameErrorNS::FATAL_ERROR, "Error initializing planet texture")); // nebula if (!nebula.initialize(graphics,0,0,0,&nebulaTexture)) throw(GameError(gameErrorNS::FATAL_ERROR, "Error initializing nebula")); // planet if (!planet.initialize(graphics,0,0,0,&planetTexture)) throw(GameError(gameErrorNS::FATAL_ERROR, "Error initializing planet")); // place planet in center of screen planet.setX(GAME_WIDTH*0.5f - planet.getWidth()*0.5f); planet.setY(GAME_HEIGHT*0.5f - planet.getHeight()*0.5f); return; }
2.render
//============================================================================= // Render game items //============================================================================= void Spacewar::render() { graphics->spriteBegin(); // begin drawing sprites nebula.draw(); // add the orion nebula to the scene planet.draw(); // add the planet to the scene graphics->spriteEnd(); // end drawing sprites }
呈现了2个图片
示例二:Spaceship
动画
重复更新1张图的4个位置
//=============================================================================
// update
// typically called once per frame
// frameTime is used to regulate the speed of movement and animation
//=============================================================================
void Image::update(float frameTime)
{
if (endFrame - startFrame > 0) // if animated sprite
{
animTimer += frameTime; // total elapsed time
if (animTimer > frameDelay)
{
animTimer -= frameDelay;
currentFrame++;
if (currentFrame < startFrame || currentFrame > endFrame)
{
if(loop == true) // if looping animation
currentFrame = startFrame;
else // not looping animation
{
currentFrame = endFrame;
animComplete = true; // animation complete
}
}
setRect(); // set spriteData.rect
}
}
}
//=============================================================================
// Set spriteData.rect to draw currentFrame
//=============================================================================
inline void Image::setRect()
{
// configure spriteData.rect to draw currentFrame
spriteData.rect.left = (currentFrame % cols) * spriteData.width;
// right edge + 1
spriteData.rect.right = spriteData.rect.left + spriteData.width;
spriteData.rect.top = (currentFrame / cols) * spriteData.height;
// bottom edge + 1
spriteData.rect.bottom = spriteData.rect.top + spriteData.height;
}
示例三:Spaceship Movement
各种效果叠加组成的动画效果(图片更换,角度,大小,位置)来模拟
//=============================================================================
// Update all game items
//=============================================================================
void Spacewar::update()
{
ship.update(frameTime);
ship.setDegrees(ship.getDegrees() + frameTime * ROTATION_RATE); // rotate ship
ship.setScale(ship.getScale() - frameTime * SCALE_RATE); // make ship smaller
ship.setX(ship.getX() + frameTime * SHIP_SPEED); // move ship right
if (ship.getX() > GAME_WIDTH) // if off screen right
{
ship.setX((float)-ship.getWidth()); // position off screen left
ship.setScale(SHIP_SCALE); // set to starting size
}
}
示例四:Spaceship Control
根据键盘来移动元素
//=============================================================================
// Update all game items
//=============================================================================
void Spacewar::update()
{
if(input->isKeyDown(SHIP_RIGHT_KEY)) // if move right
{
ship.setX(ship.getX() + frameTime * SHIP_SPEED);
if (ship.getX() > GAME_WIDTH) // if off screen right
ship.setX((float)-ship.getWidth()); // position off screen left
}
if(input->isKeyDown(SHIP_LEFT_KEY)) // if move left
{
ship.setX(ship.getX() - frameTime * SHIP_SPEED);
if (ship.getX() < -ship.getWidth()) // if off screen left
ship.setX((float)GAME_WIDTH); // position off screen right
}
if(input->isKeyDown(SHIP_UP_KEY)) // if move up
{
ship.setY(ship.getY() - frameTime * SHIP_SPEED);
if (ship.getY() < -ship.getHeight()) // if off screen top
ship.setY((float)GAME_HEIGHT); // position off screen bottom
}
if(input->isKeyDown(SHIP_DOWN_KEY)) // if move down
{
ship.setY(ship.getY() + frameTime * SHIP_SPEED);
if (ship.getY() > GAME_HEIGHT) // if off screen bottom
ship.setY((float)-ship.getHeight()); // position off screen top
}
ship.update(frameTime);
}