《俄罗斯方块》(Tetris, 俄文:Тетрис)是一款由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的休闲游戏。
我将其作为我课程设计的题目,重温程序设计的基础。由于课设时间有限,本想用OpenGL弄个3D效果的俄罗斯方块,最终借鉴网上已有程序,进行修改编写。借助Easy_X库完成我的课程设计。这也是本人花时间调整的,特在此记录,作为一次经历。并在此提供相关工程,供有需要的朋友借鉴。本人在此声明,该程序有一定借鉴,如有侵权,请联系本人进行删除。
使用前需要安装easy_x的库
- 总体设计方案(程序总体框图或流程图)
2.游戏工程目录
3.项目运行结果
由于代码比较长,我将工程上传,有需要者可以前往下载
Tetris.cc
//----------------------------------------------------------------------------
// Tetris v1.0
// 作者 : yk
//----------------------------------------------------------------------------
// email: iamabirdyk219@gmail.com
//----------------------------------------------------------------------------
// 说明:
// 该程序为2019年东北林业大学课程设计。
// 本人仅完成了俄罗斯方块的基本实现。就
// 目前来看,它已经能让我在闲暇之余体味
// 小游戏的妙处,并且该小游戏借助Easy X
// 大大节约了在编写中的繁杂过程。
// 如发现问题请联系我,互相学习交流。
//
// v1.0 June 2019
//
//----------------------------------------------------------------------------
#include <iostream>
#include"Game.h"
Game Teris("Tetris ---- yk",832,768); //初始化游戏窗口数据
int main()
{
Teris.Init(); //初始化游戏参数
Teris.Primary_Menu_(); //进入主菜单
Teris.Game_interface_init_(); //初始化游戏界面
Teris.Game_control_init_(); //初始化游戏参数
while (true)
{
Teris.Update_show(); //刷新屏显
if (!Teris.Game_active) //判断游戏状态
{
Teris.Primary_Menu_(); //进入主菜单
Teris.Game_interface_init_(); //初始化游戏界面
Teris.Game_control_init_(); //初始化游戏参数
}
}
return 0;
}
Game.h
//----------------------------------------------------------------------------
// Tetris v1.0
// 作者 : yk
//----------------------------------------------------------------------------
//
// email: iamabirdyk219@gmail.com
//
//
//----------------------------------------------------------------------------
// 说明:
// 该程序为2019年东北林业大学课程设计。
// 本人仅完成了俄罗斯方块的基本实现。就
// 目前来看,它已经能让我在闲暇之余体味
// 小游戏的妙处,并且该小游戏借助Easy X
// 大大节约了在编写中的繁杂过程。
// 如发现问题请联系我,互相学习交流。
//
//
//
// v1.0 June 2019
//
//----------------------------------------------------------------------------
#ifndef GAME_H
#define GAME_H
#include<graphics.h>
#include<iostream>
#include<time.h>
#include"Tool.h"
class Game
{
public:
bool Game_active;
Game(const std::string Title,const int game_width, const int game_height);
//构造游戏类并传入窗口参数
void Init(); //初始化游戏的相关参数,及绘图面板
void Primary_Menu_(); //实现主菜单的UI和控制
void Game_interface_init_(); //初始化游戏界面
void Game_control_init_(); //初始化游戏参数
void Show_Menu_(); //绘制主菜单
void Rand_newblock_(); //生成一个随机的方块形状
void Review_box_show(); //绘制预览面板
void Active_box_show(); //绘制游戏主界面
void Aleady_box_show(); //绘制已存在方块
void Eliminate_block_full_(); //消除满行方块
void Update_Block_site(); //更新方块位置状态
void Updatewithinput(); //处理用户输入
void Update_show(); //更新绘图
void Load_resources(); //加载资源数据
bool Game_over_(); //绘制结束游戏信息
bool Block_Down(); //控制方块下落
bool Block_Up(); //控制方块旋转
bool Block_Left(); //控制方块左移
bool Block_Right(); //控制方块右移
~Game();
private:
int grade = 0;
int rank = 30;
std::string Rank = "A";
DWORD m_oldtime;
DWORD newtime = GetTickCount();
int width;
int height;
std::string Title;
IMAGE texture[20];
Tool tool;
int Max_box=19;
int wall_WS;
int wall_HS;
int Block_type_now=14;
int Block_type_next=1;
int Block_WS=7*2;
int Block_HS=11*2;
int Block_size = 64;
int Active_x = 64;
int Active_y = 64;
int Choose_x;
int Choose_X;
int Choose_Y;
void Delete_fullblock(int n);
void Show_grade();
void Show_Aboutgame_();
void Show_systime();
};
#endif // !GAME_H
Game.cc
//----------------------------------------------------------------------------
// Tetris v1.0
// 作者 : yk
//----------------------------------------------------------------------------
//
// email: iamabirdyk219@gmail.com
//
//
//----------------------------------------------------------------------------
// 说明:
// 该程序为2019年东北林业大学课程设计。
// 本人仅完成了俄罗斯方块的基本实现。就
// 目前来看,它已经能让我在闲暇之余体味
// 小游戏的妙处,并且该小游戏借助Easy X
// 大大节约了在编写中的繁杂过程。
// 如发现问题请联系我,互相学习交流。
//
//
//
// v1.0 June 2019
//
//----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// 【游戏中核心算法】
// 使用二进制数对方块形状进行储存
// 1100 即1100 0100 0100 0000
// 0100 储存为L,在进行移动旋转以及
// 0100 碰撞检测时,用最高位为1的数
// 0000 与其 & 从而得到其形状。
//
//---------------------------------------------------------------------------
#include"Game.h"
#include"Game_properties.h"
#pragma comment(lib,"Winmm.lib")
#define _CRT_SECURE_NO_WARNINGS
#define PI 3.1415926535
#define W_UP 72 // 方块旋转
#define W_LEFT 75 // 方块向左移动
#define W_RIGHT 77 // 方块向右移动
#define W_DOWN 80 // 方块向下移动
#define W_ESC 27 // 退出游戏
#define W_ENTER 13
#define W_SPACE 32
//----------------------------------------------------------------------------------------------
//函数声明:Game(const std::string Title,const int game_width, const int game_height)
//函数参数:1.Title --[窗口名字(仅英文)] 2.game_width--[窗口宽度], game_height--[窗口高度]
//函数功能:
// 构造类并获取窗口的属性数据,以便于后续创建一个绘图窗口。
//----------------------------------------------------------------------------------------------
Game::Game(const std::string Title,const int game_width, const int game_height)
{
this->width = game_width;
this->height = game_height;
this->Title = Title;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Init();
//函数参数: 无
//函数功能:
// 初始化游戏的基本数据。包括加载资源数据,创建绘图窗口,设置游戏参数
//和进入主菜单,准备开始游戏
//----------------------------------------------------------------------------------------------
void Game::Init()
{
this->Load_resources(); //加载数据
initgraph(this->width, this->height); //创建绘图窗口
BeginBatchDraw(); //开始批量绘图,解决绘图中闪烁的问题,但是会增加游戏对CPU的占用
HWND hwnd = GetHWnd(); //获取窗口句柄,对窗口进行设置
SetWindowText(hwnd,this->tool.stringToLPCWSTR(this->Title)); //设置窗口标题
Resize(&this->texture[12], this->width, this->height); //调整主菜单背景图片与窗口适应
putimage(0, 0, &this->texture[12]); //在(0,0)位置进行贴图
setbkmode(TRANSPARENT); //设置窗口的属性
this->Primary_Menu_(); //进入主菜单
FlushBatchDraw(); //执行批量绘图操作
this->wall_WS = ((this->width / 4) * 3) / this->Block_size-1; //获取绘图窗口的相对位置属性
this->wall_HS = this->height / this->Block_size-1;
this->m_oldtime = this->newtime; //设置游戏参数
}
//----------------------------------------------------------------------------------------------
//函数声明:void Primary_Menu_()
//函数参数: 无
//函数功能:
// 绘制主菜单的界面,并实现对鼠标与键盘操作的监听,
//并且根据鼠标键盘的相关操作,执行相关功能
//----------------------------------------------------------------------------------------------
void Game::Primary_Menu_()
{
this->Choose_x = 120;
this->Choose_X = this->Choose_x + 630; //获取主菜单相对位置属性以便于鼠标,键盘的功能判断
this->Choose_Y = this->height / 4+100;
this->Show_Menu_(); //绘制主菜单
MOUSEMSG m; //创建鼠标对象
while (true) //循环绘制
{
if (_kbhit()) //等待键盘操作
{
switch (_getch()) //获取键盘操作内容
{
case 'w':
case 'W':
case W_UP: //上,对主菜单下划线位置进行控制
{
if (this->Choose_Y ==292)
{
this->Choose_Y += 360;
}
else if (this->Choose_Y == 412)
{
this->Choose_Y -= 120;
}
else if (this->Choose_Y == 532)
{
this->Choose_Y -= 120;
}
else if (this->Choose_Y == 652)
{
this->Choose_Y -= 120;
}
}
break;
case's':
case'S':
case W_DOWN: //下
{
if (this->Choose_Y == 292)
{
this->Choose_Y += 120;
}
else if (this->Choose_Y == 412)
{
this->Choose_Y += 120;
}
else if (this->Choose_Y == 532)
{
this->Choose_Y += 120;
}
else if (this->Choose_Y == 652)
{
this->Choose_Y -= 360;
}
}
break;
case W_ENTER:
case W_SPACE: //空格,对功能进行选择执行
{
if (this->Choose_Y == 292)
{
this->Game_active = true; //设置游戏状态
return;
}
else if (this->Choose_Y == 412)
{
this->Show_Aboutgame_(); //输出游戏
this->Show_Menu_(); //绘制主菜单
}
else if (this->Choose_Y == 532)
{
this->Show_systime(); //绘制时钟
}
else if (this->Choose_Y == 652)
{
EndBatchDraw(); //结束绘制
closegraph(); //关闭绘图窗口
this->~Game();
Sleep(100);
exit(0); //退出程序
}
}break;
case W_ESC:
{
EndBatchDraw(); //结束绘制
closegraph(); //关闭绘图窗口
this->~Game();
Sleep(100);
exit(0); //退出程序
}
default:
break;
}
this->Show_Menu_();
}
if (MouseHit()) //等待鼠标操作
{
m = GetMouseMsg(); //获取鼠标数据
switch (m.uMsg)
{
case WM_MOUSEMOVE: //鼠标移动,从而控制下划线移动
{
if ((m.y >= 172 && m.y < 292) && (m.x >= 120 && m.x <= 750))
{
this->Choose_Y = 292;
}
if ((m.y >= 300 && m.y < 412) && (m.x >= 120 && m.x <= 750))
{
this->Choose_Y = 412;
}
if ((m.y >= 422 && m.y < 532) && (m.x >= 120 && m.x <= 750))
{
this->Choose_Y = 532;
}
if ((m.y >= 542 && m.y < 652) && (m.x >= 120 && m.x <= 750))
{
this->Choose_Y = 652;
}
this->Show_Menu_(); //绘制主菜单
}
break;
case WM_LBUTTONDOWN: //按下左键
{
if ((m.y >= 172 && m.y < 292) && (m.x >= 120 && m.x <= 750))
{
this->Game_active = true; //设置游戏状态
return;
}
if ((m.y >= 300 && m.y < 412) && (m.x >= 120 && m.x <= 750))
{
this->Show_Aboutgame_(); //输出游戏介绍
this->Show_Menu_(); //绘制主菜单
}
if ((m.y >= 422 && m.y) < 532 && (m.x >= 120 && m.x <= 750))
{
this->Show_systime(); //显示时钟界面
}
if ((m.y >= 542 && m.y < 652) && (m.x >= 120 && m.x <= 750))
{
EndBatchDraw(); //终止批量绘图
closegraph(); //关闭绘图窗口
this->~Game();
Sleep(100);
exit(0); //退出游戏
}
}
break;
}
this->Show_Menu_(); //显示主菜单
}
FlushBatchDraw(); //执行批量绘图
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Game_interface_init_();
//函数参数: 无
//函数功能:
// 初始化游戏界面,并准备开始游戏
//----------------------------------------------------------------------------------------------
void Game::Game_interface_init_()
{
Resize(&this->texture[8], this->Block_size * (this->wall_WS-1), this->Block_size * this->wall_HS); //调整贴图尺寸
Resize(&this->texture[9], this->Block_size * 2, this->Block_size *2);
for (int i = 0; i <= this->wall_WS; i++)
{
putimage(i * this->Block_size, 0, &this->texture[0]); //绘制游戏活动区边缘部分
putimage(i * this->Block_size, this->wall_HS * this->Block_size, &this->texture[0]);
}
for (int j = 0; j < this->wall_HS; j++)
{
putimage(0, (j + 1) * this->Block_size, &this->texture[0]);
putimage(this->wall_WS *this->Block_size, (j + 1) * this->Block_size, &this->texture[0]);
}
putimage(this->Active_x, this->Active_y, &this->texture[8]);
this->Show_grade(); //显示得分情况
}
//----------------------------------------------------------------------------------------------
//函数声明:void Game_control_init_();
//函数参数: 无
//函数功能:
// 初始化游戏参数,包括游戏过程中方块的随机产生
//----------------------------------------------------------------------------------------------
void Game::Game_control_init_()
{
for (int i = 0; i < 22; i++) //游戏活动区面板范围
{
for (int j = 0; j < 14; j++)
{
block_site[i][j].state = false; //初始化相关位置数据
block_site[i][j].Block_type = 0;
}
}
this->Rand_newblock_(); //随机产生一个方块
this->Active_box_show(); //绘制方块移动面板
this->Rand_newblock_();
this->Review_box_show(); //预览面板方块位置
FlushBatchDraw(); //执行批量绘图
}
//----------------------------------------------------------------------------------------------
//函数声明:void Show_Menu_();
//函数参数: 无
//函数功能:
// 绘制主菜单UI进行显示
//----------------------------------------------------------------------------------------------
void Game::Show_Menu_()
{
setlinestyle(PS_SOLID, 5); //设置线宽
putimage(0, 0, &this->texture[12]); //绘图
setcolor(RGB(184, 61, 186));
tool.Show_text_(100, this->height / 4, "[A] New Game", 100); //输出文本
setcolor(RGB(0, 168, 243));
tool.Show_text_(100, this->height / 4 + 120, "[B] About Game", 100);
setcolor(RGB(70, 178, 36));
tool.Show_text_(100, this->height / 4 + 240, "[C] Time ", 100);
setcolor(RGB(236, 28, 36));
tool.Show_text_(100, this->height / 4 + 360, "[D] Exit Game", 100);
setcolor(RGB(0, 0, 0));
tool.Show_text_(this->width - 200, this->height - 70, "Author:Yk", 30);
tool.Show_text_(this->width - 200, this->height - 35, "ID:2017211146", 30);
line(this->Choose_x, this->Choose_Y, this->Choose_X, this->Choose_Y); //绘制直线
}
//----------------------------------------------------------------------------------------------
//函数声明:void Game_over_();
//函数参数: 无
//函数功能:
// 判断游戏是否结束
//----------------------------------------------------------------------------------------------
bool Game::Game_over_()
{
int i, j, mask, a = 0;
place_active_next.X = 6; //找到要移动到的位置
place_active_next.Y = 0; //*------------------------
for (i = 0; i < 2; i++) // 用128 64 32 ....
{ // 与存储方块数据相与从而判断
mask = 128; //相应位置上的方块存在状态
for (j = 0; j < 8; j++) //最后与已存在方块进行比较
{ //得出游戏是否结束状态
if (j % 4 == 0 && j != 0) { //*-------------------------
place_active_next.Y++;
place_active_next.X = 0;
}
if (form[this->Block_type_now].box[i] & mask) //判断相应位置上方块存在状态
{
if (block_site[place_active_next.Y][place_active_next.X].state == 1) //判断已存在方块的状态确定是否占用
{
putimage(0, 0, &this->texture[10]);
FlushBatchDraw();
return true;
} //底板有位置已占用游戏结束
}
mask = mask / 2;
}
place_active_next.Y++;
}
return false;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Rand_newblock_();
//函数参数: 无
//函数功能:
// 随机生成一个随机形状的方块
//----------------------------------------------------------------------------------------------
void Game::Rand_newblock_()
{
this->Block_type_now = this->Block_type_next;
srand((unsigned)time(NULL)); //产生随机时间种子
this->Block_type_next = rand() % this->Max_box; //产生随机形状的方块
place_active_now.X = 6; //设置生成方块的出现位置
place_active_now.Y =0;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Review_box_show();
//函数参数: 无
//函数功能:
// 绘制预览面板,显示之后的方块
//----------------------------------------------------------------------------------------------
void Game::Review_box_show()
{
putimage(this->Block_size * (this->wall_WS + 1), 0, &this->texture[9]); //显示基础背景图
putimage(this->Block_size * (this->wall_WS + 3), 0, &this->texture[9]);
putimage(this->Block_size * (this->wall_WS + 1), this->Block_size*2, &this->texture[9]);
putimage(this->Block_size * (this->wall_WS + 3), this->Block_size * 2, &this->texture[9]);
place.X = this->Block_size * (this->wall_WS+2)+32;
place.Y = 64;
int mask=0,x= place.X,y= place.Y;
for (int i = 0; i < 2; i++)
{
mask = 128;
for (int j = 0; j < 8; j++)
{
if (j % 4 == 0 && j != 0)
{
y += 32;
x = place.X;
}
if (form[this->Block_type_next].box[i] & mask) //依据相应位置的方块存在类型与状态,绘制相应图案
{
putimage(x, y, &this->texture[form[this->Block_type_next].type]); //绘制图案
}
x += 32;
mask /= 2;
}
x = place.X;
y += 32;
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Active_box_show();
//函数参数: 无
//函数功能:
// 绘制游戏活动区,在相关位置绘制游戏活动界面
//----------------------------------------------------------------------------------------------
void Game::Active_box_show()
{
int mask = 0, x = 0, y = 0;
x = place_active_now.X;
y = place_active_now.Y;
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box) //判断方块是否在指定位置
{
for (int i = 0; i < 2; i++)
{
mask = 128;
for (int j = 0; j < 8; j++)
{
if (j % 4 == 0 && j != 0)
{
y++;
x = place_active_now.X;
}
if (form[this->Block_type_now].box[i] & mask) //确定方块形状
{
putimage(this->Active_x+x*32,this->Active_y+y*32, &this->texture[form[this->Block_type_now].type]);
}
x++;
mask /= 2;
}
x = place_active_now.X;
y++;
}
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Aleady_box_show();
//函数参数: 无
//函数功能:
// 绘制已经存在的方块
//----------------------------------------------------------------------------------------------
void Game::Aleady_box_show()
{
for (int i = 0; i < 22; i++)
for (int j = 0; j < 14; j++) //游戏活动区范围
if (block_site[i][j].state == 1)
putimage((2 + j) *(this->Block_size / 2), (2 + i) * (this->Block_size / 2), &this->texture[block_site[i][j].Block_type]);
//在指定区域绘制方块
}
//----------------------------------------------------------------------------------------------
//函数声明:void Eliminate_block_full_();
//函数参数: 无
//函数功能:
// 判断是否满行,从而对满行进行消除
//----------------------------------------------------------------------------------------------
void Game::Eliminate_block_full_()
{
int m, n, top;
n = place_active_now.Y + 3; //判断是否超过活动区范围
top = place_active_now.Y;
for (; n >= top;)
{
if (n < 0 || n >= 22)
{
n--;
continue;
}
for (m = 0; m < 14; m++)
{
if (block_site[n][m].state == 0)
{
n--;
break;
}
if (m == 13)
{
this->Delete_fullblock(n); //消除满行
this->grade++;
if (this->grade >= 10) //大于10分则提升等级
this->Rank = "B";
if (this->grade >= 20)
this->Rank = "C";
this->Show_grade(); //显示得分等级情况
}
}
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Update_Block_site();
//函数参数: 无
//函数功能:
// 更新相关位置上方块状态情况
//----------------------------------------------------------------------------------------------
void Game::Update_Block_site()
{
int mask, x = place_active_now.X, y = place_active_now.Y;
for (int i = 0; i < 2; i++)
{
mask = 128;
for (int j = 0; j < 8; j++)
{
if (j % 4 == 0 && j != 0)
{
y++;
x = place_active_now.X;
}
if (form[Block_type_now].box[i] & mask) //判断方块形状,并更新位置状态
{
block_site[y][x].Block_type = form[Block_type_now].type;
block_site[y][x].state = 1;
}
x++;
mask /= 2;
}
x = place_active_now.X;
y++;
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Updatewithinput();
//函数参数: 无
//函数功能:
// 处理用户键入,此处未加入鼠标功能,但可以加入并进行抽象
//----------------------------------------------------------------------------------------------
void Game::Updatewithinput()
{
char c;
c = _getch();
switch (c)
{
case 'w':
case 'W':
case W_UP:
if (this->Block_Up()) //上,旋转
{
this->Block_type_now = form[this->Block_type_now].next; //改变方块形状
}
break;
case 's':
case 'S':
case W_DOWN:
if (this->Block_Down()) //下,向下移动
{
place_active_now.Y++;
}
break;
case 'a':
case 'A':
case W_LEFT:
if (this->Block_Left()) //左移动
{
place_active_now.X--;
}
break;
case 'd':
case 'D':
case W_RIGHT:
if (this->Block_Right()) //右移动
{
place_active_now.X++;
}
break;
case W_ESC:
this->Game_active = false; //改变游戏状态
default:
break;
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Update_show();
//函数参数: 无
//函数功能:
// 更新游戏活动区绘图
//----------------------------------------------------------------------------------------------
void Game::Update_show()
{
if(_kbhit())this->Updatewithinput(); //处理用户输入
newtime = GetTickCount(); //获取系统时间
DWORD t = (600 - this->rank* (this->grade)); //干预方块下落的速度
if (newtime - m_oldtime >= t)
{
m_oldtime = newtime;
if (this->Block_Down()) //方块下落
place_active_now.Y++;
else
{
this->Update_Block_site(); //更新方块状态信息
this->Eliminate_block_full_(); //消除满行
this->Rand_newblock_(); //产生新的方块形状
this->Review_box_show(); //预览面板方块绘制
}
}
putimage(this->Active_x, this->Active_y, &this->texture[8]);
this->Aleady_box_show(); //绘制已有的方块
this->Active_box_show(); //运动中的方块绘制
FlushBatchDraw(); //批量绘图
if (this->Game_over_()) //判断游戏是否结束
{
Sleep(150);
system("pause");
this->Game_active = false;
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Load_resources();
//函数参数: 无
//函数功能:
// 加载资源数据
//----------------------------------------------------------------------------------------------
void Game::Load_resources()
{
loadimage(&this->texture[0], _T("resources\\T_bo.jpg")); //加载图片
loadimage(&this->texture[1], _T("resources\\Type_A.jpg"));
loadimage(&this->texture[2], _T("resources\\Type_B.jpg"));
loadimage(&this->texture[3], _T("resources\\Type_C.jpg"));
loadimage(&this->texture[4], _T("resources\\Type_D.jpg"));
loadimage(&this->texture[5], _T("resources\\Type_E.jpg"));
loadimage(&this->texture[6], _T("resources\\Type_F.jpg"));
loadimage(&this->texture[7], _T("resources\\Type_G.jpg"));
loadimage(&this->texture[8], _T("resources\\background.jpg"));
loadimage(&this->texture[9], _T("resources\\preview.jpg"));
loadimage(&this->texture[10], _T("resources\\Game.jpg"));
loadimage(&this->texture[11], _T("resources\\next.jpg"));
loadimage(&this->texture[12], _T("resources\\start.jpg"));
loadimage(&this->texture[13], _T("resources\\grade_A.jpg"));
loadimage(&this->texture[14], _T("resources\\grade_B.jpg"));
loadimage(&this->texture[15], _T("resources\\grade_C.jpg"));
loadimage(&this->texture[16], _T("resources\\time.jpg"));
}
//----------------------------------------------------------------------------------------------
//函数声明:void Block_Down();
//函数参数: 无
//函数功能:
// 控制方块向下移动
//----------------------------------------------------------------------------------------------
bool Game::Block_Down()
{
int i, io, save_x, mask;
place_active_next.X = place_active_now.X; //找到要移动到的位置
place_active_next.Y = place_active_now.Y;
if (place_active_next.Y == 21) //判断是否到底部
{
return FALSE;
}
else if (place_active_next.Y == 20) //判断特定形状是否会超出游戏边界
{
if (this->Block_type_now == 17)
if (block_site[place_active_next.Y+1][place_active_next.X].state == 0 && block_site[place_active_next.Y+1][place_active_next.X + 1].state== 0 &&
block_site[place_active_next.Y + 1][place_active_next.X + 2].state == 0 && block_site[place_active_next.Y +1][place_active_next.X + 3].state == 0)
return TRUE;
else return FALSE;
}
return FALSE;
}
else if (place_active_next.Y == 19)
{
mask = 128;
for (int k = 0; k < 4; k++) {
if (form[this->Block_type_now].box[1] & mask) {
return FALSE;
}
else mask = mask / (2);
}
}
else if (place_active_next.Y == 18)
{
mask = 8;
for (int k = 0; k < 4; k++) {
if (form[this->Block_type_now].box[1] & mask) {
return FALSE;
}
else mask = mask / (2);
}
}
place_active_next.Y++;
save_x = place_active_next.X; //向下移动合理的方块
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[this->Block_type_now].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X].state == 1)
{
return FALSE;
} //底板有位置已占用,不能移动
}
place_active_next.X++;
mask = mask / (2);
}
place_active_next.X = save_x;
place_active_next.Y++;
}
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Block_Up();
//函数参数: 无
//函数功能:
// 控制方块旋转
//----------------------------------------------------------------------------------------------
bool Game::Block_Up()
{
int i, io, save_x, mask;
place_active_next.X = place_active_now.X; //找到要移动到的位置
place_active_next.Y = place_active_now.Y;
save_x = place_active_next.X;
if (place_active_next.X < 11) //当方块在底板内部时
{
if (place_active_next.Y < 19)
{
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
} //获取相关形状的位置状态
if (form[form[this->Block_type_now].next].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state == 1) {
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
}
return TRUE;
}
else if (place_active_next.Y == 19)
{
mask = 8;
for (int k = 0; k < 4; k++)
{
if (form[form[this->Block_type_now].next].box[1] & mask)
{
return FALSE;
}
else mask = mask / (2);
}
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[form[this->Block_type_now].next].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state == 1) {
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
}
return TRUE;
}
else if (place_active_next.Y > 19)
{
return FALSE;
}
}
else if (place_active_next.X == 11) //当方块在底板右边界时
{
if (place_active_next.Y < 19)
{
if ((form[form[this->Block_type_now].next].box[0] & 16) ||
(form[form[this->Block_type_now].next].box[0] & 1) ||
(form[form[this->Block_type_now].next].box[1] & 16) ||
(form[form[this->Block_type_now].next].box[1] & 1))
{
return FALSE;
}
else
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[form[this->Block_type_now].next].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state == 1)
{
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
}
return TRUE;
}
else if (place_active_next.Y == 19)
{
if ((form[form[this->Block_type_now].next].box[0] & 16) ||
(form[form[this->Block_type_now].next].box[0] & 1) ||
(form[form[this->Block_type_now].next].box[1] & 16) ||
(form[form[this->Block_type_now].next].box[1] & 1) ||
(form[form[this->Block_type_now].next].box[1] & 8) ||
(form[form[this->Block_type_now].next].box[1] & 4) ||
(form[form[this->Block_type_now].next].box[1] & 2))
{
return FALSE;
}
else
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[form[this->Block_type_now].next].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state == 1) {
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
}
return TRUE;
}
else
{
return FALSE;
}
}
return FALSE;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Block_Up();
//函数参数: 无
//函数功能:
// 控制方块左移
//----------------------------------------------------------------------------------------------
bool Game::Block_Left()
{
int i, io, save_x, mask;
place_active_next.X = place_active_now.X; //找到要移动到的位置
place_active_next.Y = place_active_now.Y;
if (place_active_next.X == 0)
{
return FALSE;
}
place_active_next.X = place_active_now.X - 1;
place_active_next.Y = place_active_now.Y;
save_x = place_active_next.X;
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box) //判断形状的正确性
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[this->Block_type_now].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state== 1)
{
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Block_Up();
//函数参数: 无
//函数功能:
// 控制方块右移
//----------------------------------------------------------------------------------------------
bool Game::Block_Right()
{
int i, io, save_x, mask;
place_active_next.X = place_active_now.X; //找到要移动到的位置
place_active_next.Y = place_active_now.Y;
if (place_active_next.X == 13)
{
return FALSE;
}
else if (place_active_next.X == 12)
{
if (this->Block_type_now == 16)
{
return TRUE;
}
else
{
return FALSE;
}
}
else if (place_active_next.X == 11) //找到右边界避免相关形状越界
{
if ((form[this->Block_type_now].box[0] & 32) || (form[this->Block_type_now].box[0] & 2)||
(form[this->Block_type_now].box[1] & 32) || (form[this->Block_type_now].box[1] & 2))
{
return FALSE;
}
else
{
return TRUE;
}
}
else if (place_active_next.X == 10)
{
if ((form[this->Block_type_now].box[0] & 16) || (form[this->Block_type_now].box[0] & 1)||
(form[this->Block_type_now].box[1] & 16) || (form[this->Block_type_now].box[1] & 1))
{
return FALSE;
}
else
{
place_active_next.X++;
save_x = place_active_next.X;
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[this->Block_type_now].box[io] &mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state == 1)
{
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
return TRUE;
}
}
}
place_active_next.X = place_active_now.X + 1;
place_active_next.Y = place_active_now.Y;
save_x = place_active_next.X;
if (this->Block_type_now >= 0 && this->Block_type_now < this->Max_box)
{
for (io = 0; io < 2; io++)
{
mask = 128;
for (i = 0; i < 8; i++)
{
if (i % 4 == 0 && i != 0) {
place_active_next.Y++;
place_active_next.X = save_x;
}
if (form[this->Block_type_now].box[io] & mask)
{
if (block_site[place_active_next.Y][place_active_next.X + i % 4].state == 1) {
return FALSE;
} //底板有位置已占用,不能移动
}
mask = mask / (2);
}
place_active_next.Y++;
}
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------------------------------
//函数声明:~Game();
//函数参数: 无
//函数功能:
// 析构函数
//----------------------------------------------------------------------------------------------
Game::~Game()
{
}
//----------------------------------------------------------------------------------------------
//函数声明:void Delete_fullblock(int n);
//函数参数: n- 行宽
//函数功能:
// 判断是否满行,满行则消除
//----------------------------------------------------------------------------------------------
void Game::Delete_fullblock(int n)
{
for (int e = 0; e < 14; e++)
{
block_site[n][e].state = 0;
}
for (; n >= 0; n--)
for (int m = 0; m < 14; m++)
if (n > 0)
{
block_site[n][m].state = block_site[n-1][m].state;
block_site[n][m].Block_type = block_site[n - 1][m].Block_type;
}
}
//----------------------------------------------------------------------------------------------
//函数声明:void Show_grade( );
//函数参数: 无
//函数功能:
// 显示得分情况及游戏等级
//----------------------------------------------------------------------------------------------
void Game::Show_grade()
{
if (this->Rank[0] == 'A') //依据等级设置等级参数
{
putimage(this->Block_size * (this->wall_WS + 1), this->Block_size * 4, &this->texture[13]);
this->rank = 30;
}
else if (this->Rank[0] == 'B')
{
putimage(this->Block_size * (this->wall_WS + 1), this->Block_size * 4, &this->texture[14]);
this->rank = 40;
}
else if (this->Rank[0] == 'C')
{
putimage(this->Block_size * (this->wall_WS + 1), this->Block_size * 4, &this->texture[15]);
this->rank = 50;
}
std::string str;
char s[20];
sprintf_s(s, "%d", this->grade); //在指定位置绘制分数情况
str = s;
tool.Show_text_(this->Block_size * (this->wall_WS + 1) + 100, this->Block_size * 4 + 10, str, 40);
tool.Show_text_(this->Block_size * (this->wall_WS + 1) + 100, this->Block_size * 4 + 60, this->Rank, 40);
}
//----------------------------------------------------------------------------------------------
//函数声明:void Show_Aboutgame_( );
//函数参数: 无
//函数功能:
// 显示游戏介绍情况
//----------------------------------------------------------------------------------------------
void Game::Show_Aboutgame_()
{
putimage(0, 0, &this->texture[11]);
FlushBatchDraw();
system("pause");
}
//----------------------------------------------------------------------------------------------
//函数声明:void Show_systime( );
//函数参数: 无
//函数功能:
// 绘制系统时钟,显示系统时间,此处借鉴他人代码
//----------------------------------------------------------------------------------------------
void Game::Show_systime()
{
int center_x, center_y; // 中心点的坐标,也是表的中心
center_x = this->width / 2;
center_y = this->height / 2;
int secondLength = this->width / 5; // 秒针的长度
int minuteLength = this->width / 6; // 分针的长度
int hourLength = this->width / 7; // 时针的长度
int secondEnd_x, secondEnd_y; // 秒针的终点
int minuteEnd_x, minuteEnd_y; // 分针的终点
int hourEnd_x, hourEnd_y; // 时针的终点
float secondAngle; // 秒钟对应的角度
float minuteAngle; // 分钟对应的角度
float hourAngle; // 时钟对应的角度
SYSTEMTIME ti; // 定义变量保存当前时间
while (true)
{
if (_kbhit())
{
_getch();
return;
}
putimage(0, 0, &this->texture[16]);
// 绘制一个简单的表盘
setlinestyle(PS_SOLID, 1);
setcolor(WHITE);
circle(center_x, center_y, this->width / 4);
// 画刻度
int x, y, i;
for (i = 0; i < 60; i++)
{
x = center_x + int(this->width / 4.3 * sin(PI * 2 * i / 60));
y = center_y + int(this->width / 4.3 * cos(PI * 2 * i / 60));
if (i % 15 == 0)
bar(x - 5, y - 5, x + 5, y + 5);
else if (i % 5 == 0)
circle(x, y, 3);
else
putpixel(x, y, WHITE);
}
GetLocalTime(&ti); // 获取当前时间
// 秒钟角度变化
secondAngle = ti.wSecond * 2 * PI / 60; // 一圈一共2*PI,一圈60秒,一秒钟秒钟走过的角度为2*PI/60
// 分钟角度变化
minuteAngle = ti.wMinute * 2 * PI / 60 + secondAngle / 60;
// 一圈一共2*PI,一圈60分,一分钟分钟走过的角度为2*PI/60
// 时钟角度变化
hourAngle = ti.wHour * 2 * PI / 12 + minuteAngle / 12;
// 一圈一共2*PI,一圈12小时,一小时时钟走过的角度为2*PI/12
// 由角度决定的秒针端点坐标
secondEnd_x = center_x + secondLength * sin(secondAngle);
secondEnd_y = center_y - secondLength * cos(secondAngle);
// 由角度决定的分针端点坐标
minuteEnd_x = center_x + minuteLength * sin(minuteAngle);
minuteEnd_y = center_y - minuteLength * cos(minuteAngle);
// 由角度决定的时针端点坐标
hourEnd_x = center_x + hourLength * sin(hourAngle);
hourEnd_y = center_y - hourLength * cos(hourAngle);
setlinestyle(PS_SOLID, 2);
setcolor(YELLOW);
line(center_x, center_y, secondEnd_x, secondEnd_y);
// 画秒针
setlinestyle(PS_SOLID, 5);
setcolor(BLUE);
line(center_x, center_y, minuteEnd_x, minuteEnd_y);
// 画分针
setlinestyle(PS_SOLID, 10);
setcolor(RED);
line(center_x, center_y, hourEnd_x, hourEnd_y);
// 画时针
FlushBatchDraw();
Sleep(10);
}
}
Tool.h
//----------------------------------------------------------------------------
// Tetris v1.0
// 作者 : yk
//----------------------------------------------------------------------------
//
// email: iamabirdyk219@gmail.com
//
//
//----------------------------------------------------------------------------
// 说明:
// 该程序为2019年东北林业大学课程设计。
// 本人仅完成了俄罗斯方块的基本实现。就
// 目前来看,它已经能让我在闲暇之余体味
// 小游戏的妙处,并且该小游戏借助Easy X
// 大大节约了在编写中的繁杂过程。
// 如发现问题请联系我,互相学习交流。
//
//
//
// v1.0 June 2019
//
//----------------------------------------------------------------------------
#ifndef TOOL_H
#define TOOL_H
#include<windows.h>
#include<iostream>
#include <conio.h>
class Tool
{
public:
LPCWSTR stringToLPCWSTR(std::string orig); //格式转换
void Show_text_(const int x, const int y, const std::string text, const int LfHeight, const int Lfwidth=0, const std::string mode="黑体");
char ProcessInput();
private:
};
#endif // TOOL_H
Tool.cc
//----------------------------------------------------------------------------
// Tetris v1.0
// 作者 : yk
//----------------------------------------------------------------------------
//
// email: iamabirdyk219@gmail.com
//
//
//----------------------------------------------------------------------------
// 说明:
// 该程序为2019年东北林业大学课程设计。
// 本人仅完成了俄罗斯方块的基本实现。就
// 目前来看,它已经能让我在闲暇之余体味
// 小游戏的妙处,并且该小游戏借助Easy X
// 大大节约了在编写中的繁杂过程。
// 如发现问题请联系我,互相学习交流。
//
//
//
// v1.0 June 2019
//
//----------------------------------------------------------------------------
#include "Tool.h"
#include<graphics.h>
#include<Windows.h>
//----------------------------------------------------------------------------------------------
//函数声明:LPCWSTR stringToLPCWSTR(std::string orig);
//函数参数: orig-需要转换的字符串
//函数功能:
// 格式转换
//----------------------------------------------------------------------------------------------
LPCWSTR Tool::stringToLPCWSTR(std::string orig)
{
wchar_t* wcstring = 0;
try
{
size_t origsize = orig.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
if (orig == "")
{
wcstring = (wchar_t*)malloc(0);
mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
}
else
{
wcstring = (wchar_t*)malloc(sizeof(wchar_t) * (orig.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
}
}
catch (std::exception e)
{
}
return wcstring;
}
//----------------------------------------------------------------------------------------------
//函数声明:void Show_text_(const int x, const int y, const std::string text,const int LfHeight,const int Lfwidth, const std::string mode);
//函数参数: 位置及内容还有格式
//函数功能:
// 在指定位置以特定形式显示字符串
//----------------------------------------------------------------------------------------------
void Tool::Show_text_(const int x, const int y, const std::string text,const int LfHeight,const int Lfwidth, const std::string mode)
{
LOGFONT f;
gettextstyle(&f); // 获取当前字体设置
f.lfHeight = LfHeight; // 设置字体高度为 48
_tcscpy_s(f.lfFaceName, this->stringToLPCWSTR(mode)); // 设置字体为“黑体”(高版本 VC 推荐使用 _tcscpy_s 函数)
f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
settextstyle(&f); // 设置字体样式
outtextxy(x, y,this->stringToLPCWSTR(text));
}
//----------------------------------------------------------------------------------------------
//函数声明:char ProcessInput();
//函数参数: 无
//函数功能:
// 获取用户输入情况
//----------------------------------------------------------------------------------------------
char Tool::ProcessInput()
{
if (_kbhit()) //监听键盘输入
{
return _getch();
}
return NULL;
}
Game_properties.h
//----------------------------------------------------------------------------
// Tetris v1.0
// 作者 : yk
//----------------------------------------------------------------------------
//
// email: iamabirdyk219@gmail.com
//
//
//----------------------------------------------------------------------------
// 说明:
// 该程序为2019年东北林业大学课程设计。
// 本人仅完成了俄罗斯方块的基本实现。就
// 目前来看,它已经能让我在闲暇之余体味
// 小游戏的妙处,并且该小游戏借助Easy X
// 大大节约了在编写中的繁杂过程。
// 如发现问题请联系我,互相学习交流。
//
//
//
// v1.0 June 2019
//
//----------------------------------------------------------------------------
#ifndef GAME_PROPERTIES_H
#define GAME_PROPERTIES_H
//判断游戏坐标下方块存在的状态
struct Block_site
{
bool state; //状态,有方块为true 无则false
short Block_type; //方块类型
}block_site[22][14];;
enum Square_Type // 定义七种方块色型
{
Type_A = 1, Type_B, Type_C, Type_D, Type_E, Type_F, Type_G
};
struct Place_active // 方块在底板中的位置。
{
short X; // 保存x坐标。
short Y; // 保存y坐标。
}place_active_now = { 3, 0 }, place_active_next;
struct Place_review //预览方块的位置
{
short X;
short Y;
}place;
struct Form //方块的形状
{
int box[2]; // 每一个数组表示方块两行
int type; //每个方块的类型
int next; //下一个方块的编号
}form[] =
{
{ 0x88, 0xc0, Type_A, 1 },//L
{ 0xe8, 0x0, Type_A, 2 },
{ 0xc4, 0x40, Type_A, 3 },
{ 0x2e, 0x0, Type_A, 0 },
{ 0x44, 0xc0, Type_B, 5 },//L
{ 0x8e, 0x0, Type_B, 6 },
{ 0xc8, 0x80, Type_B, 7 },
{ 0xe2, 0x0, Type_B, 4 },
{ 0x8c, 0x40, Type_C, 9 },
{ 0x6c, 0x0, Type_C, 8 },
{ 0x4c, 0x80, Type_D, 11 },//z
{ 0xc6, 0x0, Type_D, 10 },
{ 0x4e, 0x0, Type_E, 13 },//山
{ 0x8c, 0x80, Type_E, 14 },
{ 0xe4, 0x0, Type_E, 15 },
{ 0x4c, 0x40, Type_E, 12 },
{ 0x88, 0x88, Type_F, 17 },//I
{ 0xf0, 0x0, Type_F, 16 },
{ 0xCC, 0x0, Type_G, 18 },//田
};
#endif // !GAME_PROPERTIES_H