在图形技术的应用中,既没有什么限制,也没有什么必须遵守的规则。也就是说,没有限制使用二维图形或三维图形,完全可以将它们两者无损地混合在一起。
在三维中绘制二维贴片
需要一个代表游戏层次的三维网格模型,如下图所示:
一个角色在三维世界里四处移动(通常是沿着一个轴线移动),当角色移动时,摄像机也跟着移动。摄像机需要停留在一个比角色较高的平移位置上,这样就会产生出全三维的层次效果。不需要别的额外操作,只要加载一个代表层次的网格模型,创建一组代表了物体(例如玩家角色)的二维贴片,并将每件东西正确地排列绘制到每帧中即可。
下载源码和工程
代码:
/************************************************************************************
PURPOSE:
2D in 3D test.
************************************************************************************/
#include "core_common.h"
#include "core_framework.h"
#include "core_graphics.h"
#include "core_input.h"
#define TILE_SIZE 64
enum DIR { LEFT = 0, RIGHT };
class APP : public FRAMEWORK
{
public:
BOOL init()
{
if(! create_display(g_hwnd, get_client_width(g_hwnd), get_client_height(g_hwnd), 16, TRUE, TRUE))
return FALSE;
set_perspective(D3DX_PI / 4, 1.3333f, 1.0f, 10000.0f);
ShowCursor(TRUE);
// initialize input and input device
m_input.create(g_hwnd, get_window_inst());
m_keyboard.create_keyboard(&m_input);
// load the mesh and create a nodetree mesh from it
if(! m_level_mesh.load("..\\Data\\Level.x", "..\\Data\\"))
return FALSE;
m_level_object.create(&m_level_mesh);
// load the 2D texture
if(! m_2d_object.load("..\\Data\\Tiles.bmp", D3DCOLOR_RGBA(0, 0, 0, 255), D3DFMT_A1R5G5B5))
return FALSE;
// set player position
m_x_pos = -900.0f;
m_y_pos = m_z_pos = 0.0f;
// enable lighting and setup light
g_d3d_device->SetRenderState(D3DRS_LIGHTING, TRUE);
set_ambient_light(0, 0, 0);
g_d3d_device->LightEnable(0, TRUE);
// create a directional light to illuminate the scene
m_light.set_default_state();
m_light.set_type(D3DLIGHT_DIRECTIONAL);
m_light.set_diffuse(192, 192, 192);
m_light.set_ambient(0, 0, 0);
m_light.point(0.0f, 60.0f, -100.0f, 0.0f, 0.0f, 0.0f);
m_camera.set_default_state();
m_font.create("Arial", 16, TRUE, FALSE);
return TRUE;
}
BOOL frame()
{
static DWORD time_now = timeGetTime();
// calculate elapsed time (plus speed boost)
ulong time_elapsed = timeGetTime() - time_now;
time_now = timeGetTime();
// read keyboard data
m_keyboard.read();
// process input and update everything, ESC quits program.
if(m_keyboard.get_key_state(KEY_ESC))
return FALSE;
// process movement
float x_move = 0.0f;
if(m_keyboard.get_key_state(KEY_LEFT))
x_move = -(float)(time_elapsed * 0.5f);
if(m_keyboard.get_key_state(KEY_RIGHT))
x_move = (float)(time_elapsed * 0.5f);
uchar red, green, blue;
m_light.get_diffuse(&red, &green, &blue);
if(m_keyboard.get_key_state(KEY_ADD))
{
if(red < 255)
++red;
if(green < 255)
++green;
if(blue < 255)
++blue;
m_light.set_diffuse(red, green, blue);
}
if(m_keyboard.get_key_state(KEY_SUBTRACT))
{
if(red > 0)
--red;
if(green > 0)
--green;
if(blue > 0)
--blue;
m_light.set_diffuse(red, green, blue);
}
char diffuse_msg[256];
sprintf(diffuse_msg, "diffuse color: red = %d, green = %d, blue = %d\n", red, green, blue);
// check for intersections (allowing climbing as well)
float dist, diff;
diff = (x_move < 0.0f ? -32.0f : 32.0f);
D3DXMESH_PTR d3d_mesh = m_level_mesh.get_root_mesh_info()->m_d3d_mesh;
if(is_ray_intersect_mesh(d3d_mesh,
m_x_pos + diff, m_y_pos + m_above_floor, m_z_pos,
m_x_pos + diff + x_move, m_y_pos + m_above_floor, m_z_pos,
&dist))
{
x_move = 0.0f;
}
// fix height of player
m_y_pos = closest_height_below_object(d3d_mesh, m_x_pos + x_move, m_y_pos + m_above_floor, m_z_pos);
static float frame = 0.0f;
static enum DIR dir = RIGHT;
// update animation frame
if(! float_equal(x_move, 0.0f))
{
// change direction of travel (for aniamtion)
if(x_move < 0.0f) // move left
{
frame -= (time_elapsed * 0.015f);
if(frame < 0.0f)
frame = 7.0f;
dir = LEFT;
}
else // move right
{
frame += (time_elapsed * 0.015f);
if(frame >= 8.0f)
frame = 0.0f;
dir = RIGHT;
}
}
else
{
frame = 3.0f;
}
// move player
m_x_pos += x_move;
// position camera by character position
m_camera.point(m_x_pos, m_y_pos + 200.0f, m_z_pos - 500.0f,
m_x_pos, m_y_pos, m_z_pos);
// set camera
g_d3d_device->SetTransform(D3DTS_VIEW, m_camera.get_view_matrix());
// render everything
clear_display(0, 1.0f);
// begin render now
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
// render the level mesh
g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
g_d3d_device->SetLight(0, m_light.get_d3d_light());
m_level_object.render();
// render 2D object
g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
enable_alpha_testing();
g_d3d_sprite->Begin(0);
ulong tile_index, tile_x, tile_y;
tile_index = (dir == LEFT ? 1 : 0) * 8 + (long)frame;
tile_x = tile_index % 4 * TILE_SIZE;
tile_y = tile_index / 4 * TILE_SIZE;
m_2d_object.draw(140, 60, tile_x, tile_y, TILE_SIZE, TILE_SIZE, 2.0f, 2.0f, 0xFFFFFFFF);
g_d3d_sprite->End();
disable_alpha_testing();
m_font.draw(diffuse_msg, 0, 0, 0, 0, D3DCOLOR_RGBA(255, 255, 255, 255), DT_LEFT);
g_d3d_device->EndScene();
}
present_display();
return TRUE;
}
BOOL shutdown()
{
destroy_display();
return TRUE;
}
private:
CAMERA m_camera;
LIGHT m_light;
FONT m_font;
INPUT m_input;
INPUT_DEVICE m_keyboard;
TEXTURE m_2d_object;
MESH m_level_mesh;
OBJECT m_level_object;
float m_x_pos, m_y_pos, m_z_pos;
static const float m_above_floor;
};
const float APP::m_above_floor = 84.0f;
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
DWORD client_width = 640;
DWORD client_height = 480;
DWORD x_pos = (get_screen_width() - client_width) / 2;
DWORD y_pos = (get_screen_height() - client_height) / 4;
DWORD window_style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
if(! build_window(inst, "2d_in_3d_class", "2D in 3D Test", window_style,
x_pos, y_pos, client_width, client_height))
{
return -1;
}
APP app;
app.run();
return 0;
}
使用+或-改变光源的散射光属性,左右箭头键控制怪物行走。
截图: