Windows游戏开发学习笔记之一

本人虽然一直从事图形图像方面的研究,但对游戏开发却了解甚少,上周幸运的拿到了网易游戏开发的实习offer,为了不让自己在实习的时候太水,决定在空余时间学习下游戏开发方面的知识。

买了本《Windows游戏编程大师技巧》,先依葫芦画瓢做个Demo,程序中游戏的主要逻辑还不太清楚,就当先了解下开发环境和大概的开发流程吧。

1、游戏Demo:FreakOut,打砖块游戏

2、开发环境:VS2010+XP+DirectX 9.0

下载和安装DirectX SDK开发包,在VS2010的属性管理器->VC++目录,配置DirectX SDK的include路径和lib路径,即告诉VS去什么地方寻找DirectX的头文件和库文件,如下图所示:

Windows游戏开发学习笔记之一

库目录

Windows游戏开发学习笔记之一

头文件目录

上两个图中lib路径和include路径放置的顺序很重要,其中lib路径放置在所有路径的第一位,include路径放置在下图这四个路径后的第一个路径,即如上图所示。

如果放置顺序有问题,编译时可能会出现许多莫名其妙的错误。《Windows游戏编程大师技巧》中提到原因是许多C++编译器自己带有旧版本的DirectX,编译器可能会在自己的INCLUDE\目录下找到旧版本的头文件,而这些头文件是错误的,所以要确认DirectX SDK目录放在搜索路径列表的第一位。

3、游戏程序组成:

freakout.cpp:游戏的主要逻辑

blackbox.cpp:游戏库

blackbox.h:游戏库的头文件

ddraw.lib:用于生成应用程序的DirectDraw导入库。需要添加进工程项目中的配置属性-->[链接器 LINKER]的[输入INPUT]中。

ddraw.dll:运行时的DirectDraw库,实际上含有通过ddraw.lib导入库调用DirectDraw界面函数的COM执行程序。不必为此担心,只要确认安装了DirectX运行时文件即可。

 

在VS中创建一个Win32的应用程序,添加下面主要源代码。

blackbox.h

View Code
 1 // BLACKBOX.H - Header file for demo game engine library

 2 

 3 // watch for multiple inclusions

 4 #ifndef BLACKBOX

 5 #define BLACKBOX

 6 

 7 // DEFINES ////////////////////////////////////////////////////

 8 

 9 // default screen size

10 #define SCREEN_WIDTH    640  // size of screen

11 #define SCREEN_HEIGHT   480

12 #define SCREEN_BPP      8    // bits per pixel

13 #define MAX_COLORS      256  // maximum colors

14 

15 // MACROS /////////////////////////////////////////////////////

16 

17 // these read the keyboard asynchronously

18 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

19 #define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

20 

21 // initializes a direct draw struct

22 #define DD_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }

23 

24 // TYPES //////////////////////////////////////////////////////

25 

26 // basic unsigned types

27 typedef unsigned short USHORT;

28 typedef unsigned short WORD;

29 typedef unsigned char  UCHAR;

30 typedef unsigned char  BYTE;

31 

32 // EXTERNALS //////////////////////////////////////////////////

33 

34 extern LPDIRECTDRAW7         lpdd;                 // dd object

35 extern LPDIRECTDRAWSURFACE7  lpddsprimary;         // dd primary surface

36 extern LPDIRECTDRAWSURFACE7  lpddsback;            // dd back surface

37 extern LPDIRECTDRAWPALETTE   lpddpal;              // a pointer to the created dd palette

38 extern LPDIRECTDRAWCLIPPER   lpddclipper;          // dd clipper

39 extern PALETTEENTRY          palette[256];         // color palette

40 extern PALETTEENTRY          save_palette[256];    // used to save palettes

41 extern DDSURFACEDESC2        ddsd;                 // a direct draw surface description struct

42 extern DDBLTFX               ddbltfx;              // used to fill

43 extern DDSCAPS2              ddscaps;              // a direct draw surface capabilities struct

44 extern HRESULT               ddrval;               // result back from dd calls

45 extern DWORD                 start_clock_count;    // used for timing

46 

47 // these defined the general clipping rectangle

48 extern int min_clip_x,                             // clipping rectangle 

49            max_clip_x,                  

50            min_clip_y,     

51            max_clip_y;                  

52 

53 // these are overwritten globally by DD_Init()

54 extern int screen_width,                            // width of screen

55            screen_height,                           // height of screen

56            screen_bpp;                              // bits per pixel 

57 

58 // PROTOTYPES /////////////////////////////////////////////////

59 

60 // DirectDraw functions

61 int DD_Init(int width, int height, int bpp);

62 int DD_Shutdown(void);

63 LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds, int num_rects, LPRECT clip_list);

64 int DD_Flip(void);

65 int DD_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);

66 

67 // general utility functions

68 DWORD Start_Clock(void);

69 DWORD Get_Clock(void);

70 DWORD Wait_Clock(DWORD count);

71 

72 // graphics functions

73 int Draw_Rectangle(int x1, int y1, int x2, int y2, int color,LPDIRECTDRAWSURFACE7 lpdds=lpddsback);

74 

75 // gdi functions

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

77 int Draw_Text_GDI(char *text, int x,int y,int color, LPDIRECTDRAWSURFACE7 lpdds=lpddsback);

78 

79 #endif

blackbox.cpp

View Code
  1 // BLACKBOX.CPP - Game Engine 

  2  

  3 // INCLUDES ///////////////////////////////////////////////////

  4 

  5 #define WIN32_LEAN_AND_MEAN  // make sure all macros are included

  6 

  7 

  8 #include <windows.h>         // include important windows stuff

  9 #include <windowsx.h> 

 10 #include <mmsystem.h>

 11 

 12 #include <iostream>        // include important C/C++ stuff

 13 #include <conio.h>

 14 #include <stdlib.h>

 15 #include <malloc.h>

 16 #include <memory.h>

 17 #include <string.h>

 18 #include <stdarg.h>

 19 #include <stdio.h>

 20 #include <math.h>

 21 #include <io.h>

 22 #include <fcntl.h>

 23 

 24 #include <ddraw.h>           // directX includes

 25 #include "blackbox.h"        // game library includes

 26 using namespace std;

 27                                    

 28 // DEFINES ////////////////////////////////////////////////////

 29 

 30 // TYPES //////////////////////////////////////////////////////

 31 

 32 // PROTOTYPES /////////////////////////////////////////////////

 33 

 34 // EXTERNALS //////////////////////////////////////////////////

 35 

 36 extern HWND main_window_handle; // save the window handle

 37 extern HINSTANCE main_instance; // save the instance

 38 

 39 // GLOBALS ////////////////////////////////////////////////////

 40 

 41 LPDIRECTDRAW7         lpdd         = NULL;   // dd object

 42 LPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   // dd primary surface

 43 LPDIRECTDRAWSURFACE7  lpddsback    = NULL;   // dd back surface

 44 LPDIRECTDRAWPALETTE   lpddpal      = NULL;   // a pointer to the created dd palette

 45 LPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   // dd clipper

 46 PALETTEENTRY          palette[256];          // color palette

 47 PALETTEENTRY          save_palette[256];     // used to save palettes

 48 DDSURFACEDESC2        ddsd;                  // a direct draw surface description struct

 49 DDBLTFX               ddbltfx;               // used to fill

 50 DDSCAPS2              ddscaps;               // a direct draw surface capabilities struct

 51 HRESULT               ddrval;                // result back from dd calls

 52 DWORD                 start_clock_count = 0; // used for timing

 53 

 54 // these defined the general clipping rectangle

 55 int min_clip_x = 0,                          // clipping rectangle 

 56     max_clip_x = SCREEN_WIDTH-1,

 57     min_clip_y = 0,

 58     max_clip_y = SCREEN_HEIGHT-1;

 59 

 60 // these are overwritten globally by DD_Init()

 61 int screen_width  = SCREEN_WIDTH,            // width of screen

 62     screen_height = SCREEN_HEIGHT,           // height of screen

 63     screen_bpp    = SCREEN_BPP;              // bits per pixel

 64 

 65 // FUNCTIONS //////////////////////////////////////////////////

 66 

 67 int DD_Init(int width, int height, int bpp)

 68 {

 69 // this function initializes directdraw

 70 int index; // looping variable

 71 

 72 // create object and test for error

 73 if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)!=DD_OK)

 74    return(0);

 75 

 76 // set cooperation level to windowed mode normal

 77 if (lpdd->SetCooperativeLevel(main_window_handle,

 78            DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 

 79            DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)!=DD_OK)

 80     return(0);

 81 

 82 // set the display mode

 83 if (lpdd->SetDisplayMode(width,height,bpp,0,0)!=DD_OK)

 84    return(0);

 85 

 86 // set globals

 87 screen_height = height;

 88 screen_width  = width;

 89 screen_bpp    = bpp;

 90 

 91 // Create the primary surface

 92 memset(&ddsd,0,sizeof(ddsd));

 93 ddsd.dwSize = sizeof(ddsd);

 94 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

 95 

 96 // we need to let dd know that we want a complex 

 97 // flippable surface structure, set flags for that

 98 ddsd.ddsCaps.dwCaps = 

 99   DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;

100 

101 // set the backbuffer count to 1

102 ddsd.dwBackBufferCount = 1;

103 

104 // create the primary surface

105 lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);

106 

107 // query for the backbuffer i.e the secondary surface

108 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

109 lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);

110 

111 // create and attach palette

112 

113 // create palette data

114 // clear all entries defensive programming

115 memset(palette,0,256*sizeof(PALETTEENTRY));

116 

117 // create a R,G,B,GR gradient palette

118 for (index=0; index < 256; index++)

119     {

120     // set each entry

121     if (index < 64) 

122         palette[index].peRed = index*4; 

123     else           // shades of green

124     if (index >= 64 && index < 128) 

125         palette[index].peGreen = (index-64)*4;

126     else           // shades of blue

127     if (index >= 128 && index < 192) 

128        palette[index].peBlue = (index-128)*4;

129     else           // shades of grey

130     if (index >= 192 && index < 256) 

131         palette[index].peRed = palette[index].peGreen = 

132         palette[index].peBlue = (index-192)*4;

133     

134     // set flags

135     palette[index].peFlags = PC_NOCOLLAPSE;

136     } // end for index

137 

138 // now create the palette object

139 if (lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256,

140                          palette,&lpddpal,NULL)!=DD_OK)

141    return(0);

142 

143 // attach the palette to the primary

144 if (lpddsprimary->SetPalette(lpddpal)!=DD_OK)

145    return(0);

146 

147 // clear out both primary and secondary surfaces

148 DD_Fill_Surface(lpddsprimary,0);

149 DD_Fill_Surface(lpddsback,0);

150 

151 // attach a clipper to the screen

152 RECT screen_rect = {0,0,screen_width,screen_height};

153 lpddclipper = DD_Attach_Clipper(lpddsback,1,&screen_rect);

154 

155 // return success

156 return(1);

157 } // end DD_Init

158 

159 ///////////////////////////////////////////////////////////////

160 

161 int DD_Shutdown(void)

162 {

163 // this function release all the resources directdraw

164 // allocated, mainly to com objects

165 

166 // release the clipper first

167 if (lpddclipper)

168     lpddclipper->Release();

169 

170 // release the palette

171 if (lpddpal)

172    lpddpal->Release();

173 

174 // release the secondary surface

175 if (lpddsback)

176     lpddsback->Release();

177 

178 // release the primary surface

179 if (lpddsprimary)

180    lpddsprimary->Release();

181 

182 // finally, the main dd object

183 if (lpdd)

184     lpdd->Release();

185 

186 // return success

187 return(1);

188 } // end DD_Shutdown

189 

190 ///////////////////////////////////////////////////////////////   

191 

192 LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,

193                                       int num_rects,

194                                       LPRECT clip_list)

195 

196 {

197 // this function creates a clipper from the sent clip list and attaches

198 // it to the sent surface

199 

200 int index;                         // looping var

201 LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper

202 LPRGNDATA region_data;             // pointer to the region data that contains

203                                    // the header and clip list

204 

205 // first create the direct draw clipper

206 if ((lpdd->CreateClipper(0,&lpddclipper,NULL))!=DD_OK)

207    return(NULL);

208 

209 // now create the clip list from the sent data

210 

211 // first allocate memory for region data

212 region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));

213 

214 // now copy the rects into region data

215 memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);

216 

217 // set up fields of header

218 region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);

219 region_data->rdh.iType           = RDH_RECTANGLES;

220 region_data->rdh.nCount          = num_rects;

221 region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);

222 

223 region_data->rdh.rcBound.left    =  64000;

224 region_data->rdh.rcBound.top     =  64000;

225 region_data->rdh.rcBound.right   = -64000;

226 region_data->rdh.rcBound.bottom  = -64000;

227 

228 // find bounds of all clipping regions

229 for (index=0; index<num_rects; index++)

230     {

231     // test if the next rectangle unioned with the current bound is larger

232     if (clip_list[index].left < region_data->rdh.rcBound.left)

233        region_data->rdh.rcBound.left = clip_list[index].left;

234 

235     if (clip_list[index].right > region_data->rdh.rcBound.right)

236        region_data->rdh.rcBound.right = clip_list[index].right;

237 

238     if (clip_list[index].top < region_data->rdh.rcBound.top)

239        region_data->rdh.rcBound.top = clip_list[index].top;

240 

241     if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)

242        region_data->rdh.rcBound.bottom = clip_list[index].bottom;

243 

244     } // end for index

245 

246 // now we have computed the bounding rectangle region and set up the data

247 // now let's set the clipping list

248 

249 if ((lpddclipper->SetClipList(region_data, 0))!=DD_OK)

250    {

251    // release memory and return error

252    free(region_data);

253    return(NULL);

254    } // end if

255 

256 // now attach the clipper to the surface

257 if ((lpdds->SetClipper(lpddclipper))!=DD_OK)

258    {

259    // release memory and return error

260    free(region_data);

261    return(NULL);

262    } // end if

263 

264 // all is well, so release memory and send back the pointer to the new clipper

265 free(region_data);

266 return(lpddclipper);

267 

268 } // end DD_Attach_Clipper

269 

270 ///////////////////////////////////////////////////////////////

271    

272 int DD_Flip(void)

273 {

274 // this function flip the primary surface with the secondary surface

275 

276 // flip pages

277 while(lpddsprimary->Flip(NULL, DDFLIP_WAIT)!=DD_OK);

278 

279 // flip the surface

280 

281 // return success

282 return(1);

283 

284 } // end DD_Flip

285 

286 ///////////////////////////////////////////////////////////////

287 

288 DWORD Start_Clock(void)

289 {

290 // this function starts the clock, that is, saves the current

291 // count, use in conjunction with Wait_Clock()

292 

293 return(start_clock_count = Get_Clock());

294 

295 } // end Start_Clock

296 

297 ///////////////////////////////////////////////////////////////

298 

299 DWORD Get_Clock(void)

300 {

301 // this function returns the current tick count

302 

303 // return time

304 return(GetTickCount());

305 

306 } // end Get_Clock

307 

308 ///////////////////////////////////////////////////////////////

309 

310 DWORD Wait_Clock(DWORD count)

311 {

312 // this function is used to wait for a specific number of clicks

313 // since the call to Start_Clock

314 

315 while((Get_Clock() - start_clock_count) < count);

316 return(Get_Clock());

317 

318 } // end Wait_Clock

319 

320 ///////////////////////////////////////////////////////////////

321 

322 int DD_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)

323 {

324 DDBLTFX ddbltfx; // this contains the DDBLTFX structure

325 

326 // clear out the structure and set the size field 

327 DD_INIT_STRUCT(ddbltfx);

328 

329 // set the dwfillcolor field to the desired color

330 ddbltfx.dwFillColor = color; 

331 

332 // ready to blt to surface

333 lpdds->Blt(NULL,       // ptr to dest rectangle

334            NULL,       // ptr to source surface, NA            

335            NULL,       // ptr to source rectangle, NA

336            DDBLT_COLORFILL | DDBLT_WAIT | DDBLT_ASYNC,   // fill and wait                   

337            &ddbltfx);  // ptr to DDBLTFX structure

338 

339 // return success

340 return(1);

341 } // end DD_Fill_Surface

342 

343 ///////////////////////////////////////////////////////////////   

344 

345 int Draw_Rectangle(int x1, int y1, int x2, int y2, int color,

346                    LPDIRECTDRAWSURFACE7 lpdds)

347 {

348 // this function uses directdraw to draw a filled rectangle

349 

350 DDBLTFX ddbltfx; // this contains the DDBLTFX structure

351 RECT fill_area;  // this contains the destination rectangle

352 

353 // clear out the structure and set the size field 

354 DD_INIT_STRUCT(ddbltfx);

355 

356 // set the dwfillcolor field to the desired color

357 ddbltfx.dwFillColor = color; 

358 

359 // fill in the destination rectangle data (your data)

360 fill_area.top    = y1;

361 fill_area.left   = x1;

362 fill_area.bottom = y2+1;

363 fill_area.right  = x2+1;

364 

365 // ready to blt to surface, in this case blt to primary

366 lpdds->Blt(&fill_area, // ptr to dest rectangle

367            NULL,       // ptr to source surface, NA            

368            NULL,       // ptr to source rectangle, NA

369            DDBLT_COLORFILL | DDBLT_WAIT | DDBLT_ASYNC,   // fill and wait                   

370            &ddbltfx);  // ptr to DDBLTFX structure

371 

372 // return success

373 return(1);

374 

375 } // end Draw_Rectangle

376 

377 ///////////////////////////////////////////////////////////////

378 

379 int Draw_Text_GDI(char *text, int x,int y,int color, LPDIRECTDRAWSURFACE7 lpdds)

380 {

381 // this function draws the sent text on the sent surface 

382 // using color index as the color in the palette

383 

384 HDC xdc; // the working dc

385 

386 // get the dc from surface

387 if (lpdds->GetDC(&xdc)!=DD_OK)

388    return(0);

389 

390 // set the colors for the text up

391 SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue) );

392 

393 // set background mode to transparent so black isn't copied

394 SetBkMode(xdc, TRANSPARENT);

395 

396 // draw the text a

397 TextOut(xdc,x,y,text,strlen(text));

398 

399 // release the dc

400 lpdds->ReleaseDC(xdc);

401 

402 // return success

403 return(1);

404 } // end Draw_Text_GDI

405 

406 ///////////////////////////////////////////////////////////////

freakout.cpp

View Code
  1 // FREAKOUT.CPP - break game demo

  2 

  3 // INCLUDES ///////////////////////////////////////////////////

  4 

  5 #define WIN32_LEAN_AND_MEAN // include all macros

  6 #define INITGUID            // include all GUIDs 

  7 

  8 #include <windows.h>        // include important windows stuff

  9 #include <windowsx.h> 

 10 #include <mmsystem.h>

 11 

 12 #include <iostream>       // include important C/C++ stuff

 13 #include <conio.h>

 14 #include <stdlib.h>

 15 #include <malloc.h>

 16 #include <memory.h>

 17 #include <string.h>

 18 #include <stdarg.h>

 19 #include <stdio.h>

 20 #include <math.h>

 21 #include <io.h>

 22 #include <fcntl.h>

 23 

 24 #include <ddraw.h>          // directX includes

 25 #include "blackbox.h"       // game library includes

 26 using namespace std;

 27 

 28 // DEFINES ////////////////////////////////////////////////////

 29 

 30 // defines for windows 

 31 #define WINDOW_CLASS_NAME "WIN3DCLASS"  // class name

 32 

 33 #define WINDOW_WIDTH            640     // size of window

 34 #define WINDOW_HEIGHT           480

 35 

 36 // states for game loop

 37 #define GAME_STATE_INIT         0

 38 #define GAME_STATE_START_LEVEL  1

 39 #define GAME_STATE_RUN          2

 40 #define GAME_STATE_SHUTDOWN     3

 41 #define GAME_STATE_EXIT         4 

 42 

 43 // block defines

 44 #define NUM_BLOCK_ROWS          6

 45 #define NUM_BLOCK_COLUMNS       8

 46 

 47 #define BLOCK_WIDTH             64

 48 #define BLOCK_HEIGHT            16

 49 #define BLOCK_ORIGIN_X          8

 50 #define BLOCK_ORIGIN_Y          8

 51 #define BLOCK_X_GAP             80

 52 #define BLOCK_Y_GAP             32

 53 

 54 // paddle defines

 55 #define PADDLE_START_X          (SCREEN_WIDTH/2 - 16)

 56 #define PADDLE_START_Y          (SCREEN_HEIGHT - 32);

 57 #define PADDLE_WIDTH            32

 58 #define PADDLE_HEIGHT           8

 59 #define PADDLE_COLOR            191

 60 

 61 // ball defines

 62 #define BALL_START_Y            (SCREEN_HEIGHT/2)

 63 #define BALL_SIZE                4

 64 

 65 // PROTOTYPES /////////////////////////////////////////////////

 66 

 67 // game console

 68 int Game_Init(void *parms=NULL);

 69 int Game_Shutdown(void *parms=NULL);

 70 int Game_Main(void *parms=NULL);

 71 

 72 // GLOBALS ////////////////////////////////////////////////////

 73 

 74 HWND main_window_handle  = NULL; // save the window handle

 75 HINSTANCE main_instance  = NULL; // save the instance

 76 int game_state           = GAME_STATE_INIT; // starting state

 77 

 78 int paddle_x = 0, paddle_y = 0; // tracks position of paddle

 79 int ball_x   = 0, ball_y   = 0; // tracks position of ball

 80 int ball_dx  = 0, ball_dy  = 0; // velocity of ball

 81 int score    = 0;               // the score

 82 int level    = 1;               // the current level

 83 int blocks_hit = 0;             // tracks number of blocks hit

 84 

 85 // this contains the game grid data   

 86 

 87 UCHAR blocks[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS];     

 88 

 89 // FUNCTIONS //////////////////////////////////////////////////

 90 

 91 LRESULT CALLBACK WindowProc(HWND hwnd, 

 92                             UINT msg, 

 93                             WPARAM wparam, 

 94                             LPARAM lparam)

 95 {

 96 // this is the main message handler of the system

 97 PAINTSTRUCT    ps;           // used in WM_PAINT

 98 HDC            hdc;       // handle to a device context

 99 

100 // what is the message 

101 switch(msg)

102     {    

103     case WM_CREATE: 

104         {

105         // do initialization stuff here

106         return(0);

107         } break;

108 

109     case WM_PAINT:

110          {

111          // start painting

112          hdc = BeginPaint(hwnd,&ps);

113 

114          // the window is now validated 

115 

116          // end painting

117          EndPaint(hwnd,&ps);

118          return(0);

119         } break;

120 

121     case WM_DESTROY: 

122         {

123         // kill the application            

124         PostQuitMessage(0);

125         return(0);

126         } break;

127 

128     default:break;

129 

130     } // end switch

131 

132 // process any messages that we didn't take care of 

133 return (DefWindowProc(hwnd, msg, wparam, lparam));

134 

135 } // end WinProc

136 

137 // WINMAIN ////////////////////////////////////////////////////

138 

139 int WINAPI WinMain(    HINSTANCE hinstance,

140                     HINSTANCE hprevinstance,

141                     LPSTR lpcmdline,

142                     int ncmdshow)

143 {

144 // this is the winmain function

145 

146 WNDCLASS winclass;    // this will hold the class we create

147 HWND     hwnd;        // generic window handle

148 MSG         msg;        // generic message

149 HDC      hdc;       // generic dc

150 PAINTSTRUCT ps;     // generic paintstruct

151 

152 // first fill in the window class stucture

153 winclass.style            = CS_DBLCLKS | CS_OWNDC | 

154                           CS_HREDRAW | CS_VREDRAW;

155 winclass.lpfnWndProc    = WindowProc;

156 winclass.cbClsExtra        = 0;

157 winclass.cbWndExtra        = 0;

158 winclass.hInstance        = hinstance;

159 winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);

160 winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);

161 winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);

162 winclass.lpszMenuName    = NULL; 

163 winclass.lpszClassName    = WINDOW_CLASS_NAME;

164 

165 // register the window class

166 if (!RegisterClass(&winclass))

167     return(0);

168 

169 // create the window, note the use of WS_POPUP

170 if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME,    // class

171              "WIN3D Game Console",    // title

172              WS_POPUP | WS_VISIBLE,

173              0,0,                    // initial x,y

174                 GetSystemMetrics(SM_CXSCREEN),  // intial width

175              GetSystemMetrics(SM_CYSCREEN),  // initial height

176              NULL,        // handle to parent 

177              NULL,        // handle to menu

178              hinstance,// instance

179              NULL)))    // creation parms

180 return(0);

181 

182 // hide mouse

183 ShowCursor(FALSE);

184 

185 // save the window handle and instance in a global

186 main_window_handle = hwnd;

187 main_instance      = hinstance;

188 

189 // perform all game console specific initialization

190 Game_Init();

191 

192 // enter main event loop

193 while(1)

194     {

195     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

196         { 

197         // test if this is a quit

198         if (msg.message == WM_QUIT)

199            break;

200     

201         // translate any accelerator keys

202         TranslateMessage(&msg);

203 

204         // send the message to the window proc

205         DispatchMessage(&msg);

206         } // end if

207     

208     // main game processing goes here

209     Game_Main();

210 

211     } // end while

212 

213 // shutdown game and release all resources

214 Game_Shutdown();

215 

216 // show mouse

217 ShowCursor(TRUE);

218 

219 // return to Windows like this

220 return(msg.wParam);

221 

222 } // end WinMain

223 

224 // T3DX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////////

225 

226 int Game_Init(void *parms)

227 {

228 // this function is where you do all the initialization 

229 // for your game

230 

231 

232 // return success

233 return(1);

234 

235 } // end Game_Init

236 

237 ///////////////////////////////////////////////////////////////

238 

239 int Game_Shutdown(void *parms)

240 {

241 // this function is where you shutdown your game and

242 // release all resources that you allocated

243 

244 

245 // return success

246 return(1);

247 

248 } // end Game_Shutdown

249 

250 ///////////////////////////////////////////////////////////////

251 

252 void Init_Blocks(void)

253 {

254 // initialize the block field

255 for (int row=0; row < NUM_BLOCK_ROWS; row++)

256     for (int col=0; col < NUM_BLOCK_COLUMNS; col++)

257          blocks[row][col] = row*16+col*3+16;

258 

259 } // end Init_Blocks

260 

261 ///////////////////////////////////////////////////////////////

262 

263 void Draw_Blocks(void)

264 {

265 // this function draws all the blocks in row major form

266 int x1 = BLOCK_ORIGIN_X, // used to track current position

267     y1 = BLOCK_ORIGIN_Y; 

268 

269 // draw all the blocks

270 for (int row=0; row < NUM_BLOCK_ROWS; row++)

271     {    

272     // reset column position

273     x1 = BLOCK_ORIGIN_X;

274 

275     // draw this row of blocks

276     for (int col=0; col < NUM_BLOCK_COLUMNS; col++)

277         {

278         // draw next block (if there is one)

279         if (blocks[row][col]!=0)

280             {

281             // draw block     

282             Draw_Rectangle(x1-4,y1+4,

283                  x1+BLOCK_WIDTH-4,y1+BLOCK_HEIGHT+4,0);

284 

285             Draw_Rectangle(x1,y1,x1+BLOCK_WIDTH,

286                  y1+BLOCK_HEIGHT,blocks[row][col]);

287             } // end if

288 

289         // advance column position

290         x1+=BLOCK_X_GAP;

291         } // end for col

292 

293     // advance to next row position

294     y1+=BLOCK_Y_GAP;

295 

296     } // end for row

297 

298 } // end Draw_Blocks

299 

300 ///////////////////////////////////////////////////////////////

301 

302 void Process_Ball(void)

303 {

304 // this function tests if the ball has hit a block or the paddle

305 // if so, the ball is bounced and the block is removed from 

306 // the playfield note: very cheesy collision algorithm :)

307 

308 // first test for ball block collisions

309 

310 // the algorithm basically tests the ball against each 

311 // block's bounding box this is inefficient, but easy to 

312 // implement, later we'll see a better way

313 

314 int x1 = BLOCK_ORIGIN_X, // current rendering position

315     y1 = BLOCK_ORIGIN_Y; 

316 

317 int ball_cx = ball_x+(BALL_SIZE/2),  // computer center of ball

318     ball_cy = ball_y+(BALL_SIZE/2);

319 

320 // test of the ball has hit the paddle

321 if (ball_y > (SCREEN_HEIGHT/2) && ball_dy > 0)

322    {

323    // extract leading edge of ball

324    int x = ball_x+(BALL_SIZE/2);

325    int y = ball_y+(BALL_SIZE/2);

326 

327    // test for collision with paddle

328    if ((x >= paddle_x && x <= paddle_x+PADDLE_WIDTH) &&

329        (y >= paddle_y && y <= paddle_y+PADDLE_HEIGHT))

330        {

331        // reflect ball

332        ball_dy=-ball_dy;

333 

334        // push ball out of paddle since it made contact

335        ball_y+=ball_dy;

336 

337        // add a little english to ball based on motion of paddle

338        if (KEY_DOWN(VK_RIGHT))

339           ball_dx-=(rand()%3);

340        else

341        if (KEY_DOWN(VK_LEFT))

342           ball_dx+=(rand()%3);

343        else

344           ball_dx+=(-1+rand()%3);

345        

346        // test if there are no blocks, if so send a message

347        // to game loop to start another level

348        if (blocks_hit >= (NUM_BLOCK_ROWS*NUM_BLOCK_COLUMNS))

349           {

350           game_state = GAME_STATE_START_LEVEL;

351           level++;

352           } // end if

353 

354        // make a little noise

355        MessageBeep(MB_OK);

356 

357        // return

358        return; 

359 

360        } // end if

361 

362    } // end if

363 

364 // now scan thru all the blocks and see of ball hit blocks

365 for (int row=0; row < NUM_BLOCK_ROWS; row++)

366     {    

367     // reset column position

368     x1 = BLOCK_ORIGIN_X;

369 

370     // scan this row of blocks

371     for (int col=0; col < NUM_BLOCK_COLUMNS; col++)

372         {

373         // if there is a block here then test it against ball

374         if (blocks[row][col]!=0)

375            {

376            // test ball against bounding box of block

377            if ((ball_cx > x1) && (ball_cx < x1+BLOCK_WIDTH) &&     

378                (ball_cy > y1) && (ball_cy < y1+BLOCK_HEIGHT))

379                {

380                // remove the block

381                blocks[row][col] = 0; 

382 

383                // increment global block counter, so we know 

384                // when to start another level up

385                blocks_hit++;

386 

387                // bounce the ball

388                ball_dy=-ball_dy;

389 

390                // add a little english

391                ball_dx+=(-1+rand()%3);

392 

393                // make a little noise

394                MessageBeep(MB_OK);

395 

396                // add some points

397                score+=5*(level+(abs(ball_dx)));

398 

399                // that's it -- no more block

400                return;

401 

402                } // end if  

403 

404            } // end if

405 

406         // advance column position

407         x1+=BLOCK_X_GAP;

408         } // end for col

409 

410     // advance to next row position

411     y1+=BLOCK_Y_GAP;

412 

413     } // end for row

414 

415 } // end Process_Ball

416 

417 ///////////////////////////////////////////////////////////////

418 

419 int Game_Main(void *parms)

420 {

421 // this is the workhorse of your game it will be called

422 // continuously in real-time this is like main() in C

423 // all the calls for you game go here!

424 

425 char buffer[80]; // used to print text

426 

427 // what state is the game in? 

428 if (game_state == GAME_STATE_INIT)

429     {

430     // initialize everything here graphics

431     DD_Init(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP);

432 

433     // seed the random number generator

434     // so game is different each play

435     srand(Start_Clock());

436 

437     // set the paddle position here to the middle bottom

438     paddle_x = PADDLE_START_X;

439     paddle_y = PADDLE_START_Y;

440 

441     // set ball position and velocity

442     ball_x = 8+rand()%(SCREEN_WIDTH-16);

443     ball_y = BALL_START_Y;

444     ball_dx = -4 + rand()%(8+1);

445     ball_dy = 6 + rand()%2;

446 

447     // transition to start level state

448     game_state = GAME_STATE_START_LEVEL;

449 

450     } // end if 

451 ////////////////////////////////////////////////////////////////

452 else

453 if (game_state == GAME_STATE_START_LEVEL)

454     {

455     // get a new level ready to run

456 

457     // initialize the blocks

458     Init_Blocks();

459 

460     // reset block counter

461     blocks_hit = 0;

462 

463     // transition to run state

464     game_state = GAME_STATE_RUN;

465 

466     } // end if

467 ///////////////////////////////////////////////////////////////

468 else

469 if (game_state == GAME_STATE_RUN)

470     {

471     // start the timing clock

472     Start_Clock();

473 

474     // clear drawing surface for the next frame of animation

475     Draw_Rectangle(0,0,SCREEN_WIDTH-1, SCREEN_HEIGHT-1,200);

476 

477     // move the paddle

478     if (KEY_DOWN(VK_RIGHT))

479        {

480        // move paddle to right

481        paddle_x+=8;

482  

483        // make sure paddle doesn't go off screen

484        if (paddle_x > (SCREEN_WIDTH-PADDLE_WIDTH))

485           paddle_x = SCREEN_WIDTH-PADDLE_WIDTH;

486 

487        } // end if

488     else

489     if (KEY_DOWN(VK_LEFT))

490        {

491        // move paddle to right

492        paddle_x-=8;

493  

494        // make sure paddle doesn't go off screen

495        if (paddle_x < 0)

496           paddle_x = 0;

497 

498        } // end if

499 

500     // draw blocks

501     Draw_Blocks();

502 

503     // move the ball

504     ball_x+=ball_dx;

505     ball_y+=ball_dy;

506 

507     // keep ball on screen, if the ball hits the edge of 

508     // screen then bounce it by reflecting its velocity

509     if (ball_x > (SCREEN_WIDTH - BALL_SIZE) || ball_x < 0) 

510        {

511        // reflect x-axis velocity

512        ball_dx=-ball_dx;

513 

514        // update position 

515        ball_x+=ball_dx;

516        } // end if

517 

518     // now y-axis

519     if (ball_y < 0) 

520        {

521        // reflect y-axis velocity

522        ball_dy=-ball_dy;

523 

524        // update position 

525        ball_y+=ball_dy;

526        } // end if

527    else 

528    // penalize player for missing the ball

529    if (ball_y > (SCREEN_HEIGHT - BALL_SIZE))

530        {

531        // reflect y-axis velocity

532        ball_dy=-ball_dy;

533 

534        // update position 

535        ball_y+=ball_dy;

536 

537        // minus the score

538        score-=100;

539 

540        } // end if

541 

542     // next watch out for ball velocity getting out of hand

543     if (ball_dx > 8) ball_dx = 8;

544     else

545     if (ball_dx < -8) ball_dx = -8;    

546 

547     // test if ball hit any blocks or the paddle

548     Process_Ball();

549 

550     // draw the paddle and shadow

551     Draw_Rectangle(paddle_x-8, paddle_y+8, 

552                    paddle_x+PADDLE_WIDTH-8, 

553                    paddle_y+PADDLE_HEIGHT+8,0);

554 

555     Draw_Rectangle(paddle_x, paddle_y, 

556                    paddle_x+PADDLE_WIDTH, 

557                    paddle_y+PADDLE_HEIGHT,PADDLE_COLOR);

558 

559     // draw the ball

560     Draw_Rectangle(ball_x-4, ball_y+4, ball_x+BALL_SIZE-4, 

561                    ball_y+BALL_SIZE+4, 0);

562     Draw_Rectangle(ball_x, ball_y, ball_x+BALL_SIZE, 

563                    ball_y+BALL_SIZE, 255);

564 

565     // draw the info

566     sprintf(buffer,"F R E A K O U T           Score %d             Level %d",score,level);

567     Draw_Text_GDI(buffer, 8,SCREEN_HEIGHT-16, 127);

568     

569     // flip the surfaces

570     DD_Flip();

571 

572     // sync to 33ish fps

573     Wait_Clock(30);

574 

575     // check of user is trying to exit

576     if (KEY_DOWN(VK_ESCAPE))

577        {

578        // send message to windows to exit

579        PostMessage(main_window_handle, WM_DESTROY,0,0);

580 

581        // set exit state

582        game_state = GAME_STATE_SHUTDOWN;

583 

584        } // end if

585 

586     } // end if

587 ///////////////////////////////////////////////////////////////

588 else

589 if (game_state == GAME_STATE_SHUTDOWN)

590    {

591    // in this state shut everything down and release resources

592    DD_Shutdown();

593 

594    // switch to exit state

595    game_state = GAME_STATE_EXIT;

596 

597    } // end if

598 

599 // return success

600 return(1);

601 

602 } // end Game_Main

603 

604 ///////////////////////////////////////////////////////////////

编译链接时,如果出现error LNK2019: 无法解析的外部符号 __imp__CreateWindowEx等,说明连接时缺少了windows的某些库,主要因为在重定位过程中,链接器会去查找由所有输入目标文件的符号表组成的全局符号表,找到相应的符号进行重定位,如果没有找到相应的符号,则链接器会报符号未定义错误。

编译链接没问题后,游戏运行结果图如下:

 Windows游戏开发学习笔记之一

 

 

你可能感兴趣的:(windows)