一個俄羅斯方塊遊戲源程式 (轉)

amyz發表於2007-11-10
一個俄羅斯方塊遊戲源程式 (轉)[@more@]

///////////////////[stdafx.cpp]/////////////////////////

// stdafx.cpp : file that includes just the standard includes
// ToyBricks.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

// TODO: reference any additional headers you need in STDAFX.H
// and not in this fil

檔案二

//////////////////////////////////////[stdafx.h]//////////////////////////////////////////

// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//  are changed infrequently
//

#if !defined(AFX_STDAFX_H__A983DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define _LEAN_AND_MEAN // Exclude rarely-used stuff from headers

#include


// TODO: reference additional headers your program requires here

//{{AFX_INSERT_LOCATION}}
// Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)

檔案三

/////////////////////////////////[game.cpp]////////////////////////////////////////////////////

// ToyBricks.cpp : Defines the entry point for the application.
//

#include "StdAfx.h"

 

/*******************************************************/

#include   //windows.h檔案中包含應用中所需的資料型別和資料結構的定義
#include   //包含SetTimer()、KillTimer()等關於定時器的
#include

#define CELL 15  // 【方格】的邊長(pix) 
#define W 20  // 遊戲區寬(12個【方格】邊長,8個格子用來繪製"下一個"方塊)
#define H 26  // 遊戲區高(26個【方格】邊長)
#define MS_NEWBLOCK WM_USER+1  // 訊息ID,產生新的【方塊】
#define MS_DRAW WM_USER+2  // 訊息ID,用來畫【方塊】
#define MS_NEXTBLOCK WM_USER+3 //訊息ID,用來顯示下一個【俄羅斯方塊】形狀


//------------------------視窗函式的說明------------------------
LRESULT CALLBACK WndProc ( HWND, UINT, WPARAM, LPARAM);

//---------------------------------------------------------------
int WIN WinMain ( HINSTANCE hInstance, 
  HINSTANCE hPrevInstance,
  PSTR szCmdLine,
  int iCmdShow)

{
 static char AppName[]="ToyBrick";  //視窗類名
 HWND hwnd; 
 MSG msg; //訊息結構
 WNDCLASSEX wndclass; //視窗類
 int iScreenW;  //定義一個整型變數來取得視窗的寬度 

 wndclass.cbSize = sizeof(wndclass);
 wndclass.style = CS_HREDRAW|CS_VREDRAW;//視窗型別
 
  //CS_HREDRAW :Redraws the entire window if a movement or size
  //  adjustment changes the width of the client area.
  //CS_VREDRAW :Redraws the entire window if a movement or size
  //  adjustment changes the height of the client area. 
 
 wndclass.lpfnWndProc = WndProc; //視窗處理函式為 WndProc
 wndclass.cbClsExtra = 0; //視窗類無擴充套件
 wndclass.cbWndExtra = 0; //視窗例項無擴充套件 
 wndclass.hInstance = hInstance;  //當前例項控制程式碼
 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);  //預設圖示
 wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);  //箭頭游標
 wndclass.hbrBackground = (HBRUSH)GetStock (WHITE_BRUSH); //背景為黑色
 wndclass.lpszMenuName = NULL; //視窗中無選單
 wndclass.lpszClassName = AppName;  //類名為"ToyBrick"
 wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION); 

//----------------------------------視窗類的註冊-----------------------------------------

 if(!RegisterClassEx (&wndclass))  //如果註冊失敗則發出警報,返回FALSE
 {
 MessageBeep(0); 
 return FALSE;
 }

 // 獲取顯示器解析度的X值iScreenWide,將程式視窗置於螢幕中央
 iScreenWide=GetSystemMetrics (SM_CXFULLSCREEN);

 hwnd =CreateWindow (
  AppName,  //視窗類名
  "俄羅斯方塊模擬專案(學院.錢彥江)", //視窗例項的標題名
 WS_MINIMIZEBOX|WS_SYSMENU , //視窗的風格
 iScreenWide/2-W*CELL/2,  //視窗左上角橫座標(X)
 CELL,  //視窗左上角縱座標(Y)
 W*CELL,   //視窗的寬
 H*CELL,  //視窗的高
 NULL,  //視窗無父視窗 
 NULL, //視窗無主選單
 hInstance, //建立此視窗的應用程式的當前控制程式碼
 NULL  //不使用該值
  );
 if(!hwnd) return FALSE;
  //顯示視窗
 ShowWindow (hwnd,iCmdShow);
 //繪製區
 UpdateWindow (hwnd);
 MessageBox(hwnd,"  開始遊戲nn_軟體學院模擬專案","開始",MB_OK);
 SendMessage(hwnd,MS_NEWBLOCK,0,0);
  SetTimer (hwnd, 1, 500,NULL);
 
 //訊息迴圈
 while (GetMessage (&msg, NULL, 0, 0))
 {
 TranslateMessage (&msg);
 DispatchMessage (&msg);
 }
  //訊息迴圈結束即程式終止時將訊息返回
 return msg.wParam; 
}

 

// 函式DrawRact: 畫【正方形】----- (□)
// 引數: 裝置環境控制程式碼和【正方形】的四角座標
void DrawRect (HDC hdc, int l, int t, int r, int b)
{
 MoveToEx (hdc, l, t, NULL);  //將游標移動到(l,t)
 Lo (hdc, r, t); 
 LineTo (hdc, r, b);
 LineTo (hdc, l, b);
 LineTo (hdc, l,t);
}

 


// 函式DrawCell: 畫【方格】-----(紅色■)
// 引數: 裝置環境控制程式碼和【方格】的四角座標
void DrawCell (HDC hdc, int l, int t, int r, int b)

 HBRUSH hbrush; 

 hbrush=CreateSolidBrush(RGB(255,0,0));  // 紅色畫刷
  Object(hdc,hbrush); 
   Rectangle(hdc,l, t, r, b);
  DeleteObject (hbrush);


}

//繪出遊戲區域的方格,其中包括"遊戲空間"和"顯示下一個【方塊】空間"
//此函式包含在Cover函式中。引數:裝置環境控制程式碼
void DrawGamePlace(HDC hdc)
{
 int i,j;
 HPEN hpen1,hpen2;
 hpen1=CreatePen(PS_SOLID,1,RGB(0,255,0));
 hpen2=CreatePen(PS_DASHDOTDOT,3,RGB(0,0,255));

  //繪製分割線
 SelectObject(hdc,hpen2);
 MoveToEx(hdc,(W-8)*CELL,0,NULL);
 LineTo(hdc,(W-8)*CELL,H*CELL);
 
  //繪製遊戲區域方格線(綠色)
 SelectObject(hdc,hpen1);
 for (i=1; i for(j=1; j<=W-8; j++)
 DrawRect (hdc, (j-1)*CELL, (i-1)*CELL, j*CELL, i*CELL);

 //繪製"顯示下一個"區域的方格線
 for(i=5;i<9;i++)  // 5≤i≤8
 for(j=W-5;j DrawRect (hdc, (j-1)*CELL, (i-1)*CELL, j*CELL, i*CELL);
 
  DeleteObject(hpen2);
  DeleteObject(hpen1);
 
}

// 函式DrawBlock: 畫遊戲中出現的【俄羅斯方塊】
// 引數: 裝置環境控制程式碼和【俄羅斯方塊】中四個【方格】在遊戲區域中的位置
// 每個【俄羅斯方塊】由四個【方格】組成7種不同的形狀
void DrawBlock (HDC hdc, int block[4][2])
{
 int i;
 for(i=0; i<4; i++)
 DrawCell (hdc, (block[i][0]-1)*CELL, (block[i][1]-1)*CELL, //....
  block[i][0]*CELL, block[i][1]*CELL);

}

// 函式Cover: 清除原來位置的【俄羅斯方塊】
// 引數: 裝置環境控制程式碼和待清除的【俄羅斯方塊】
//作用(1) 清除【俄羅斯方塊】即在該【俄羅斯方塊】的每個【方格】處畫一個正方形的白塊
//  (2) 重新繪製遊戲區域的方格

void Cover (HDC hdc, int org[4][2])
{
 int i;
 HBRUSH hbrush;
  //重新繪製遊戲區域
 DrawGamePlace(hdc);

 hbrush=(HBRUSH)GetStockObject (WHITE_BRUSH);
  SelectObject (hdc,hbrush );
 for(i=0; i<4; i++)
 Rectangle ( hdc, (org[i][0]-1)*CELL, (org[i][1]-1)*CELL, //.....
 org[i][0]*CELL, org[i][1]*CELL); 
 DeleteObject(hbrush);

}

//-------------------視窗過程函式WndProc-----------------------------

LRESULT CALLBACK WndProc ( HWND hwnd,
  UINT iMsg,
  WPARAM wParam,
  LPARAM lParam )
{
 int i,j,k,lines,r;
 static int top, sel, flag;
 static int cells[W-6][H];  // 控制遊戲區域的【方格矩陣】
 static int org[4][2], block[4][2],org2[4][2];  // 【方塊】
 HDC hdc;
 HPEN hpen;
 PAINTSTRUCT ps;

 switch (iMsg)
 {
 case WM_CREATE:
 //當一個應用程式使用函式CreateWindow或CreateWindowEx來建立一個視窗時,
 //系統將傳送該訊息給此新建視窗過程。該訊息將在建立視窗之後,顯示視窗
 //之前傳送該訊息,該訊息將在CreateWindow或CreateWindowEx函式返回之前傳送。
 
 top=H-1;
 // 將第一列和最後一列【方格】置1,控制【方塊】不超出遊戲區域
 for(i=0; i {
 cells[0][i]=1;
 cells[W-7][i]=1;
 }

 // 將最底下一行【方格】置1,控制【方塊】不超出遊戲區域
 for(i=0; i cells[i][H-1]=1;

 // 其他【方格】置0,遊戲方塊只能在這裡移動
 for(i=1; i<=W-8; i++)
 for(j=0; j cells[i][j]=0;
 
 
 return 0;

 case MS_NEWBLOCK:
 
 flag=0;  // flag表示【方塊】旋轉了幾次

 for(i=top; i {
 lines =0;

 // 迴圈語句檢查是否有某一行全部被【方格】都填滿
 for(j=1; j<=W-7; j++)
 if(! cells[j][i])
 {
 lines=1;
 break;
 }

 // 若該行被填滿,則將上一行的填充狀態複製到該行,依此類推
 // 即從該行開始,所有的【方格】都下移一行
 if(!lines)
 { for(j=1;j for(k=i; k>=top; k--)
 cells[j][k]=cells[j][k-1];
 top++;

  //該函式把指定視窗使用者區域內的矩形加入到該視窗的區域之外
  //使該矩形無效。這個無效的矩形,連同更新區域中的其他區域,在收到下
  //一條WM_PAINT訊息時將被重畫。無效區一直積累在更新區域之中,直到
 //下一條WM_PAINT訊息發生時對該區域進行處理。
 InvalidateRect(hwnd, NULL, TRUE);
 }
 }

 // 產生隨機數0~7,分別代表【方塊】的7種形狀
 srand( (unsigned)time( NULL ) );
 sel =rand()%7;

 //【方塊】形狀初始化
 //【方塊】的形狀由其每個【方格】的位置決定
 // 遊戲區寬W=20,block[?][0]=4/5/6/7,block[?][1]=0/1/2
 // 這樣【方塊】初始位置在遊戲區域的最頂部的中央
 switch(sel)
 {
 case 0:
 // ▓▓
 // ▓▓
 org[0][0]=block[0][0] =5; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =6; org[1][1]=block[1][1] =0;
 org[2][0]=block[2][0] =5; org[2][1]=block[2][1] =1;
 org[3][0]=block[3][0] =6; org[3][1]=block[3][1] =1;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

 break;

 case 1:
 //▓▓▓▓
 org[0][0]=block[0][0] =4; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =5; org[1][1]=block[1][1] =0;
 org[2][0]=block[2][0] =6; org[2][1]=block[2][1] =0;
 org[3][0]=block[3][0] =7; org[3][1]=block[3][1] =0;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

 break;


 case 2:
 //▓
 //▓▓
 //  ▓
 org[0][0]=block[0][0] =5; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =5; org[1][1]=block[1][1] =1;
 org[2][0]=block[2][0] =6; org[2][1]=block[2][1] =1;
 org[3][0]=block[3][0] =6; org[3][1]=block[3][1] =2;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

 break;

 case 3:
 //  ▓
 //▓▓
 //▓
 org[0][0]=block[0][0] =6; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =6; org[1][1]=block[1][1] =1;
 org[2][0]=block[2][0] =5; org[2][1]=block[2][1] =1;
 org[3][0]=block[3][0] =5; org[3][1]=block[3][1] =2;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

 break;
 
 case 4:
 //▓
 //▓
 //▓▓
 org[0][0]=block[0][0] =5; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =5; org[1][1]=block[1][1] =1;
 org[2][0]=block[2][0] =5; org[2][1]=block[2][1] =2;
 org[3][0]=block[3][0] =6; org[3][1]=block[3][1] =2;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

 break;

 case 5:
 //  ▓
 //  ▓
 //▓▓
 org[0][0]=block[0][0] =5; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =5; org[1][1]=block[1][1] =1;
 org[2][0]=block[2][0] =5; org[2][1]=block[2][1] =2;
 org[3][0]=block[3][0] =4; org[3][1]=block[3][1] =2;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

 break;
 case 6:
 //  ▓
 //▓▓▓
 org[0][0]=block[0][0] =5; org[0][1]=block[0][1] =0;
 org[1][0]=block[1][0] =4; org[1][1]=block[1][1] =1;
 org[2][0]=block[2][0] =5; org[2][1]=block[2][1] =1;
 org[3][0]=block[3][0] =6; org[3][1]=block[3][1] =1;
 for(i=0;i<4;i++)
 {
   org2[i][0]=org[i][0]+11;
  org2[i][1]=org[i][1]+5;
 }

   SendMessage (hwnd, MS_NEXTBLOCK, 0, 0);
 break;

 default:
 
 SendMessage (hwnd, MS_NEWBLOCK, 0, 0);
 SendMessage (hwnd, MS_NEXTBLOCK, 0, 0);
 break;
 }

 return 0;

 case WM_TIMER:
 
 // 每個時間節拍【方塊】自動下移一行
 for(i=0; i<4; i++)
 block[i][1]++;

 // 檢查【方塊】下移是否被檔住,即判斷下移後新位置是否有【方格】
 for(i=0; i<4; i++)
 if(cells[ block[i][0] ][ block[i][1] ])
 {
 SendMessage (hwnd, MS_NEXTBLOCK, 0, 0);

 for(i=0; i<4; i++)
 cells[ org[i][0] ][ org[i][1] ]=1;

 if(top>org[0][1]-2)
 top=org[0][1]-2;

 if (top<1)
 {
 KillTimer (hwnd, 1);
 MessageBox (hwnd, "遊戲結束,即將退出 !n四川大學軟體學院", "退出", MB_OK);
 PostQuitMessage (0);
 }
 
 SendMessage (hwnd, MS_NEWBLOCK, 0, 0);
 return 0;
 }

 SendMessage (hwnd, MS_DRAW, 0, 0);

 return 0;

 // 響應鍵盤控制
 case WM_KEYDOWN:
 r=0;
 switch((int)wParam)
 {
 case VK_LEFT:
 for(i=0; i<4; i++)
 block[i][0]--;
 break;

 case VK_RIGHT:
 for(i=0; i<4; i++)
 block[i][0]++;
 break;
 case VK_DOWN:
 for(i=0; i<4; i++)
 block[i][1]++;
 break;

 // 按[向上鍵],【方塊】順時針旋轉
 //【方塊】的旋轉不是真正的旋轉,而是根據不同的【方塊】形狀和該【方塊】旋轉過的
 // 次數來移動其中的一個或幾個【方格】,從而達到旋轉的效果 。這樣做很複雜,演算法
 // 不夠理想,但是能夠保持【方塊】旋轉時的重心比較穩定。
 
 case VK_UP:
 r=1;
 flag++;  //【方塊】旋轉加1

 switch(sel)  // sel代表當前【方塊】的形狀
 {
 case 0: break;

 case 1:
 flag =flag%2;
 for(i=0; i<4; i++)
 {
 block[i][(flag+1)%2] =org[2][(flag+1)%2];
 block[i][flag] =org[2][flag]-2+i;
 }
 break;

 case 2:
 flag =flag%2;
 if(flag)
 { block[0][1] +=2; block[3][0] -=2; }
 else
 { block[0][1] -=2; block[3][0] +=2; }
 break;

 case 3:
 flag =flag%2;
 if(flag)
 { block[0][1] +=2; block[3][0] +=2; }
 else
 { block[0][1] -=2; block[3][0] -=2; }
 break;

 case 4:
 flag=flag%4;
 switch(flag)
 {
 case 0:
 block[2][0] +=2; block[3][0] +=2;
 block[2][1] +=1; block[3][1] +=1;
 break;
 case 1:
 block[2][0] +=1; block[3][0] +=1;
 block[2][1] -=2; block[3][1] -=2;
 break;
 case 2:
 block[2][0] -=2; block[3][0] -=2;
 block[2][1] -=1; block[3][1] -=1;
 break;
 case 3:
 block[2][0] -=1; block[3][0] -=1;
 block[2][1] +=2; block[3][1] +=2;
 break;
 }
 break;

 case 5:
 flag=flag%4;
 switch(flag)
 {
 case 0:
 block[2][0] +=1; block[3][0] +=1;
 block[2][1] +=2; block[3][1] +=2;
 break;
 case 1:
 block[2][0] +=2; block[3][0] +=2;
 block[2][1] -=1; block[3][1] -=1;
 break;
 case 2:
 block[2][0] -=1; block[3][0] -=1;
 block[2][1] -=2; block[3][1] -=2;
 break;
 case 3:
 block[2][0] -=2; block[3][0] -=2;
 block[2][1] +=1; block[3][1] +=1;
 break;
 }
 break;

 case 6:
 flag =flag%4;
 switch(flag)
 {
 case 0:
 block[0][0]++; block[0][1]--;
 block[1][0]--; block[1][1]--;
 block[3][0]++; block[3][1]++;
 break;
 case 1:
 block[1][0]++; block[1][1]++; break;
 case 2:
 block[0][0]--; block[0][1]++; break;
 case 3:
 block[3][0]--; block[3][1]--; break;
 }
 break;
 }
 break;
 }

 // 判斷【方塊】旋轉後新位置是否有【方格】,若有,則旋轉取消
 for(i=0; i<4; i++)
 if(cells[ block[i][0] ][ block[i][1] ])
 {
 if(r) flag +=3;
 for(i=0; i<4; i++)
 for(j=0; j<2; j++)
 block[i][j]=org[i][j];
 return 0;
 }
 SendMessage(hwnd, MS_DRAW, 0, 0);;
 return 0;

  // 清楚當前【方塊】,並在顯示“下一個方塊”處繪製下一個【方塊】
 case MS_NEXTBLOCK:

  hdc=GetDC(hwnd); 
 Cover(hdc,org2);
// DrawBlock(hdc,org2);


 return 0;

 // 清除當前【方塊】,並在新的位置重新繪製【方塊】
 case MS_DRAW:
 
 hdc =GetDC (hwnd);
 Cover (hdc, org);

 DrawBlock(hdc,org2);

 for(i=0; i<4; i++)
 for(j=0; j<2; j++)
 org[i][j]=block[i][j];

 DrawBlock (hdc,block);
 ReleaseDC (hwnd, hdc);
 
 return 0;

 // 按照【方格矩陣】重繪遊戲區域的【方格】
 case WM_PAINT:
 
 hdc =BeginPaint (hwnd, &ps);
 DrawGamePlace(hdc);
 TextOut(hdc,15*CELL,12*CELL,"re",lstrlen("Score"));
 TextOut(hdc,15*CELL,13*CELL,"i",lstrlen("i"));
 TextOut(hdc,15*CELL,15*CELL,"Level",lstrlen("Level"));
 TextOut(hdc,15*CELL-5,19*CELL,"錢彥江",lstrlen("錢彥江"));
 hpen =CreatePen (PS_SOLID,1,RGB(0,255,0));
 SelectObject (hdc,hpen);
 for (i=top; i for(j=1; j<=W-8; j++)
 if( cells[j][i] )
 DrawCell (hdc, (j-1)*CELL, (i-1)*CELL, j*CELL, i*CELL);
 
 DeleteObject (hpen);
 EndPaint (hwnd, &ps);
 return 0;

 case WM_DESTROY:
 KillTimer (hwnd, 1);
 PostQuitMessage (0);
 return 0;
 }

 return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

 /*************************-----結------束------*******************************/

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-981631/,如需轉載,請註明出處,否則將追究法律責任。

相關文章