------------------------------------------------------------------------------
原文作者:lovedday
原文地址:点击打开链接
------------------------------------------------------------------------------
贴片与地图
二维游戏的核心绘制技术就是所谓的贴片技术(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行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的任何元素去加载一个纹 理。所有的纹理都是通过它们在纹理数组中的索引来进行引用的。当加载一个纹理文件时,必须指定存储在纹理上的贴片的大小(以像素计),那些贴片将被装配到 纹理上,从左到右从上到下,第一个贴片从纹理左上角的像素开始。
如果想使用透明位块传送,最后的两个参数将会非常有用。将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);
}