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

在DirectX中使用貼片
渲染小型矩形紋理映射的多邊形并不困難,它可以非常完美地表現(xiàn)出貼片。要想實(shí)現(xiàn)它,可以通過一個(gè)特殊的D3DX對(duì)象ID3DXSprite。ID3DXSprite對(duì)象惟一的工作就是使用所指定的具體紋理,將矩形多邊形繪制到屏幕上。當(dāng)然,給出的紋理將被包含在貼片中。
來看看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中使用貼片,首先要實(shí)例化一個(gè)ID3DXSprite對(duì)象,使用D3DXCreateSprite功能函數(shù)對(duì)它進(jìn)行初始化。
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.
繪制貼片可以調(diào)用ID3DXSprite::Draw函數(shù)。
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函數(shù)的技巧就是構(gòu)造一個(gè)源矩形的RECT結(jié)構(gòu)以及貼片紋理的坐標(biāo)。比如,有一個(gè)256 x 256像素大小的紋理,它包含了64個(gè)貼片(每個(gè)貼片為32
x 32像素大小),排列布置為8行8列,如下圖所示:

如果需要對(duì)要繪制的貼片進(jìn)行旋轉(zhuǎn)、縮放、平移等操作,則需要在調(diào)用Draw之前調(diào)用SetTransform進(jìn)行設(shè)置。
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
構(gòu)造處理貼片的類
貼片類的代碼以創(chuàng)建游戲內(nèi)核中編寫的游戲內(nèi)核代碼為基礎(chǔ)。
來看看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;
構(gòu)造函數(shù)初始化數(shù)據(jù),析構(gòu)函數(shù)釋放已分配的內(nèi)存:
//----------------------------------------------------------------------------------
// 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函數(shù)分配TEXTURE對(duì)象數(shù)組以便在其中存儲(chǔ)貼片,請(qǐng)確保給該函數(shù)傳遞一個(gè)預(yù)先初始化好的GRAPHICS對(duì)象。
//----------------------------------------------------------------------------------
// 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負(fù)責(zé)將一個(gè)紋理加載到指定的紋理數(shù)組中。例如,如果創(chuàng)建TILE對(duì)象使用了5個(gè)紋理,可以指定從0-4的任何元素去加載一個(gè)紋理。所有的紋理都是通過它們?cè)诩y理數(shù)組中的索引來進(jìn)行引用的。當(dāng)加載一個(gè)紋理文件時(shí),必須指定存儲(chǔ)在紋理上的貼片的大?。ㄒ韵袼赜?jì)),那些貼片將被裝配到紋理上,從左到右從上到下,第一個(gè)貼片從紋理左上角的像素開始。
如果想使用透明位塊傳送,最后的兩個(gè)參數(shù)將會(huì)非常有用。將transparent參數(shù)設(shè)置為一個(gè)有效的D3DCOLOR數(shù)值(使用
D3DCOLOR_RGBA或其他類似的宏,請(qǐng)確保使用alpha值255),而且讓format保留它的默認(rèn)設(shè)置D3DFMT_A1R5G5B5,或者從Direect3D提供的可用格式列表中指定一個(gè)。
//----------------------------------------------------------------------------------
// 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;
}
釋放特定的紋理資源可以調(diào)用free_texture函數(shù)。
//----------------------------------------------------------------------------------
// 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來分別獲得指定紋理貼片的寬度、高度、貼片總數(shù)。
//----------------------------------------------------------------------------------
// 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測(cè)試,這意味著當(dāng)啟動(dòng)時(shí),被加載的帶有適當(dāng)透明色彩及顏色格式的紋理將使用透明位塊傳送。默認(rèn)情況下,enabled被設(shè)置為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);
}