C++制作俄罗斯方块_C 语言

缘起:

  在玩Codeblocks自带的俄罗斯方块时觉得不错,然而有时间限制。所以想自己再写一个。

程序效果:

主要内容:

  程序中有一个board数组,其中有要显示的部分,也有不显示的部分,不显示的部分都存储1。

  如下图:

  shape采用4*4数组(shape)保存。如:

    0 0 0 0
    0 1 0 0
    1 1 1 0
    0 0 0 0

  另外用变量row和column保存shape数组左上角在board中的位置。

  每次下落或左右移动,先对row和column做出改变,然后检测当前row和column下,shape是否重合了为1的格子,如果有重合,就说明shape出界了或者到达下落最低点,则要恢复row和column值。另外,如果是下落,还要将shape放在board上,并产生新的shape。

  旋转时,先对shape数组进行旋转操作,然后检测重合,如果有重合,则反向旋转回来。

代码:

#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif

#include <tchar.h>
#include <windows.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
/*-----------------宏定义--------------------------------------------------------*/
#define WIDTH 180
#define HEIGHT 400
#define LONG_SLEEP 300
#define BKCOLOR RGB(238,238,238)//背景色
/*-----------------变量----------------------------------------------------------*/
static int shapes[7][4][4];//存储7个形状
static int high_score[4]= {0,0,0,0};//前三个元素存储最高分,最后一个元素存储此次得分
static int **shape;//当前形状
static int **board;
static int M=15;//显示的列数
static int N=30;//显示的行数
static int MM=M+8;//board的列数
static int NN=N+4;//board的行数
static int LEFT=4;//显示的最左一列
static int RIGHT=LEFT+M-1;//显示的最右一列
static int TOP=0;//显示的最上一列
static int BOTTOM=N-1;//显示的最下一列
static int score=0;
static int row=0;//形状所在行
static int column=MM/2;//形状坐在列
static bool is_pause=false;
static HBRUSH grey_brush =CreateSolidBrush (RGB(210,210,210));
static HBRUSH white_brush =CreateSolidBrush (RGB(130,130,130));
static HBRUSH bk_brush =CreateSolidBrush (BKCOLOR);
static HPEN hPen = CreatePen(PS_SOLID,1,RGB(147,155,166));
static int lattices_top=40;//上面留白
static int lattices_left=20;//左侧留白
static int width=WIDTH/M;//每个格子的宽度
static int height=(HEIGHT-lattices_top)/N;//每个格子的高度
/*-----------------函数-----------------------------------------------------------*/
void add_score() ;
bool check_is_lose() ;
void clear_up() ;//消除没有空格子的行
void* down_thread_function(void * args) ;//形状下落进程要执行的函数
void exit_game(HWND hwnd) ;
void give_new_shape() ;//随机生成一个新形状
int handle_key(HWND hwnd,WPARAM wParam) ;
int init_down_thread(HWND hwnd) ;//初始化形状下落进程
int init_game(HWND hwnd) ;//初始化游戏程序
void init_play() ;//初始化游戏数据
bool is_legel() ;//检测形状在当前位置是否合法(即是否重合了非空的格子)
int load_scores(int* a) ;//读取游戏最高分数据
int load_shape() ;//从文件中加载7个形状
void lose_game(HWND hwnd) ;
int move_down(HWND hwnd) ;//形状下落
int move_lr(HWND hwnd,int lr) ;//形状左右移动
void paint_lattice(HDC hdc,int x,int y,int color) ;//显示一个格子
void paint_UI(HDC hdc) ;//画界面
void reset_rc() ;
void rerotate_matrix(int mn) ;//顺时针旋转一个行列数为mn的方阵
void rotate_matrix(int mn) ;//逆时针旋转一个行列数为mn的方阵
int rotate_shape(HWND hwnd) ;//旋转当前形状并更新界面
bool save_score(HWND hwnd) ;//保存最高分数据
void shape_to_ground() ;//当前形状落地之后,更新board
bool sort_scores(int* a) ;//对最高分和此次得分排序,若创造新纪录则返回true
void update_UI(HWND hwnd) ;//更新界面,仅更新Rect区域(形状所在的那几行)内
void update_UI_all(HWND hwnd) ;//更新界面,更新整个界面
int write_scores(int* a) ;//写最高分数据

/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("Tris");

int WINAPI WinMain (HINSTANCE hThisInstance,
          HINSTANCE hPrevInstance,
          LPSTR lpszArgument,
          int nCmdShow) {
  HWND hwnd;        /* This is the handle for our window */
  MSG messages;      /* Here messages to the application are saved */
  WNDCLASSEX wincl;    /* Data structure for the windowclass */

  /* The Window structure */
  wincl.hInstance = hThisInstance;
  wincl.lpszClassName = szClassName;
  wincl.lpfnWndProc = WindowProcedure;   /* This function is called by windows */
  wincl.style = CS_DBLCLKS;         /* Catch double-clicks */
  wincl.cbSize = sizeof (WNDCLASSEX);

  /* Use default icon and mouse-pointer */
  wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
  wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
  wincl.lpszMenuName = NULL;         /* No menu */
  wincl.cbClsExtra = 0;           /* No extra bytes after the window class */
  wincl.cbWndExtra = 0;           /* structure or the window instance */
  /* Use Windows's default colour as the background of the window */
  wincl.hbrBackground =bk_brush;
  /* Register the window class, and if it fails quit the program */
  if (!RegisterClassEx (&wincl))
    return 0;

  /* The class is registered, let's create the program*/
  hwnd = CreateWindowEx (
        0,          /* Extended possibilites for variation */
        szClassName,     /* Classname */
        _T("Tris"),    /* Title Text */
        WS_OVERLAPPEDWINDOW, /* default window */
        CW_USEDEFAULT,    /* Windows decides the position */
        CW_USEDEFAULT,    /* where the window ends up on the screen */
        WIDTH+200,         /* The programs width */
        HEIGHT+70,         /* and height in pixels */
        HWND_DESKTOP,    /* The window is a child-window to desktop */
        NULL,        /* No menu */
        hThisInstance,    /* Program Instance handler */
        NULL         /* No Window Creation data */
      );

  /* Make the window visible on the screen */
  ShowWindow (hwnd, nCmdShow);

  /* Run the message loop. It will run until GetMessage() returns 0 */
  while (GetMessage (&messages, NULL, 0, 0)) {
    /* Translate virtual-key messages into character messages */
    TranslateMessage(&messages);
    /* Send message to WindowProcedure */
    DispatchMessage(&messages);
  }

  /* The program return-value is 0 - The value that PostQuitMessage() gave */
  return messages.wParam;
}
//从文件中加载7个形状
int load_shape() {
  FILE* f=fopen("shapes.txt","rb");
  if(f==NULL) {
    return -1;
  }
  for(int i=0; i<7; i++) {
    for(int j=0; j<4; j++) {
      for(int k=0; k<4; k++) {
        if(fscanf(f,"%d",&shapes[i][j][k])!=1) {
          return -1;
        }
      }
    }
  }
  fclose(f);
  return 0;
}
//随机生成一个新形状
void give_new_shape() {
  int shape_num=rand()%7;
  for(int i=0; i<4; i++) {
    for(int j=0; j<4; j++) {
      shape[i][j]=shapes[shape_num][i][j];
    }
  }
}
void add_score() {
  score+=100;
}
//消除没有空格子的行
void clear_up() {
  for(int i=row; i<=row+3; i++) {
    if(i>BOTTOM)continue;
    bool there_is_blank=false;
    for(int j=LEFT; j<=RIGHT; j++) {
      if(board[i][j]==0) {
        there_is_blank=true;
        break;
      }
    }
    if(!there_is_blank) {
      add_score();
      for(int r=i; r>=1; r--) {
        for(int c=LEFT; c<=RIGHT; c++) {
          board[r][c]=board[r-1][c];
        }
      }
    }
  }
}
//检测形状在当前位置是否合法(即是否重合了非空的格子)
bool is_legel() {
  for(int i=0; i<4; i++) {
    for(int j=0; j<4; j++) {
      if(shape[i][j]==1&&board[row+i][column+j]==1) {
        return false;
      }
    }
  }
  return true;
}
//逆时针旋转一个行列数为mn的方阵
void rotate_matrix(int mn) {
  int** a=shape;
  int s=0;
  for(int n=mn; n>=1; n-=2) {
    for(int i=0; i<n-1; i++) {
      int t=a[s+i][s];
      a[s+i][s]=a[s][s+n-i-1];
      a[s][s+n-i-1]=a[s+n-i-1][s+n-1];
      a[s+n-i-1][s+n-1]=a[s+n-1][s+i];
      a[s+n-1][s+i]=t;
    }
    s++;
  }
}
//顺时针旋转一个行列数为mn的方阵
void rerotate_matrix(int mn) {
  int** a=shape;
  int s=0;
  for(int n=mn; n>=1; n-=2) {
    for(int i=0; i<n-1; i++) {
      int t=a[s+i][s];
      a[s+i][s]=a[s+n-1][s+i];
      a[s+n-1][s+i]=a[s+n-i-1][s+n-1];
      a[s+n-i-1][s+n-1]=a[s][s+n-i-1];
      a[s][s+n-i-1]=t;
    }
    s++;
  }
}
//显示一个格子
void paint_lattice(HDC hdc,int x,int y,int color) {
  if(x<TOP||x>BOTTOM||y<LEFT||y>RIGHT) {
    return ;
  }
  x-=TOP;
  y-=LEFT;
  int left=lattices_left+y*width;
  int right=lattices_left+y*width+width;
  int top=lattices_top+x*height;
  int bottom=lattices_top+x*height+height;
  MoveToEx (hdc,left,top, NULL) ;
  LineTo (hdc,right,top) ;
  MoveToEx (hdc,left,top, NULL) ;
  LineTo (hdc,left,bottom) ;
  MoveToEx (hdc,left,bottom, NULL) ;
  LineTo (hdc,right,bottom) ;
  MoveToEx (hdc,right,top, NULL) ;
  LineTo (hdc,right,bottom) ;
  SelectObject(hdc, grey_brush);
  if(color==0) {
    SelectObject(hdc, white_brush);
  }
  Rectangle(hdc,left,top,right,bottom);
}
//更新界面,仅更新Rect区域(形状所在的那几行)内
void update_UI(HWND hwnd) {
  static RECT rect;
  rect.left=lattices_left;
  rect.right=lattices_left+M*width+width;
  rect.top=lattices_top+(row-1)*height;
  rect.bottom=lattices_top+(row+4)*height;
  InvalidateRect (hwnd,&rect, false) ;
}
//更新界面,更新整个界面
void update_UI_all(HWND hwnd) {
  InvalidateRect (hwnd,NULL, false) ;
}
//画界面
void paint_UI(HDC hdc) {
  SetBkColor(hdc,BKCOLOR);
  SelectObject(hdc,hPen); //选用画笔
  char score_str[20];
  sprintf(score_str,"Score:%d",score);
  TextOut(hdc,10,10,score_str,strlen(score_str));
  sprintf(score_str,"Highest Scores:");
  TextOut(hdc,WIDTH+50,50,score_str,strlen(score_str));
  for(int i=0; i<3; i++) {
    sprintf(score_str,"%d",high_score[i]);
    TextOut(hdc,WIDTH+50,50+(i+1)*20,score_str,strlen(score_str));
  }
  for(int i=TOP; i<=BOTTOM; i++) {
    for(int j=LEFT; j<=RIGHT; j++) {
      paint_lattice(hdc,i,j,board[i][j]);
    }
  }
  for(int i=0; i<4; i++) {
    for(int j=0; j<4; j++) {
      if(shape[i][j]==1)
        paint_lattice(hdc,row+i,column+j,shape[i][j]);
    }
  }
}
//旋转当前形状并更新界面
int rotate_shape(HWND hwnd) {
  int mn=4;
  rotate_matrix(mn);
  if(!is_legel()) {
    rerotate_matrix(mn);
  }
  update_UI(hwnd);
}
void reset_rc() {
  row=0;
  column=MM/2-2;
}
//读取游戏最高分数据
int load_scores(int* a) {
  FILE* f=fopen("scores.txt","r");
  if(f==NULL)return -1;
  fscanf(f,"%d%d%d",&a[0],&a[1],&a[2]);
  return 0;
}
//初始化游戏数据
void init_play() {
  load_scores(high_score);
  for(int i=0; i<NN; i++) {
    for(int j=0; j<MM; j++) {
      board[i][j]=0;
    }
  }
  for(int i=0; i<N; i++) {
    for(int j=0; j<LEFT; j++) {
      board[i][j]=1;
    }
  }
  for(int i=0; i<N; i++) {
    for(int j=RIGHT+1; j<MM; j++) {
      board[i][j]=1;
    }
  }
  for(int i=BOTTOM+1; i<NN; i++) {
    for(int j=0; j<MM; j++) {
      board[i][j]=1;
    }
  }
  reset_rc();
  score=0;
  give_new_shape();
  is_pause=false;
  return ;
}
bool check_is_lose() {
  if(row==0)return true;
  return false;
}
//对最高分和此次得分排序,若创造新纪录则返回true
bool sort_scores(int* a) {
  int temp=a[3];
  for(int i=0; i<4; i++) {
    for(int j=0; j<3; j++) {
      if(a[j]<a[j+1]) {
        int t=a[j];
        a[j]=a[j+1];
        a[j+1]=t;
      }
    }
  }
  if(temp>a[3])return true;
  return false;
}
//写最高分数据
int write_scores(int* a) {
  FILE* f=fopen("scores.txt","w");
  if(f==NULL)return -1;
  fprintf(f,"%d\n%d\n%d\n",a[0],a[1],a[2]);
  return 0;
}
//保存最高分数据
bool save_score(HWND hwnd) {
  high_score[3]=score;
  bool made_record=sort_scores(high_score);
  if(write_scores(high_score)!=0) {
    MessageBox(hwnd,"Write file error.Program will exit.","Error",NULL);
    DestroyWindow(hwnd);
  }
  return made_record;
}
void lose_game(HWND hwnd) {
  if(is_pause)return ;
  is_pause=true;
  char message[200]="You lose the Game.\n";
  char title[50]="Game Over";
  if(save_score(hwnd)) {
    strcat(message,"You have made a new record.\n");
    char score_str[100];
    sprintf(score_str,"The Highest Scores:\n%d\n%d\n%d\n",high_score[0],high_score[1],high_score[2]);
    strcat(message,score_str);
  }
  strcat(message,"\nPlay again?\n");
  if(MessageBox(hwnd,message,title,MB_YESNO)==IDYES) {
    init_play();
    update_UI_all(hwnd);
  } else {
    exit(0);
  }
}
void exit_game(HWND hwnd) {
  is_pause=true;
  char message[200]="";
  char title[50]="Exit";
  if(save_score(hwnd)) {
    strcat(message,"You have made a new record.\n");
    char score_str[100];
    sprintf(score_str,"The Highest Scores:\n%d\n%d\n%d\n",high_score[0],high_score[1],high_score[2]);
    strcat(message,score_str);
    MessageBox(hwnd,message,title,NULL);
  }
  exit(0);
}
//当前形状落地之后,更新board
void shape_to_ground() {
  for(int i=0; i<4; i++) {
    for(int j=0; j<4; j++) {
      board[row+i][column+j]=shape[i][j]==1?1:board[row+i][column+j];
    }
  }
}
//形状下落
int move_down(HWND hwnd) {
  row++;
  if(!is_legel()) {
    row--;
    if(check_is_lose()) {
      lose_game(hwnd);
      return 0;
    }
    shape_to_ground();
    clear_up();
    update_UI_all(hwnd);
    reset_rc();
    give_new_shape();
  }
  update_UI(hwnd);
}
//进程参数结构体
struct thread_arg {
  HWND arg_hwnd;
};
//形状下落进程要执行的函数
void* down_thread_function(void * args) {
  thread_arg *arg=(thread_arg*)args;
  HWND dhwnd=arg->arg_hwnd;
  while(true) {
    if(is_pause) {
      Sleep(300);
      continue;
    }
    move_down(dhwnd);
    Sleep(LONG_SLEEP);
  }
}
//初始化形状下落进程
int init_down_thread(HWND hwnd) {
  int ret;
  pthread_t t;
  thread_arg *argp=new thread_arg;
  argp->arg_hwnd=hwnd;
  ret=pthread_create(&t,NULL,down_thread_function,argp);
  delete argp;
  if(ret!=0) {
    return -1;
  }
  return 0;
}
//初始化游戏程序
int init_game(HWND hwnd) {
  board=new int*[NN];
  for(int i=0; i<NN; i++) {
    board[i]=new int[MM];
  }
  shape=new int*[4];
  for(int i=0; i<4; i++) {
    shape[i]=new int[4];
  }
  srand(time(0));
  if(load_shape()!=0) {
    MessageBox(hwnd,"Read file error.Program will exit.","Error",NULL);
    exit(-1);
  }
  init_play();
  update_UI_all(hwnd);
  if(init_down_thread(hwnd)!=0) {
    MessageBox(hwnd,"Thread error.Program will exit.","Error",NULL);
    exit(-1);
  }
  return 0;
}
//形状左右移动
int move_lr(HWND hwnd,int lr) {
  int temp=column;
  if(lr==0)column--;
  else {
    column++;
  }
  if(!is_legel()) {
    column=temp;
  }
  update_UI(hwnd);
}
int handle_key(HWND hwnd,WPARAM wParam) {
  if(wParam==VK_ESCAPE) {//ESC退出
    exit_game(hwnd);
  }
  if(wParam==VK_SPACE) {//空格暂停
    is_pause=!is_pause;
  }
  if(is_pause==true) {
    Sleep(300);
    return 0;
  }
  if(wParam==VK_UP) {
    rotate_shape(hwnd);
  }
  if(wParam==VK_DOWN) {
    move_down(hwnd);
  }
  if(wParam==VK_LEFT) {
    move_lr(hwnd,0);
  }
  if(wParam==VK_RIGHT) {
    move_lr(hwnd,1);
  }
  return 0;
}
/* This function is called by the Windows function DispatchMessage() */
HWND hwnd;
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  static HDC hdc;
  static HDC hdcBuffer;
  static HBITMAP hBitMap;
  static PAINTSTRUCT ps ;
  switch (message) {        /* handle the messages */
  case WM_CREATE:
    init_game(hwnd);
    break;
  case WM_KEYDOWN:
    handle_key(hwnd,wParam);
    break;
  case WM_DESTROY:
    exit_game(hwnd);
    PostQuitMessage (0);    /* send a WM_QUIT to the message queue */
    break;
  case WM_PAINT:
    hdc = BeginPaint (hwnd, &ps) ;
    paint_UI(hdc);
    EndPaint (hwnd, &ps) ;
    break;
  default:           /* for messages that we don't deal with */
    return DefWindowProc (hwnd, message, wParam, lParam);
  }
  return 0;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c++
俄罗斯方块
俄罗斯方块c语言代码、c语言俄罗斯方块、c语言俄罗斯方块教程、俄罗斯方块c语言程序、c语言编写俄罗斯方块,以便于您获取更多的相关知识。

时间: 2024-10-25 05:53:52

C++制作俄罗斯方块_C 语言的相关文章

C++俄罗斯方块游戏 无需图形库的俄罗斯方块_C 语言

本文实例为大家分享了C++俄罗斯方块游戏的具体实现代码,供大家参考,具体内容如下. #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<time.h> #include<conio.h> #define MOD 28 #define SIZE_N 19 #define SIZE_M 12 int cur_x,cur_y; int score,mark,next,map

Linux下用C++实现俄罗斯方块_C 语言

本文实例为大家分享了C++实现俄罗斯方块游戏代码,供大家参考,具体内容如下 1.block.c #include <stdio.h> #include <termios.h> #include <unistd.h> #include <stdlib.h> #include <setjmp.h> #include <sys/time.h> #include <string.h> #include "block.h&

Android App仿微信界面切换时Tab图标变色效果的制作方法_C 语言

概述 1.概述学习Android少不了模仿各种app的界面,自从微信6.0问世以后,就觉得微信切换时那个变色的Tab图标屌屌的,今天我就带大家自定义控件,带你变色变得飞起~~ 好了,下面先看下效果图: 清晰度不太好,大家凑合看~~有木有觉得这个颜色弱爆了了的,,,下面我动动手指给你换个颜色: 有没有这个颜色比较妖一点~~~好了~下面开始介绍原理.2.原理介绍通过上面的效果图,大家可能也猜到了,我们的图标并非是两张图片,而是一张图,并且目标颜色是可定制的,谁让现在动不动就谈个性化呢. 那么我们如何

c语言-俄罗斯方块C语言 12列改为10列后出错,新人求助!

问题描述 俄罗斯方块C语言 12列改为10列后出错,新人求助! #include #include #include #include #include #include #ifdef _MSC_VER // M$的编译器要给予特殊照顾 #if _MSC_VER <= 1200 // VC6及以下版本 #error 你是不是还在用VC6?! #else // VC6以上版本 #if _MSC_VER >= 1600 // 据说VC10及以上版本有stdint.h了 #include #else

二维码制作-二维码如何制作需要什么语言

问题描述 二维码如何制作需要什么语言 如何制作这样的二维码扫描结果!扫描后进行安装需要什么语言开发,能详细说明一下吗?CSDN移动问答 解决方案 这个用什么语言开发都行的,最主要的不是开发语言,而是二维码生成的原理.不过真正自己开发二维码生成太难了,网上有很多API接口或者现成的源代码,拿来用就行了,主要看你用在哪个平台,用在Android上就用Java,用在IOS上就用Obj-C...

排列和组合算法的实现方法_C语言经典案例_C 语言

排列和组合算法是考查递归的常见算法,这两种算法能用递归简洁地实现. 本人在经过多次摸索和思考之后,总结如下,以供参考. 程序代码如下: #include <stdio.h> #include <stdlib.h> char array[] = "abcd"; #define N 4 #define M 3 int queue[N] = {0}; int top = 0; int flag[N] = {0}; void perm(int s, int n) { i

C++开发:为什么多线程读写shared_ptr要加锁的详细介绍_C 语言

我在<Linux 多线程服务端编程:使用 muduo C++ 网络库>第 1.9 节"再论 shared_ptr 的线程安全"中写道: (shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化.根据文档(http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#ThreadSafety), shared_ptr 的线程

老生常谈C语言静态函数库的制作和使用_C 语言

C语言的函数库是多组经过验证的常用函数的集合,编写C语言程序时使用库函数,既可以提高程序运行效率,又可以提高编程质量,使用方法如#include 和#include. 根据使用库函数时,函数库加载时机的差异,将函数库分为静态函数库和动态函数库,具体差异是:C语言程序如果使用静态函数库的函数,那么整个函数库的代码都会和C语言程序一起编译成可执行代码,程序的体积会膨胀:如果使用动态函数库的函数,则C语言程序只会和函数库文件名以及函数名一起编译成可执行代码(不编译函数代码),运行时去查找函数库文件和函

老生常谈C语言动态函数库的制作和使用(推荐)_C 语言

>>>>>>老生常谈C语言接静态函数库的制作和使用>>点击进入 2 动态函数库的制作和使用 动态函数库的制作步骤可以用下图来描述,具体包括 (1) 编写函数的.c文件(例如add.c.sub.c.mul.c和div.c) (2) 编写Makefile,然后make,实现函数的编译和归档入库 函数的编译:使用gcc –c add.c -fPIC只编译不链接函数.c文件,分别生成函数的目标文件(例如add.o.sub.o.mul.o和div.o). 函数的归档入