《Windows游戏编程大师技巧》(第二版)第1章(下)

本文是一个游戏编程入门教程,以FreakOut游戏为例,介绍了使用DirectX和Windows编程制作2D游戏的方法。作者创建了BLACKBOX库封装DirectX函数,构建游戏所需功能。还展示了游戏的结构、代码及运行逻辑,最后鼓励读者修改游戏。

实例:FreakOut
在沉溺于所讨论的有关Windows、DirectX 和3D 图形之前,应当暂停一下,先给你看一个完整的游戏——虽然简单了一点,但毫无疑问是一个完整的游戏。你会看到一个实际的游戏循环和一些图形功能调用,最后一霎那就可以通过编译。不错吧?跟我来吧!
问题是我们现在才讲到第一章。我不应该使用后面章节中的内容……这有点像作弊,对吧?因此,我决定要做的是让你习惯于使用黑黑(black box)API来进行游戏编程。基于这个要求,我要提一个问题“要制作一个类似Breakout(打砖块)的2D游戏,其最低要求是什么?”我们真正所需要的是下面的功能:
? 在任意图像模式中切换
? 在屏幕上画各种颜色的矩形
? 获取键盘输入
? 使用一些定时函数同步游戏循环
? 在屏幕上画彩色文字串
因此我建了一个名为BLACKBOX.CPP|H的库。它封装了一套DirectX函数集(限于DirectDraw),并且包含实现所需功能的支持代码。妙处是,读者根本不需要看这些代码,只需依照函数原型来使用这些函数就可以了,并与BLACKBOX.CPP|H连接来产生.EXE可执行文件。
以BLACKBOX库为基础,我编写了一个名字为FreakOut的游戏,这个游戏演示了本章中所讨论的许多概念。FreakOut 游戏包含真正游戏的全部主要组成部分,包括:游戏循环、计分、关卡,甚至还有为球而写的迷你物理模型。真是可爱。图1.9 是一幅游戏运行中的屏幕画面。显然它比不上Arkanoid(经典的打砖块类游戏),但4 个小时的工作有此成果也不赖!
图1.9 FreakOut游戏的截屏
 
在阅读游戏源代码之前,我希望读者能看一下工程和游戏各组成部分是如何协调一致的。参见图1.10。
图1.10 FreakOut 的结构
 
从图中可以看到,游戏由下面文件构成:
FREAKOUT.CPP——游戏的主要逻辑,使用BLACKBOX.CPP,创建一个最小化的Win32应用程序。
BLACKBOX.CPP——游戏库(请不要偷看:)。
BLACKBOX.H——游戏库的头文件。
DDRAW.LIB——用于生成应用程序的DirectDraw输入库。其中并不含有真正的DirectX代码。它主要是用作让用户调用的中间库,然后轮流调用进行实际工作的DDRAW.DLL动态链接库。它可以在DirectX SDK 安装目录下的LIB子目录内被找到。
DDRAW.DLL——运行时(Runtime)的DirectDraw 库,实际上含有通过DDRAW.LIB 输入库调用DirectDraw 接口函数的COM 执行程序。不必为此担心;只要确认已经安装了DirectX运行时文件即可。
为了通过编译,需要将BLACKBOX.CPP和FREAKOUT.CPP加入工程里面,连接上DDRAW.LIB库文件,并确保BLACKBOX.H在头文件搜索路径或工作目录里,以便编译器可以正确地找到它。
现在我们已大致了解了FreakOut的结构。让我们看一下BLACKOUT.H头文件,看看它包含了哪些函数。
程序清单1.2 BLACKOUT.H 头文件
// BLACKBOX.H - Header file for demo game engine library

// watch for multiple inclusions
#ifndef BLACKBOX
#define BLACKBOX

// DEFINES ////////////////////////////////////////////////////

// default screen size
#define SCREEN_WIDTH    640  // size of screen
#define SCREEN_HEIGHT   480
#define SCREEN_BPP      8    // bits per pixel
#define MAX_COLORS      256  // maximum colors

// MACROS /////////////////////////////////////////////////////

// these read the keyboard asynchronously
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

// initializes a direct draw struct
#define DD_INIT_STRUCT(ddstruct) {memset(&ddstruct,0,sizeof(ddstruct));
ddstruct.dwSize=sizeof(ddstruct); }

// TYPES //////////////////////////////////////////////////////

// basic unsigned types
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char  UCHAR;
typedef unsigned char  BYTE;

// EXTERNALS //////////////////////////////////////////////////

extern LPDIRECTDRAW7         lpdd;             // dd object
extern LPDIRECTDRAWSURFACE7  lpddsprimary;     // dd primary surface
extern LPDIRECTDRAWSURFACE7  lpddsback;        // dd back surface
extern LPDIRECTDRAWPALETTE   lpddpal;          // a pointer dd palette
extern LPDIRECTDRAWCLIPPER   lpddclipper;      // dd clipper
extern PALETTEENTRY          palette[256];     // color palette
extern PALETTEENTRY          save_palette[256]; // used to save palettes
extern DDSURFACEDESC2        ddsd;    // a ddraw surface description struct
extern DDBLTFX               ddbltfx;           // used to fill
extern DDSCAPS2              ddscaps; // a ddraw surface capabilities struct
extern HRESULT               ddrval;            // result back from dd calls
extern DWORD                 start_clock_count; // used for timing
// these defined the general clipping rectangle
extern int min_clip_x,                             // clipping rectangle
           max_clip_x,
           min_clip_y,
           max_clip_y;

// these are overwritten globally by DD_Init()
extern int screen_width,                            // width of screen
           screen_height,                           // height of screen
           screen_bpp;                              // bits per pixel

// PROTOTYPES /////////////////////////////////////////////////

// DirectDraw functions
int DD_Init(int width, int height, int bpp);
int DD_Shutdown(void);
LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,
                                      int num_rects, LPRECT clip_list);
int DD_Flip(void);
int DD_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);

// general utility functions
DWORD Start_Clock(void);
DWORD Get_Clock(void);
DWORD Wait_Clock(DWORD count);

// graphics functions
int Draw_Rectangle(int x1, int y1, int x2, int y2,
                   int color,LPDIRECTDRAWSURFACE7 lpdds=lpddsback);

// gdi functions
int Draw_Text_GDI(char *text, int x,int y,COLORREF color,
                  LPDIRECTDRAWSURFACE7 lpdds=lpddsback);
int Draw_Text_GDI(char *text, int x,int y,int color,
                  LPDIRECTDRAWSURFACE7 lpdds=lpddsback);

#endif
现在,不要花费太多时间绞尽脑汁研究这里的程序代码,搞清楚那些神秘的全局变量究竟表示什么并不重要。让我们来看一看这些函数。如你所想,这里有实现我们的简单图形界面所需的全部函数。基于这个图形界面和最小化的Win32 应用程序(我们要做的Windows 编程工作越少越好)的基础上,我创建了游戏FREAKOUT.CPP,如清单1.3 所示。请认真地看一看,尤其是游戏主循环和对游戏处理功能的调用。
程序清单1.3 FREAKOUT.CPP 源文件

// INCLUDES ///////////////////////////////////////////////////

#define WIN32_LEAN_AND_MEAN // include all macros
#define INITGUID  &n

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值