一个俄罗斯方块游戏源程序

类别:VC语言 点击:0 评论:0 推荐:

文件一

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

// stdafx.cpp : source 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__A9DB83DB_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 WIN32_LEAN_AND_MEAN  // Exclude rarely-used stuff from Windows headers

#include <windows.h>


// TODO: reference additional headers your program requires here

//{{AFX_INSERT_LOCATION}}
// Microsoft 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>           //windows.h文件中包含应用程序中所需的数据类型和数据结构的定义
#include <time.h>              //包含SetTimer()、KillTimer()等关于定时器的函数
#include <stdlib.h>

#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 WINAPI WinMain ( HINSTANCE hInstance, 
      HINSTANCE hPrevInstance,
      PSTR  szCmdLine,
      int  iCmdShow)

{
 static char AppName[]="ToyBrick";           //窗口类名
 HWND  hwnd;       
 MSG   msg;       //消息结构
 WNDCLASSEX wndclass;      //窗口类
 int   iScreenWide;                    //定义一个整型变量来取得窗口的宽度  

 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)GetStockObject (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,"      开始游戏\n\n_软件学院模拟项目","开始",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)
 LineTo (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));    // 红色画刷
    SelectObject(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<H-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<W-1;j++)                     // 15≤j≤18
    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<H; i++)
  {
   cells[0][i]=1;
   cells[W-7][i]=1;
  }

  // 将最底下一行【方格】置1,控制【方块】不超出游戏区域
  for(i=0; i<W-6; i++)
   cells[i][H-1]=1;

  // 其他【方格】置0,游戏方块只能在这里移动
  for(i=1; i<=W-8; i++)
   for(j=0; j<H-1; j++)
    cells[i][j]=0;
  
 
  return 0;

 case MS_NEWBLOCK:
 
  flag=0;         // flag表示【方块】旋转了几次

  for(i=top; i<H-1; i++)
  {
   lines =0;

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

   // 若该行被填满,则将上一行的填充状态复制到该行,依此类推
   // 即从该行开始,所有的【方格】都下移一行
   if(!lines)
   { for(j=1;j<W-7; 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,"Score",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<H-1; 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);
}

 /*************************-----结------束------*******************************/

 

本文地址:http://com.8s8s.com/it/it1561.htm