client.cpp
来自「对游戏编程感兴趣的 朋友可以 下载下来看看 对DX讲解的很很详细」· C++ 代码 · 共 389 行
CPP
389 行
#include <windows.h>
#include <mmsystem.h>
#include "resource.h"
#include "ddutil.h"
#define SCREEN_WIDTH 800 //创建DirectX的宽度,高度,颜色深度
#define SCREEN_HEIGHT 600
#define SCREEN_BPP 16 //XXXXX(红)XXXXXX(绿)XXXXX(蓝)
#define RGB16_GREEN 0x07E0 //0000,0111,1110,0000
#define RGB16_WHITE 0xFFFF //1111,1111,1111,1111
#define RGB16_BLACK 0x0000 //0000,0000,0000,0000
#define YUNDONG_UP 1 //定义运动的方向
#define YUNDONG_DOWN 2
#define YUNDONG_LEFT 3
#define YUNDONG_RIGHT 4
#define NUM_SPRITES 1 //定义出现的精灵图像个数
struct SPRITE //定义精灵的运动结构
{
FLOAT fPosX; //出现的位置
FLOAT fPosY;
FLOAT fVelX; //水平或垂直运动的速度
FLOAT fVelY;
DWORD dwWidth; //定义的大小;
DWORD dwHeight;
INT iFangXiang; //精灵运动的方向
};
CDisplay* g_pDisplay; //创建DirectX类的实例
CSurface* g_pLogoSurface; //创建一个位图表面
CSurface* g_pTextSurface; //创建一个文字表面
SPRITE g_Sprite[NUM_SPRITES]; //创建图像精灵
DWORD g_dwLastTick ; //记录时间
BOOL g_bActive; //判断DirectX是否能活动
BOOL g_bLianJie; //跳过窗口的判断变量
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );//窗口的消息处理函数
HRESULT ProcessNextFrame(); //显示下一帧
void UpdateSprite( SPRITE* pSprite, FLOAT fTimeDelta ); //更新精灵的范围的边界情况
HRESULT DisplayFrame(); //显示帧的内容
HRESULT RestoreSurfaces(); //当平面信息丢失时更新平面的内容
VOID FreeDirectDraw(); //释放表面及DirectX实例
//////////////////////////////////////
// 应用程序入口 //
//////////////////////////////////////
int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
{
WNDCLASS wc;
HWND hWnd;
HACCEL hAccel;
MSG msg;
ZeroMemory( &g_Sprite, sizeof(SPRITE) * NUM_SPRITES );
srand( GetTickCount() );
//////////////////////////////////////
// 创建游戏窗体 //
//////////////////////////////////////
wc.lpszClassName = TEXT("Client"); //窗口类名称
wc.lpfnWndProc = MainWndProc; //消息处理函数
wc.style = CS_VREDRAW | CS_HREDRAW; //窗口的类型
wc.hInstance = hInst; //窗口实例(继承)
wc.hIcon = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) ); //窗口图标
wc.hCursor = LoadCursor( NULL, IDC_ARROW ); //窗口鼠标
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //窗口的背景
wc.lpszMenuName = NULL; //窗口菜单
wc.cbClsExtra = 0; //保留
wc.cbWndExtra = 0; //保留
if( RegisterClass( &wc ) == 0 ) //判断窗口类是否注册成功
return E_FAIL;
hWnd = CreateWindow( TEXT("Client"), TEXT("Client1"), //创建窗口
WS_SYSMENU | WS_MAXIMIZEBOX, 180,110,
430, 230, NULL, NULL, hInst, NULL );
if( hWnd == NULL ) //判断窗口是否创建成功
return E_FAIL;
ShowWindow( hWnd, nCmdShow ); //显示窗口
UpdateWindow( hWnd ); //更新窗口
//以下四行内容显示一个窗口,可删除
g_bLianJie = false; //设置窗口退出条件
while(GetMessage( &msg, NULL, 0, 0 ) && !g_bLianJie) //显示窗口并处理消息
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) ); //创建按键关联表
//////////////////////////////////
// 创建DirectDraw //
//////////////////////////////////
HRESULT hr;
g_pDisplay = new CDisplay(); //定义DirectX实例
//创建一个全屏的窗体
if( FAILED( hr = g_pDisplay->Create( hWnd, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP ) ) )
return hr;
//创建一个平面,并且在画上一个位图资源,用于显示位图
if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap(&g_pLogoSurface, MAKEINTRESOURCE( IDB_DIRECTX ), 0, 0) ) )
return hr;
//设置位图显示时的透明颜色
if( FAILED( hr = g_pLogoSurface->SetColorKey( RGB16_BLACK ) ) )
return hr;
//创建一个平面,并且在输出文字资源,用于显示文字
if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, "123456789",
RGB(0,255,0), RGB(255, 255, 0) ) ) )
return hr;
//设置文字显示时的透明颜色(应该与文字背景色一致)
if( FAILED( hr = g_pTextSurface->SetColorKey( RGB16_GREEN ) ) )
return hr;
for( int i = 0; i < NUM_SPRITES; i++ ) //定义精灵初始值
{
g_Sprite[i].fPosX = 0.0f;
g_Sprite[i].fPosY = 0.0f;
g_Sprite[i].fVelX = 0.0f;
g_Sprite[i].fVelY = 0.0f;
g_Sprite[i].dwWidth = g_pLogoSurface->GetWidth(); //得到位图平面的宽度和高度
g_Sprite[i].dwHeight = g_pLogoSurface->GetHeight();
g_Sprite[i].iFangXiang = YUNDONG_UP;
}
g_dwLastTick = timeGetTime(); //记录当前时间
while(true)//进入消息循环,以下内容不明白,请有心人帮忙解释一下
{
if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) //判断是否收到消息
{
//WM_QUIT退出消息
if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
{
return (int)msg.wParam;
}
//翻译并且分派消息
if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) ) //是否是按键表对应的消息
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
if( g_bActive ) //当可以重画屏幕时
{
if( FAILED( ProcessNextFrame() ) ) //显示下一帧
return 0;
}
else
{
WaitMessage(); //等待消息
g_dwLastTick = timeGetTime();
}
}
}
return 0;
}
//////////////////////////////////////////////
// 游戏窗体消息处理函数 //
//////////////////////////////////////////////
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
switch (msg)
{
case WM_KEYDOWN: //当任意键按下时退出开始的窗口
g_bLianJie = true;
return 0L;
case WM_PAINT: //重画屏幕消息与DirectX无关
{
hdc = BeginPaint(hWnd, &ps); //得到DC
HFONT hFont = CreateFont(30,0,0,0,0,0,0,0,0,0,0,0,0,"宋体"); //创建字体
SelectObject(hdc, hFont); //设置字体
DeleteObject(hFont); //删除字体
//GetClientRect( hWnd, &rect );
SetTextColor(hdc, RGB(0, 0, 0)); //设置颜色
TextOut(hdc, 100, 50, "欢迎使用游戏", 12); //显示文字
SetTextColor(hdc, RGB(0, 0, 255));
TextOut(hdc, 100, 100, "我的DirectXDraw", 15);
EndPaint( hWnd, &ps); //删除DC
return 0L;
}
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDM_EXIT: //按键表中的退出消息
PostMessage( hWnd, WM_CLOSE, 0, 0 );
return 0L;
case IDM_UP: //按键表中的向上消息
g_Sprite[0].fVelX = 0.0f; //水平不运动
g_Sprite[0].fVelY = -100.0f; //竖直向上
g_Sprite[0].iFangXiang = YUNDONG_UP; //运动方向
break;
case IDM_DOWN: //按键表中的向下消息
g_Sprite[0].fVelX = 0.0f;
g_Sprite[0].fVelY = 100.0f;
g_Sprite[0].iFangXiang = YUNDONG_DOWN;
break;
case IDM_LEFT: //按键表中的向左消息
g_Sprite[0].fVelX = -100.0f;
g_Sprite[0].fVelY = 0.0f;
g_Sprite[0].iFangXiang = YUNDONG_LEFT;
break;
case IDM_RIGHT: //按键表中的向右消息
g_Sprite[0].fVelX = 100.0f;
g_Sprite[0].fVelY = 0.0f;
g_Sprite[0].iFangXiang = YUNDONG_RIGHT;
break;
}
break;
case WM_SIZE: //尺寸改变时
if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam )
g_bActive = FALSE;
else
g_bActive = TRUE;
case WM_SETCURSOR: //鼠标隐藏
// Hide the cursor in fullscreen
SetCursor( NULL );
return TRUE;
case WM_SYSCOMMAND: //系统消息,不可少
switch( wParam )
{
case SC_MONITORPOWER:
return TRUE;
}
break;
case WM_DESTROY: //窗口释放消息
PostQuitMessage( 0 ); //抛出窗口退出消息
FreeDirectDraw(); //释放平面
return 0L;
}
return DefWindowProc(hWnd, msg, wParam, lParam); //系统默认详细处理
}
//////////////////////////////////
// 显示下一帧 //
//////////////////////////////////
HRESULT ProcessNextFrame()
{
HRESULT hr;
DWORD dwCurrTick = timeGetTime(); //得到当前时间
DWORD dwTickDiff = dwCurrTick - g_dwLastTick; //显示暂停时间
if( dwTickDiff == 0 ) //没有暂停退出
return S_OK;
g_dwLastTick = dwCurrTick; //重新得到当前时间
for( int i = 0; i < NUM_SPRITES; i++ )
UpdateSprite( &g_Sprite[i], dwTickDiff / 1000.0f ); //循环更新精灵的运动位置
if( FAILED( hr = DisplayFrame() ) ) //显示屏幕的内容
{
if( hr != DDERR_SURFACELOST ) //判断屏幕信息是否丢失
return hr;
RestoreSurfaces(); //重新刷新表面内容
}
return S_OK;
}
//////////////////////////////////////////
// 更新精灵的运动位置 //
// //
// 参数:精灵结构指针,屏幕未更新时间 //
//////////////////////////////////////////
void UpdateSprite( SPRITE* pSprite, FLOAT fTimeDelta )
{
pSprite->fPosX += pSprite->fVelX * fTimeDelta;//计算新的位置
pSprite->fPosY += pSprite->fVelY * fTimeDelta;
//以下判断是否超出屏幕的范围
if( pSprite->fPosX < 0.0f )
{
pSprite->fPosX = FLOAT( SCREEN_WIDTH -1 - pSprite->dwWidth/2 );
}
if( pSprite->fPosX >= SCREEN_WIDTH - pSprite->dwWidth/2 )
{
pSprite->fPosX = 0;
}
if( pSprite->fPosY < 0 )
{
pSprite->fPosY = FLOAT( SCREEN_HEIGHT - 1 - pSprite->dwHeight/2 );
}
if( pSprite->fPosY > SCREEN_HEIGHT - pSprite->dwHeight/2 )
{
pSprite->fPosY = 0;
}
}
//////////////////////////////////////
// 显示帧的内容 //
//////////////////////////////////////
HRESULT DisplayFrame()
{
HRESULT hr;
RECT prc;
g_pDisplay->Clear( 0x3F1F ); //使用指定的颜色覆盖屏幕
for( int i =0; i < NUM_SPRITES; i++ )//循环显示每一个精灵
{
if ( g_Sprite[i].iFangXiang == YUNDONG_UP ) //显示箭头的方向
{
prc.left=1; //在平面位图中的位置
prc.top=1;
prc.bottom = g_Sprite[i].dwHeight / 2;
prc.right = g_Sprite[i].dwWidth / 2;
}
else if( g_Sprite[i].iFangXiang == YUNDONG_DOWN )
{
prc.top = g_Sprite[i].dwHeight / 2 + 1;
prc.left = 1;
prc.bottom = g_Sprite[i].dwHeight;
prc.right = g_Sprite[i].dwWidth / 2;
}
else if( g_Sprite[i].iFangXiang == YUNDONG_RIGHT )
{
prc.top = 1;
prc.left = g_Sprite[i].dwWidth / 2 + 1;
prc.bottom = g_Sprite[i].dwHeight / 2;
prc.right = g_Sprite[i].dwWidth;
}
else if( g_Sprite[i].iFangXiang == YUNDONG_LEFT )
{
prc.top = g_Sprite[i].dwHeight / 2 + 1;
prc.left = g_Sprite[i].dwWidth / 2 + 1;
prc.bottom = g_Sprite[i].dwHeight;
prc.right = g_Sprite[i].dwWidth;
}
g_pDisplay->Blt( (DWORD)g_Sprite[i].fPosX, (DWORD)g_Sprite[i].fPosY, //显示精灵
g_pLogoSurface, &prc );
}
prc.top = 1;
prc.bottom = g_pTextSurface->GetHeight();
prc.left = 1;
prc.right = g_pTextSurface->GetWidth();
g_pDisplay->Blt( 10, 10, g_pTextSurface, NULL ); //在指定位置显示文字
if( FAILED(hr = g_pDisplay->Present() ) ) //呈现这一帧图像
return hr;
return S_OK;
}
//////////////////////////////////
// 更新表面 //
//////////////////////////////////
HRESULT RestoreSurfaces()
{
HRESULT hr;
if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) ) //实例恢复所有表面
return hr;
if( FAILED( hr = g_pTextSurface->DrawText( NULL, "2935629", RGB( 0, 0, 0 ), RGB( 255, 255, 255 ) ) ) )
return hr;
if( FAILED( hr = g_pLogoSurface->DrawBitmap( MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )
return hr;
return S_OK;
}
//////////////////////////////////////
// 释放表面及实例 //
//////////////////////////////////////
VOID FreeDirectDraw()
{
for( int i =0; i < NUM_SPRITES; i++ )
SAFE_DELETE( g_pLogoSurface );
SAFE_DELETE( g_pTextSurface );
SAFE_DELETE( g_pDisplay );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?