俄罗斯方块彩蛋(附星空表白彩蛋)

简介: 俄罗斯方块彩蛋(附星空表白彩蛋)

俄罗斯方块🎩

前言

该文字主要讲解游戏逻辑代码实现,代码直接复制粘贴是无法直接运行的,直接运行可以在下文的传送门下载(0积分下载),下载好直接点击解决方案运行即可(需要按照要求安装easyx) ,或者去gitee查看源码,传送门在下文。

更新时间: 2022、5、18 、16:11

演示视频传送门传送门

源码见:

gitee: 传送门

0积分 可直接下载:传送门

开发中途的启发:开发心得

效果图展示

游戏开始界面

图片.png

游戏介绍页面:

图片.png

游戏倒计时:

图片.png

游戏界面

图片.png

游戏失败:

图片.png

彩蛋:星星是会动的

图片.png

游戏BGM:

歌名:SAD(Clap Your Hands)

在线听

彩蛋BGM:Mistleoe

在线听

游戏过程全部BGM都在资源里了,包括倒计时,消行,彩蛋音乐,游戏音乐

俄罗斯方块游戏逻辑

俄罗斯方块是在一块特定的长方形区域进行游戏运行,还有一个显示下一个方块的区域,得到的分数可以用一个变量贮存,然后在窗口打印出来,那么此时要完成这些基本游戏逻辑我们需要选择一个好的图形工具,可以画方块,可以画游戏区域和下一个方块提示,我们这里选择由C++开发的easyx图形开发库来实现,整个游戏开发最难的部分在于 如何在地图动态标记方块,方块贮存的数据结构,触底判断等。

- 第一步难度:⭐⭐

1.用函数绘出所需窗口,设置好每一步的像素(还有一个方法是可以通过电脑的画图绘图出来,然后在游戏直接加载,注意加载像素和窗口像素要一样,这样可以美观的显示游戏区域了像这样:两张图对比)…)这个是最关键的一步,因为这里不配置好,后面要改的话已全部都要改,所以这里花时间是没问题的

2.

1.游戏窗口

//窗口长
#define InterfaceX 500 
//窗口宽
#define InterfaceY 620
//游戏区起始点横坐标
#define GameViewX_1 10 
//游戏区起始点纵坐标
#define GameViewY_1 10
//游戏区终点横坐标
#define GameViewX_2 310
//游戏区终点纵坐标
#define GameViewY_2 610
//分数显示起始点横坐标
#define GameScoreX_1 320
//分数显示起始点纵坐标
#define GameScoreY_1 220
//分数显示终点横坐标
#define GameScoreX_2 490
//分数显示终点纵坐标
#define GameScoreY_2 380
//提示框起始点横坐标
#define GameRemindX_1 320
//提示框起始点纵坐标
#define GameRemindY_1 10
//提示框终点横坐标
#define GameRemindX_2 490
//提示框终点纵坐标
#define GameRemindY_2 210
//操作介绍框起始点横坐标
#define GameOperaX_1 320
//操作介绍框起始点纵坐标
#define GameOperaY_1 390
//操作介绍框终横坐标
#define GameOperaX_2 490
//操作介绍框终点纵坐标
#define GameOperaY_2 610

也可以美观使用画图画一个一样的图 见文章 开发心得

2.游戏欢迎界面(这里比较简单 主要是利用了递归函数保持页面存在和按键接受)

/*函数名:UI_WelcomeView
功能:游戏欢迎界面
参数:无
返回值:无
*/
void UI_WelcomeView()
{
  initgraph(700, 500);
  setbkmode(TRANSPARENT);
  putimage(0, 0, &BeginImage);
  setcolor(BLACK);
  settextstyle(45, 0, _T("楷体"));
  outtextxy(150, 150, "Welcome to the Game");
  settextstyle(18, 0, _T("仿宋"));
  setcolor(RGB(20, 20, 120));
  outtextxy(230, 460, "--按空格键开始游戏--");
  settextstyle(12, 0, _T("仿宋"));
  setcolor(RGB(20, 20, 200));
  outtextxy(250, 450, "查看游戏说明按ESC");
  while (1)
  {
    _getch();
    if (GetAsyncKeyState(VK_SPACE))
    {
      break;
    }
    else if (GetAsyncKeyState(VK_ESCAPE)) //游戏介绍
    {
      cleardevice();
        putimage(0, 0, &ExplainImage);
        settextcolor(RGB(15, 10, 204));
        settextstyle(23, 0, _T("仿宋"));
        outtextxy(150, 70, "游戏介绍");
        outtextxy(50, 100, "俄罗斯方块是一个老少咸宜的小游戏,它实现有");
        outtextxy(50, 120, "四个正方形的色块组成,然后存储于一个数");
        outtextxy(50, 140, "组的四个元素中,计算机随机产生七种不同类型的");
        outtextxy(50, 160, "方块,根据计算机时钟控制它在一定的时间");
        outtextxy(50, 180, "不停的产生,用户根据键盘的四个方向键进行向");
        outtextxy(50, 200, "左,向右,向下,翻转操作,暂停。");
        setcolor(RGB(20, 20, 120));
        outtextxy(450, 230, "操作说明:");
        outtextxy(450, 260, "←:向左移动");
        outtextxy(450, 290, "↓:向下移动");
        outtextxy(450, 320, "→:向右移动");
        outtextxy(450, 350, "↑:方块旋转");
        outtextxy(450, 380, "Esc:暂停游戏");
        settextstyle(18, 0, _T("仿宋"));
        setcolor(RGB(20, 20, 120));
        outtextxy(230, 460, "--按Tab返回主页面--");
        while (1) //不按键窗口不消失
        {
          _getch();
          if (GetAsyncKeyState(VK_TAB))
          {
            break;
          }
        }
        UI_WelcomeView();
    }
  }
} 

3.倒计时页面

/*函数名:UI_StartView
功能:游戏开始倒计时函数
参数:无
返回值:无
*/
void UI_StartView()
{
  closegraph();
  //存放num转化字符 并留一个‘/0’所以str[2]长度为2
  char str[2] = { 0 };
  //创建游戏窗口        特别注意事项:这里的控制台窗口显示不是因为 printf 第三个参数
                       //而是在用该函数创建窗口 可以选择是否 显示控制台   initgraph(InterfaceX, InterfaceY,SHOWCONSOLE);
  initgraph(InterfaceX, InterfaceY);
  //字体大小及风格
  settextstyle(30, 0, _T("仿宋"));
  //文字输出
  outtextxy(110, 180, "俄罗斯方块开始倒计时");
  //加载音乐倒计时
  UI_LoadMusicT();
  mciSendString("close gamerun", NULL, 0, 0);
  for (int num = 3; num > 0; num--)
  {
    //整数 
    _itoa_s(num, str,10);
    //sprintf(str, "%c", num);
    outtextxy(240, 480, str);
    //设置播放起点 from 时间点 或者重复播放 repeat
    //延时  
    Sleep(1000); //1-1ms
  }
}

- 第二步难度:⭐⭐⭐

实现游戏逻辑(按照难度从小到大排序)

1.方块实现下落功能,

2.触边判断(包括触底,触左,触右,实现了最重要触底,触右触左判断就可以举一反三了),

3.随机生成方块,以及显示下一个出现的方块,

4.方块用怎样的数据结构来存储

5.消行实现

1.方块实现逻辑:

每一个方块使用4 * 4的数组存贮,总共有七种基本类型,其中每一种需要旋转四次,则共有28中类型的方块,那么建立一个3维的数组

int Block[BLOCKTYPE][4][4](注:BLOCKTYPE 宏定义为28)

其中BLOCKTYPE 用rand() 函数随机生成,种子是系统时间 srand(time(NULL));,这就实现了方块的贮存以及第一个方块随机生成

特别注意: 有些小伙伴可能会问为什么 有些方块模型旋转了 也是一样啊,比如田形状方块,只用一个数组存贮就好啦,为什么要弄四个一样的呢?这是因为后面在实现方块旋转逻辑时 旋转一次是BLOCKTYPE加一,且要保持时同一方块类型,就需要BLOCKTYPE加一后变为4的倍数时减去4,回到原来方块类型。

图片.png

代码实现:

  int Block[BLOCKTYPE][4][4] =
  {
    //I形方块
  {
    0,1,0,0,
    0,1,0,0,
    0,1,0,0,
    0,1,0,0,
  },
  {
    0,0,0,0,
    1,1,1,1,
    0,0,0,0,
    0,0,0,0,
  },
  {
    0,1,0,0,
    0,1,0,0,
    0,1,0,0,
    0,1,0,0,
  },
  {
    0,0,0,0,
    1,1,1,1,
    0,0,0,0,
    0,0,0,0,
  },
  //L形方块
  {
    1,0,0,0,
    1,0,0,0,
    1,1,0,0,
    0,0,0,0,
  },
  {
    1,1,1,0,
    1,0,0,0,
    0,0,0,0,
    0,0,0,0,
  },
  {
    1,1,0,0,
    0,1,0,0,
    0,1,0,0,
    0,0,0,0,
  },
  {
    0,0,1,0,
    1,1,1,0,
    0,0,0,0,
    0,0,0,0,
  },
  //T型
  {
    0,0,0,0,
    1,1,1,0,
    0,1,0,0,
    0,0,0,0,
  },
  {
    1,0,0,0,
    1,1,0,0,
    1,0,0,0,
    0,0,0,0,
  },
  {
    0,1,0,0,
    1,1,1,0,
    0,0,0,0,
    0,0,0,0,
  },
  {
    0,1,0,0,
    1,1,0,0,
    0,1,0,0,
    0,0,0,0,
  },
  //田字形
  {
    0,0,0,0,
    0,1,1,0,
    0,1,1,0,
    0,0,0,0,
  },
  {
    0,0,0,0,
    0,1,1,0,
    0,1,1,0,
    0,0,0,0,
  },
  {
    0,0,0,0,
    0,1,1,0,
    0,1,1,0,
    0,0,0,0,
  },
  {
    0,0,0,0,
    0,1,1,0,
    0,1,1,0,
    0,0,0,0,
  },
  //反L型
  {
    0,1,0,0,
    0,1,0,0,
    1,1,0,0,
    0,0,0,0,
  },
  {
    0,0,0,0,
    1,1,1,0,
    0,0,1,0,
    0,0,0,0,
  },
  {
    0,1,1,0,
    0,1,0,0,
    0,1,0,0,
    0,0,0,0,
  },
  {
    1,0,0,0,
    1,1,1,0,
    0,0,0,0,
    0,0,0,0,
  },
  // 错位型
  {
    0,0,0,0,
    1,1,0,0,
    0,1,1,0,
    0,0,0,0,
  },
  {
    0,1,0,0,
    1,1,0,0,
    1,0,0,0,
    0,0,0,0,
  },
  {
    1,1,0,0,
    0,1,1,0,
    0,0,0,0,
    0,0,0,0,
   },
  {
    0,0,1,0,
    0,1,1,0,
    0,1,0,0,
    0,0,0,0,
   },
   //反错位型
  {
    0,0,0,0,
    0,1,1,0,
    1,1,0,0,
    0,0,0,0,
   },
  {
    0,1,0,0,
    0,1,1,0,
    0,0,1,0,
    0,0,0,0,
   },
  {
    0,0,0,0,
    0,1,1,0,
    1,1,0,0,
    0,0,0,0,
   },
  {
    0,1,0,0,
    0,1,1,0,
    0,0,1,0,
    0,0,0,0,
  },
  };

2.方块绘图

因为我们设置20行 10 列的游戏区域(像素为 600 x 300) 则每一个 方块 对呀像素为30 所以设置文字大小为30像素

代码实现:

/*函数名:App_Show_Block
功能:显示方块
参数:方块类型,坐标X,Y
返回值:无
*/
void App_Show_Block(int type,int X,int Y)
{
  settextstyle(30, 0, _T("黑体"));
  setcolor(RGB(200, 130, 40));
  for (int x = 0; x < 4; x++)
    for (int y = 0; y < 4; y++)
    {
      if (Block[type][x][y] == 1)
      {
        outtextxy(X + y * 30, Y + x * 30, "■");
      }
    }

3.方块清除

实现方块下落功能就是 设置延时 每过 0.3s 纵坐标加30像素 ,然后 方块清除函数再画一个一样的方块 不过 是和底色一样的白色 ,就相当于 墙弄脏了 油漆刷墙一样 消去原先绘出的方块

/*函数名:App_Clear_Block
功能:清楚方块
参数:方块类型,坐标X,Y
返回值:无
*/
void App_Clear_Block(int type,int X,int Y)
{
  //与背景颜色一致
  setcolor(WHITE);
  settextstyle(30, 0, _T("黑体"));
  for (int x = 0; x < 4; x++)
    for (int y = 0; y < 4; y++)
    {
      if (Block[type][x][y] == 1)
      {
        outtextxy(X + y * 30, Y + x * 30, "■");
      }
    }
}

- 第三步难度:⭐⭐

1.实现消行音效,2.游戏开始音效,3.游戏暂停同时停止音效(这里有个难点就是重新播放不会从 原本暂停地方重新播放,如果要实现我的想法是弄一个计时器)4.保存游戏分数最高记录

- 代码优化建议

1、进行函数封装,可以分为几个头文件,例如实现页面窗口绘图的函数声明的,放在UI.h头文件中(use interface) 实现游戏逻辑函数声明的放在APP.h头文件中,再分别在UI.cpp,APP.cpp中进行函数实现,在主函数main.cpp中引入UI.h和APP.h文件 再运行主函数,

更新中————


相关文章
|
前端开发 JavaScript
中秋之美——html+css+js制作中秋网页
中秋之美——html+css+js制作中秋网页
689 0
中秋之美——html+css+js制作中秋网页
|
存储 前端开发 JavaScript
你小子!过年了,写了一个拼图小游戏来拼掘金兔年礼盒,来玩玩不?
你小子!过年了,写了一个拼图小游戏来拼掘金兔年礼盒,来玩玩不?
208 2
【代码分享】【像极了恋爱】甜甜的汤圆,祝丽姿元宵快乐(表白特效)
【代码分享】【像极了恋爱】甜甜的汤圆,祝丽姿元宵快乐(表白特效)
120 0
|
前端开发 JavaScript
2022圣诞代码合集(圣诞树+圣诞老人)
2022圣诞代码合集(圣诞树+圣诞老人)
262 0
|
前端开发 JavaScript 程序员
2023将至,前端程序员们应该一起放个烟花庆祝一下,走起
前言:小时候,在我印象中,每到快过年的时候就有很多卖炮仗的,一般也就是阳历的12月份到明年的正月15号卖炮仗的商家比较多,省下买辣条的钱去买炮仗,在老家也就过年和除夕两天及正月15日这几天放烟花和炮仗比较猛,现在年纪大了,听不得炮仗那种噪声了,也考虑到环保,工作之后的程序员以代码的形式演绎一下烟花的效果。
273 0
2023将至,前端程序员们应该一起放个烟花庆祝一下,走起
我做的一个超级好玩的中秋节小游戏
我做的一个超级好玩的中秋节小游戏
我做的一个超级好玩的中秋节小游戏
|
Web App开发 JavaScript 前端开发
【程序员的浪漫】七夕到了,还不快给你女朋友做一个专属chrome插件
【程序员的浪漫】七夕到了,还不快给你女朋友做一个专属chrome插件
157 0
【程序员的浪漫】七夕到了,还不快给你女朋友做一个专属chrome插件
|
移动开发 JavaScript 前端开发
教你用200行代码写一个爱豆拼拼乐H5小游戏(附源码)
本文将带大家一步步实现一个H5拼图小游戏,考虑到H5游戏的轻量级和代码体积,我没有使用react或vue这些框架,而采用我自己写的dom库和原生javascript来实现业务功能,具体库代码可见我的文章如何用不到200行代码写一款属于自己的js类库,构建工具我采用了自己搭建的gulp4开发项目脚手架。
432 0
|
编译器 Python
圣诞节来了,怎能还没有圣诞树呢 快来为心爱的她送上专属的圣诞礼物叭~
圣诞节来了,怎能还没有圣诞树呢 快来为心爱的她送上专属的圣诞礼物叭~
178 0
圣诞节来了,怎能还没有圣诞树呢 快来为心爱的她送上专属的圣诞礼物叭~