📄 qgamewidget.cpp
字号:
/*********************************************************************** * * * linux版仿联众俄罗斯方块 v1.0 * 该软件在GPL(GNU通用公共许可证)下发布 * * Copyright (C) <codeky@126.com> * * This source code is licensed under the GNU General Public License * ************************************************************************/#include <qapplication.h>#include <qpainter.h>#include <qdrawutil.h>#include <qpixmap.h>#include "config.h"#include "qmainwidget.h"#include "qgamewidget.h"#include "qgamethread.h"#define gamelock() gameAccessMutex.lock()#define gameunlock() gameAccessMutex.unlock()extern char curPath[];static QMutex gameAccessMutex; //访问 BLOCK_GAME game 的锁// 访问,修改 都应该加琐,因为存在线程QGameWidget::QGameWidget( QWidget *parent, const char *name ) : QWidget( parent, name ){ InitGame(&game); // 初始状态不必加琐 bPlayMode = ePlaySinle; // 默认为自由模式 bComputerRun = false; clrLastBlockRect(); bRefresh = true; brcolor[0] = Qt::darkRed; brcolor[1] = Qt::red; brcolor[2] = Qt::blue; brcolor[3] = Qt::darkCyan; brcolor[4] = Qt::darkMagenta; brcolor[5] = Qt::darkYellow; brcolor[6] = Qt::darkGreen; egcolor = Qt::lightGray; gamePix = new QPixmap( DEF_GAME_WIDTH,DEF_GAME_HEIGHT ); nextPix = new QPixmap( DEF_BLOCK_SIZE*4,DEF_BLOCK_SIZE*4 ); blockSize = DEF_BLOCK_SIZE ; if(!gamePix) exit(-1); connect( this, SIGNAL(SelPainSignal(int)), SLOT(drawGame(int)) ); setPalette( QPalette( lightGray ));}// 必然是 开始 运行 后 才会调用该 函数void QGameWidget::overDriveDownBlock(){ gamelock(); FixCurBlock(&game); _bS8 n = AdjustGrid(&game); bool newSuccess=true; if(!NewBlock(&game)){ GameOver(&game); newSuccess=false; if(bPlayMode!=ePalyVS) palyAufile("au/lost_attacked.au"); // 对战模式说verygood } gameunlock(); if(!newSuccess){ if( bPlayMode==ePalyVS) emit NoticeOtherWinGame(); }else{ // 游戏仍然继续 if(n==0) palyAufile("au/normal_downed.au"); else if(n==1) palyAufile("au/normal_full_row.au"); else if(n>1) palyAufile("au/multiple_full_row.au"); } emit AddOtherLine(n); emit SelPainSignal(1); // 无论如何都要重绘 clrLastBlockRect(); bRefresh = true;}// 充分利用系统命令~~void QGameWidget::palyAufile(const char * filename){ extern char curPath[]; char cmd[PATH_MAX+50]; sprintf(cmd,"cat %s%s > /dev/audio 2> /dev/null &",curPath,filename); system(cmd);}void QGameWidget::gameAddLine(_bS8 n){ if(bPlayMode!=ePalyVS || n>4 || n<=0 ) return; gamelock(); AddLine(&game,n-1); gameunlock(); emit SelPainSignal(1); //~~}int QGameWidget::gameStatus(){ gamelock(); int s = game.nGameStatus; gameunlock(); return s;}void QGameWidget::startGame(){ gamelock(); NewGame(&game); gameunlock(); drawGame(1);}void QGameWidget::setPlayMode(int mode){ bPlayMode = mode; //}void QGameWidget::setGamePause(bool p){ gamelock(); if(p){ game.nGameStatus = eGamePause; }else{ game.nGameStatus = eGameRun; } gameunlock(); if(p){ drawGame(1); }}void QGameWidget::iWinTheGame() // 自己赢了{ gamelock(); WinGame(&game); gameunlock(); drawGame(1); palyAufile("au/very_good.au");}void QGameWidget::handleKeyEvent( int key){ if(bComputerRun) return; int s= gameStatus(); if(s==eGameRun) { bool b = false; switch(key){ case eMoveTurn: gamelock(); b = MoveBlock(&game,eMoveTurn); gameunlock(); if(b)drawGame(0); break; case eMoveLeft: gamelock(); b = MoveBlock(&game,eMoveLeft); gameunlock(); if(b)drawGame(0); break; case eMoveRight: gamelock(); b = MoveBlock(&game,eMoveRight); gameunlock(); if(b)drawGame(0); break; case eMoveSDown: gamelock(); b = MoveBlock(&game,eMoveDown); gameunlock(); if(!b) overDriveDownBlock(); // 自己有锁 drawGame(0); break; case eMoveDown: gamelock(); while(MoveBlock(&game,eMoveDown)); gameunlock(); overDriveDownBlock(); drawGame(0); break; } }}void QGameWidget::resizeEvent ( QResizeEvent * e){ int c = e->size().width()/GAME_COL; // 列宽 int r = e->size().height()/GAME_ROW;// 行高 blockSize = (c > r) ? r: c; // 选小的 setGeometry(x(),y(),blockSize*GAME_COL,blockSize*GAME_ROW); // 居然这样能行,可能是当下次resize之前,先进行了判断。 gamePix->resize(blockSize*GAME_COL,blockSize*GAME_ROW); bRefresh = true;}void QGameWidget::drawGame(int rBack){ painter_lock(); QPainter p(gamePix); if(rBack | bRefresh){ drawBackGrid(&p); bRefresh = false; // 免得重绘背景,绘图耗时 } switch(gameStatus()){ case eGameRun: case eGamePause: drawClrLastBlock(&p); drawCurBlock(&p); break; case eGameLost: drawOverShow(&p,0); break; case eGameWin: drawOverShow(&p,1); break; } p.end(); p.begin( this ); p.drawPixmap(0,0, *gamePix ); painter_unlock(); drawNextBlock();}void QGameWidget::paintEvent( QPaintEvent * ){ drawGame(1); // 这样就不怕系统刷新了}void QGameWidget::drawOverShow( QPainter *p ,int type ){ char tmpName[PATH_MAX]; if(type==0){ sprintf(tmpName,"%simages/lost.bmp",curPath); }else{ sprintf(tmpName,"%simages/win.bmp",curPath); } QPixmap t(tmpName); int a = t.width(); int b =blockSize*GAME_COL; int c = t.height(); int h = blockSize*GAME_ROW; //新高度 QRect r; if(a>b){ // 图像宽于框框,只考虑这中情况,简单点 b-=6; // 不要压在边框上了 h = c*b/a; if(h) r.setRect(3,(blockSize*GAME_ROW-h)/2,b,h); }else{ r.setRect((b-a)/2,(h-c)/2,a,c); } p->drawPixmap(r,t);}void QGameWidget::drawBackGrid( QPainter *p ){ QRect BlockRect; _bS8 i, j; gamelock(); for(i=GAME_FIRST_ROW;i<=GAME_LAST_ROW;i++) { for(j=GAME_FIRST_COL;j<=GAME_LAST_COL;j++) { BlockRect.setRect((j-GAME_FIRST_COL)*blockSize, (i-GAME_FIRST_ROW)*blockSize, blockSize,+blockSize); if(0!=game.GameGrid.Grid[i][j].bFillBlock) { // p->setBrush( brcolor[game.GameGrid.Grid[i][j].nBlockType] ); // p->drawRect(BlockRect); QBrush br(brcolor[game.GameGrid.Grid[i][j].nBlockType]); qDrawShadeRect(p,BlockRect,colorGroup(),false,1,0,&br); } else { //p->eraseRect(BlockRect); p->fillRect(BlockRect,QBrush(Qt::black)); } } } gameunlock();}void QGameWidget::drawNextBlock(){ QRect BlockRect; if(!nextPix) nextPix = new QPixmap(DEF_BLOCK_SIZE*4,DEF_BLOCK_SIZE*4); nextPix->fill(Qt::black); painter_lock(); QPainter p( nextPix ); int s = gameStatus(); if(s==eGameRun || s== eGamePause){ gamelock(); for(int i=0;i<4;i++) for(int j=0;j<4;j++) { if(GameBlock[game.GameBlock.nNextBlockType][0][i][j]){ BlockRect.setRect(j*DEF_BLOCK_SIZE, i*DEF_BLOCK_SIZE, DEF_BLOCK_SIZE, DEF_BLOCK_SIZE ); QBrush br(brcolor[game.GameBlock.nNextBlockType]); qDrawShadeRect(&p,BlockRect,colorGroup(),false,1,0,&br); } } gameunlock(); } p.end(); painter_unlock(); emit PaintNextSignal(nextPix);}void QGameWidget::drawCurBlock( QPainter *p ){ QRect BlockRect; int nCount=0; gamelock(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { if(GameBlock[game.GameBlock.nCurBlockType][game.GameBlock.nCurBlockStatus][i][j]){ BlockRect.setRect( (game.GameBlock.CurFirstBlock.col+j-GAME_FIRST_COL)*blockSize, (game.GameBlock.CurFirstBlock.row+i-GAME_FIRST_ROW)*blockSize, blockSize, blockSize ); QBrush br(brcolor[game.GameBlock.nCurBlockType]); qDrawShadeRect(p,BlockRect,colorGroup(),false,1,0,&br); LastBlockRect[nCount++]=BlockRect; } } } gameunlock();}void QGameWidget::clrLastBlockRect(){ LastBlockRect[0] =LastBlockRect[1] =LastBlockRect[2] =LastBlockRect[3] =QRect(0,0,0,0);}void QGameWidget::drawClrLastBlock( QPainter *p ){ for(int i=0;i<4;i++) //p->eraseRect(LastBlockRect[i]); p->fillRect(LastBlockRect[i],QBrush(Qt::black));}//-----------------------------------------------------------// 这是一组电脑运行相关的程序,void QGameWidget::setComputerRun(bool r){ bComputerRun = r;}bool QGameWidget::ComputerRun(){ GAME_GRID GridBack; GAME_BLOCK BlockBack; BLOCK_GAME GameBack; BLOCK_GAME CmpGame; GRID_ATTR CurGridAttr; GRID_ATTR BestGridAttr; if( !bComputerRun ) return false; if(gameStatus()!=eGameRun) return false; gamelock(); CopyGame(&GameBack, &game); gameunlock(); _bS8 i=0,j=0; _bS8 TurnCount=0; //需要旋转的次数 _bS8 BestCol=GameBack.GameBlock.CurFirstBlock.col; // 最好状态所在列 unsigned int timer0 = GameBack.nGameTimer; CopyGame(&CmpGame, &GameBack); BestGridAttr.nFullRowCount=-1; // 保证比较不出问题 for(i=0;i<4;i++) { for(j=0;j<i;j++) TurnBlock(&CmpGame); // 旋转i次 while(MoveBlock(&CmpGame,eMoveLeft)); // 移到最左边 do{ CopyGameGrid(&GridBack,&CmpGame.GameGrid); // 保存格子 CopyGameBlock(&BlockBack,&CmpGame.GameBlock); // 保存方块 j=CmpGame.GameBlock.CurFirstBlock.col; while(MoveBlock(&CmpGame,eMoveDown)); // 落下 FixCurBlock(&CmpGame); // 固定 GetGridAttr(&CmpGame,&CurGridAttr); // 获取属性 if(judgeBetterAttr(CurGridAttr,BestGridAttr)){ CopyGridAttr(&BestGridAttr,&CurGridAttr); TurnCount=i; BestCol=j; } CopyGameGrid(&CmpGame.GameGrid,&GridBack); // 恢复格子 CopyGameBlock(&CmpGame.GameBlock,&BlockBack); // 恢复方块 }while(MoveBlock(&CmpGame,eMoveRight)); // 单步向右移动 CopyGame(&CmpGame,&GameBack); // 恢复为初时状态 } /*****************************************************************/ gamelock(); unsigned int timer1 = game.nGameTimer; gameunlock(); if(timer0 != timer1) return false; return driveBlockRun(TurnCount,BestCol);}#define HaveNewGame_OR_Dirtied() \do{ \ if(timer0!=timer1){ \ return false; \ } \ if(dirty){ \ gamelock(); \ game.bDirty = _bFalse; \ gameunlock(); \ return false; \ } \}while(0)bool QGameWidget::driveBlockRun(int status, int col){ gamelock(); unsigned int timer0 = game.nGameTimer; _bBool dirty = game.bDirty; gameunlock(); unsigned int timer1 = timer0; while(status-->0) { gamelock(); timer1 = game.nGameTimer; dirty = game.bDirty; gameunlock(); HaveNewGame_OR_Dirtied(); gamelock(); TurnBlock(&game); gameunlock(); emit SelPainSignal(0); QGameThread::msleep(100); }; _bBool b = _bTrue; while(1){ gamelock(); timer1 = game.nGameTimer; dirty = game.bDirty; b = game.GameBlock.CurFirstBlock.col>col; gameunlock(); HaveNewGame_OR_Dirtied(); if(!b) break; gamelock(); MoveBlock(&game,eMoveLeft); gameunlock(); emit SelPainSignal(0); QGameThread::msleep(100); }; while(1){ gamelock(); b = game.GameBlock.CurFirstBlock.col<col; timer1 = game.nGameTimer; dirty = game.bDirty; gameunlock(); HaveNewGame_OR_Dirtied(); if(!b) break; gamelock(); MoveBlock(&game,eMoveRight); gameunlock(); emit SelPainSignal(0); QGameThread::msleep(100); }; do{ gamelock(); timer1 = game.nGameTimer; dirty = game.bDirty; gameunlock(); HaveNewGame_OR_Dirtied(); gamelock(); b = MoveBlock(&game,eMoveDown); gameunlock(); emit SelPainSignal(0); QGameThread::msleep(50); }while(b); overDriveDownBlock(); // 自己有锁 emit SelPainSignal(1); return true;}bool QGameWidget::judgeBetterAttr(const GRID_ATTR& CurAttr, const GRID_ATTR& BestAttr){ if(CurAttr.nFullRowCount>BestAttr.nFullRowCount){ return true; } else if(CurAttr.nFullRowCount==BestAttr.nFullRowCount || BestAttr.nFullRowCount==1){ if(CurAttr.nIdleBankCount<BestAttr.nIdleBankCount){ return true; }else if(CurAttr.nIdleBankCount ==BestAttr.nIdleBankCount){ if(CurAttr.nLastBlockFirstRow >BestAttr.nLastBlockFirstRow){ return true; }else if(CurAttr.nLastBlockFirstRow ==BestAttr.nLastBlockFirstRow) { if(CurAttr.nMostHighEdgeHeight <BestAttr.nMostHighEdgeHeight) return true; else if(CurAttr.nMostHighEdgeHeight ==BestAttr.nMostHighEdgeHeight) { if(CurAttr.nHighEdgeCount <=BestAttr.nHighEdgeCount){ return true; } } } } } return false;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -