1. 程式人生 > >win32遊戲開發(2) --連連看遊戲製作(vc++版)

win32遊戲開發(2) --連連看遊戲製作(vc++版)

工程目錄一覽

檔案功能及關係圖: GameEngine類

成員名 作用
static GameEngine * m_pGameEngine 指向自身的指標,供外界程式訪問
HINSTANCE m_hInstance 例項控制代碼
HWND m_hWnd 視窗控制代碼
TCHAR m_szWindowClass[32] 視窗類名
TCHAR m_szWndTitle[32] 視窗標題
int m_iWidth,m_iHeight 視窗寬高
int m_iFrameDelay 調節遊戲幀數
bool start_sign 遊戲開始標記
函式名 功能
GameEngine(HINSTANCE hInstance,LPTSTR szWindowClass,LPTSTR szTitle,int iWidth,int iHeight,int iDelay) 建構函式建立遊戲例項
static GameEngine* GetEngine() 返回成員 *m_pGameEngine
HINSTANCE GetInstance() 返回成員 m_hInstance
HWND GetWnd() 返回成員 m_hWnd
void SetWnd(HWND hWnd) 賦值給 m_hWnd
LPTSTR GetTitle() 返回成員 m_szWndTitle
int GetWidth() 返回成員 m_iWidth
void SetWidth(int iWidth) 賦值給 m_iWidth
int GetHeight() 返回成員 m_iHeight
void SetHeight(int iHeight) 賦值給 m_iHeight
int GetDelay() 返回成員 m_iFrameDelay
void SetDelay(int iDelay) 賦值給 m_iFrameDelay
void setStart(bool sign) 賦值給 start_sign
bool getStart() 返回成員start_sign
BOOL Initiallize(int cmdShow) 建立視窗
LRESULT HandleEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) 訊息處理

GameEgine核心函式(不是GameEngine類函式)

函式名 功能
BOOL GameInitial(HINSTANCE hInstance) 建立GameEgine類物件
void GameStartBg() 繪製遊戲初始畫面(遊戲介面)
void setDffclt(int difficult) 設定遊戲難度
void GameStart() 繪製遊戲初始畫面(開始遊戲畫面)
void LButtonDown(int x,int y) 滑鼠單擊觸發函式
void GameEnd() 遊戲結束相關操作
void GamePaint() 遊戲重繪
void GameCycle() 遊戲迴圈
bool IsResult() 判斷初始化後的2維陣列是否有解
void set_clue_sign(bool sign) 設定提示標誌
bool IsTimeEnd() 判斷時間是否已經用完(倒計時)
void playSound(int s_sort) 播放音樂
void setSound(int s_sort) 選擇音樂

針對連連看設定的全域性常量

巨集定義 常量值 作用
row 16 地圖行數
col 17 地圖列數
BLANK_STATE -2 用於判斷是否加邊框(選中加邊框,再次點選不加,)
EASY 1 簡單難度
NORMAL 2 中等難度
HARD 3 困難難度

針對連連看遊戲設定的變數(宣告在llk.h)

變數名 作用
int map[row][col] 儲存圖片位置的2維陣列(在陣列中-1為有圖片(之後會賦值),0為無圖片)
int num 方塊總個數
int sort_num[39] 39個圖形,每種圖形4個
int sort_place[39][16] 記錄圖形位置,即每種圖片4個,位置表示(舉例)[1][0]和[1][1]表示行座標(十位和個位),[1][2]和[1][3]表示列座標
POINT p1,p2 記錄選中的兩個方塊位置
bool fram_sign 繪畫邊框標誌,true為有邊框,false為無邊框
int clue_x1,clue_y1,clue_x2,clue_y2 用於提示的一對方塊(能消掉的)
bool clue_sign 提示標誌
long int score 分數
int game_time 遊戲時間

針對連連看遊戲設定的函式

函式名 功能
void SortPlace(int p_sort,int p_sort_num,int p_row,int p_col) 記錄圖片放置位置
void temp_SortPlace(int p_sort,int p_sort_num,int p_row,int p_col) 臨時記錄圖片放置位置
void initial() 初始化遊戲變數
void ReInitial() 重新初始化遊戲變數
void clue() 提示邊框
void set_clue_sign(bool sign) 設定提示標誌
void PaintFrame(int g_left,int g_right,int g_top,int g_bottom,int c_index,int r_index) 方塊外框繪製,線條環繞繪製框架
bool IsLink(int x1, int y1, int x2, int y2) 判斷選中的兩個方塊是否可以連線
bool X1_Link_X2(int x,int y1,int y2) X直連
bool Y1_Link_Y2(int x1,int x2,int y) Y直連
bool OneCornerLink(int x1,int y1,int x2,int y2) 判斷是否只有一個拐角
bool TwoCornerLink(int x1,int y1,int x2,int y2) 判斷是否有兩個拐角
bool X_Link(int x,int y1,int y2) 判斷有拐角是否能x直連
bool Y_Link(int x1,int x2,int y) 判斷有拐角是否能y直連
void playStartSound() 播放遊戲開始音樂
bool end(int n) 判斷遊戲是否結束
void paintInfo() 顯示資訊

實現細節

在具體實現每一個函式之前,首先要清楚的是應該在哪些地方呼叫這些函式.因此我們不妨跟隨著遊戲執行時的執行順序對這些函式進行放置,並對函式進行定義. 首先是winmain部分:

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hpreInstance,LPSTR lpcmdline,int iShowCmd)
{
  MSG msg;
  static int iticktrigger=0;//設為開始時間0ms
  int itickcount;
  if(!GameInitial(hInstance))//建立GameEngine類物件g_pGame
     return 0;
  if(!GameEngine::GetEngine()->Initiallize(SW_SHOWNORMAL))//對視窗類物件wndclass進行賦值並註冊,建立視窗
     return 0;
  ::ZeroMemory(&msg,sizeof(msg));
    GameStartBg();//繪製遊戲背景
  while(msg.message!=WM_QUIT)
  {
	  if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
	  {
		  ::TranslateMessage(&msg);
		  ::DispatchMessage(&msg);
	  }
	  else
	  {
		  ::Sleep(1);
		  itickcount=::GetTickCount();//返回從程式開始到現在的執行ms數
		  if(itickcount-iticktrigger>0)
		  {		 
			 if(GameEngine::GetEngine()->getStart() == true)//如果獲取到的start_sign為真,開始遊戲
			 {
				GamePaint();//遊戲重繪
				GameCycle();//遊戲迴圈
				iticktrigger= itickcount+GameEngine::GetEngine()->GetDelay();//設定下一次重繪時間
			 }
		  }
	  }
  }
  return TRUE;

}

對winmain中出現的未定義函式進行定義:

BOOL GameInitial(HINSTANCE hInstance)
{
   g_pGame=new GameEngine(hInstance,"MYCLASS","連連看 v1.0",960,600,delay);
   if(g_pGame==NULL)
	   return FALSE;
   return TRUE;
}

GameEngine::GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle, 
					  int iWidth, int iHeight,int iDelay)
{
  m_pGameEngine=this;
  m_hInstance=hInstance;
  m_hWnd=NULL;
  if(lstrlen(szWindowClass)>0)
	  lstrcpy(m_szWindowClass,szWindowClass);
  if(lstrlen(szTitle)>0)
	  lstrcpy(m_szWndTitle,szTitle);
  m_iWidth=iWidth;
  m_iHeight=iHeight;
  m_iFrameDelay=iDelay;
  start_sign = false;
}

BOOL GameEngine::Initiallize(int icmdShow)
{
  static WNDCLASS wndclass;
  wndclass.hInstance=m_hInstance;
  wndclass.lpszClassName=m_szWindowClass;
  wndclass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);
  wndclass.style=CS_HREDRAW|CS_VREDRAW;
  wndclass.lpfnWndProc=WndProc;
  wndclass.hbrBackground=(HBRUSH)::GetStockObject(WHITE_BRUSH);
  if(!RegisterClass(&wndclass))
	  return FALSE;
m_hWnd=CreateWindow(m_szWindowClass,m_szWndTitle,WS_OVERLAPPEDWINDOW,150,50,m_iWidth,m_iHeight,NULL,NULL,m_hInstance,NULL);
  if(!m_hWnd)
	  return FALSE;
  SendMessage(m_hWnd,WM_SETICON,(WPARAM)TRUE,(LPARAM)LoadIcon(GetModuleHandle(NULL),(LPCTSTR)IDI_ICON1));
  ::ShowWindow(m_hWnd,icmdShow);
  ::UpdateWindow(m_hWnd);	 
  return TRUE;
}

void GameStartBg()
{   
	HWND hwnd = g_pGame->GetWnd();
	dc = ::GetDC(hwnd);
	bufdc = ::CreateCompatibleDC(dc);
	mdc = ::CreateCompatibleDC(dc);
	mid = ::CreateCompatibleBitmap(dc,960,600);

	bg = (HBITMAP)::LoadImage(NULL,"./image/bg.bmp",IMAGE_BITMAP,960,600,LR_LOADFROMFILE);	//載入背景圖片
	::SelectObject(mdc,bg);
	::BitBlt(dc,0,0,960,600,mdc,0,0,SRCCOPY);

	::ReleaseDC(hwnd,bufdc);
	::ReleaseDC(hwnd,mdc);
}

void GamePaint()
{
	HWND hwnd = g_pGame->GetWnd();
	int i,j,m;
	//重繪背景
	::SelectObject(bufdc,game_bg);
	::BitBlt(mdc,0,0,960,600,bufdc,0,0,SRCCOPY);
	//重繪遊戲區
	for(i = 0;i < row;i++)
	{
		for(j = 0;j < col;j++)
		{
			::ReleaseDC(hwnd,bufdc);
			for(m = 1;m <= 39;m++)
			{
				if(map[i][j] == m)
				{
					::SelectObject(bufdc,pic[m-1]);
					::BitBlt(mdc,game_left+j*31-2*31,game_top+i*34-2*34,31,34,bufdc,0,0,SRCCOPY);
				}
			}
		}
	}
	//繪製邊框
	if(fram_sign == true)
		PaintFrame(game_left,game_right,game_top,game_bottom,g_col_index,g_row_index);//繪製矩形邊框
	if(clue_sign == true)
		clue();//繪製提示框
	//顯示資訊
	paintInfo();
	::BitBlt(dc,0,0,960,600,mdc,0,0,SRCCOPY);
	::ReleaseDC(hwnd,bufdc);
	::ReleaseDC(hwnd,mdc);
}

//方塊外框繪製,線條環繞繪製框架
void PaintFrame(int g_left,int g_right,int g_top,int g_bottom,int c_index,int r_index)
{
	HWND hwnd = g_pGame->GetWnd();	

	::SelectObject(mdc,pen);

	::MoveToEx(mdc,g_left+c_index*31,g_top+r_index*34,NULL);
	::LineTo(mdc,g_left+c_index*31+31,g_top+r_index*34);
	::LineTo(mdc,g_left+c_index*31+31,g_top+r_index*34+34);
	::LineTo(mdc,g_left+c_index*31,g_top+r_index*34+34);
	::LineTo(mdc,g_left+c_index*31,g_top+r_index*34);
}

//提示邊框
void clue()
{
	fram_sign = false;
	//方塊外框繪製,線條環繞繪製框架
	PaintFrame(game_left,game_right,game_top,game_bottom,clue_y1,clue_x1);		
	PaintFrame(game_left,game_right,game_top,game_bottom,clue_y2,clue_x2);
}
//顯示資訊
void paintInfo()
{
	char s_level[20]={0};
	char s_score[20]={0};
	char s_time[20]={0};
	if( difficult == EASY)
		::TextOut(mdc,100,34*2,"級別: 簡單",10);
	else if( difficult == NORMAL)
		::TextOut(mdc,100,34*2,"級別: 中等",10);
	else if( difficult == HARD)
		::TextOut(mdc,100,34*2,"級別: 難",8);
	::sprintf(s_score,"得分: %d",score);
	::sprintf(s_time,"剩餘時間: %d",game_time);
   	::TextOut(mdc,100,34*2+25,s_score,strlen(s_score));
	::TextOut(mdc,100,34*2+50,s_time,strlen(s_time));
	::TextOut(mdc,100,34*2+75+50,"“空格”鍵: 提示!",18);
}	

void GameCycle()
{
    
}

接下來是最重要的訊息機制設定,

LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
   return GameEngine::GetEngine()->HandleEvent(hWnd,msg,wParam,lParam);
}

對於HandleEvent(hWnd,msg,wParam,lParam)的定義:

LRESULT GameEngine::HandleEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  int m,x,y;
  switch(msg)
  {
  case WM_SYSCOMMAND:							//使最大化失效
      if(wParam == SC_MAXIMIZE)   
         return 0;   
      break;;
  case WM_COMMAND:
	  {
		m = LOWORD(wParam);
		switch(m)
		{
		case ID_EASY:							//處理選單“簡單”事件
			start_sign = true;
			setDffclt(1);
			GameStart();
			::SetTimer(m_hWnd,1,1000,NULL);
			break;
		case ID_NORMAL:							//處理選單“正常”事件
			start_sign = true;
			setDffclt(2);
			GameStart();
			::SetTimer(m_hWnd,1,1000,NULL);
			break;
		case ID_HARD:							//處理選單“難”事件
			start_sign = true;
			setDffclt(3);
			GameStart();
			::SetTimer(m_hWnd,1,1000,NULL);
			break;
		case ID_EXIT:							//處理選單“退出”事件
			::PostQuitMessage(0);
			break;
		case ID_SOUND0:							//處理選單“音樂1”事件
			setSound(0);
			break;
		case ID_SOUND1:							//處理選單“音樂2”事件
			setSound(1);
			break;
		case ID_SOUND2:							//處理選單“音樂3”事件
			setSound(2);
			break;
		case ID_HELP1:							//處理選單“幫助”事件		
			::MessageBox(hWnd," 操作說明:\n1. 選擇“音樂”\n2. 選擇遊戲難度進行遊戲(預設是音樂1)\n\n按鍵說明:\n1. “空格”鍵將會有提示出現\n3.選擇“退出”,退出整個遊戲\n","說明",MB_OK);
			break;
		case ID_ABOUT1:							//處理選單“關於”事件
			::MessageBox(hWnd,"版本:\t連連看 v1.0","關於",MB_OK);
			break;
		}
	  }
	  break;
  case WM_TIMER:								//響應定時器
	  if( IsTimeEnd() )
		  start_sign = false;
	  break;
  case WM_CHAR:
	  switch(wParam)
	  {
	  case ' ':									//處理“空格”事件
		  set_clue_sign(true);
		  break;
	  }
	  break;
  case WM_LBUTTONDOWN:							//處理滑鼠左鍵單擊事件
	  x = LOWORD(lParam);
	  y = HIWORD(lParam);
	  LButtonDown(x,y);
	  break;
  case WM_DESTROY:
	   GameEnd();
	   ::PostQuitMessage(0);
	   return 0;
  }
  return ::DefWindowProc(hWnd,msg,wParam,lParam);
}

對在訊息機制出現的未定義函式進行定義:

void setDffclt(int n)
{
	difficult = n;
	if(n == EASY)            //簡單
		game_time = 180;
	if(n == NORMAL)			 //中等
		game_time = 120;
	if(n == HARD)			 //難
		game_time = 60;
}

void GameStart()
{
	HWND hwnd = g_pGame->GetWnd();//獲取視窗控制代碼m_hWnd
	RECT rect;
	char s[16];
	int i,j,m;
	//載入方塊圖片
	for(i = 0;i < 39;i++)
	{
		sprintf(s,"./image/%d.bmp",i+1);
		pic[i] = (HBITMAP)::LoadImage(NULL,s,IMAGE_BITMAP,31,34,LR_LOADFROMFILE);
	}
	initial();			//初始化
	IsResult();			//判斷是否有解
	playStartSound();	//播放開始音樂
	dc = ::GetDC(hwnd);
	bufdc = ::CreateCompatibleDC(dc);
	mdc = ::CreateCompatibleDC(dc);
	mid = ::CreateCompatibleBitmap(dc,960,600);
	::SelectObject(mdc,mid);
	//繪製背景
	game_bg = (HBITMAP)::LoadImage(NULL,"./image/GameBg.bmp",IMAGE_BITMAP,960,600,LR_LOADFROMFILE);
	::SelectObject(bufdc,game_bg);
	::BitBlt(mdc,0,0,960,600,bufdc,0,0,SRCCOPY);
	//繪製遊戲區
	::GetClientRect(hwnd,&rect);
	game_left = int((rect.left+rect.right)/2-6.5*31);
	game_right = int((rect.left+rect.right)/2+6.5*31);
	game_top = int((rect.bottom+rect.top)/2-6*34);
	game_bottom = int((rect.bottom+rect.top)/2+6*34);
	for(i = 0;i < row;i++)
	{
		for(j = 0;j < col;j++)
		{
			::ReleaseDC(hwnd,bufdc);
			for(m = 1;m <= 39;m++)
			{
				if(map[i][j] == m)
				{
					::SelectObject(bufdc,pic[m-1]);
					::BitBlt(mdc,game_left+j*31-2*31,game_top+i*34-2*34,31,34,bufdc,0,0,SRCCOPY);
					break;
				}
			}
		}
	}
	::BitBlt(dc,0,0,960,600,mdc,0,0,SRCCOPY);
	::ReleaseDC(hwnd,bufdc);
	::ReleaseDC(hwnd,mdc);
}

void initial()
{
	srand((unsigned)time(NULL));
	int i,j;
	int sort;
	score = 0;
	p1.x = BLANK_STATE;
	p1.y = BLANK_STATE;
	p2.x = BLANK_STATE;
	p2.y = BLANK_STATE;
	pen = ::CreatePen(PS_SOLID,3,RGB(255,0,0));
	fram_sign = false;
	clue_sign = false;
	//清空map二維陣列
	for(i = 0;i < row-4;i++)						
	{
		for(j = 0;j < col-4;j++)
			map[i+2][j+2] = -1;
	}	

	//初始化sort_num陣列
	for(i = 0;i < 39;i++)							
		sort_num[i] = 0;
	//初始化sort_place二維陣列
	for(i = 0;i < 39;i++)							
	{
		for(j = 0;j < 16;j++)
			sort_place[i][j] = -1;
	}

	//初始化map二維陣列
	for(i = 0;i < row;i++)							
	{
		for(j = 0;j < col;j++)
		{
			if(map[i][j] == -1)
			{
				while(1)
				{
					sort = rand()%39+1;									//產生隨機數

					if(sort_num[sort - 1]<4)
					{
						map[i][j] = sort;								//放進地圖中
						sort_num[sort - 1]++;							//該種圖片數量加1
						num++;											//方塊總個數加1
						SortPlace(sort,sort_num[sort-1],i-2,j-2);		//記錄圖片放置位置
						break;
					}
				}
			}
		}
	}
}

//記錄圖片放置位置
void SortPlace(int p_sort,int p_sort_num,int p_row,int p_col)
{	
	if(p_row < 10)
	{
		sort_place[p_sort-1][p_sort_num*4-4] = 0;				//一位數的話將十位補0
		sort_place[p_sort-1][p_sort_num*4-3] = p_row;			//取個位
	}
	else
	{
		sort_place[p_sort-1][p_sort_num*4-4] = p_row/10;		//取十位
		sort_place[p_sort-1][p_sort_num*4-3] = p_row%10;		//取個位
	}

	if(p_col < 10)
	{
		sort_place[p_sort-1][p_sort_num*4-2] = 0;				//一位數的話將十位補0
		sort_place[p_sort-1][p_sort_num*4-1] = p_col;			//取個位
	}
	else
	{
		sort_place[p_sort-1][p_sort_num*4-2] = p_col/10;		//取十位
		sort_place[p_sort-1][p_sort_num*4-1] = p_col%10;		//取個位
	}
}

//判斷是否有解
bool IsResult()
{
	int i,j,m,n;
	POINT pp[4];

	//取出對應種類方塊的位置
	for(i = 0;i < 39;i++)
	{
		for(j = 0;j < 16;j+=4)				
		{
			pp[j/4].x = sort_place[i][j]*10 + sort_place[i][j+1];
			pp[j/4].y = sort_place[i][j+2]*10 + sort_place[i][j+3];
		}

		//兩兩比較,判斷是否存在能連通的方塊
		for(m = 0;m < 3;m++)
		{
			for(n = m+1;n < 4;n++)
			{
				if( IsLink(pp[m].x,pp[m].y,pp[n].x,pp[n].y) )
				{
					clue_x1 = pp[m].x;
					clue_y1 = pp[m].y;
					clue_x2 = pp[n].x;
					clue_y2 = pp[n].y;
					return true;
				}
			}
		}
	}
	::MessageBox(NULL,"無解,將重列","提醒",MB_OK);
	return false;
}

bool IsLink(int x1, int y1, int x2, int y2)
{
	//X直連
	if(x1 == x2)
	{
		if( X1_Link_X2(x1,y1,y2) )
			return true;
	}

	//Y直連
	if( y1 == y2 )
	{
		if( Y1_Link_Y2(x1,x2,y1) )
			return true;
	}

	//一個拐角
	if( OneCornerLink(x1,y1,x2,y2) )
		return true;

	//兩個拐角
	if( TwoCornerLink(x1,y1,x2,y2) )
		return true;

	return false;
}

//一個拐角					
bool OneCornerLink(int x1,int y1,int x2,int y2)
{
	if( X_Link(x1,y1,y2) && Y_Link(x2,x1,y2) )			//檢測拐點1
		return true;
	else if( X_Link(x2,y2,y1) && Y_Link(x1,x2,y1) )		//檢測拐點2
		return true;
	return false;
}
		
//兩個拐角						
bool TwoCornerLink(int x1,int y1,int x2,int y2)
{
	int i;
	int aa;
	for(i = y1+1;i <= col-4;i++)			//右檢測
	{
		aa=map[x1+2][i+2];
		if(map[x1+2][i+2] > 0)
		{
			break;
		}
		if( OneCornerLink(x1,i,x2,y2) )
			return true;
	}
	for(i = x1+1;i <= row-4;i++)			//下檢測
	{
		aa=map[i+2][y1+2];
		if(map[i+2][y1+2] > 0)
		{
			break;
		}
		if( OneCornerLink(i,y1,x2,y2) )
			return true;
	}
	for(i = y1-1;i >= 0;i--)				//左檢測
	{
		aa=map[x1+2][i+2];
		if(map[x1+2][i+2] > 0)
		{
			break;
		}
		if( OneCornerLink(x1,i,x2,y2) )
			return true;
	}
	for(i = x1-1;i >= 0;i--)				//上檢測
	{
		aa=map[i+2][y1+2];
		if(map[i+2][y1+2] > 0)
		{
			break;
		}
		if( OneCornerLink(i,y1,x2,y2) )
			return true;
	}

	return false;
}

//播放遊戲開始音樂
void playStartSound()
{
	PlaySound("./music/start.wav",NULL,SND_ASYNC); 
}

//選擇音樂
void setSound(int s_sort)
{
	sound_sort = s_sort;
}

//播放音樂
void playSound(int s_sort)
{
	char ss_sort[20]={0};
	::sprintf(ss_sort,"./music/clear%d.wav",s_sort);
	PlaySound(ss_sort,NULL,SND_ASYNC); 
}

//左鍵按下
void LButtonDown(int x,int y)
{
	int m;
	POINT pp[4];

	int xx,yy;
	int sort;
	int col_index,row_index;
	
	xx = x - game_left;
	yy = y - game_top;

	if(xx<=0 || yy<=0 || xx>=(col-4)*31 || yy>=(row-4)*34)		//判斷是否在遊戲區內
		return;
	
	col_index = xx/31;				//轉化成列下標
	row_index = yy/34;				//轉化成行下標

	if( (map[row_index+2][col_index+2] != -1) && (map[row_index+2][col_index+2] != 0) )
	{
		if(p1.x == BLANK_STATE)				//假設尚未記錄第一個方塊
		{
			p1.x = row_index;
			p1.y = col_index;
		
			PaintFrame(game_left,game_right,game_top,game_bottom,col_index,row_index);		//方塊外框繪製,線條環繞繪製框架
			fram_sign = true;

			g_row_index = row_index;
			g_col_index = col_index;
			return;
		}
		else
		{
			if( p1.x==row_index && p1.y==col_index )	//第二次點選本身
			{
				p1.x = BLANK_STATE;
				fram_sign = false;
				return;
			}
			else		//第二次點選非本身
			{
				if(map[p1.x+2][p1.y+2] == map[row_index+2][col_index+2])	//第一次和第二次點選的兩個方塊型別一樣
				{
					if( IsLink(p1.x,p1.y,row_index,col_index) )				//可以連線,消去連線的2個方塊
					{
						sort = map[p1.x+2][p1.y+2];

						score += 100;							//計分							
						game_time += 1;							//遊戲時間+1

						map[p1.x+2][p1.y+2] = -1;				//將已消去的位置X置-1
						map[row_index+2][col_index+2] = -1;		//將已消去的位置Y置-1				
						fram_sign = false;
						num-=2;									//方塊總數-2
	
						playSound(sound_sort);					//播放消去的聲音

						if (end(num) )							//判斷遊戲是否結束
						{
							g_pGame->setStart(false);
							return;
						}

						sort_num[sort-1]-=1;					//對應種類的方塊數量-1

						//寫入對應種類方塊的位置
						for(m = 0;m < 16;m+=4)				
						{
							//取出相同種類所對應的位置
							pp[m/4].x = sort_place[sort-1][m]*10 + sort_place[sort-1][m+1];
							pp[m/4].y = sort_place[sort-1][m+2]*10 + sort_place[sort-1][m+3];

							//種類相同的話,將其位置置-1
							if( (pp[m/4].x==p1.x) && (pp[m/4].y==p1.y) )
							{
								sort_place[sort-1][m] = -1;
								sort_place[sort-1][m+1] = -1;
								sort_place[sort-1][m+2] = -1;
								sort_place[sort-1][m+3] = -1;
							}
							if( (pp[m/4].x == row_index) && (pp[m/4].y == col_index) )
							{
								sort_place[sort-1][m] = -1;
								sort_place[sort-1][m+1] = -1;
								sort_place[sort-1][m+2] = -1;
								sort_place[sort-1][m+3] = -1;
							}
						}

						p1.x = BLANK_STATE;
						
						clue_sign = false;

						//判斷是否有解
						while( !IsResult() )
						{
							ReInitial();
						}
					}
					else		//不可以連線
					{
						p1.x = row_index;
						p1.y = col_index;

						g_row_index = row_index;
						g_col_index = col_index;
					}
					return;
				}
				else			//第一次和第二次點選的兩個方塊型別不一樣
				{
					p1.x = row_index;
					p1.y = col_index;

					g_row_index = row_index;
					g_col_index = col_index;
					return;
				}
			}
		}
	}
}

這樣寫搞得我也暈了,可能會導致我漏了一些沒寫出來的未定義函式(因為這是我專案完成後寫的部落格,如果是邊寫邊做我可以通過除錯知道那些函式還沒定義),為了方便觀察,下面粘貼出函式與函式之間的呼叫關係. Winmain:在這裡插入圖片描述 wndprc: 在這裡插入圖片描述 貌似還有遊戲相關演算法還沒有介紹,有點累了,對連連看遊戲演算法感興趣的可以下載我上傳的vc++版連連看檔案,我有寫註釋.因為我還要試著用老師給的遊戲引擎再寫一版vs2010的連連看遊戲,下次我會具體介紹遊戲演算法,至於遊戲是怎麼執行的,函式呼叫應該放在哪個地方我就不說了. 附上下載連結:連連看vc++版原始碼