当前位置:首页 » 《随便一记》 » 正文

Visual C++实现俄罗斯方块游戏实战三:核心算法设计与实现(附源码和资源)

7 人参与  2023年04月01日 19:21  分类 : 《随便一记》  评论

点击全文阅读


需要源码和资源请点赞关注收藏后评论区留言私信~~~

一、主游戏类的设计

俄罗斯方块的主游戏类负责显示游戏界面,方块游戏等级等内容,同时还要管理游戏的输入操作

可以分为以下几个模块

1:游戏界面和方块的显示

2:游戏操作输入的处理

3:游戏计分的处理

4:游戏升级的处理

下面是主游戏类的实现代码

主游戏类的声明中包括消行处理,方块移动,碰撞判断,方块随机出现等成员函数

#ifndef __RUSSIA_H__#define __RUSSIA_H__#include "Rule.h"#define KEY_LEFT 1#define KEY_RIGHT 2#define KEY_DOWN 3#define KEY_UP 4class CRussia  {public:void HeroWrite();CRussia();virtual ~CRussia();void LineDelete();void Move(int direction);bool Change(int a[][4],CPoint p,int  b[][100]);bool Meet(int a[][4],int direction,CPoint p);//判碰撞void DrawWill();//绘将要出现方块void DrawBK(CDC*pDC);//绘界面void DrawScore(CDC*pDC);//绘分数void GameStart();//游戏开始int Russia[100][100];//游戏数组int Now[4][4];// 当前图形int Will[4][4];//上一图形int After[4][4];//变换后的图形CPoint NowPosition;//当前图形的左上角位置int Count;//当前可能出现的图形形状数,bool end;  //游戏结束int m_Level;//级别int m_Speed;//速度int m_Score;    //分数int m_CountLine;//合计消除行数int m_RowCount,m_ColCount;//行列数CBitmap fkMap;//方块CBitmap bkMap;//界面CRule rule;//游戏规则对象};#endif

主游戏类的基本功能函数中包括构造函数,析构函数以及绘制方块函数等,代码如下

#include "stdafx.h"#include "Tetris.h"#include "Russia.h"#include "HeroDlg.h"////构造函数//CRussia::CRussia(){bkMap.LoadBitmap(IDB_BACK);fkMap.LoadBitmap(IDB_FANGKUAI);}////析构函数//CRussia::~CRussia(){}////行消除函数//void CRussia::LineDelete(){int m=0;//本次共消去的行数bool flag=0;for(int i=0;i<m_RowCount;i++){//检查要不要消行flag=true;for(int j=0;j<m_ColCount;j++){if(Russia[i][j]==0){flag=false;}}//如果要if(flag==true){m++;for(int k=i;k>0;k--){//上行给下行for(int l=0;l<m_ColCount;l++){Russia[k][l]=Russia[k-1][l];}}//第一行为零for(int l=0;l<m_ColCount;l++){Russia[0][l]=0;}}}DrawWill();//加分switch(m){case 1:m_Score= m_Score + 10 + m_Level * 10;break;case 2:m_Score= m_Score + 30 + m_Level * 10;break;case 3:m_Score= m_Score + 50 + m_Level * 10;break;case 4:m_Score= m_Score + 100 + m_Level * 10;break;default:break;}m_CountLine+=m;m_Level = rule.UpLevel(m_CountLine);end = rule.Win(Now, Russia, NowPosition);//速度m_Speed=320 - m_Level * 20;if(end){HeroWrite();}}////移动方块//void CRussia::Move(int direction){if(end) return;switch(direction){//左case KEY_LEFT:if(Meet(Now,KEY_LEFT,NowPosition)) break;NowPosition.y--;break;//右case KEY_RIGHT:if(Meet(Now,KEY_RIGHT,NowPosition)) break;NowPosition.y++;break;//下case KEY_DOWN:if(Meet(Now,KEY_DOWN,NowPosition)){LineDelete();break;}NowPosition.x++;break;//上case KEY_UP:Meet(Now,KEY_UP,NowPosition);break;default:break;}}////方块旋转//bool CRussia::Change(int a[][4],CPoint p,int  b[][100]){int tmp[4][4];int i,j;int k=4,l=4;for(i=0;i<4;i++){for(j=0;j<4;j++){tmp[i][j]=a[j][3-i];After[i][j]=0;//存放变换后的方块矩阵}}for(i=0;i<4;i++){for(j=0;j<4;j++){if(tmp[i][j]==1){if(k>i) k=i;if(l>j) l=j;}}}for(i=k;i<4;i++){for(j=l;j<4;j++){After[i-k][j-l]=tmp[i][j];}//把变换后的矩阵移到左上角}//判断是否接触,是:返回失败for(i=0;i<4;i++){for(j=0;j<4;j++){if(After[i][j]==0){continue;}if(((p.x+i)>=m_RowCount)||((p.y+j)<0)||((p.y+j)>=m_ColCount)){return false;}if(b[p.x+i][p.y+j]==1){return false;}}}return true;}////判碰撞,遇到了边界或者有其他方块档住//bool CRussia::Meet(int a[][4],int direction,CPoint p){int i,j;//先把原位置清0 for(i=0;i<4;i++){for(j=0;j<4;j++){if(a[i][j]==1){Russia[p.x+i][p.y+j]=0;}}}for(i=0;i<4;i++){for(j=0;j<4;j++){if(a[i][j]==1){switch(direction){case 1://左移if((p.y+j-1)<0) goto exit;if(Russia[p.x+i][p.y+j-1]==1) goto exit;break;case 2://右移if((p.y+j+1)>=m_ColCount) goto exit;if(Russia[p.x+i][p.y+j+1]==1) goto exit;break;case 3://下移if((p.x+i+1)>=m_RowCount) goto exit;if(Russia[p.x+i+1][p.y+j]==1) goto exit;break;case 4://变换if(!Change(a,p,Russia)) goto exit;for(i=0;i<4;i++){for(j=0;j<4;j++){Now[i][j]=After[i][j];a[i][j]=Now[i][j];}}return false;break;}}}}int x,y;x=p.x;y=p.y;//移动位置,重新给数组赋值switch(direction){case 1:y--;break;case 2:y++;break;case 3:x++;break;case 4:break;}for(i=0;i<4;i++){for(j=0;j<4;j++){if(a[i][j]==1){Russia[x+i][y+j]=1;}}}return false;exit:for(i=0;i<4;i++){for(j=0;j<4;j++){if(a[i][j]==1){Russia[p.x+i][p.y+j]=1;}}}return true;}////绘将出现的方块图//void CRussia::DrawWill(){int i,j;int k=4,l=4;    //把将要出现的方块给当前数组,并把将要出现数组赋值为零for(i=0;i<4;i++){for(j=0;j<4;j++){Now[i][j]=Will[i][j];Will[i][j]=0;}}//初始化随即数种子srand(GetTickCount());int nTemp=rand()%Count;//各种图形switch(nTemp){case 0:Will[0][0]=1;Will[0][1]=1;Will[1][0]=1;Will[1][1]=1;break;case 1:Will[0][0]=1;Will[0][1]=1;Will[1][0]=1;Will[2][0]=1;break;case 2:Will[0][0]=1;Will[0][1]=1;Will[1][1]=1;Will[2][1]=1;break;case 3:Will[0][1]=1;Will[1][0]=1;Will[1][1]=1;Will[2][0]=1;break;case 4:Will[0][0]=1;Will[1][0]=1;Will[1][1]=1;Will[2][1]=1;break;case 5:Will[0][0]=1;Will[1][0]=1;Will[1][1]=1;Will[2][0]=1;break;case 6:Will[0][0]=1;Will[1][0]=1;Will[2][0]=1;Will[3][0]=1;break;default:break;}int tmp[4][4];for(i=0;i<4;i++){for(j=0;j<4;j++){tmp[i][j]=Will[j][3-i];}}for(i=0;i<4;i++){for(j=0;j<4;j++){if(tmp[i][j]==1){if(k>i) k=i;if(l>j) l=j;}}}for(i=0;i<4;i++){for(j=0;j<4;j++){Will[i][j]=0;}}//把变换后的矩阵移到左上角for(i=k;i<4;i++){for(j=l;j<4;j++){Will[i-k][j-l]=tmp[i][j];}}//开始位置NowPosition.x=0;NowPosition.y=m_ColCount/2;}////绘游戏界面//void CRussia::DrawBK(CDC*pDC){CDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE){AfxMessageBox("Can't create DC");}//画背景    Dc.SelectObject(bkMap);pDC->BitBlt(0,0,540,550,&Dc,0,0,SRCCOPY);    //画分数,速度,难度DrawScore(pDC);    //如果有方块,显示方块//游戏区for(int i=0;i<m_RowCount;i++){for(int j=0;j<m_ColCount;j++){if(Russia[i][j]==1){Dc.SelectObject(fkMap);pDC->BitBlt(j*30,i*30,30,30,&Dc,0,0,SRCCOPY);}}}//预先图形for(int n=0;n<4;n++){for(int m=0;m<4;m++){if(Will[n][m]==1){Dc.SelectObject(fkMap);pDC->BitBlt(365+m*30,240+n*30,30,30,&Dc,0,0,SRCCOPY);}}}}////绘分数和等级//void CRussia::DrawScore(CDC*pDC){int nOldDC=pDC->SaveDC();//设置字体CFont font;    if(0==font.CreatePointFont(300,"Comic Sans MS")){AfxMessageBox("Can't Create Font");}pDC->SelectObject(&font);    //设置字体颜色及其背景颜色CString str;pDC->SetTextColor(RGB(39,244,10));pDC->SetBkColor(RGB(255,255,0));    //输出数字str.Format("%d",m_Level);if(m_Level>=0)pDC->TextOut(420,120,str);str.Format("%d",m_CountLine);if(m_Speed>=0)pDC->TextOut(420,64,str);str.Format("%d",m_Score);if(m_Score>=0)pDC->TextOut(420,2,str);pDC->RestoreDC(nOldDC);}////游戏开始//void CRussia::GameStart(){end=false;//运行结束标志    m_Score=0;//初始分数m_RowCount=18;//行数m_ColCount=12;//列数Count=7;//方块种类m_CountLine = 0;//合计消除行数为0char pszTmp[128] = {0};//读取当前游戏等级GetPrivateProfileString("SETUP", "level", "1", pszTmp, 127, ".\\setup.ini");m_Level = atoi(pszTmp);//初始等级m_Speed=320 - m_Level * 20;//初始速度rule.SetLevel(m_Level);for(int i=0;i<m_RowCount;i++){for(int j=0;j<m_ColCount;j++){Russia[i][j]=0;}}for(i=0;i<4;i++){for(int j=0;j<4;j++){Now[i][j]=0;Will[i][j]=0;}}//开始时将要出现方块没有生成,其不能赋值给当前方块数组,所以连续调用两次DrawWill();DrawWill();}void CRussia::HeroWrite(){CHeroDlg dlg;char pszTmp[128] = {0};int nHighScore = 0;GetPrivateProfileString("HERO", "score", "0", pszTmp, 127, ".\\hero.ini");nHighScore = atoi(pszTmp);if(m_Score>nHighScore){dlg.SetWriteFlg(TRUE);//设置可写入标志dlg.m_level = m_Level;//设置等级dlg.m_score = m_Score;//设置分数dlg.DoModal();//弹出对话框}else{AfxMessageBox("游戏结束,您未能进入英雄榜!");}}

三、游戏规则类的设计与实现

包括对游戏胜负判断处理与游戏升级处理,实现如下

游戏规则声明类代码如下,包括构造函数,析构函数,升级判断函数以及胜负判断函数等等

#ifndef __RULE_H__#define __RULE_H__class CRule{public:CRule();~CRule();void SetLevel(int nLevel);//设置当前等级int UpLevel(int nLine);//升级判断bool Win(int Now[4][4], int Russia [100][100], CPoint NowPosition);//胜负判断private:int m_nLevel;//当前等级};#endif

实现游戏规则类中的升级判断函数和胜负判断函数,实现代码如下 

#include "stdafx.h"#include "Rule.h"CRule::CRule(){}CRule::~CRule(){}void CRule::SetLevel(int nLevel){m_nLevel = nLevel;}int CRule::UpLevel(int nLine){if(nLine / 30){m_nLevel++;}return m_nLevel;}bool CRule::Win(int Now[4][4], int Russia [100][100], CPoint NowPosition){if(m_nLevel == 11){//消除行数已经超过10级,游戏结束return true;}for(int i=0;i<4;i++){for(int j=0;j<4;j++){if(Now[i][j]==1){//到了顶点if(Russia[i+NowPosition.x][j+NowPosition.y]==1){return true;}}}}return false;}

 

 

 

创作不易 觉得有帮助请点赞关注收藏~~~


点击全文阅读


本文链接:http://zhangshiyu.com/post/57881.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1