具体细节说明请参考二维图形的使用。
下载源码和工程
为了简化编程,首先定义一些辅助宏和对一些类型进行重定义。
#define release_com(x) { if(x) { x->Release(); x = NULL; } }
#define free_memory(x) { free(x); (x) = NULL; }
#define STREQ(a, b) (*(a) == (*b) && strcmp((a), (b)) == 0)
#define err_msg_box(msg) MessageBox(NULL, msg, "Error", MB_OK)
typedef unsigned char uchar;
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef char* char_ptr;
typedef char* pstr;
typedef uchar* uchar_ptr;
typedef long* long_ptr;
typedef float* float_ptr;
typedef const char* pcstr;
TILE类的定义:
/*************************************************************************
PURPOSE:
Interface for 2D tile.
*************************************************************************/
#ifndef _TILE_H_
#define _TILE_H_
#include "core_common.h"
//=========================================================================================
// This class encapsulate 2D graphics tile draw.
//=========================================================================================
typedef class TILE
{
public:
TILE();
~TILE();
// functions to create and free the tile interface
BOOL create(long num_textures);
void free();
// functions to load and free a single texture
BOOL load_texture(long texture_index, pcstr texture_filename,
short tile_width, short tile_height,
D3DCOLOR transparent, D3DFORMAT format);
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);
// draw a single tile at specified location
BOOL draw_tile(long texture_index, long tile_index,
long screen_x, long screen_y,
D3DCOLOR color,
float x_scale, float y_scale);
private:
long m_num_textures; // number of textures
TEXTURE_PTR m_textures; // TEXTURE array
long_ptr m_tile_widths; // tile width array
long_ptr m_tile_heights; // tile height array
long_ptr m_tile_columns; // number of tile columns in texture
} *TILE_PTR;
#endif
TILE类的实现:
/*************************************************************************
PURPOSE:
Implements for 2D graphics tile.
*************************************************************************/
#include "core_common.h"
#include "core_graphics.h"
#include "tile.h"
//----------------------------------------------------------------------------------
// Constructor, zero member data.
//----------------------------------------------------------------------------------
TILE::TILE()
{
memset(this, 0, sizeof(*this));
}
//----------------------------------------------------------------------------------
// Destructor, free allocated resource.
//----------------------------------------------------------------------------------
TILE::~TILE()
{
free();
}
//----------------------------------------------------------------------------------
// Free allocated resource.
//----------------------------------------------------------------------------------
void TILE::free()
{
// free all tetxures
if(m_num_textures)
{
for(short i = 0; i < m_num_textures; i++)
m_textures[i].free();
}
delete[] m_textures;
m_textures = NULL;
// free width, height, and column arrays.
delete[] m_tile_widths;
delete[] m_tile_heights;
delete[] m_tile_columns;
m_tile_widths = m_tile_heights = m_tile_columns = NULL;
m_num_textures = 0;
}
//----------------------------------------------------------------------------------
// Allocate memory.
//----------------------------------------------------------------------------------
BOOL TILE::create(long num_textures)
{
// free in case of existing data
free();
if((m_num_textures = num_textures) == 0)
return FALSE;
// allocate texture objects
if((m_textures = new TEXTURE[m_num_textures]) == NULL)
return FALSE;
// allocate width, height, and column count arrays
m_tile_widths = new long[m_num_textures];
m_tile_heights = new long[m_num_textures];
m_tile_columns = new long[m_num_textures];
return TRUE;
}
//----------------------------------------------------------------------------------
// Load texture from file.
//----------------------------------------------------------------------------------
BOOL TILE::load_texture(long texture_index, pcstr texture_filename,
short tile_width, short tile_height,
D3DCOLOR transparent, D3DFORMAT format)
{
// error checking
if(texture_index >= m_num_textures || m_textures == NULL || texture_filename == NULL)
return FALSE;
// free older texture resource
free_texture(texture_index);
// load the texture
if(! m_textures[texture_index].load(texture_filename, transparent, format))
return FALSE;
// store width value (get width of texture if no tile_width was specified).
if(tile_width == 0)
m_tile_widths[texture_index] = m_textures[texture_index].get_width();
else
m_tile_widths[texture_index] = tile_width;
// store height value (get height of texture if no tile_height was specified).
if(tile_height == 0)
m_tile_heights[texture_index] = m_textures[texture_index].get_height();
else
m_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.
m_tile_columns[texture_index] = m_textures[texture_index].get_width() / m_tile_widths[texture_index];
return TRUE;
}
//----------------------------------------------------------------------------------
// Free specified texture.
//----------------------------------------------------------------------------------
void TILE::free_texture(long texture_index)
{
// error checking
if(texture_index >= m_num_textures || m_textures == NULL)
return;
// free a single texture resource
m_textures[texture_index].free();
}
//----------------------------------------------------------------------------------
// Return tile width.
//----------------------------------------------------------------------------------
long TILE::get_tile_width(long texture_index)
{
// error checking
if(texture_index >= m_num_textures || m_tile_widths == NULL)
return 0;
return m_tile_widths[texture_index];
}
//----------------------------------------------------------------------------------
// Return tile height.
//----------------------------------------------------------------------------------
long TILE::get_tile_height(long texture_index)
{
// error checking
if(texture_index >= m_num_textures || m_tile_widths == NULL)
return 0;
return m_tile_heights[texture_index];
}
//----------------------------------------------------------------------------------
// Return number of tiles.
//----------------------------------------------------------------------------------
long TILE::get_tile_number(long texture_index)
{
// error checking
if(texture_index >= m_num_textures || m_textures == NULL ||
m_tile_columns == NULL || m_tile_widths == NULL || m_tile_heights == NULL)
{
return 0;
}
return m_tile_columns[texture_index] * (m_textures[texture_index].get_height() / m_tile_heights[texture_index]);
}
//----------------------------------------------------------------------------------
// 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(m_textures == NULL || texture_index >= m_num_textures)
return FALSE;
// calculate the source tile coordinates from texture
long _src_x = (tile_index % m_tile_columns[texture_index]) * m_tile_widths[texture_index];
long _src_y = (tile_index / m_tile_columns[texture_index]) * m_tile_heights[texture_index];
return m_textures[texture_index].draw(screen_x ,screen_y, _src_x, _src_y,
m_tile_widths[texture_index], m_tile_heights[texture_index], x_scale, y_scale, color);
}
MAP类的定义:
/*************************************************************************
PURPOSE:
Interface for 2D map.
*************************************************************************/
#ifndef _MAP_H_
#define _MAP_H_
#include "core_common.h"
#define MAX_OBJECTS 1024
typedef struct OBJECT_INFO
{
long x_pos, y_pos;
char tile_index;
} *OBJECT_INFO_PTR;
//=========================================================================================
// This class encapsulate 2D map draw.
//=========================================================================================
typedef class MAP
{
public:
MAP();
~MAP();
// function to create and free a map class
BOOL create(long num_layers, long map_column, long map_row);
void free();
// function to set a map's layer data
BOOL set_map_layer_data(long layer_index, char_ptr layer_data);
// function to clear and add an object to list
void clear_object_list();
BOOL add_object(long x_pos, long y_pos, char tile_index);
char_ptr get_ptr(long layer_index); // get pointer to map array
long get_map_column(); // get column of map
long get_map_row(); // get row of map
// assign TILE object to use for drawing map tiles
BOOL use_tile(TILE_PTR tile);
// Render map using specified top-left map coordinates,
// as well as number of columns and rows to draw, plus layer used to draw objects.
BOOL render(long pos_x, long pos_y,
long num_rows, long num_columns,
long object_layer,
D3DCOLOR color,
float scale_x, float scale_y);
private:
long m_map_column; // column of map
long m_map_row; // row of map
long m_per_layer_size; // size of per map
long m_num_layers; // number of layers
char_ptr m_map_info; // array for tile informarion
TILE_PTR m_tile; // pointer to TILE object
long m_num_objects_to_draw; // number of object need to be drawed
OBJECT_INFO m_objects_info[MAX_OBJECTS]; // object information array
} *MAP_PTR;
#endif
MAP类的实现:
/*************************************************************************
PURPOSE:
Implement for 2D map.
*************************************************************************/
#include "core_common.h"
#include "core_graphics.h"
#include "tile.h"
#include "map.h"
//----------------------------------------------------------------------------------
// Constructor, zero member data.
//----------------------------------------------------------------------------------
MAP::MAP()
{
memset(this, 0, sizeof(*this));
}
//----------------------------------------------------------------------------------
// Destructor, release allocated resources.
//----------------------------------------------------------------------------------
MAP::~MAP()
{
free();
}
//----------------------------------------------------------------------------------
// Release allocated resources.
//----------------------------------------------------------------------------------
void MAP::free()
{
// free map information array
delete[] m_map_info;
m_map_info = NULL;
m_map_column = m_map_row = 0;
m_num_layers = 0;
}
//----------------------------------------------------------------------------------
// Create map object.
//----------------------------------------------------------------------------------
BOOL MAP::create(long num_layers, long map_column, long map_row)
{
// free a prior map
free();
// save number of layers, map column and row.
m_num_layers = num_layers;
m_map_column = map_column;
m_map_row = map_row;
m_per_layer_size = map_column * map_row;
long total_map_size = num_layers * m_per_layer_size;
// allocate map data memory
if((m_map_info = new char[total_map_size]) == NULL)
return FALSE;
// clear it out
ZeroMemory(m_map_info, total_map_size);
// reset number of objexts to draw
m_num_objects_to_draw = 0;
return TRUE;
}
//----------------------------------------------------------------------------------
// Set map data.
//----------------------------------------------------------------------------------
BOOL MAP::set_map_layer_data(long layer_index, char_ptr layer_data)
{
// error checking
if(layer_index >= m_num_layers)
return FALSE;
// copy over data
memcpy(&m_map_info[layer_index * m_per_layer_size], layer_data, m_per_layer_size);
return TRUE;
}
//----------------------------------------------------------------------------------
// Clear object list which need to be drawed.
//----------------------------------------------------------------------------------
void MAP::clear_object_list()
{
m_num_objects_to_draw = 0;
}
//----------------------------------------------------------------------------------
// Add object to object list.
//----------------------------------------------------------------------------------
BOOL MAP::add_object(long x_pos, long y_pos, char tile_index)
{
if(m_num_objects_to_draw < MAX_OBJECTS)
{
m_objects_info[m_num_objects_to_draw].x_pos = x_pos;
m_objects_info[m_num_objects_to_draw].y_pos = y_pos;
m_objects_info[m_num_objects_to_draw].tile_index = tile_index;
m_num_objects_to_draw++;
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------------------
// Return pointer to specfied layer map data.
//----------------------------------------------------------------------------------
char_ptr MAP::get_ptr(long layer_index)
{
if(layer_index >= m_num_layers)
return NULL;
return &m_map_info[layer_index * m_per_layer_size];
}
//----------------------------------------------------------------------------------
// Return map columns.
//----------------------------------------------------------------------------------
long MAP::get_map_column()
{
return m_map_column;
}
//----------------------------------------------------------------------------------
// Return map rows.
//----------------------------------------------------------------------------------
long MAP::get_map_row()
{
return m_map_row;
}
//----------------------------------------------------------------------------------
// Set tile to map.
//----------------------------------------------------------------------------------
BOOL MAP::use_tile(TILE_PTR tile)
{
if((m_tile = tile) == NULL)
return FALSE;
return TRUE;
}
//----------------------------------------------------------------------------------
// Render map.
//----------------------------------------------------------------------------------
BOOL MAP::render(long pos_x, long pos_y,
long num_rows, long num_columns,
long object_layer,
D3DCOLOR color,
float scale_x, float scale_y)
{
// error checking
if(m_map_info == NULL || m_tile == NULL)
return FALSE;
long _tile_width = m_tile->get_tile_width(0);
long _tile_height = m_tile->get_tile_height(0);
// calculate smooth scrolling variables
long _map_x = pos_x / _tile_width;
long _map_y = pos_y / _tile_height;
long _off_x = pos_x % _tile_width;
long _off_y = pos_y % _tile_height;
// loop through each layer
for(long _layer = 0; _layer < m_num_layers; _layer++)
{
// get a pointer to the map data
char_ptr _map_ptr = &m_map_info[_layer * m_per_layer_size];
// loop for each row and column
for(long _row = 0; _row <= num_rows; _row++)
{
for(long _column = 0; _column <= num_columns; _column++)
{
// get the tile index to draw
char _tile_index = _map_ptr[(_row + _map_y) * m_map_column + _column + _map_x];
long _screen_x = _column * _tile_width - _off_x;
long _screen_y = _row * _tile_height - _off_y;
// draw tile
m_tile->draw_tile(0, _tile_index, (DWORD)_screen_x, (DWORD)_screen_y, color, scale_x, scale_y);
}
}
// draw objects if on object _layer
if(_layer == object_layer)
{
for(long i = 0; i < m_num_objects_to_draw; i++)
{
m_tile->draw_tile(0, m_objects_info[i].tile_index,
m_objects_info[i].x_pos - _off_x, m_objects_info[i].y_pos - _off_y,
color, scale_x, scale_y);
}
}
}
return TRUE;
}
测试代码1,展示了缩放2D贴片的用法。
/*****************************************************************************
PURPOSE:
Test for class TILE and MAP.
*****************************************************************************/
#include "core_common.h"
#include "core_framework.h"
#include "core_graphics.h"
#include "tile.h"
#include "map.h"
#pragma warning(disable : 4996)
class APP : public FRAMEWORK
{
public:
BOOL init()
{
if(! create_display(g_hwnd, get_client_width(g_hwnd), get_client_height(g_hwnd), 16, TRUE, FALSE))
return FALSE;
// create and load the tile set
if(! m_tile.create(1))
return FALSE;
if(! m_tile.load_texture(0, "tiles.bmp", 64, 64, TRUE, D3DFMT_A1R5G5B5))
{
err_msg_box("load texture failed.");
return FALSE;
}
// create and set the map
char _map_data[3][3] = {
{ 0, 1, 0 },
{ 2, 2, 2 },
{ 1, 2, 3 }
};
m_map.create(1, 3, 3);
m_map.set_map_layer_data(0, (char*) &_map_data);
m_map.use_tile(&m_tile);
return TRUE;
}
BOOL APP::frame()
{
// calculate elapsed time
static DWORD _s_last_time = timeGetTime();
DWORD _now_time = timeGetTime();
DWORD _elapsed_time = _now_time - _s_last_time;
// frame lock to 30ms per frame
if(_elapsed_time < 30)
return TRUE;
_s_last_time = _now_time;
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
if(SUCCEEDED(g_d3d_sprite->Begin(0)))
{
D3DCOLOR _color;
static uchar _s_red = 0, _s_green = 0, _s_blue = 0;
static BOOL _s_increment_color = TRUE;
if(_s_increment_color)
{
_color = D3DCOLOR_RGBA(_s_red++, _s_green++, _s_blue++, 255);
if(_s_red >= 255)
_s_increment_color = FALSE;
}
else
{
_color = D3DCOLOR_RGBA(_s_red--, _s_green--, _s_blue--, 255);
if(_s_red <= 0)
_s_increment_color = TRUE;
}
// draw the map
m_map.render(0, 0, 3, 3, 0, _color, 2.0f, 2.0f);
g_d3d_sprite->End();
}
g_d3d_device->EndScene();
present_display();
}
return TRUE;
}
BOOL shutdown()
{
return TRUE;
}
private:
TILE m_tile;
MAP m_map;
};
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
DWORD _window_width = 384;
DWORD _window_height = 384;
DWORD _x_pos = (get_screen_width() - _window_width) / 2;
DWORD _y_pos = (get_screen_height() - _window_height) / 4;
if(! build_window(inst, "tile_class", "tile test", WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
_x_pos, _y_pos, _window_width, _window_height))
{
return -1;
}
APP app;
app.run();
return 0;
}
测试代码2,展示了平滑卷轴技术的使用。
/*****************************************************************************
PURPOSE:
Test for class TILE and MAP.
*****************************************************************************/
#include "core_common.h"
#include "core_framework.h"
#include "core_graphics.h"
#include "tile.h"
#include "map.h"
#pragma warning(disable : 4996)
#define TILE_WIDTH 64
#define TILE_HEIGHT 64
#define MAP_COLUMNS 16
#define MAP_ROWS 16
#define TOTAL_MAP_SIZE 1024
class APP : public FRAMEWORK
{
public:
BOOL init()
{
long client_width = get_client_width(g_hwnd);
long client_height = get_client_height(g_hwnd);
m_num_columns_to_draw = client_width / TILE_WIDTH + 1;
m_num_rows_to_draw = client_height / TILE_HEIGHT + 1;
m_max_move_width = TOTAL_MAP_SIZE - client_width;
m_max_move_height = TOTAL_MAP_SIZE - client_height;
if(! create_display(g_hwnd, get_client_width(g_hwnd), get_client_height(g_hwnd), 16, TRUE, FALSE))
return FALSE;
// create and load the tile set
if(! m_tile.create(1))
return FALSE;
if(! m_tile.load_texture(0, "tiles.bmp", TILE_WIDTH, TILE_HEIGHT, TRUE, D3DFMT_A1R5G5B5))
{
err_msg_box("load texture failed.");
return FALSE;
}
// create and set the map
char _map_data[MAP_ROWS][MAP_COLUMNS] = {
{ 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 },
{ 1, 2, 2, 1, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0 },
{ 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 2, 0 },
{ 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 0 },
{ 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
{ 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
{ 3, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0 },
{ 3, 0, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0 },
{ 0, 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 2, 2, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 0 },
{ 0, 1, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 1, 1, 2, 0 },
{ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 },
{ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 },
{ 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
m_map.create(1, MAP_COLUMNS, MAP_ROWS);
m_map.set_map_layer_data(0, (char*) &_map_data);
m_map.use_tile(&m_tile);
return TRUE;
}
BOOL APP::frame()
{
static long _s_x_pos = 0, _s_y_pos = 0;
// calculate elapsed time
static DWORD _s_last_time = timeGetTime();
DWORD _now_time = timeGetTime();
DWORD _elapsed_time = _now_time - _s_last_time;
// frame lock to 33ms per frame
if(_elapsed_time < 33)
return TRUE;
_s_last_time = _now_time;
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
if(SUCCEEDED(g_d3d_sprite->Begin(0)))
{
// draw the map
m_map.render(_s_x_pos, _s_y_pos, m_num_rows_to_draw, m_num_columns_to_draw, 0, 0xFFFFFFFF, 1.0f, 1.0f);
// press arrows to scroll map around
if(GetAsyncKeyState(VK_LEFT)) _s_x_pos -= 8;
if(GetAsyncKeyState(VK_RIGHT)) _s_x_pos += 8;
if(GetAsyncKeyState(VK_UP)) _s_y_pos -= 8;
if(GetAsyncKeyState(VK_DOWN)) _s_y_pos += 8;
// bounds check map coordinates
if(_s_x_pos < 0)
_s_x_pos = 0;
if(_s_x_pos > m_max_move_width)
_s_x_pos = m_max_move_width;
if(_s_y_pos < 0)
_s_y_pos = 0;
if(_s_y_pos > m_max_move_height)
_s_y_pos = m_max_move_height;
g_d3d_sprite->End();
}
g_d3d_device->EndScene();
present_display();
}
return TRUE;
}
BOOL shutdown()
{
return TRUE;
}
private:
TILE m_tile;
MAP m_map;
long m_num_columns_to_draw;
long m_num_rows_to_draw;
long m_max_move_width;
long m_max_move_height;
};
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
DWORD _window_width = 640;
DWORD _window_height = 480;
DWORD _x_pos = (get_screen_width() - _window_width) / 2;
DWORD _y_pos = (get_screen_height() - _window_height) / 4;
if(! build_window(inst, "map_class", "map test", WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
_x_pos, _y_pos, _window_width, _window_height))
{
return -1;
}
APP app;
app.run();
return 0;
}