1. 程式人生 > >利用VS建立一個遊戲(3)遊戲地圖繪製(程式碼+註釋)

利用VS建立一個遊戲(3)遊戲地圖繪製(程式碼+註釋)

首先注意的是我們要將地圖素材放置專案資料夾中。

#include "stdafx.h"    
#include "MyGameFrame.h" //源cpp檔案引申出的標頭檔案 也可以用resource.h代替    
#include <stdio.h>       //標準輸入輸出標頭檔案    

// 全域性變數:     
HINSTANCE hInst;                               // 當前例項    
HWND      hWnd;
HDC       mdc;                                 //記憶體DC
HDC       hdc;
HBITMAP   fullmap;                             //地圖
const int cols = 8;
const int rows = 8;



// 此程式碼模組中包含的函式的前向宣告:     
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitWindow(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR    lpCmdLine,
	int       nCmdShow)
{
	// 初始化全域性字串    
	MyRegisterClass(hInstance);

	// 執行應用程式初始化:     
	if (!InitWindow(hInstance, nCmdShow))//初始化視窗    
	{
		return FALSE;//如果不成功則返回FALSE,並退出程式    
	}

	/*
	MSG型別見 https://blog.csdn.net/wanghaofeng/article/details/6632165
	*/
	MSG msg; //建立訊息類物件  

	// TODO: 在此放置執行程式碼。      

	HDC hdc = GetDC(hWnd);//建立記憶體DC    
	mdc = CreateCompatibleDC(hdc);//建立視窗DC,CreateCompatibleDC( )函式建立建立記憶體裝置描述表,把儲存在記憶體DC上的點陣圖貼到視窗DC中  
	HDC bufdc = CreateCompatibleDC(hdc);

	//檔名  
	char filename[20] = "";

	//行列及座標  
	int rowNum, colNum;
	int i, x, y;
    
	//---------------------------------------------平面地圖貼圖方式--------------------------------------------------------------  

	//地圖陣列  
	int mapIndex[64] = {
		2,2,2,2,0,1,0,1,                  //第1行   
		0,2,2,0,0,0,1,1,                  //第2行   
		0,0,0,0,0,0,0,1,                  //第3行   
		2,0,0,0,0,0,2,2,                  //第4行   
		2,0,0,0,0,2,2,2,                  //第5行   
		2,0,0,0,2,2,0,0,                  //第6行   
		0,0,2,2,2,0,0,1,                  //第7行   
		0,0,2,0,0,0,1,1                   //第8行  
	};

	fullmap = CreateCompatibleBitmap(hdc, cols * 50, rows * 50);//cols列數 rows行數

	SelectObject(mdc, fullmap);

	//儲存三種不同的地圖格式  
	HBITMAP map[3];

	//載入各圖塊點陣圖  
	for (i = 0; i<3; i++) {
		sprintf_s(filename, "map%d.bmp", i);
		map[i] = (HBITMAP)LoadImage(NULL, filename, IMAGE_BITMAP, 50, 50, LR_LOADFROMFILE);
	}

	//計算圖塊貼圖位置並進行地圖拼接並繪製的  
	for (i = 0; i<rows*cols; i++) {
		SelectObject(bufdc, map[mapIndex[i]]);
		rowNum = i / cols; //求行編號  
		colNum = i % cols; //求列編號  
		x = colNum * 50; //求貼圖X 座標  
		y = rowNum * 50; //求貼圖Y 座標  

		BitBlt(mdc, x, y, 50, 50, bufdc, 0, 0, SRCCOPY); //地圖拼接  
	}
	//---------------------------------------------------------------------------------------------------------------------------- 
	SelectObject(mdc, fullmap); 
	BitBlt(hdc, 0, 0, cols * 50, rows * 50, mdc, 0, 0, SRCCOPY);

	//主訊息迴圈:     
	PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);//賦初值    

	while (msg.message != WM_QUIT)         //進入遊戲訊息迴圈:    
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg); //獲得遊戲玩家輸入的訊息;    
			DispatchMessage(&msg);//分配玩家訊息並響應使用者訊息。    
		}
	}
	return (int)msg.wParam;
}



//    
//  函式: MyRegisterClass()    
//    
//  註冊Windows類,一款遊戲有且僅有一個主視窗,與遊戲程式唯一對應。建立遊戲視窗前要填寫視窗類結構體WNDCLASSEX    
//    
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex =
	{
		wcex.cbSize = sizeof(WNDCLASSEX),
		CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
		WndProc,0,0,
		hInstance,
		LoadIcon(hInstance, (LPCTSTR)IDI_MYGAMEFRAME),
		LoadCursor(NULL, IDC_ARROW),
		(HBRUSH)(COLOR_WINDOW + 1),NULL,
		_T("GameFrame"),
		LoadIcon(NULL,(LPCTSTR)IDI_SMALL)
	};
	return RegisterClassEx(&wcex);
}

//    
//   函式: InitInstance(HINSTANCE, int)    
//    
//   目的: 儲存例項控制代碼並建立主視窗    
//    
//   註釋:     
//    
//        在此函式中,我們在全域性變數中儲存例項控制代碼並    
//        建立和顯示主程式視窗。    
//    
BOOL InitWindow(HINSTANCE hInstance, int nCmdShow)
{	
	hInst = hInstance; // 將例項控制代碼儲存在全域性變數中          
    hWnd = CreateWindow
	(
		_T("GameFrame"),
		_T("遊戲框架"),
		WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX,//普通樣式,不能改變大小,不能最大化    
		CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, nullptr, nullptr, hInstance, nullptr
	);

	if (!hWnd)
	{
		return FALSE;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	return TRUE;
}

//    
//  函式: WndProc(HWND, UINT, WPARAM, LPARAM)    
//    
//  目的:    處理主視窗的訊息。    
//    
//  WM_COMMAND  - 處理應用程式選單    
//  WM_PAINT    - 繪製主視窗    
//  WM_DESTROY  - 傳送退出訊息並返回    
//    
//    
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	PAINTSTRUCT ps;                     //用於WM_PAINT     
	switch (msg)                        //判斷訊息    
	{
	case WM_CREATE:
		//執行初始化程式碼                  
		return(0);
		break;
	case WM_PAINT:
		//確定視窗是否有效    
		hdc = BeginPaint(hwnd, &ps);
		//執行繪製程式碼    
		SelectObject(mdc, fullmap);  //影象重繪處要加上這兩句程式碼  
		BitBlt(hdc, 0, 0, cols * 50, rows * 50, mdc, 0, 0, SRCCOPY);   //繪製 
		//結束程式碼    
		EndPaint(hwnd, &ps);
		return(0);
		break;
	case WM_DESTROY:
		//關閉程式,傳送WM_QUIT訊息    
		PostQuitMessage(0);
		return(0);
		break;
	default:
		break;
	}
	return (DefWindowProc(hwnd, msg, wparam, lparam));
}


測試結果如下:


同樣我們要繪製斜角地圖,我們先將地圖大小做更換

全域性變數裡更改

const int cols = 8;
const int rows = 8;

同樣我們要繪製斜角地圖,先將標線部分更換為

//-----------------------------------------斜角地圖貼圖方式(需把其他貼圖方式註釋掉)------------------------------------------
//地圖陣列
int mapIndex[100] = {
	2,2,2,2,2,0,1,0,1,0, 					//第1行  
	3,3,2,2,0,0,0,1,1,0, 					//第2行 
	3,0,0,0,0,0,0,0,1,2, 					//第3行  
	2,2,0,0,0,0,0,2,2,2, 					//第4行  
	2,2,0,0,0,0,2,2,2,2, 					//第5行  
	2,2,0,0,0,2,2,0,0,2, 					//第6行 
	2,0,0,2,2,2,0,0,1,0, 					//第7行 
	0,0,2,0,0,0,1,1,1,1, 					//第8行  
	0,2,0,3,3,3,3,3,3,1, 					//第9行  
	2,0,3,3,3,3,3,3,3,3                     //第10行
};

//-------------------景物地圖貼圖方式使用-----------------------------------------
//景物陣列sceneIndex[100]:
int sceneIndex[100] = {
	0,2,2,0,2,0,1,0,1,1, 					//景物 
	0,0,0,0,0,0,0,1,1,0,
	0,0,0,0,0,0,1,0,1,0,
	0,0,1,0,1,0,0,0,2,0,
	2,2,0,0,1,0,0,0,0,2,
	0,0,0,0,0,0,0,0,0,0,
	0,0,1,0,0,0,0,0,1,0,
	0,0,0,0,0,0,1,1,1,1,
	1,0,0,0,0,0,0,0,0,1,
	2,0,0,0,0,0,0,0,0,0
};
//-----------------------------------------------------------------------------------

//儲存四種不同的地圖格式
HBITMAP map[4];

//xstart與ystart表示第一張圖塊左上角貼圖座標
int xstart, ystart;
xstart = 32 * (rows - 1);//每個菱形的大小為64*32所以第0行第0列小圖塊座標應該為此應該是(行數-1)*32
ystart = 160;  //從y=160處開始繪製地圖(即視窗高1/3處開始)


fullmap = (HBITMAP)LoadImage(NULL, "bgtwo.bmp", IMAGE_BITMAP, 640, 480, LR_LOADFROMFILE);
SelectObject(mdc, fullmap);




for (i = 0; i<4; i++) {
	sprintf_s(filename, "maptwo%d.bmp", i);
	map[i] = (HBITMAP)LoadImage(NULL, filename, IMAGE_BITMAP, 128, 32, LR_LOADFROMFILE);
}




//載入景物點陣圖
HBITMAP scene[2];
for (i = 0; i<2; i++) {
	sprintf_s(filename, "scene%d.bmp", i + 1);
	scene[i] = (HBITMAP)LoadImage(NULL, filename, IMAGE_BITMAP, 100, 60, LR_LOADFROMFILE);
}



//計算圖塊貼圖位置程式程式碼
for (i = 0; i<rows*cols; i++)
{
	SelectObject(bufdc, map[mapIndex[i]]);
	rowNum = i / cols;                                     //求行編號
	colNum = i % cols;                                     //求列編號
	x = xstart + colNum * 32 + rowNum * (-32);             //求貼圖X 座標
	y = ystart + rowNum * 16 + colNum * 16;                //求貼圖Y 座標
	BitBlt(mdc, x, y, 64, 32, bufdc, 64, 0, SRCAND);               //透明處理
	BitBlt(mdc, x, y, 64, 32, bufdc, 0, 0, SRCPAINT);

	//貼圖座標修正程式碼
	//-------------------景物地圖貼圖方式使用-----------------------------------------

	switch (sceneIndex[i]) {
	case 1:
		SelectObject(bufdc, scene[0]);
		BitBlt(mdc, x + 7, y - 44, 50, 60, bufdc, 50, 0, SRCAND);     //景物1
		BitBlt(mdc, x + 7, y - 44, 50, 60, bufdc, 0, 0, SRCPAINT);
		break;
	case 2:
		SelectObject(bufdc, scene[1]);
		BitBlt(mdc, x + 7, y - 30, 50, 60, bufdc, 50, 0, SRCAND);    //景物2
		BitBlt(mdc, x + 7, y - 30, 50, 60, bufdc, 0, 0, SRCPAINT);
		break;
	}
	//-------------------------------------------------------------------------------
}
SelectObject(mdc, fullmap);
BitBlt(hdc, 0, 0, 640, 480, mdc, 0, 0, SRCCOPY);

然後更換視窗大小 :(InitWindow()函式中)


	HWND hWnd = CreateWindow
	(
		_T("GameFrame"),
		_T("遊戲框架"),
		WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX,//普通樣式,不能改變大小,不能最大化
		CW_USEDEFAULT, CW_USEDEFAULT,640,480, nullptr, nullptr, hInstance, nullptr
	);

更換繪製程式碼:(WndProc()函式中)

		SelectObject(mdc, fullmap);
		BitBlt(hdc, 0, 0, 640, 480, mdc, 0, 0, SRCCOPY);

效果分別如下: