俄罗斯方块(游戏介绍)

栏目:游戏资讯  时间:2022-11-10
手机版

  一、案例说明:

  这是一个俄罗斯方块的游戏,在这里游戏里面我们希望利用多维数组还原童年经典游戏,这个游戏考察了枚举、结构体、绘图函数、分支、循环、函数、数组这些常用的C++知识。这个游戏的玩法是当程序运行的时候,我们按W键可以切换下落方块的姿态,按A键可以左移下落方块,按D键可以右移下落方块,按空格键可以让下落方块快速下落,按ESC键可以结束游戏,在结束游戏的时候会弹出一个对话框再次确认是否真的需要退出游戏。

  

  二、实现步骤:

  这个游戏程序的实现主要分成以下几个步骤。

  切换下落方块的姿态

  2、左移方块

  3、右移方块

  4、让方块快速下落

  

  

  5.退出游戏

  6.游戏源码:

  #include <easyx.h>

  #include <conio.h>

  #include <time.h>

  /////////////////////////////////////////////

  // 定义常量、枚举量、结构体、全局变量

  /////////////////////////////////////////////

  #define WIDTH 10

  #define HEIGHT 22

  #define UNIT 20

  // 定义操作类型

  enum CMD

  {

  CMD_ROTATE,

  CMD_LEFT, CMD_RIGHT, CMD_DOWN,

  CMD_SINK,

  CMD_QUIT

  };

  enum DRAW

  {

  SHOW,

  CLEAR,

  FIX

  };

  struct BLOCK

  {

  WORD dir[4];

  COLORREF color;

  };

  BLOCK g_Blocks[7] = { {0x0F00, 0x4444, 0x0F00, 0x4444, RED}, // I

  {0x0660, 0x0660, 0x0660, 0x0660, BLUE}, // 口

  {0x4460, 0x02E0, 0x0622, 0x0740, MAGENTA}, // L

  {0x2260, 0x0E20, 0x0644, 0x0470, YELLOW}, // 反L

  {0x0C60, 0x2640, 0x0C60, 0x2640, CYAN}, // Z

  {0x0360, 0x4620, 0x0360, 0x4620, GREEN}, // 反Z

  {0x4E00, 0x4C40, 0x0E40, 0x4640, BROWN} }; // T

  struct BLOCKINFO

  {

  byte id;

  char x, y;

  byte dir : 2;

  } g_CurBlock, g_NextBlock;

  BYTE g_World[WIDTH][HEIGHT] = { 0 };

  /////////////////////////////////////////////

  // 函数声明

  /////////////////////////////////////////////

  void Init();

  void Quit();

  void NewGame();

  void GameOver();

  CMD GetCmd();

  void DispatchCmd(CMD _cmd);

  void NewBlock();

  bool CheckBlock(BLOCKINFO _block);

  void DrawUnit(int x, int y, COLORREF c, DRAW _draw);

  void DrawBlock(BLOCKINFO _block, DRAW _draw = SHOW);

  void OnRotate();

  void OnLeft();

  void OnRight();

  void OnDown();

  void OnSink();

  /////////////////////////////////////////////

  // 函数定义

  /////////////////////////////////////////////

  // 主函数

  void main()

  {

  Init();

  CMD c;

  while (true)

  {

  c = GetCmd();

  DispatchCmd(c);

  if (c == CMD_QUIT)

  {

  HWND wnd = GetHWnd();

  if (MessageBox(wnd, _T("您要退出游戏吗?"), _T("提醒"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK)

  Quit();

  }

  }

  void Init()

  {

  initgraph(640, 480);

  srand((unsigned)time(NULL));

  setbkmode(TRANSPARENT);

  settextstyle(14, 0, _T("宋体"));

  outtextxy(20, 330, _T("操作说明"));

  outtextxy(20, 350, _T("上:旋转"));

  outtextxy(20, 370, _T("左:左移"));

  outtextxy(20, 390, _T("右:右移"));

  outtextxy(20, 410, _T("下:下移"));

  outtextxy(20, 430, _T("空格:沉底"));

  outtextxy(20, 450, _T("ESC:退出"));

  setorigin(220, 20);

  rectangle(-1, -1, WIDTH * UNIT, HEIGHT * UNIT);

  rectangle((WIDTH + 1) * UNIT - 1, -1, (WIDTH + 5) * UNIT, 4 * UNIT);

  NewGame();

  }

  void Quit()

  {

  closegraph();

  exit(0);

  }

  void NewGame()

  {

  setfillcolor(BLACK);

  solidrectangle(0, 0, WIDTH * UNIT - 1, HEIGHT * UNIT - 1);

  ZeroMemory(g_World, WIDTH * HEIGHT);

  g_NextBlock.id = rand() % 7;

  g_NextBlock.dir = rand() % 4;

  g_NextBlock.x = WIDTH + 1;

  g_NextBlock.y = HEIGHT - 1;

  NewBlock();

  }

  void GameOver()

  {

  HWND wnd = GetHWnd();

  if (MessageBox(wnd, _T("游戏结束。\n您想重新来一局吗?"), _T("游戏结束"), MB_YESNO | MB_ICONQUESTION) == IDYES)

  NewGame();

  else

  Quit();

  }

  DWORD m_oldtime;

  CMD GetCmd()

  {

  while (true)

  {

  DWORD newtime = GetTickCount();

  if (newtime - m_oldtime >= 500)

  {

  m_oldtime = newtime;

  return CMD_DOWN;

  }

  if (_kbhit())

  {

  switch (_getch())

  {

  case 'w':

  case 'W': return CMD_ROTATE;

  case 'a':

  case 'A': return CMD_LEFT;

  case 'd':

  case 'D': return CMD_RIGHT;

  case 's':

  case 'S': return CMD_DOWN;

  case 27: return CMD_QUIT;

  case ' ': return CMD_SINK;

  case 0:

  case 0xE0:

  switch (_getch())

  {

  case 72: return CMD_ROTATE;

  case 75: return CMD_LEFT;

  case 77: return CMD_RIGHT;

  case 80: return CMD_DOWN;

  }

  }

  }

  Sleep(20);

  }

  }

  void DispatchCmd(CMD _cmd)

  {

  switch (_cmd)

  {

  case CMD_ROTATE: OnRotate(); break;

  case CMD_LEFT: OnLeft(); break;

  case CMD_RIGHT: OnRight(); break;

  case CMD_DOWN: OnDown(); break;

  case CMD_SINK: OnSink(); break;

  case CMD_QUIT: break;

  }

  }

  void NewBlock()

  {

  g_CurBlock.id = g_NextBlock.id, g_NextBlock.id = rand() % 7;

  g_CurBlock.dir = g_NextBlock.dir, g_NextBlock.dir = rand() % 4;

  g_CurBlock.x = (WIDTH - 4) / 2;

  g_CurBlock.y = HEIGHT + 2;

  WORD c = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];

  while ((c & 0xF) == 0)

  {

  g_CurBlock.y--;

  c >>= 4;

  }

  DrawBlock(g_CurBlock);

  setfillcolor(BLACK);

  solidrectangle((WIDTH + 1) * UNIT, 0, (WIDTH + 5) * UNIT - 1, 4 * UNIT - 1);

  DrawBlock(g_NextBlock);

  m_oldtime = GetTickCount();

  }

  void DrawUnit(int x, int y, COLORREF c, DRAW _draw)

  {

  int left = x * UNIT;

  int top = (HEIGHT - y - 1) * UNIT;

  int right = (x + 1) * UNIT - 1;

  int bottom = (HEIGHT - y) * UNIT - 1;

  switch (_draw)

  {

  case SHOW:

  setlinecolor(0x006060);

  roundrect(left + 1, top + 1, right - 1, bottom - 1, 5, 5);

  setlinecolor(0x003030);

  roundrect(left, top, right, bottom, 8, 8);

  setfillcolor(c);

  setlinecolor(LIGHTGRAY);

  fillrectangle(left + 2, top + 2, right - 2, bottom - 2);

  break;

  case FIX:

  setfillcolor(RGB(GetRValue(c) * 2 / 3, GetGValue(c) * 2 / 3, GetBValue(c) * 2 / 3));

  setlinecolor(DARKGRAY);

  fillrectangle(left + 1, top + 1, right - 1, bottom - 1);

  break;

  case CLEAR:

  setfillcolor(BLACK);

  solidrectangle(x * UNIT, (HEIGHT - y - 1) * UNIT, (x + 1) * UNIT - 1, (HEIGHT - y) * UNIT - 1);

  break;

  }

  }

  void DrawBlock(BLOCKINFO _block, DRAW _draw)

  {

  WORD b = g_Blocks[_block.id].dir[_block.dir];

  int x, y;

  for (int i = 0; i < 16; i++, b <<= 1)

  if (b & 0x8000)

  {

  x = _block.x + i % 4;

  y = _block.y - i / 4;

  if (y < HEIGHT)

  DrawUnit(x, y, g_Blocks[_block.id].color, _draw);

  }

  }

  bool CheckBlock(BLOCKINFO _block)

  {

  WORD b = g_Blocks[_block.id].dir[_block.dir];

  int x, y;

  for (int i = 0; i < 16; i++, b <<= 1)

  if (b & 0x8000)

  {

  x = _block.x + i % 4;

  y = _block.y - i / 4;

  if ((x < 0) || (x >= WIDTH) || (y < 0))

  return false;

  if ((y < HEIGHT) && (g_World[x][y]))

  return false;

  }

  return true;

  }

  void OnRotate()

  {

  int dx;

  BLOCKINFO tmp = g_CurBlock;

  tmp.dir++; if (CheckBlock(tmp)) { dx = 0; goto rotate; }

  tmp.x = g_CurBlock.x - 1; if (CheckBlock(tmp)) { dx = -1; goto rotate; }

  tmp.x = g_CurBlock.x + 1; if (CheckBlock(tmp)) { dx = 1; goto rotate; }

  tmp.x = g_CurBlock.x - 2; if (CheckBlock(tmp)) { dx = -2; goto rotate; }

  tmp.x = g_CurBlock.x + 2; if (CheckBlock(tmp)) { dx = 2; goto rotate; }

  return;

  rotate:

  DrawBlock(g_CurBlock, CLEAR);

  g_CurBlock.dir++;

  g_CurBlock.x += dx;

  DrawBlock(g_CurBlock);

  }

  void OnLeft()

  {

  BLOCKINFO tmp = g_CurBlock;

  tmp.x--;

  if (CheckBlock(tmp))

  {

  DrawBlock(g_CurBlock, CLEAR);

  g_CurBlock.x--;

  DrawBlock(g_CurBlock);

  }

  }

  void OnRight()

  {

  BLOCKINFO tmp = g_CurBlock;

  tmp.x++;

  if (CheckBlock(tmp))

  {

  DrawBlock(g_CurBlock, CLEAR);

  g_CurBlock.x++;

  DrawBlock(g_CurBlock);

  }

  }

  void OnDown()

  {

  BLOCKINFO tmp = g_CurBlock;

  tmp.y--;

  if (CheckBlock(tmp))

  {

  DrawBlock(g_CurBlock, CLEAR);

  g_CurBlock.y--;

  DrawBlock(g_CurBlock);

  }

  else

  OnSink();

  }

  void OnSink()

  {

  int i, x, y;

  DrawBlock(g_CurBlock, CLEAR);

  BLOCKINFO tmp = g_CurBlock;

  tmp.y--;

  while (CheckBlock(tmp))

  {

  g_CurBlock.y--;

  tmp.y--;

  }

  DrawBlock(g_CurBlock, FIX);

  WORD b = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];

  for (i = 0; i < 16; i++, b <<= 1)

  if (b & 0x8000)

  {

  if (g_CurBlock.y - i / 4 >= HEIGHT)

  {

  GameOver();

  return;

  }

  else

  g_World[g_CurBlock.x + i % 4][g_CurBlock.y - i / 4] = 1;

  }

  BYTE remove = 0;

  for (y = g_CurBlock.y; y >= max(g_CurBlock.y - 3, 0); y--)

  {

  i = 0;

  for (x = 0; x < WIDTH; x++)

  if (g_World[x][y] == 1)

  i++;

  if (i == WIDTH)

  {

  remove |= (1 << (g_CurBlock.y - y));

  setfillcolor(LIGHTGREEN);

  setlinecolor(LIGHTGREEN);

  setfillstyle(BS_HATCHED, HS_DIAGCROSS);

  fillrectangle(0, (HEIGHT - y - 1) * UNIT + UNIT / 2 - 5, WIDTH * UNIT - 1, (HEIGHT - y - 1) * UNIT + UNIT / 2 + 5);

  setfillstyle(BS_SOLID);

  }

  }

  if (remove)

  {

  Sleep(300);

  IMAGE img;

  for (i = 0; i < 4; i++, remove >>= 1)

  {

  if (remove & 1)

  {

  for (y = g_CurBlock.y - i + 1; y < HEIGHT; y++)

  for (x = 0; x < WIDTH; x++)

  {

  g_World[x][y - 1] = g_World[x][y];

  g_World[x][y] = 0;

  }

  getimage(&img, 0, 0, WIDTH * UNIT, (HEIGHT - (g_CurBlock.y - i + 1)) * UNIT);

  putimage(0, UNIT, &img);

  }

  }

  }

  NewBlock();

  }

上一篇:《永劫无间》7月27日更新公告,技能/奥义解锁新方式
下一篇:《传说之下》制作人新作,是延续?还是全新的故事?