翻看1年前的帖子,感慨呀。。。这个代码。。还是稚嫩了一点。
现在编程风格也改了很多。而且逐渐的抛弃了LINUX,转为WIN程序员。
谢谢大家的支持,补上个图把
复制下面地址,在浏览器访问:
学C++和linux有1.5年了,但是来论坛才没几天。昨天发个帖子,大家回复都很热情
,谢谢各位帮助!(昨天帖子地址是 )
这个方块游戏是用linux终端的光标控制、颜色设置做的
用 A S D W 控制移动、转向,空格键下坠到底;
最初是2个线程,1个用来显示画面,1个用来接收用户输入;
后来改用单线程,linux的异步aio函数解决了很多麻烦;
用了个简单的模板单例模式,继承它就可以;
对POSIX线程简单封装成java线程接口;
bug不少,大家不吝指教和建议。
///////////main.cpp
-
#include
-
#include "Tetris.h"
-
#include "TtyAuto.h"
-
-
int main(int ac, char *av[])
-
{
-
std::auto_ptr autoAdjustTty(TtyAuto::getInstance());
-
-
Tetris game;
-
game.start();
-
game.join();
-
-
printf("\t\t\t\t\t\t\t\t\r");
-
printf("GAME OVER!\n");
-
-
return 0;
-
}
复制代码
///////// Thread.h
-
#ifndef BERT_THREAD_H
-
#define BERT_THREAD_H
-
-
#include
-
-
/**
-
* 线程封装,接口模仿JAVA
-
*/
-
class Runnable
-
{
-
public:
-
virtual ~Runnable() { }
-
-
/**
-
* 线程逻辑在此实现
-
*/
-
virtual void run() = 0;
-
};
-
-
class Thread: public Runnable
-
{
-
/**
-
* 本线程ID
-
*/
-
pthread_t m_tid;
-
-
/**
-
* 是否在运行的标志
-
*/
-
bool running;
-
-
/**
-
* 线程函数,内部调用run
-
*/
-
static void * threadFunc(void * arg);
-
-
public:
-
Thread();
-
~Thread();
-
-
/**
-
* 睡眠 秒
-
*/
-
static unsigned int sleep( unsigned int seconds);
-
-
/**
-
* 睡眠毫秒
-
*/
-
static unsigned int msleep( unsigned int mSeconds);
-
-
/**
-
* 启动线程
-
*/
-
bool start() ;
-
-
/**
-
* 等待本线程运行完
-
*/
-
void join() const;
-
-
/**
-
* 是否在运行
-
*/
-
bool isAlive() const
-
{
-
return running;
-
}
-
-
/**
-
* 终止线程运行
-
*/
-
void stop()
-
{
-
running = false;
-
}
-
};
-
-
#endif
复制代码
//////// Thread.cc
-
#include
-
#include
-
#include
-
#include "Thread.h"
-
-
Thread::Thread( ) : running(false)
-
{
-
}
-
-
Thread::~Thread()
-
{
-
}
-
-
void * Thread::threadFunc(void * arg)
-
{
-
Thread * r = (Thread *) arg;
-
r->running = true;
-
srand(time(NULL));
-
r->run();
-
::pthread_exit(NULL);
-
return NULL;
-
}
-
-
unsigned int Thread::sleep( unsigned int seconds)
-
{
-
return ::sleep(seconds);
-
}
-
-
unsigned int Thread::msleep( unsigned int mSeconds)
-
{
-
return ::usleep(mSeconds * 1000U);
-
}
-
-
bool Thread::start()
-
{
-
if ( !running )
-
{
-
if ( ::pthread_create(&m_tid, NULL, threadFunc, this ) )
-
return false;
-
}
-
return true;
-
}
-
-
void Thread::join() const
-
{
-
::pthread_join(m_tid, NULL);
-
}
复制代码
/// 俄罗斯方块头文件
-
#ifndef BERT_TETRIS_H
-
#define BERT_TETRIS_H
-
-
#include
-
#include
-
-
#include "Thread.h"
-
-
/**
-
* 一个用printf做的linux俄罗斯方块
-
*/
-
-
class Tetris : public Thread
-
{
-
public:
-
Tetris();
-
~Tetris();
-
private:
-
enum BOARD_T
-
{
-
TYPE_BLANK = 0, //空白
-
TYPE_BLOCK, //阻挡
-
TYPE_BORDER, //边界
-
-
TYPE_MAX = 3,
-
};
-
-
/**
-
* 游戏背景,尺寸
-
*/
-
static const int HEIGHT = 22;
-
static const int WIDTH = 14;
-
BOARD_T board[HEIGHT][WIDTH] ;
-
-
/**??是否用volatile
-
* 当前活动方块的坐标
-
*/
-
int curx, cury;
-
-
/**
-
* 当前活动方块的样式及翻转形状
-
*/
-
int curstyle;
-
int curpos;
-
-
/**
-
* 当前活动方块的颜色
-
*/
-
int curcolor ;
-
-
/**
-
* 玩家当前得分和等级
-
*/
-
unsigned int score;
-
unsigned short level;
-
static const unsigned short MAXLEVEL = 9;
-
-
/**
-
* 一个方块的定义
-
*/
-
typedef std::bitset<16> Block;
-
-
/**
-
* 方块的样式种类
-
*/
-
static const unsigned short STYLE_MAX = 7;
-
-
/**
-
* 当前活动方块与下一个方块
-
*/
-
Block activeBlock, nextBlock;
-
-
/**
-
* 现在是否有活动方块?
-
*/
-
bool active;
-
-
/**
-
* 方块样式预定义
-
*/
-
static const unsigned short _styles_[STYLE_MAX][4] ;
-
Block styles[STYLE_MAX][4];
-
-
/**
-
* 初始化方块样式
-
*/
-
void initStyles();
-
-
/**
-
* 显示分数
-
*/
-
void drawScore();
-
-
/**
-
* 显示等级
-
*/
-
void drawLevel();
-
-
/**
-
* 显示下一个方块
-
*/
-
void drawNext();
-
-
/**
-
* 异步IO,使得单线程能完成显示和响应键盘的功能
-
*/
-
struct aiocb cb;
-
static const int SIZE = 16;
-
unsigned char inputBuf[SIZE];
-
friend void handler(int sig, siginfo_t *info, void * context);
-
-
/**
-
* 初始化背景数据
-
*/
-
void initBackground();
-
-
/**
-
* 绘制游戏画面
-
*/
-
void paint(int srcx = 0, int dstx = HEIGHT);
-
-
/**
-
* 判断方块是否与阻挡或边界冲突
-
*/
-
bool isCollide();
-
-
/**
-
* 消行,并返回削去的行数(0-4)
-
*/
-
int removeLines();
-
-
/**
-
* 判断line行是否为空
-
*/
-
bool isEmptyLine(int line);
-
-
/**
-
* 根据消行,返回应得分数
-
*/
-
static const unsigned short bonus[5];
-
-
/**
-
* 达到相应等级所需要的分数;10-levels
-
*/
-
static const unsigned int levels[10];
-
-
/**
-
* 根据得分,计算等级
-
*/
-
static unsigned short getLevel(unsigned int score);
-
-
/**
-
* 线程函数,游戏逻辑
-
*/
-
virtual void run();
-
};
-
-
#endif
复制代码
//////////// 俄罗斯方块 实现
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#include "Tetris.h"
-
-
// 清除屏幕
-
#define CLEAR() printf("\033[2J")
-
-
// 上移光标
-
#define MOVEUP(x) printf("\033[%dA", (x))
-
// 下移光标
-
#define MOVEDOWN(x) printf("\033[%dB", (x))
-
// 左移光标
-
#define MOVELEFT(y) printf("\033[%dD", (y))
-
// 右移光标
-
#define MOVERIGHT(y) printf("\033[%dC",(y))
-
-
// 定位光标
-
#define MOVETO(x,y) printf("\033[%d;%dH", (x), (y))
-
// 光标复位
-
#define RESET_CURSOR() printf("\033[H")
-
-
// 隐藏光标
-
#define HIDE_CURSOR() printf("\033[?25l")
-
// 显示光标
-
#define SHOW_CURSOR() printf("\033[?25h")
-
-
// 画背景
-
#define DRAW_BLANK() printf("\033[1;31;40m%s\033[0m",". " )
-
// 画阻挡
-
#define DRAW_BLOCK() printf("\033[7m\033[1;37;40m%s\033[0m", "[]" )
-
// 画活动方块
-
#define DRAW_ACTIVE_BLOCK() printf("\033[7m\033[1;%d;40m%s\033[0m",curcolor, "[]" )
-
// 画边界
-
#define DRAW_BORDER() printf("\033[1;33;43m%s\033[0m", "||" )
-
// 随机获得一种颜色
-
#define GET_COLOR() (rand()%6 + 31)
-
-
const int Tetris::HEIGHT;
-
const int Tetris::WIDTH;
-
const int Tetris::SIZE;
-
const unsigned short Tetris::STYLE_MAX;
-
const unsigned short Tetris::MAXLEVEL;
-
const unsigned short Tetris::bonus[5] = {0, 100, 300, 600, 1000};
-
const unsigned int Tetris::levels[MAXLEVEL+1] = {0, 10000, 30000, 60000, 100000, 150000, 210000, 280000, 360000, 450000};
-
-
const unsigned short Tetris::_styles_[STYLE_MAX][4] = {
-
{0x000f, 0x4444, 0x000f, 0x4444},
-
{0x004e, 0x0464, 0x00e4, 0x04c4},
-
{0x0462, 0x006c, 0x0462, 0x006c},
-
{0x0264, 0x00c6, 0x0264, 0x00c6},
-
{0x0622, 0x0017, 0x0223, 0x0074},
-
{0x0644, 0x00e2, 0x044c, 0x008e},
-
{0x0066, 0x0066, 0x0066, 0x0066},
-
};
-
-
unsigned short Tetris::getLevel(unsigned int score )
-
{
-
int low = 0, high = MAXLEVEL;
-
int mid;
-
-
while ( true )
-
{
-
mid = (low + high ) / 2;
-
-
if ( score >= levels[mid])
-
{
-
if ( mid==MAXLEVEL || score < levels[mid+1])
-
return mid;
-
else
-
low = mid + 1;
-
}
-
else//不可能是mid等级
-
{
-
assert(mid>0);
-
high = mid - 1;
-
}
-
}
-
}
-
-
Tetris::Tetris() : score(0), level(0), active(false)
-
{
-
bzero(&cb, sizeof(cb));
-
initStyles();
-
initBackground();
-
HIDE_CURSOR();
-
}
-
-
Tetris::~Tetris()
-
{
-
SHOW_CURSOR();
-
}
-
-
void Tetris::initStyles()
-
{
-
for ( int i=0; i
-
{
-
for ( int j=0; j<4; ++j)
-
{
-
styles[i][j] = _styles_[i][j];
-
}
-
}
-
}
-
-
void Tetris::initBackground()
-
{
-
for ( int i=0; i
-
for( int j=0; j
-
{
-
if ( i==0 || j==0 || i==HEIGHT-1 || j==WIDTH-1)
-
board[i][j] = TYPE_BORDER;
-
else
-
board[i][j] = TYPE_BLANK;
-
}
-
}
-
-
void Tetris::paint(int srcx, int dstx)
-
{
-
if ( dstx > HEIGHT )
-
dstx = HEIGHT-1;
-
-
for ( int i=srcx; i
-
{
-
for ( int j=0; j
-
{
-
if ( board[i][j] == TYPE_BORDER )
-
{
-
DRAW_BORDER();
-
continue;
-
}
-
-
if ( i>=curx && i=cury && j
-
{
-
if ( board[i][j] == TYPE_BLANK && activeBlock[(i-curx)*4 + j-cury] == TYPE_BLANK )
-
DRAW_BLANK();
-
else
-
DRAW_ACTIVE_BLOCK();
-
}
-
else
-
{
-
if ( board[i][j] == TYPE_BLOCK )
-
DRAW_BLOCK();
-
else
-
DRAW_BLANK();
-
}
-
}
-
printf("\n");
-
}
-
}
-
-
void Tetris::drawScore()
-
{
-
MOVETO(2, 2*WIDTH+2);
-
-
printf("\033[7m\033[1;33;46m");
-
printf(" SCORE: ");
-
printf("\033[1;37;40m %-8u", score);
-
printf("\033[0m");
-
}
-
-
void Tetris::drawLevel()
-
{
-
MOVETO(6, 2*WIDTH+2);
-
-
printf("\033[7m\033[1;34;43m");
-
printf(" LEVEL: ");
-
printf("\033[1;31;42m %-8u", level+1);//不显等级0
-
printf("\033[0m");
-
}
-
-
void Tetris::drawNext()
-
{
-
MOVETO(11, 2*WIDTH+2);
-
printf("\033[1;34;43m\tNEXT:\033[0m");
-
MOVELEFT(5);
-
MOVEDOWN(2);
-
-
for ( int i=0; i<16; ++i)
-
{
-
if ( nextBlock[i] )
-
DRAW_BLOCK();
-
else
-
//printf(" ");
-
DRAW_BLANK();
-
-
if ( (i+1)%4 == 0 )
-
{
-
MOVELEFT(8);
-
MOVEDOWN(1);
-
}
-
}
-
}
-
-
bool Tetris::isCollide()
-
{
-
for ( int i=curx; i
-
for ( int j=cury; j
-
if ( board[i][j] && activeBlock[(i-curx) * 4 + j-cury])
-
return true;
-
-
return false;
-
}
-
-
bool Tetris::isEmptyLine(int line)
-
{
-
for ( int j=1; j
-
if ( board[line][j] != TYPE_BLANK )
-
return false;
-
return true;
-
}
-
-
int Tetris::removeLines()
-
{
-
int nLines = 0 ;
-
bool full;
-
-
for ( int i=HEIGHT-2; i>0; --i)
-
{
-
full = true;
-
for ( int j=1; j
-
if ( board[i][j] == TYPE_BLANK )
-
{
-
full = false;
-
break;
-
}
-
-
if ( full )
-
{
-
++nLines;
-
int k, m;
-
for ( k=i-1; k>0 && !isEmptyLine(k); --k)
-
for ( m=1; m
-
board[k+1][m] = board[k][m];
-
// 消行了,k行一定为空
-
assert ( k>=0 && isEmptyLine(k) );
-
for ( m=1; m
-
board[k+1][m] = TYPE_BLANK;
-
-
++i;
-
}
-
}
-
-
return nLines;
-
}
-
-
void handler(int sig, siginfo_t *info, void * context)
-
{
-
Tetris * game = (Tetris *)info->si_value.sival_ptr;
-
struct aiocb *pcb = &(game->cb);
-
-
assert( !aio_error(pcb) && "aio_handler error" );
-
-
int nbytes = aio_return(pcb);
-
if ( nbytes == 0 )
-
return;
-
-
int nread = -1;
-
if ( !game->active)
-
goto end;
-
-
while ( ++nread < nbytes )
-
{
-
switch(game->inputBuf[nread])
-
{
-
case 'a':
-
case 'A':
-
--game->cury;
-
if ( game->isCollide() )
-
++game->cury;
-
else
-
{
-
MOVETO(game->curx+1, 0);
-
game->paint(game->curx, game->curx+4);
-
}
-
break;
-
case 's':
-
case 'S':
-
++game->curx;
-
if ( game->isCollide( ) )
-
--game->curx;
-
else
-
{
-
MOVETO(game->curx, 0 );
-
game->paint(game->curx-1, game->curx+4 );
-
}
-
break;
-
case 'd':
-
case 'D':
-
++game->cury;
-
if ( game->isCollide( ) )
-
--game->cury;
-
else
-
{
-
MOVETO(game->curx+1, 0);
-
game->paint(game->curx, game->curx+4);
-
}
-
break;
-
case 'w':
-
case 'W':
-
{
-
Tetris::Block saveblock = game->activeBlock;
-
int savedpos = game->curpos;
-
-
game->curpos = (game->curpos + 1) % 4;
-
game->activeBlock = game->styles[game->curstyle][game->curpos];
-
if ( game->isCollide( ) )
-
{
-
game->curpos = savedpos;
-
game->activeBlock = saveblock;
-
}
-
else
-
{
-
MOVETO(game->curx+1, 0);
-
game->paint(game->curx, game->curx+4);
-
}
-
}
-
break;
-
case ' ':
-
{
-
int oldx = game->curx;
-
// 提高效率,一次移两行
-
while ( !game->isCollide() )
-
game->curx += 2;
-
-
if ( game->isCollide() )
-
{
-
--game->curx;
-
if ( game->isCollide() )
-
--game->curx;
-
}
-
-
if ( oldx == game->curx )
-
break;
-
-
if ( game->curx - oldx < 4)
-
{
-
MOVETO(oldx+1, 0);
-
game->paint(oldx, game->curx+4);
-
}
-
else
-
{
-
MOVETO(oldx+1, 0);
-
game->paint(oldx, oldx+4);
-
MOVETO(game->curx+1, 0);
-
game->paint(game->curx, game->curx+4);
-
}
-
-
goto end;
-
}
-
break;
-
default:
-
break;
-
}
-
}
-
-
end:
-
int ret = aio_read(pcb);
-
assert ( ret==0 && "aio_read error!!!");
-
-
return;
-
}
-
-
void Tetris::run()
-
{
-
struct sigaction st;
-
sigemptyset(&st.sa_mask);
-
st.sa_flags = SA_SIGINFO;
-
st.sa_handler = reinterpret_cast(handler);
-
sigaction(SIGRTMAX, &st, NULL);
-
-
cb.aio_fildes = STDIN_FILENO;
-
cb.aio_offset = 0;
-
cb.aio_buf = inputBuf;
-
cb.aio_nbytes = 16;
-
cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
-
cb.aio_sigevent.sigev_signo = SIGRTMAX;
-
cb.aio_sigevent.sigev_value.sival_ptr = (void *)this;
-
-
sleep(1);
-
-
int ret = aio_read(&cb);
-
assert ( ret==0 && "aio_read error!!!");
-
-
CLEAR();
-
RESET_CURSOR();
-
paint();
-
drawScore();
-
drawLevel();
-
-
/*预先产生一个方块*/
-
int next = rand()%7;
-
nextBlock = styles[next][0];
-
-
-
while ( true )
-
{
-
if ( !active )
-
{
-
activeBlock = nextBlock;
-
curstyle = next;
-
curcolor = GET_COLOR();
-
active = true;
-
curpos = 0;
-
-
next = rand()%7;
-
nextBlock = styles[next][0];
-
//画下一个方块
-
drawNext();
-
curx = 1;
-
cury = WIDTH/2 - 2;
-
if ( isCollide( ) )
-
{
-
return; //GAME OVER
-
}
-
MOVETO(curx+1, 0);
-
paint(curx, curx+4);
-
}
-
else
-
{
-
++curx;
-
if ( !isCollide() )
-
{
-
MOVETO(curx, 0);
-
paint(curx-1, curx+4 );
-
}
-
else
-
{
-
--curx;
-
for ( int i=curx; i
-
for( int j=cury; j
-
{
-
if ( activeBlock[(i-curx)*4 + j-cury] )
-
board[i][j] = TYPE_BLOCK;
-
}
-
active = false;
-
activeBlock = 0;
-
//判断是否得分
-
int n = removeLines();
-
if ( n != 0 )
-
{
-
score += bonus[n];
-
drawScore();
-
-
int newlevel = getLevel(score);
-
if ( newlevel > this->level)
-
{
-
this->level = newlevel;
-
drawLevel();
-
}
-
//RESET_CURSOR(); //暂时全部重画,以后优化
-
//paint();
-
MOVETO(2,0);
-
paint(1, curx+4);
-
}
-
else
-
{
-
MOVETO(curx+1, 0);
-
paint(curx, curx+4 );
-
}
-
}
-
}
-
msleep(700 - level * 60);
-
}
-
return ;
-
}
复制代码
/////////////// 模板单例模式
-
#ifndef BERT_SINGLETON_H
-
#define BERT_SINGLETON_H
-
-
/**
-
* 模板单例模式
-
*/
-
template
-
class Singleton
-
{
-
protected:
-
Singleton() {}
-
~Singleton() {}
-
-
static T * instance;
-
-
public:
-
static T * getInstance()
-
{
-
if ( instance == NULL )
-
instance = new T();
-
return instance;
-
}
-
-
static void delInstance()
-
{
-
if ( instance )
-
{
-
delete instance;
-
instance = NULL;
-
}
-
}
-
};
-
-
template
-
T * Singleton::instance = NULL;
-
-
#endif
复制代码
///////// 自动设置终端属性
-
#ifndef BERT_TTYAUTO_H
-
#define BERT_TTYAUTO_H
-
-
#include
-
#include
-
#include
-
#include "Singleton.h"
-
-
/**
-
* 前向声明
-
*/
-
namespace std
-
{
-
-
template
-
class auto_ptr;
-
-
}
-
-
class TtyAuto : public Singleton
-
{
-
friend class Singleton;
-
friend class std::auto_ptr;
-
-
struct termios state;
-
protected:
-
/**
-
* 构造函数,自动设置非缓冲,非回显模式
-
*/
-
TtyAuto()
-
{
-
tcgetattr(STDIN_FILENO, &state);
-
state.c_lflag &= ~ICANON;
-
state.c_lflag &= ~ECHO;
-
tcsetattr(STDIN_FILENO, TCSANOW, &state);
-
}
-
/**
-
* 析构函数,自动恢复缓冲,回显模式
-
*/
-
~TtyAuto()
-
{
-
state.c_lflag |= ICANON;
-
state.c_lflag |= ECHO;
-
tcsetattr(STDIN_FILENO, TCSANOW, &state);
-
}
-
};
-
-
#endif
复制代码
|
|