演示程序下载地址:http://download.csdn.net/detail/jiangcaiyang123/4060455
程序的截图如下所示:
设计游戏菜单背景循环移动
DirectX的纹理很重要。就像一个人的脸一样。如果没有它,就好像人的脸上没有五官一样难看。所以要对于我们这些初学者来说,掌握纹理的处理就相当于了解相当部分的DirectX知识一样。这回我就利用上了DirectX中纹理的一些知识,来实现游戏中常常出现的菜单背景循环移动的场景。
要使用纹理,首先要学会载入纹理。我使用D3DXCreateTextureFromFileEx()这个函数。因为它可控制的参数多,可以达到很好的效果。欲了解此函数的参数,请查阅MSDN。载入了图片后,我使用其中的D3DXIMAGE_INFO的结构体来获得它的宽和高。获得了以后可以将该纹理平铺至屏幕上。这里假设屏幕的分辨率是640×480。
在载入了纹理之后,使用自定义的顶点格式。该格式的定义如下:
struct STVertex// 定义自己的顶点结构体
{
float x, y, z;// 纹理坐标位置
float u, v; // 纹理坐标内的位置
}
其中控制纹理的平铺则使用的是U和V这两个变量。那么接下来我就在渲染的过程中改变这两个变量,获得循环移动的效果。在U和V处于0以下或者是1.0以上的范围,它的渲染行为通常是不固定的。但是DirectX内部默认的是平铺的效果。也可以改变其为镜面平铺、不渲染的效果(参见《Real Time Rendering》丛书)。我们不必更改,使用默认平铺效果即可。
最后设置灵活顶点格式(FVF),设置顶点流的源,和使用DrawPrimitive来绘制图形。
以下是程序的部分代码:
// BackgroundMove.cpp 实现文件
#include "BackgroundMove.h"
CBackgroundMove::CBackgroundMove( HINSTANCE hInst, HWND hWnd, LPDIRECT3DDEVICE9 pDevice, int width, int height ) // 构造函数
{
// 成员赋值
m_pDevice = pDevice;
m_TexOffsetX = 0.0f;
m_TexOffsetY = 0.0f;
m_MoveSpeedX = 0.005f;
m_MoveSpeedY = 0.02f;
// 初始化输入系统
m_ImmediateInput.Initialize( IMMEDIATE, hInst, hWnd );
m_BufferInput.Initialize( BUFFERED, hInst, hWnd );
// 设置视角范围
SetViewport( width, height );
// 初始化顶点
InitializeVertices( );
// 设置纹理
SetTexture( width, height );
}
void CBackgroundMove::SetViewport( int width, int height ) // 设置视角
{
ZeroMemory( &m_Viewport, sizeof( m_Viewport ) );// 清零
m_Viewport.X = 0;
m_Viewport.Y = 0;
m_Viewport.Width = width;
m_Viewport.Height = height;
m_Viewport.MinZ = 0.0f;
m_Viewport.MaxZ = 1.0f;
m_pDevice->SetViewport( &m_Viewport );
}
void CBackgroundMove::Draw( void ) // 绘图
{
m_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); // 绘图函数
// 开始交互
m_ImmediateInput.UpdateKeyState( );
if ( m_ImmediateInput.KeyDown( DIK_UP ) )
{
m_pVertices[1].y += 0.05f;
m_pVertices[3].y += 0.05f;
}
if ( m_ImmediateInput.KeyDown( DIK_DOWN ) )
{
m_pVertices[1].y -= 0.05f;
m_pVertices[3].y -= 0.05f;
}
// 调整移动速率的
if ( m_ImmediateInput.KeyDown( DIK_D ) )
{
m_MoveSpeedX += 0.005f;
}
if ( m_ImmediateInput.KeyDown( DIK_A ) )
{
m_MoveSpeedX -= 0.005f;
}
if ( m_ImmediateInput.KeyDown( DIK_W ) )
{
m_MoveSpeedY += 0.005f;
}
if ( m_ImmediateInput.KeyDown( DIK_S ) )
{
m_MoveSpeedY -= 0.005f;
}
// 纹理的背景自动移动
int i;
for ( i = 0; i < 4; i++ )
{
m_pVertices[i].u += m_MoveSpeedX;
m_pVertices[i].v += m_MoveSpeedY;
}
}
unsigned long CBackgroundMove::Release( void ) // 释放空间
{
if ( m_pBuffer != 0 )
{
m_pBuffer->Release( );
m_pBuffer = 0;
}
if ( m_pTexture != 0 )
{
m_pBuffer->Release( );
m_pBuffer = 0;
}
m_ImmediateInput.Release( );
m_BufferInput.Release( );
return 0;
}
void CBackgroundMove::InitializeVertices( void ) // 初始化顶点
{
// 创建顶点缓存
HRESULT hr;
hr = m_pDevice->CreateVertexBuffer( 4 * sizeof( STVertex ), D3DUSAGE_WRITEONLY,
TEXTURE_FVF, D3DPOOL_MANAGED, &m_pBuffer, NULL );
ThrowIfFailed( hr, "不会吧,这都无法创建顶点缓存。⊙﹏⊙b汗" );
hr = m_pBuffer->Lock( 0, 4 * sizeof( STVertex ), (void**)&m_pVertices, D3DLOCK_DISCARD );
ThrowIfFailed( hr, "不可能,顶点怎么会锁住失败呢??o(>﹏<)o" );
hr = m_pBuffer->Unlock( );
ThrowIfFailed( hr, "不可能,顶点怎么会也会解锁失败呢??o(>﹏<)o" );
// 设置顶点缓存和灵活顶点格式
m_pDevice->SetStreamSource( 0, m_pBuffer, 0, sizeof( STVertex ) ); // 相同资源的顶点缓存要在一起为好
m_pDevice->SetFVF( TEXTURE_FVF );
}
void CBackgroundMove::SetTexture( int width, int height ) // 设置纹理
{
// 载入纹理
D3DXIMAGE_INFO imageInfo;
HRESULT hr;
hr = D3DXCreateTextureFromFileEx( // 从文件创建纹理
m_pDevice, // DIRECT3DDEVICE9结构指针
TEXT( "试验图片.png" ), // 载入的图像文件名
D3DX_DEFAULT, // 宽
D3DX_DEFAULT, // 高
D3DX_FROM_FILE, // mip级别
0, // 用途
D3DFMT_A8R8G8B8, // 格式
D3DPOOL_MANAGED, // 内存池格式
D3DX_DEFAULT, // 滤波器
D3DX_DEFAULT, // mip滤波器
0, // 关键色(作掩码用)
&imageInfo, // 源文件信息
NULL, // 调色板
&m_pTexture ); // IDirect3DTexture9指针
ThrowIfFailed( hr, "不可能,载入纹理竟然会失败!是不是文件名错误了呢?" );
// 设置顶点
float nU, nV;
nU = float( width ) / float( imageInfo.Width ), nV = float( height ) / float( imageInfo.Height );
m_pVertices[0].Set( -1.0f, -1.0f, 1.0f, m_TexOffsetX, m_TexOffsetY + nV );
m_pVertices[1].Set( -1.0f, 1.0f, 1.0f, m_TexOffsetX, m_TexOffsetY );
m_pVertices[2].Set( 1.0f, -1.0f, 1.0f, m_TexOffsetX + nU, m_TexOffsetY + nV );
m_pVertices[3].Set( 1.0f, 1.0f, 1.0f, m_TexOffsetX + nU, m_TexOffsetY );
// 设置关灯
hr = m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
ThrowIfFailed( hr, "怎么不能关灯了呢?" );
// 设置纹理
hr = m_pDevice->SetTexture( 0, m_pTexture );
ThrowIfFailed( hr, "不可能啊,设置纹理竟然错误?" );
}