貼片與地圖
二維游戲的核心繪制技術就是所謂的貼片技術(tiling),在進行貼圖的過程中,用較小的像素矩形分組(小位圖稱之為貼片)構造一個較大的場景,貼片的繪制過程稱為映射。
如下圖所示,左邊4個編號的小圖像就是貼片,中間一個加了編號的柵格代表了繪制貼片的布局(按編號順序進行描繪的方式)。對于每個柵格單元,開始繪制編號各自代表的貼片,直到整個場景被繪制完。這個柵格就是地圖,當柵格被繪制完成后,便得到右邊的圖像。

在DirectX中使用貼片
渲染小型矩形紋理映射的多邊形并不困難,它可以非常完美地表現出貼片。要想實現它,可以通過一個特殊的D3DX對象ID3DXSprite。ID3DXSprite對象惟一的工作就是使用所指定的具體紋理,將矩形多邊形繪制到屏幕上。當然,給出的紋理將被包含在貼片中。
來看看DirectX SDK文檔提供的ID3DXSprite類的簡要信息:
The ID3DXSprite interface provides a set of methods that simplify the process
of drawing sprites using Microsoft Direct3D.
ID3DXSprite Members
Method |
Description |
ID3DXSprite::Begin |
Prepares
a device for drawing sprites. |
ID3DXSprite::Draw |
Adds a
sprite to the list of batched sprites. |
ID3DXSprite::End |
Calls
ID3DXSprite::Flush and restores the device state to how it was before
ID3DXSprite::Begin was called. |
ID3DXSprite::Flush |
Forces
all batched sprites to be submitted to the device. Device states remain
as they were after the last call to ID3DXSprite::Begin. The list
of batched sprites is then cleared. |
ID3DXSprite::GetDevice |
Retrieves the device associated with the sprite object. |
ID3DXSprite::GetTransform |
Gets the
sprite transform. |
ID3DXSprite::OnLostDevice |
Use this
method to release all references to video memory resources and delete
all stateblocks. This method should be called whenever a device is lost
or before resetting a device. |
ID3DXSprite::OnResetDevice |
Use this
method to re-acquire resources and save initial state. |
ID3DXSprite::SetTransform |
Sets the
sprite transform. |
ID3DXSprite::SetWorldViewLH |
Sets the
left-handed world-view transform for a sprite. A call to this method is
required before billboarding or sorting sprites. |
ID3DXSprite::SetWorldViewRH |
Sets the
right-handed world-view transform for a sprite. A call to this method is
required before billboarding or sorting sprites. |
Remarks
The ID3DXSprite interface is obtained by calling the
D3DXCreateSprite function.
The application typically first calls ID3DXSprite::Begin,
which allows control over the device render state, alpha blending, and sprite
transformation and sorting. Then for each sprite to be displayed, call
ID3DXSprite::Draw. ID3DXSprite::Draw can be called
repeatedly to store any number of sprites. To display the batched sprites to the
device, call ID3DXSprite::End or ID3DXSprite::Flush.
The LPD3DXSPRITE type is defined as a pointer to the ID3DXSprite
interface.
typedef interface ID3DXSprite ID3DXSprite;
typedef interface ID3DXSprite *LPD3DXSPRITE;
在Direct3D中使用貼片,首先要實例化一個ID3DXSprite對象,使用D3DXCreateSprite功能函數對它進行初始化。
Creates a sprite object which is associated with a particular device. Sprite
objects are used to draw 2D images to the screen.
HRESULT D3DXCreateSprite(
LPDIRECT3DDEVICE9 pDevice,
LPD3DXSPRITE * ppSprite
);
Parameters
- pDevice
- [in] Pointer to an IDirect3DDevice9 interface, the device to be
associated with the sprite.
- ppSprite
- [out] Address of a pointer to an ID3DXSprite interface. This interface
allows the user to access sprite functions.
Return Values
If the function succeeds, the return value is S_OK. If the function fails,
the return value can be one of the following: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
Remarks
This interface can be used to draw two dimensional images in screen space of
the associated device.
繪制貼片可以調用ID3DXSprite::Draw函數。
Adds a sprite to the list of batched sprites.
HRESULT Draw(
LPDIRECT3DTEXTURE9 pTexture,
CONST RECT * pSrcRect,
CONST D3DXVECTOR3 * pCenter,
CONST D3DXVECTOR3 * pPosition,
D3DCOLOR Color
);
Parameters
- pTexture
- [in] Pointer to an IDirect3DTexture9 interface that represents the
sprite texture.
- pSrcRect
- [in] Pointer to a RECT structure that indicates the portion of the
source texture to use for the sprite. If this parameter is NULL, then the
entire source image is used for the sprite.
- pCenter
- [in] Pointer to a D3DXVECTOR3 vector that identifies the center of the
sprite. If this argument is NULL, the point (0,0,0) is used, which is the
upper-left corner.
- pPosition
- [in] Pointer to a D3DXVECTOR3 vector that identifies
the position of the sprite. If this argument is NULL, the point (0,0,0) is
used, which is the upper-left corner.
- Color
- [in] D3DCOLOR type. The color and alpha channels are modulated by this
value. A value of 0xFFFFFFFF maintains the original source color and alpha
data. Use the D3DCOLOR_RGBA macro to help generate this color.
Return Values
If the method succeeds, the return value is S_OK. If the method fails, the
return value can be one of the following: D3DERR_INVALIDCALL,
D3DXERR_INVALIDDATA.
Remarks
To scale, rotate, or translate a sprite, call ID3DXSprite::SetTransform with
a matrix that contains the scale, rotate, and translate (SRT) values, before
calling ID3DXSprite::Draw. For information about setting SRT values in a matrix,
see Matrix Transforms.
使用Draw函數的技巧就是構造一個源矩形的RECT結構以及貼片紋理的坐標。比如,有一個256 x 256像素大小的紋理,它包含了64個貼片(每個貼片為32
x 32像素大?。帕胁贾脼?行8列,如下圖所示:

如果需要對要繪制的貼片進行旋轉、縮放、平移等操作,則需要在調用Draw之前調用SetTransform進行設置。
Sets the sprite transform.
HRESULT SetTransform(
CONST D3DXMATRIX * pTransform
);
Parameters
- pTransform
- [in] Pointer to a D3DXMATRIX that contains a transform of the sprite
from the original world space. Use this transform to scale, rotate, or
transform the sprite.
Return Values
If the method succeeds, the return value is S_OK. If the method fails, the
following value will be returned.
D3DERR_INVALIDCALL
構造處理貼片的類
貼片類的代碼以創建游戲內核中編寫的游戲內核代碼為基礎。
來看看TILE類的定義:
//=========================================================================================
// This class encapsulate 2D graphics tile draw.
//=========================================================================================
typedef class TILE
{
private:
GRAPHICS_PTR _graphics; // parent graphics
long _num_textures; // number of textures
TEXTURE_PTR _textures; // TEXTURE array
long* _tile_widths; // tile width array
long* _tile_heights; // tile height array
long* _tile_columns; // number of tile columns in texture
public:
TILE();
~TILE();
// functions to create and free the tile interface
BOOL create(GRAPHICS_PTR graphics, long num_textures);
void free();
// functions to load and free a single texture
BOOL load_texture(long texture_index, const char* texture_filename,
short tile_width = 0, short tile_height = 0,
D3DCOLOR transparent = 0,
D3DFORMAT format = D3DFMT_A1R5G5B5);
void free_texture(long texture_index);
// functions to retrieve tile dimensions and number of tiles in a texture
long get_tile_width(long texture_index);
long get_tile_height(long texture_index);
long get_tile_number(long texture_index);
// enable or disable transparent blitting
BOOL set_transparent(BOOL enabled = TRUE);
// draw a single tile at specified location
BOOL draw_tile(long texture_index, long tile_index,
long screen_x, long screen_y,
D3DCOLOR color = 0xFFFFFFFF,
float x_scale = 1.0f, float y_scale = 1.0f);
} *TILE_PTR;
構造函數初始化數據,析構函數釋放已分配的內存:
//----------------------------------------------------------------------------------
// Constructor, zero member data.
//----------------------------------------------------------------------------------
TILE::TILE()
{
memset(this, 0, sizeof(*this));
}
//----------------------------------------------------------------------------------
// Destructor, free allocated resource.
//----------------------------------------------------------------------------------
TILE::~TILE()
{
free();
}
//----------------------------------------------------------------------------------
// Free allocated resource.
//----------------------------------------------------------------------------------
void TILE::free()
{
_graphics = NULL;
// free all tetxures
if(_num_textures)
{
for(short i = 0; i < _num_textures; i++)
_textures[i].free();
}
delete[] _textures;
_textures = NULL;
// free width, height, and column arrays.
delete[] _tile_widths;
delete[] _tile_heights;
delete[] _tile_columns;
_tile_widths = _tile_heights = _tile_columns = NULL;
_num_textures = 0;
}
create函數分配TEXTURE對象數組以便在其中存儲貼片,請確保給該函數傳遞一個預先初始化好的GRAPHICS對象。
//----------------------------------------------------------------------------------
// Allocate memory.
//----------------------------------------------------------------------------------
BOOL TILE::create(GRAPHICS_PTR graphics, long num_textures)
{
// free in case of existing data
free();
// error checking
if((_graphics = graphics) == NULL)
return FALSE;
if((_num_textures = num_textures) == 0)
return FALSE;
// allocate texture objects
if((_textures = new TEXTURE[_num_textures]) == NULL)
return FALSE;
// allocate width, height, and column count arrays
_tile_widths = new long[_num_textures];
_tile_heights = new long[_num_textures];
_tile_columns = new long[_num_textures];
return TRUE;
}
load_texture負責將一個紋理加載到指定的紋理數組中。例如,如果創建TILE對象使用了5個紋理,可以指定從0-4的任何元素去加載一個紋理。所有的紋理都是通過它們在紋理數組中的索引來進行引用的。當加載一個紋理文件時,必須指定存儲在紋理上的貼片的大?。ㄒ韵袼赜嫞切┵N片將被裝配到紋理上,從左到右從上到下,第一個貼片從紋理左上角的像素開始。
如果想使用透明位塊傳送,最后的兩個參數將會非常有用。將transparent參數設置為一個有效的D3DCOLOR數值(使用
D3DCOLOR_RGBA或其他類似的宏,請確保使用alpha值255),而且讓format保留它的默認設置D3DFMT_A1R5G5B5,或者從Direect3D提供的可用格式列表中指定一個。
//----------------------------------------------------------------------------------
// Load texture from file.
//----------------------------------------------------------------------------------
BOOL TILE::load_texture(long texture_index, const char* texture_filename,
short tile_width, short tile_height,
D3DCOLOR transparent, D3DFORMAT format)
{
// error checking
if(texture_index >= _num_textures || _textures == NULL || texture_filename == NULL)
return FALSE;
// free older texture resource
free_texture(texture_index);
// load the texture
if(! _textures[texture_index].load(_graphics, texture_filename, transparent, format))
return FALSE;
// store width value (get width of texture if no tile_width was specified).
if(tile_width == 0)
_tile_widths[texture_index] = _textures[texture_index].get_width();
else
_tile_widths[texture_index] = tile_width;
// store height value (get height of texture if no tile_height was specified).
if(tile_height == 0)
_tile_heights[texture_index] = _textures[texture_index].get_height();
else
_tile_heights[texture_index] = tile_height;
// Calculate how many columns of tiles there are in the texture.
// This is used to speed up calculations when drawing tiles.
_tile_columns[texture_index] = _textures[texture_index].get_width() / _tile_widths[texture_index];
return TRUE;
}
釋放特定的紋理資源可以調用free_texture函數。
//----------------------------------------------------------------------------------
// Free specified texture.
//----------------------------------------------------------------------------------
void TILE::free_texture(long texture_index)
{
// error checking
if(texture_index >= _num_textures || _textures == NULL)
return;
// free a single texture resource
_textures[texture_index].free();
}
使用get_tile_width,get_tile_height,get_tile_number來分別獲得指定紋理貼片的寬度、高度、貼片總數。
//----------------------------------------------------------------------------------
// Return tile width.
//----------------------------------------------------------------------------------
long TILE::get_tile_width(long texture_index)
{
// error checking
if(texture_index >= _num_textures || _tile_widths == NULL)
return 0;
return _tile_widths[texture_index];
}
//----------------------------------------------------------------------------------
// Return tile height.
//----------------------------------------------------------------------------------
long TILE::get_tile_height(long texture_index)
{
// error checking
if(texture_index >= _num_textures || _tile_widths == NULL)
return 0;
return _tile_heights[texture_index];
}
//----------------------------------------------------------------------------------
// Return number of tiles.
//----------------------------------------------------------------------------------
long TILE::get_tile_number(long texture_index)
{
// error checking
if(texture_index >= _num_textures || _textures == NULL ||
_tile_columns == NULL || _tile_widths == NULL || _tile_heights == NULL)
{
return 0;
}
return _tile_columns[texture_index] * (_textures[texture_index].get_height() / _tile_heights[texture_index]);
}
使用set_transparent來啟用或禁用alpha測試,這意味著當啟動時,被加載的帶有適當透明色彩及顏色格式的紋理將使用透明位塊傳送。默認情況下,enabled被設置為TRUE。
//----------------------------------------------------------------------------------
// Enable or disable alpha testing.
//----------------------------------------------------------------------------------
BOOL TILE::set_transparent(BOOL enabled)
{
// error checking
if(_graphics == NULL)
return FALSE;
return _graphics->enable_alpha_testing(enabled);
}
繪制貼片使用draw_tile方法:
//----------------------------------------------------------------------------------
// Draw tile.
//----------------------------------------------------------------------------------
BOOL TILE::draw_tile(long texture_index, long tile_index,
long screen_x, long screen_y,
D3DCOLOR color,
float x_scale, float y_scale)
{
// error checking
if(_graphics == NULL || _textures == NULL || texture_index >= _num_textures)
return FALSE;
// calculate the source tile coordinates from texture
long src_x = (tile_index % _tile_columns[texture_index]) * _tile_widths[texture_index];
long src_y = (tile_index / _tile_columns[texture_index]) * _tile_heights[texture_index];
return _textures[texture_index].blit(screen_x ,screen_y, src_x, src_y,
_tile_widths[texture_index], _tile_heights[texture_index], x_scale, y_scale, color);
}