C++实现俄罗斯方块
本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下
工具:vc++2010,图库:EasyX
先看效果图片
纯手写,没有面向对象思想,看全部源码
#include <stdio.h>
#include <graphics.h>
#include <time.h>
#include <conio.h>
#define BLOCK_COUNT 5
#define BLOCK_WIDTH 5
#define BLOCK_HEIGHT 5
#define UNIT_SIZE 20
#define START_X 130
#define START_Y 30
#define KEY_UP 72
#define KEY_RIGHT 77
#define KEY_LEFT 75
#define KEY_SPACE 32
#define KEY_DOWN 76
typedef enum{
BLOCK_UP,
BLOCK_RIGHT,
BLOCK_DOWN,
BLOCK_LEFT
}block_dir_t;
typedef enum{
MOVE_DOWN,
MOVE_LEFT,
MOVE_RIGHT
}move_dir_t;
int speed = 500;
int NextIndex = -1;//下一个方块种类
int BlockIndex = -1;//当前方块种类
int score = 0;//分数
int rank = 0;//等级
int visit[30][15];//访问数组
int markcolor[30][15];//表示颜色
int minX = 30;
int minY = 30;
int color[BLOCK_COUNT]={
GREEN,CYAN,MAGENTA,BROWN,YELLOW
};
int block[BLOCK_COUNT*4][BLOCK_HEIGHT][BLOCK_WIDTH] = {
//条形方块
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,0,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,0,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0},
//L形方块
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,1,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,0,0,
0,1,1,1,0,
0,1,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,1,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,1,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0},
//田字型
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0},
//T字形方块
{
0,0,0,0,0,
0,1,1,1,0,
0,0,1,0,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,1,0,
0,0,1,1,0,
0,0,0,1,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,1,0,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,1,0,
0,0,1,0,0,
0,0,0,0,0},
//Z字形方块
{
0,0,0,0,0,
0,1,1,0,0,
0,0,1,1,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,1,0,
0,0,1,1,0,
0,0,1,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,1,1,0,0,
0,0,1,1,0,
0,0,0,0,0,
0,0,0,0,0},
{
0,0,0,0,0,
0,0,0,1,0,
0,0,1,1,0,
0,0,1,0,0,
0,0,0,0,0}
};
//欢迎界面
void welcome(){
//初始化画布
initgraph(550,660);
//设置窗口标题
HWND window = GetHWnd();//获取窗口
SetWindowText(window,_T("俄罗斯方块 GWF"));//设置窗口标题
//设置文本字体样式
setfont(0,30,_T("微软雅黑"));
setcolor(YELLOW);
outtextxy(150,200,_T("俄罗斯方块"));
setfont(0,10,_T("微软雅黑"));
outtextxy(175,300,_T("IT编程从俄罗斯方块开始"));
Sleep(3000);
}
//初始化游戏屏幕
void initGameScene(){
char str[16];
//清除屏幕
cleardevice();
rectangle(27,27,336,635);
rectangle(29,29,334,633);
rectangle(370,50,515,195);
setfont(24,0,_T("楷体"));
setcolor(LIGHTGRAY);
outtextxy(405,215,_T("下一个"));
setcolor(RED);
outtextxy(405,280,_T("分数"));
sprintf(str,"%d",score);
outtextxy(415,310,str);
outtextxy(405,375,_T("等级"));
sprintf(str,"%d",rank);
outtextxy(415,405,str);
setcolor(LIGHTBLUE);
outtextxy(390,475,"操作说明");
outtextxy(390,500,"↑:旋转");
outtextxy(390,525,"↓:下降");
outtextxy(390,550,"→:向右");
outtextxy(390,575,"←:向左");
outtextxy(390,600,"空格:暂停");
}
void drawBlock(int x,int y){//右上角画出方块
setcolor(color[NextIndex]);
setfont(23,0,"楷体");
for(int i= 0;i<BLOCK_HEIGHT;i++){
for(int j= 0;j<BLOCK_WIDTH;j++){
if(block[NextIndex*4][i][j] == 1){
outtextxy(x+UNIT_SIZE*j,y+UNIT_SIZE*i,"■");
}
}
}
}
void drawBlock(int x,int y,int blockIndex,block_dir_t dir){//按索引画出什么方块指定位置方块指定方向
setcolor(color[blockIndex]);
setfont(23,0,"楷体");
int id = blockIndex*4+dir;
for(int i= 0;i<BLOCK_HEIGHT;i++){
for(int j= 0;j<BLOCK_WIDTH;j++){
if(block[id][i][j] == 1){
outtextxy(x+UNIT_SIZE*j,y+UNIT_SIZE*i,"■");
}
}
}
}
void clearBlock(int x, int y){
setcolor(BLACK);
setfont(23,0,"楷体");
for(int i= 0;i<BLOCK_HEIGHT;i++){
for(int j= 0;j<BLOCK_WIDTH;j++){
outtextxy(x+UNIT_SIZE*j,y+UNIT_SIZE*i,"■");
}
}
}
void clearBlock(int x, int y,block_dir_t dir){
setcolor(BLACK);
int id = BlockIndex *4+dir;
y+=START_Y;
for(int i= 0;i<BLOCK_HEIGHT;i++){
for(int j= 0;j<BLOCK_WIDTH;j++){
if(block[id][i][j] == 1){
outtextxy(x+UNIT_SIZE*j,y+UNIT_SIZE*i,"■");
}
}
}
}
void nextblock(){
clearBlock(391,71);//清除右上角方块
//随机选择一种方块
srand(time(NULL));//时间函数的返回值产生随机数种子
NextIndex = rand()%BLOCK_COUNT;
drawBlock(391,71);//画出方块
}
//如果在指定位置可以向方向移动
int moveable(int x0,int y0,move_dir_t moveDir,block_dir_t blockDir){
int x = (y0 - minY)/UNIT_SIZE;
int y = (x0 - minX)/UNIT_SIZE;
int id = BlockIndex * 4+blockDir;
int ret = 1;
if(moveDir == MOVE_DOWN){
for(int i = 0;i<5;i++){
for(int j = 0;j<5;j++){
if(block[id][i][j] == 1 &&(x+i+1>=30 || visit[x+i+1][y+j]==1)){
ret=0;
}
}
}
}else if(moveDir == MOVE_LEFT){
for(int i = 0;i<5;i++){
for(int j = 0;j<5;j++){
if(block[id][i][j] == 1 &&(y+j==0 || visit[x+i][y+j-1]==1)){
ret=0;
}
}
}
}else if(moveDir == MOVE_RIGHT){
for(int i = 0;i<5;i++){
for(int j = 0;j<5;j++){
if(block[id][i][j] == 1 &&(y+j+1>=15 || visit[x+i][y+j+1]==1)){
ret=0;
}
}
}
}
return ret;
}
void failCheck(){//游戏是否结束
if(!moveable(START_X,START_Y,MOVE_DOWN,BLOCK_UP)){
setcolor(WHITE);
setfont(45,0,"隶体");
outtextxy(75,300,"GAME OVER!");
Sleep(1000);
system("pause");
closegraph();
exit(0);
}
}
int wait(int interval){//等待
int count = interval/5;
for(int i = 0;i<count;i++){
Sleep(5);
if(kbhit()){
return 0;
}
}
}//判断当前方向是否可以转到指定方向
int rotatable(int x,int y,block_dir_t dir){
int id= BlockIndex * 4 +dir;
int xIndex = (y-minY)/20;
int yIndex = (x-minX)/20;
if(!moveable(x,y,MOVE_DOWN,dir)){
return 0 ;
}
for(int i = 0;i<5;i++){
for(int j = 0;j<5;j++){
if(block[id][i][j] ==1&&(yIndex+j<0||yIndex+j>=15||visit[xIndex+i][yIndex+j] ==1)){
return 0 ;
}
}
}
return 1;
}
void mark(int x,int y,int blockIndex,block_dir_t dir){
int id = blockIndex*4+dir;
int x2 = (y-minY)/20;
int y2 = (x-minX)/20;
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(block[id][i][j] ==1){
visit[x2+i][y2+j]=1;
markcolor[x2+i][y2+j]=color[blockIndex];
}
}
}
}
void clear_down(int x){//消除第x行,并把上面的行都下移
for(int i = x;i>0;i--){
for(int j=0;j<15;j++){
if(visit[i-1][j]){//上面有东西
visit[i][j]=1;
markcolor[i][j]=markcolor[i-1][j];
setcolor(markcolor[i][j]);
outtextxy(20*j+minX,20*i+minY,"■");
}else{
visit[i][j] =0;
setcolor(BLACK);
outtextxy(20*j+minX,20*i+minY,"■");
}
}
}
//清除最顶层那一行,就是行标位0的哪一行
setcolor(BLACK);
for(int j = 0;j<15;j++){
visit[0][j] = 0;
outtextxy(20*j+minX,minY,"■");
}
}
void updataGrade(){
//更新等级提示
//假设:50分一级
char str[10];
rank = score/50;
sprintf(str,"%d",rank);
outtextxy(425,405,str);
//更新速度,等级越高速度越快,speed越小
//最慢是500,最快是50
speed = 500-rank*50;
if(speed<=0){
speed = 50;
}
}
void addScore(int lines){//更新分数,line表示消除的行数
char str[32];
setcolor(RED);
score+=lines*10;
sprintf(str,"%d",score);
outtextxy(415,310,str);
}
void check(){//消去方块
int i,j;
int clearLines =0;
for(i=29;i>=0;i--){
for(j=0;j<15 && visit[i][j];j++);
//执行到此处有两种情况,
//1.第I行没有满,即表示有空位,此时j<15
//2.第i行已经满了,j就大于等于15
if(j>=15){
//此时第i行已经满了,就需要消除第i行
clear_down(i);//清除第i行,并把上面的行都下移动
i++;
clearLines++;
}
}
//更新分数
addScore(clearLines);
//更新等级
updataGrade();
}
void move(){
int x = START_X;
int y = START_Y;
int k = 0;
int curSpeed = speed;
block_dir_t blockDir = BLOCK_UP;
//检查游戏是否结束
failCheck();
while(1){
if(kbhit()){
int key = getch();
if(KEY_SPACE == key){
getch();
}
}
//清除当前方块
clearBlock(x,k,blockDir);
if(kbhit()){
int key = getch();
if(KEY_UP == key){//变形
block_dir_t nextDir = (block_dir_t)((blockDir+1)%4);
if(rotatable(x,y+k,nextDir)){
blockDir= nextDir;
}
}else if(KEY_DOWN == key){//乡下加速
curSpeed = 50;
}else if(KEY_RIGHT == key){//右移动
if(moveable(x,y+k+20,MOVE_RIGHT,blockDir)){
x+=20;
}
}else if(KEY_LEFT == key){//左移动
if(moveable(x,y+k+20,MOVE_LEFT,blockDir)){
x-=20;
}
}
}
k+=20;
//绘制当前方块
drawBlock(x,y+k,BlockIndex,blockDir);
wait(curSpeed);
//方块降落到底层的固化处理
if(!moveable(x,y+k,MOVE_DOWN,blockDir)){
mark(x,y+k,BlockIndex,blockDir);
break;
}
}
}
void newblock(){
//确定即将使用的方块
BlockIndex = NextIndex;
//绘制方块从顶部掉下来
drawBlock(START_X,START_Y);
//新出现的方块等一下
Sleep(100);
//右上角绘制下一个方块
nextblock();
//向下降落的动作
move();
}
int main (void){
welcome();
initGameScene();
//产生新方块
nextblock();
Sleep(500);
memset(visit,0,sizeof(visit));
while(1){
newblock();
//消除满行,并更新分数和速度
check();
}
system("pause");
closegraph();
return 0;
}
分析项目:
1.必须要有欢迎界面
2.搭建合理的边界,就是游戏范围
3.逻辑1:先出现右上方的方块样式,等待一段时间,将右上方的样式在游戏区打印出
4.逻辑2,方块降落,要擦除原先印记,将1改为0
5.逻辑3,热键控制移动方向,暂停及变形,且不能移动出界,判断方块是否还能移动
6.逻辑4,方块凝固在下方不出界
7.逻辑5,最下面一行方块叠满了,消去它并把上面的行都下移(分两种情况),并且再次检查这一行
8.逻辑6,计算消除行数次数,统计分数,控制休眠时间长度
9.逻辑7,每次移动先判断是否能移动,默认结束程序,在合理游戏区返回false,结束界面
总结:从界面开始到完整的架构,功能后实现,一步一步,逻辑严谨,思路清晰,注释在代码里。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
以上是 C++实现俄罗斯方块 的全部内容, 来源链接: utcz.com/p/244748.html