不知不觉工作有一段时间了,感觉总在忙碌,却不知道学到了多少东西,同样感觉到跟别人的差距越来越大。很多东西要学却又有些没有方向。工作也有些不稳定,心情挺郁闷的,动力都少了些。不吐槽了,言归正传。

界面用Qt实现的。

box3 box1 box2

原理很简单,可以看到游戏里界面上有六种元素:

BoxAtDest = 0 ,
BoxOnRoad,
EmptyBlock,
TheBoy,
Wall,
Dest,
Error(暂时没有用到)

根据前面是什么元素来判断下一步数据如何更新,界面从数据取然后试图表现出来就可以了。

需要从txt文件里读取关卡内容。

想写一个自动推的路径算法,不过没想出来。

所有的源代码,程序里用到的图片就不贴了。。

数据类

#ifndef BOXDATA_H
#define BOXDATA_H

class BoxDataer {

public:
enum State {
BoxAtDest = 0 ,
BoxOnRoad,
EmptyBlock,
TheBoy,
Wall,
Dest,
Error
};
enum Direction {
Up = 0,
Down,
Right,
Left
};

BoxDataer() {}

bool loadFile();
bool boyMove(Direction d);
void print();
State at(int i, int j) { return mStateData[i][j]; }

void getSize(int &w, int &h)
{
w = mRows;
h = mCols;
}

void getBoyPos(int &i, int &j)
{
i = mBoyPosRow;
j = mBoyPosCol;
}

private:
State char2State(char c);
void setBoyPos(int i, int j)
{
mBoyPosRow = i;
mBoyPosCol = j;
}

private:
int mBoyPosRow;
int mBoyPosCol;

State mBoyState;
int mRows;
int mCols;
State **mStateData;
};


#endif//BOXDATA_H

每个小单元的类(算是视图类的辅助类?)

#ifndef CELLWIDGET_H
#define CELLWIDGET_H

#include <QWidget>

class QPaintEvent;
class QPixmap;
class CellWidget : public QWidget {

public:
CellWidget(QWidget *parent = NULL);

void setPix(QPixmap *p) { mPix = p; }

protected:
virtual void paintEvent(QPaintEvent *e);

private:
QPixmap *mPix;
};
#endif//CELLWIDGET_H

视图类:

#ifndef GAMEWIDGET_H
#define GAMEWIDGET_H

#include <QWidget>
#include "BoxDataer.h"

class QLabel;
class QKeyEvent;
class CellWidget;
class QPaintEvent;
typedef CellWidget* CellWidgetPtr;

class GameWidget : public QWidget {
Q_OBJECT
public:
GameWidget(QWidget *parent = NULL);

protected:
virtual void keyPressEvent(QKeyEvent *e);
virtual void paintEvent(QPaintEvent *e);

private:
bool go(BoxDataer::Direction r);
QPixmap *state2Pix(BoxDataer::State s);
void check();

private:

CellWidgetPtr **mCellWidget;

QLabel *mBoxCounterLabel;

QPixmap *mBoxAtDest;
QPixmap *mBoxOnRoad;
QPixmap *mEmptyBlock;
QPixmap *mTheBoy;
QPixmap *mWall;
QPixmap *mDest;

int mRows;
int mCols;
int mBoxOnRoadCount;

bool success;

BoxDataer *mBoxDataer;
};
#endif//GAMEWIDGET_H

相关的实现,代码冗余其实挺多的,看不惯的自己可以改下。。。

#include <iostream>
#include <stdio.h>
using namespace std;
#include "BoxDataer.h"

bool BoxDataer::loadFile()
{
FILE *fp = fopen("./Box/stage.txt","r");
fscanf(fp,"%d",&mRows);
fscanf(fp,"%d",&mCols);
cout << mRows << mCols << endl;

mStateData = new State*[mRows];
for ( int i=0; i<mRows; ++i)
mStateData[i] = new State[mCols];

int boyCounter = 0;
int destCounter = 0;
int boxCounter = 0;

for ( int i=0; i<mRows; i++) {
for ( int j=0; j<mCols; j++) {
char temp = '\n';
while (temp=='\n' || temp=='\r') {
fscanf(fp,"%c",&temp);
}

mStateData[i][j] = char2State(temp);
if (mStateData[i][j]==Error)
return false;
else if (mStateData[i][j]==TheBoy) {
boyCounter++;
mBoyPosRow = i;
mBoyPosCol = j;
}
else if (mStateData[i][j]==Dest)
destCounter++;
else if (mStateData[i][j]==BoxOnRoad)
boxCounter++;
}
}

fclose(fp);
if (boyCounter!=1) return false;
if (destCounter!=boxCounter) return false;
mBoyState = EmptyBlock;

print();
return true;
}

bool BoxDataer::boyMove(Direction d)
{
printf("boyMove,d: %d,%d,%d,%d,%d\n",d,Up,Down,Right,Left);
int nexti = mBoyPosRow;
int nextj = mBoyPosCol;
int next2i = mBoyPosRow;
int next2j = mBoyPosCol;

switch(d) {
case Up:
nexti = mBoyPosRow - 1;
next2i = mBoyPosRow - 2;
break;
case Down:
nexti = mBoyPosRow + 1;
next2i = mBoyPosRow + 2;
break;
case Right:
nextj = mBoyPosCol + 1;
next2j = mBoyPosCol + 2;
break;
case Left:
nextj = mBoyPosCol - 1;
next2j = mBoyPosCol - 2;
break;
default:
printf("wrong direction\n");
return false;
}

printf("next: %d,%d,next2: %d,%d\n",nexti,nextj,next2i,next2j);
switch (mStateData[nexti][nextj]) {
case Wall:
cout << __LINE__ << endl;
return false;
case EmptyBlock:
cout << __LINE__ << endl;
mStateData[mBoyPosRow][mBoyPosCol] = mBoyState;
mStateData[nexti][nextj] = TheBoy;
setBoyPos(nexti,nextj);
mBoyState = EmptyBlock;
return true;
case Dest:
cout << __LINE__ << endl;
mStateData[mBoyPosRow][mBoyPosCol] = mBoyState;
mStateData[nexti][nextj] = TheBoy;
setBoyPos(nexti,nextj);
mBoyState = Dest;
return true;
case BoxOnRoad:
cout << __LINE__ << endl;
switch(mStateData[next2i][next2j]) {
case Dest:
cout << __LINE__ << endl;
mStateData[mBoyPosRow][mBoyPosCol] = mBoyState;
mStateData[nexti][nextj] = TheBoy;
setBoyPos(nexti,nextj);
mStateData[next2i][next2j] = BoxAtDest;
mBoyState = EmptyBlock;
return true;
case EmptyBlock:
cout << __LINE__ << endl;
mStateData[mBoyPosRow][mBoyPosCol] = mBoyState;
mStateData[nexti][nextj] = TheBoy;
setBoyPos(nexti,nextj);
mStateData[next2i][next2j] = BoxOnRoad;
mBoyState = EmptyBlock;
return true;
default:
return false;
}
case BoxAtDest:
cout << __LINE__ << endl;
switch(mStateData[next2i][next2j]) {
case Dest:
cout << __LINE__ << endl;
mStateData[mBoyPosRow][mBoyPosCol] = mBoyState;
mStateData[nexti][nextj] = TheBoy;
setBoyPos(nexti,nextj);
mStateData[next2i][next2j] = BoxAtDest;
mBoyState = Dest;
return true;
case EmptyBlock:
cout << __LINE__ << endl;
mStateData[mBoyPosRow][mBoyPosCol] = mBoyState;
mStateData[nexti][nextj] = TheBoy;
setBoyPos(nexti,nextj);
mStateData[next2i][next2j] = BoxOnRoad;
mBoyState = Dest;
return true;
default:
return false;
}
}
}

BoxDataer::State BoxDataer::char2State(char c)
{
switch (c) {
case 'O':
return BoxAtDest;
case 'B':
return BoxOnRoad;
case ' ':
return EmptyBlock;
case 'M':
return TheBoy;
case '#':
return Wall;
case 'o':
return Dest;
default:
cout << "wrong file content" << endl;
return Error;
}
}

void BoxDataer::print()
{
for ( int i=0; i<mRows; ++i) {
for ( int j=0; j<mCols; ++j)
cout << mStateData[i][j];
cout << endl;
}
}

#include <QPixmap>
#include <QPainter>
#include "CellWidget.h"

CellWidget::CellWidget(QWidget *parent) :
QWidget(parent)
{
setFixedSize(30,30);
setFocusPolicy(Qt::NoFocus);
}

void CellWidget::paintEvent(QPaintEvent *e)
{
QPainter painter(this);
painter.drawPixmap(0,0,*mPix);
QWidget::paintEvent(e);
}

#include <QKeyEvent>
#include <QLabel>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QPainter>
#include "GameWidget.h"
#include "CellWidget.h"
#include <iostream>
using namespace std;

GameWidget::GameWidget(QWidget *parent) :
QWidget(parent)
{
mBoxAtDest = new QPixmap("./Box/BoxAtDestination");
mBoxOnRoad = new QPixmap("./Box/BoxOnRoad");
mEmptyBlock = new QPixmap("./Box/EmptyBlock");
mTheBoy = new QPixmap("./Box/TheBoy");
mWall = new QPixmap("./Box/Wall");
mDest = new QPixmap("./Box/Destination");

mBoxDataer = new BoxDataer();

while (!mBoxDataer->loadFile()) {
cout << "wrong file" << endl;
//TODO
}

QGridLayout *cellLayout = new QGridLayout;
cellLayout->setSpacing(0);
mBoxDataer->getSize(mRows,mCols);
cout << mRows << mCols << endl;
mCellWidget = new CellWidgetPtr*[mRows];
for ( int i=0; i<mRows; i++)
mCellWidget[i] = new CellWidgetPtr[mCols];

for ( int i=0; i<mRows; i++)
for ( int j=0; j<mCols; j++) {
mCellWidget[i][j] = new CellWidget(this);
mCellWidget[i][j]->setPix(state2Pix(mBoxDataer->at(i,j)));
cellLayout->addWidget(mCellWidget[i][j],i,j);
cellLayout->setColumnStretch(0,j);
}
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->addLayout(cellLayout);

QVBoxLayout *rightLayout = new QVBoxLayout;
mBoxCounterLabel = new QLabel("",this);
mBoxCounterLabel->setFixedWidth(40);
mBoxCounterLabel->setFrameShape(QFrame::Box);
mBoxCounterLabel->setFrameShadow(QFrame::Raised);

rightLayout->addWidget(mBoxCounterLabel);
rightLayout->addStretch();
mainLayout->addLayout(rightLayout);
mainLayout->addStretch(1);
setLayout(mainLayout);
setAutoFillBackground(true);
setBackgroundRole(QPalette::Dark);
}

QPixmap *GameWidget::state2Pix(BoxDataer::State s)
{
switch (s) {
case BoxDataer::BoxAtDest:
return mBoxAtDest;
case BoxDataer::BoxOnRoad:
return mBoxOnRoad;
case BoxDataer::EmptyBlock:
return mEmptyBlock;
case BoxDataer::TheBoy:
return mTheBoy;
case BoxDataer::Wall:
return mWall;
case BoxDataer::Dest:
return mDest;
default:
return NULL;
}
}

void GameWidget::keyPressEvent(QKeyEvent *e)
{
BoxDataer::Direction d;
switch(e->key()) {
case Qt::Key_Up:
d = BoxDataer::Up;
break;
case Qt::Key_Down:
d = BoxDataer::Down;
break;
case Qt::Key_Right:
d = BoxDataer::Right;
break;
case Qt::Key_Left:
d = BoxDataer::Left;
break;
default:
return;
}

if (mBoxDataer->boyMove(d)) {
int m,n;
mBoxDataer->getBoyPos(m,n);
for (int i=m-2; i<=m+2; ++i)
for ( int j=n-2; j<=n+2; ++j)
if (i>=0 && i<mRows && j>=0 && j<mCols)
mCellWidget[i][j]->setPix(state2Pix(mBoxDataer->at(i,j)));
update();
}

check();
if (mBoxOnRoadCount==0)
QMessageBox::information(this,"U Win","WellPlay,Go Next Game");
}

void GameWidget::check()
{
mBoxOnRoadCount = 0;
for ( int i=0; i<mRows; ++i)
for ( int j=0; j<mCols; ++j)
if (mBoxDataer->at(i,j)==BoxDataer::BoxOnRoad)
mBoxOnRoadCount++;
mBoxCounterLabel->setText(QString(" ") + QString::number(mBoxOnRoadCount) + QString(" "));
}

void GameWidget::paintEvent(QPaintEvent *e)
{
QPainter painter(this);
painter.fillRect(rect(),Qt::black);

QWidget::paintEvent(e);
}

用到的txt文件

 

8
6
######
## ##
#MB ##
# BB##
# o B#
#oB #
#ooOo#
######