贴片与地图
二维游戏的核心绘制技术就是所谓的贴片技术(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);
}