赞
踩
目录
使用easyX库,基于c/c++,实现俄罗斯方块小游戏。
作者使用的是VS2010版本,VS2019版本也可用。
一、游戏截图和全部代码
可直接拷贝,并运行俄罗斯方块小游戏
- #pragma once
-
- #define GAMEMAP1 200 // 预生成方块区域
- #define GAMEMAP2 10
- #define GAMEMAP3 500
- #define GAMEMAP4 610
- #define GAMEMAP5 40 // 游戏地图区域
- #define GAMEMAP6 50
- #define GAMEMAP7 140
- #define GAMEMAP8 130
- #define GAMEGUIDE1 40 // 按键说明
- #define GAMEGUIDE2 300
- #define GAMEGUIDE3 150
- #define GAMEGUIDE4 440
- #define GAMELEVEL1 30 // 游戏等级区域
- #define GAMELEVEL2 160
- #define GAMERANK1 30 // 游戏rank分数
- #define GAMERANK2 190
-
- #define TETRISWIDTH 15 // 游戏地图宽
- #define TETRISHEIGHT 30 // 游戏地图高
- #define BLOCKTYPE 8 // 方块种类数
- #define BLOCKSTYLE 4 // 每种方块的样式数
- #define BLOCKSPACE 20 // 方块占用空间 5 x 4
- #define SIDELENGTH 20 // 方块边长 20 像素
-
- #define ESC 27
-
- #define CLEARKEY(); { while(_kbhit()) { _getch(); } } // 清除按键输入缓存
-
- enum BLOCKCOLER
- {
- BLOCKNONE,
- BLOCKBLUE,
- BLOCKGREEN,
- BLOCKCYAN,
- BLOCKRED,
- BLOCKMAGENTA,
- BLOCKBROWN,
- BLOCKYELLOW,
- };
-
- typedef struct _GAME_TETRIS
- {
- int ttime; // 计时
- int ctime; // 计时
- int level; // 当前游戏等级
- int rank; // 当前游戏分数
- int key; // 玩家按键值
- int blockType; // 当前方块类型
- int blockStyle; // 当前方块朝向
-
- bool moveFlag; // 移动标识,标识为1时,移动当前方块
- bool newBlockFlag; // 载入新方块标识,当标识为真时,将预生成的随机方块载入地图
- bool gameOverFlag; // 游戏结束标识
- }GAME_TETRIS;
-
- typedef struct _GAME_PREBLOCK
- {
- int tetrisPreBlock[BLOCKSPACE]; // 预生成的方块数组
- int blockType,blockStyle; // 预生成方块的类型和朝向
- }GAME_PREBLOCK;
-
- typedef struct _GAME_MOVE_BLOCK
- {
- int blockSite[4][2]; // 4个方块格坐标
- int blockColor; // 方块颜色
- }GAME_MOVE_BLOCK;
-
-
- void tetrisrun(void);
- void tetrisInit(void);
- void tetrisDraw(void);
- void tetrisNewBlock(void);
- void tetrisMoveUp(void);
- void tetrisMoveDown(void);
- void tetrisMoveLeft(void);
- void tetrisMoveRight(void);
- void tetrisLoadBlock(void);
- void tetrisIsOver(void);
- void tetrisQuit(void);
- void tetrisKeyHandle(void);
- void tetrisReset(void);
- void tetrisRemove(void);
- #include "stdafx.h"
- #include "tetrisnew.h"
- #include<graphics.h>
- #include<conio.h>
- #include<stdio.h>
- #include<time.h>
-
- // 所有方块数组库
- const int block[BLOCKTYPE][BLOCKSTYLE][BLOCKSPACE] =
- {
- // 总共有8种方块,每种方块有4种样式
-
- // 'I'形方块
- {
- {
- BLOCKNONE, BLOCKBLUE, BLOCKBLUE, BLOCKBLUE, BLOCKBLUE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKBLUE, BLOCKBLUE, BLOCKBLUE, BLOCKBLUE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'Z'形方块
- {
- {
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 反'Z'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'T'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'T'形方块 X 2 增加T形方块出现概率
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // '田'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'L'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKBROWN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKBROWN, BLOCKBROWN,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKBROWN, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKBROWN, BLOCKBROWN, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 反'L'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKYELLOW,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKYELLOW,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- }
-
- };
-
- // 游戏实时画面
- int tetrisMap[TETRISHEIGHT][TETRISWIDTH] =
- {
-
- };
-
- GAME_TETRIS player; // 玩家数据
- GAME_PREBLOCK preBlock; // 预生成方块数据
- GAME_MOVE_BLOCK moveBlock; // 当前控制方块数据
-
- int main(void)
- {
- tetrisrun();
- return 0;
- }
-
- void tetrisrun(void)
- {
- tetrisInit();
- while(1)
- {
- player.ctime = GetTickCount();
- if( (player.ctime - 500 + 30*player.level) > player.ttime )
- {
- player.moveFlag = TRUE;
- player.ttime = GetTickCount();
- }
- if(player.moveFlag)
- {
- player.moveFlag = FALSE;
-
- tetrisMoveDown();
- tetrisDraw();
- }
- if(_kbhit())
- {
- player.key = _getch();
- tetrisKeyHandle();
- }
- if(player.newBlockFlag)
- {
- player.newBlockFlag = FALSE;
- tetrisLoadBlock();
- tetrisRemove();
- tetrisNewBlock();
- tetrisIsOver();
- }
- if(player.gameOverFlag)
- {
- player.gameOverFlag = FALSE;
- break;
- }
-
- }
-
- }
-
- void tetrisInit(void)
- {
- int i,j,k;
- HWND window = initgraph(510, 620);
- SetWindowText(window, "俄罗斯方块 - by耒阳阿杰");
- //SetWindowPos(window,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
-
- rectangle(GAMEMAP1 - 2,GAMEMAP2 - 2,GAMEMAP3 + 2,GAMEMAP4 + 2);
- rectangle(GAMEMAP5 - 2,GAMEMAP6 - 2,GAMEMAP7 + 2,GAMEMAP8 + 2);
- rectangle(GAMEGUIDE1 - 5,GAMEGUIDE2 - 5,GAMEGUIDE3 + 5,GAMEGUIDE4 + 5);
-
- outtextxy(GAMEMAP5 + 10 ,GAMEMAP6 - 26,"下个方块");
- settextcolor(GREEN);
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 ,"W :改变形状");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 25 ,"A :方块左移");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 50 ,"S :方块右移");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 75 ,"D :方块下移");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 100 ,"R :重新开始");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 125 ,"ESC:退出游戏");
-
- memset ( &player, 0, sizeof ( GAME_TETRIS ) );
- memset ( &preBlock, 0, sizeof ( GAME_PREBLOCK ) );
- memset(tetrisMap,0,sizeof(tetrisMap));
- player.ttime = GetTickCount();
-
- srand((unsigned)time(NULL));
- i = (rand() + 1) % BLOCKTYPE;
- j = rand() % BLOCKSTYLE;
- for(k = 0; k < BLOCKSPACE;k++)
- {
- preBlock.tetrisPreBlock[k] = block[i][j][k];
- }
- preBlock.blockType = i;
- preBlock.blockStyle = j;
- tetrisNewBlock();
- }
-
- void tetrisDraw(void)
- {
- int i,j;
- int x,y;
- char ch[20];
-
- settextstyle(20,12,"宋体");
- settextcolor(CYAN);
- if(player.level < 10)
- {
- sprintf_s(ch, "%s%d","LEVEL:", player.level);
- }
- else
- {
- sprintf_s(ch, "%s","LEVEL:MAX");
- }
- outtextxy(GAMELEVEL1,GAMELEVEL2,ch);
- settextcolor(LIGHTBLUE);
- sprintf_s(ch, "%s%d","RANK:", player.rank);
- outtextxy(GAMERANK1,GAMERANK2,ch);
-
- setfillcolor(BLACK);
- solidrectangle(GAMEMAP5,GAMEMAP6,GAMEMAP7,GAMEMAP8);
-
- for(i = 0; i < BLOCKSPACE; i++)
- {
- switch(preBlock.tetrisPreBlock[i])
- {
- case BLOCKNONE:
- continue;
- break;
- case BLOCKBLUE:
- setfillcolor(BLUE);
- break;
- case BLOCKGREEN:
- setfillcolor(GREEN);
- break;
- case BLOCKCYAN:
- setfillcolor(CYAN);
- break;
- case BLOCKRED:
- setfillcolor(RED);
- break;
- case BLOCKMAGENTA:
- setfillcolor(MAGENTA);
- break;
- case BLOCKBROWN:
- setfillcolor(BROWN);
- break;
- case BLOCKYELLOW:
- setfillcolor(YELLOW);
- break;
- }
- fillrectangle(GAMEMAP5 + (i%5) * SIDELENGTH ,GAMEMAP6 + (i/5) * SIDELENGTH ,GAMEMAP5 + ((i%5)+1)*SIDELENGTH ,GAMEMAP6 + ((i/5)+1) * SIDELENGTH );
- }
-
- setfillcolor(BLACK);
- solidrectangle(GAMEMAP1,GAMEMAP2,GAMEMAP3,GAMEMAP4);
-
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- switch(moveBlock.blockColor)
- {
- case BLOCKNONE:
- continue;
- break;
- case BLOCKBLUE:
- setfillcolor(BLUE);
- break;
- case BLOCKGREEN:
- setfillcolor(GREEN);
- break;
- case BLOCKCYAN:
- setfillcolor(CYAN);
- break;
- case BLOCKRED:
- setfillcolor(RED);
- break;
- case BLOCKMAGENTA:
- setfillcolor(MAGENTA);
- break;
- case BLOCKBROWN:
- setfillcolor(BROWN);
- break;
- case BLOCKYELLOW:
- setfillcolor(YELLOW);
- break;
- }
- fillrectangle(GAMEMAP1 + y * SIDELENGTH ,GAMEMAP2 + x * SIDELENGTH ,GAMEMAP1 + (y+1)*SIDELENGTH ,GAMEMAP2 + (x+1) * SIDELENGTH );
- }
-
- for(i = 0; i < TETRISHEIGHT; i++)
- {
- for(j = 0; j < TETRISWIDTH; j++)
- {
- switch(tetrisMap[i][j])
- {
- case BLOCKNONE:
- continue;
- break;
- case BLOCKBLUE:
- setfillcolor(BLUE);
- break;
- case BLOCKGREEN:
- setfillcolor(GREEN);
- break;
- case BLOCKCYAN:
- setfillcolor(CYAN);
- break;
- case BLOCKRED:
- setfillcolor(RED);
- break;
- case BLOCKMAGENTA:
- setfillcolor(MAGENTA);
- break;
- case BLOCKBROWN:
- setfillcolor(BROWN);
- break;
- case BLOCKYELLOW:
- setfillcolor(YELLOW);
- break;
- }
- fillrectangle(GAMEMAP1 + j * SIDELENGTH ,GAMEMAP2 + i * SIDELENGTH ,GAMEMAP1 + (j+1)*SIDELENGTH ,GAMEMAP2 + (i+1) * SIDELENGTH );
- }
- }
- }
-
- void tetrisNewBlock(void)
- {
- int i,j,k;
-
- k = 0;
- for(i = 0; i < BLOCKSPACE; i++)
- {
- if(preBlock.tetrisPreBlock[i])
- {
- moveBlock.blockColor = preBlock.tetrisPreBlock[i];
- moveBlock.blockSite[k][0] = i/5;
- moveBlock.blockSite[k][1] = 5 + i%5;
- k++;
- }
- }
- player.blockType = preBlock.blockType;
- player.blockStyle = preBlock.blockStyle;
-
- srand((unsigned)time(NULL));
- i = rand() % BLOCKTYPE;
- j = rand() % BLOCKSTYLE;
- for(k = 0; k < BLOCKSPACE;k++)
- {
- preBlock.tetrisPreBlock[k] = block[i][j][k];
- }
- preBlock.blockType = i;
- preBlock.blockStyle = j;
- }
-
- void tetrisMoveUp(void)
- {
- int i,k;
- int bStyle;
- int ux,uy; // 改变方块朝向前后,方块格的位移矢量
- int blocksite2[4][2]; // 记录改变朝向前,4个方块的方块库坐标
- int blocksite3[4][2]; // 记录改变朝向后,4个方块的方块库坐标
- int blocksite4[4][2]; // 记录改变朝向后,4个方块的游戏地图坐标
-
- k = 0;
- for(i = 0; i < BLOCKSPACE; i++)
- {
- if(k > 3)
- {
- break;
- }
- if(block[player.blockType][player.blockStyle][i])
- {
- blocksite2[k][0] = i / 5;
- blocksite2[k][1] = i % 5;
- k++;
- }
- }
- k = 0;
- bStyle = (player.blockStyle + 1)%BLOCKSTYLE;
- for(i = 0; i < BLOCKSPACE; i++)
- {
- if(k > 3)
- {
- break;
- }
- if(block[player.blockType][bStyle][i])
- {
- blocksite3[k][0] = i / 5;
- blocksite3[k][1] = i % 5;
- k++;
- }
- }
- for(i = 0; i < 4; i++)
- {
- ux = blocksite3[i][0] - blocksite2[i][0];
- uy = blocksite3[i][1] - blocksite2[i][1];
-
- blocksite4[i][0] = moveBlock.blockSite[i][0] + ux;
- blocksite4[i][1] = moveBlock.blockSite[i][1] + uy;
-
- if( (blocksite4[i][0] < 0)
- || (blocksite4[i][1] < 0)
- || (blocksite4[i][0] > TETRISHEIGHT - 1)
- || (blocksite4[i][1] > TETRISWIDTH - 1)
- || ( tetrisMap[blocksite4[i][0]][blocksite4[i][1]] ) )
- {
- return;
- }
- }
- for(i = 0;i < 4; i++)
- {
- moveBlock.blockSite[i][0] = blocksite4[i][0];
- moveBlock.blockSite[i][1] = blocksite4[i][1];
- }
- player.blockStyle = bStyle;
-
- }
-
- void tetrisMoveDown(void)
- {
- int i;
- int x,y;
-
- for(i = 0; i < 4; i++)
- {
- if(moveBlock.blockSite[i][0] > TETRISHEIGHT - 2)
- {
- player.newBlockFlag = TRUE;
- return;
- }
- }
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0] + 1;
- y = moveBlock.blockSite[i][1];
- if(tetrisMap[x][y])
- {
- player.newBlockFlag = TRUE;
- return;
- }
- }
- for(i = 0; i < 4; i++)
- {
- moveBlock.blockSite[i][0]++;
- }
-
- }
-
- void tetrisMoveLeft(void)
- {
- int i;
- int x,y;
-
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- if( (y - 1) < 0
- || tetrisMap[x][y - 1])
- {
- return;
- }
- }
- for(i = 0; i < 4; i++)
- {
- moveBlock.blockSite[i][1]--;
- }
-
- }
-
- void tetrisMoveRight(void)
- {
- int i;
- int x,y;
- //k = 0;
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- if( ((y + 1) >= TETRISWIDTH)
- || (tetrisMap[x][y + 1]) )
- {
- return;
- }
- }
- for(i = 0; i < 4; i++)
- {
- moveBlock.blockSite[i][1]++;
- }
-
- }
-
- void tetrisLoadBlock(void)
- {
- int i;
- int x,y;
-
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- if(!tetrisMap[x][y])
- {
- tetrisMap[x][y] = moveBlock.blockColor;
- }
- }
- }
-
- void tetrisIsOver(void)
- {
- int i;
- int x,y;
-
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- if(tetrisMap[x][y])
- {
- player.gameOverFlag = TRUE;
- tetrisDraw();
- tetrisQuit();
- return;
- }
- }
- }
-
- void tetrisQuit(void)
- {
- int key,flag;
- flag = player.gameOverFlag;
- key = MessageBox(NULL,"是否退出游戏?","提示",MB_YESNO| MB_SYSTEMMODAL);
- switch(key)
- {
- case IDYES:
- player.gameOverFlag = TRUE;
- break;
- case IDNO:
- player.gameOverFlag = FALSE;
- break;
- default:
- break;
- }
- while(flag
- && !player.gameOverFlag)
- {
- key = MessageBox(NULL,"检测到游戏已无法继续,\n请选择\"是\": 退出游戏;\n或者选择\"否\": 重启游戏;","提示",MB_YESNO| MB_SYSTEMMODAL);
- switch(key)
- {
- case IDYES:
- player.gameOverFlag = TRUE;
- break;
- case IDNO:
- tetrisInit();
- player.gameOverFlag = FALSE;
- return;
- default:
- break;
- }
- }
- CLEARKEY();
- }
-
- void tetrisKeyHandle(void)
- {
- switch(player.key)
- {
- case 'w':
- case 'W':
- tetrisMoveUp();
- break;
- case 'a':
- case 'A':
- tetrisMoveLeft();
- break;
- case 's':
- case 'S':
- player.moveFlag = TRUE;
- player.ttime = GetTickCount();
- return;
- case 'd':
- case 'D':
- tetrisMoveRight();
- break;
- case ESC:
- tetrisQuit();
- break;
- case 'r':
- case 'R':
- tetrisReset();
- break;
- default:
- break;
- }
- tetrisDraw();
- }
-
- void tetrisReset(void)
- {
- int key;
- key = MessageBox(NULL,"是否重新开始游戏?","提示",MB_YESNO| MB_SYSTEMMODAL);
- CLEARKEY();
- switch(key)
- {
- case IDYES:
- tetrisInit();
- break;
- case IDNO:
- break;
- default:
- break;
- }
- }
-
- void tetrisRemove(void)
- {
- int i,j,m,n;
- int flag,bnum;
- bnum = 0;
-
- for(i = TETRISHEIGHT - 1; i >= 0; i-- )
- {
- flag = 0;
- for(j = 0; j < TETRISWIDTH; j++)
- {
- if(!tetrisMap[i][j])
- {
- flag = 1;
- break;
- }
- }
- if(flag)
- {
- continue;
- }
- bnum++;
- for(j = 0; j < TETRISWIDTH; j++)
- {
- tetrisMap[i][j] = BLOCKNONE;
- }
- for(m = i; m > 0; m--)
- {
- for(n = 0; n < TETRISWIDTH; n++)
- {
- tetrisMap[m][n] = tetrisMap[m - 1][n];
- }
- }
- i++;
- }
-
- if(!bnum)
- {
- return;
- }
- switch(bnum)
- {
- case 0:
- break;
- case 1:
- player.rank += 10;
- break;
- case 2:
- player.rank += 20;
- break;
- case 3:
- player.rank += 40;
- break;
- case 4:
- player.rank += 80;
- break;
- default:
- break;
- }
- player.level = player.rank/100;
- if(player.level > 10)
- {
- player.level = 10;
- }
-
- }
EasyX Graphics Library for C++
进入以上链接,下载并安装easyX库
方块为正方形,大小为20X20像素
#define SIDELENGTH 20
游戏地图为矩形,大小为600X300像素,四个角坐标为下面的宏定义。
- #define GAMEMAP1 200
- #define GAMEMAP2 10
- #define GAMEMAP3 500
- #define GAMEMAP4 610
使用rectangle函数,填入四个角坐标,画出游戏地图边界
rectangle(GAMEMAP1 - 2,GAMEMAP2 - 2,GAMEMAP3 + 2,GAMEMAP4 + 2);
把地图按20X20像素分割,就是30X15个方块,这样就把地图转换为坐标的形式了,选中一个方块格,再进行涂色,就是一个相应的方块了。
预生成方块区域为100X80像素的矩形,四个角坐标如下宏定义
- #define GAMEMAP5 40 // 预生成方块区域
- #define GAMEMAP6 50
- #define GAMEMAP7 140
- #define GAMEMAP8 130
使用rectangle函数,填入四个角坐标,画出游戏地图边界
rectangle(GAMEMAP5 - 2,GAMEMAP6 - 2,GAMEMAP7 + 2,GAMEMAP8 + 2);
把区域按照20X20像素分割,就是4X5个方块,这样就可以转换为坐标的形式;
根据随机得到的方块种类,换算成四个坐标,再选择颜色进行填充,就可以得到预生成的方块了。
- typedef struct _GAME_TETRIS
- {
- int ttime; // 计时
- int ctime; // 计时
- int level; // 当前游戏等级
- int rank; // 当前游戏分数
- int key; // 玩家按键值
- int blockType; // 当前方块类型
- int blockStyle; // 当前方块朝向
-
- bool moveFlag; // 移动标识,标识为1时,移动当前方块
- bool newBlockFlag; // 载入新方块标识,当标识为真时,将预生成的随机方块载入地图
- bool gameOverFlag; // 游戏结束标识
- }GAME_TETRIS;
GAME_TETRIS player; // 玩家数据
player会保存玩家在游戏中的数据,ttime和ctime是用来定时的,每隔(500ms - 等级*30毫秒),会将moveflag置1,方块下降一行;
level和rank是玩家当前获得分数,已经根据分数得到的level;
key是玩家按下的键盘输入值;
blockType和blockStyle是玩家当前控制方块的方块类型和方块朝向,用来判定方块是否可以左、右、下移、变换形态;
moveflag,移动标识,标识为1时,当前方块会下移一行;
bewBlockFlag,新方块标识,标识为1时,会执行以下函数:当前方块载入游戏地图、消除满行的方块、生成新的方块、判断游戏是否结束;
gameOverFlag,游戏结束标识,标识为1时,会让玩家选择结束游戏,或重新开始游戏
数据库是一个三维数组
总共有8种类型的方块,每个类型的方块颜色都不一样;每个方块有4个样式(朝向);每种方块的每种朝向都是一个5X4的方块矩形。
生成新方块时,就会从方块数据库中获取方块数据。
- #define BLOCKTYPE 8 // 方块种类数
- #define BLOCKSTYLE 4 // 每种方块的样式数
- #define BLOCKSPACE 20 // 方块占用空间 5 x 4
- const int block[BLOCKTYPE][BLOCKSTYLE][BLOCKSPACE] =
- {
- // 总共有8种方块,每种方块有4种样式
-
- // 'I'形方块
- {
- {
- BLOCKNONE, BLOCKBLUE, BLOCKBLUE, BLOCKBLUE, BLOCKBLUE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKBLUE, BLOCKBLUE, BLOCKBLUE, BLOCKBLUE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBLUE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'Z'形方块
- {
- {
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKGREEN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKGREEN, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 反'Z'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKCYAN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'T'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'T'形方块 X 2 增加T形方块出现概率
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKRED, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKRED, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKRED, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // '田'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKMAGENTA,BLOCKMAGENTA,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 'L'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKBROWN, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKBROWN, BLOCKBROWN,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKBROWN, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKBROWN, BLOCKBROWN, BLOCKBROWN, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- },
- // 反'L'形方块
- {
- {
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKYELLOW,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- },
- {
- BLOCKNONE, BLOCKYELLOW,BLOCKYELLOW,BLOCKYELLOW,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKYELLOW,BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE,
- BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE, BLOCKNONE
- }
- }
-
- };
- typedef struct _GAME_MOVE_BLOCK
- {
- int blockSite[4][2]; // 4个方块格坐标
- int blockColor; // 方块颜色
- }GAME_MOVE_BLOCK;
GAME_MOVE_BLOCK moveBlock; // 当前控制方块数据
数据结构由两部分组成,一个是保存了四个方块坐标的二维数组;一个是当前控制方块的颜色;
有了坐标和颜色,就可以在游戏地图中,准确的画出当前控制方块。
主函数由一个初始化函数,和一个死循环组成;初始化游戏数据后,会在死循环while(1)中不停的执行游戏数据处理,直到玩家选择退出游戏。
通过主函数,也能看出来整个代码的运行逻辑,了解编程思路。
- void tetrisrun(void)
- {
- tetrisInit();
- while(1)
- {
- // (每500毫秒 - 游戏等级*30毫秒)运行一次,方块下移
- player.ctime = GetTickCount();
- if( (player.ctime - 500 + 30*player.level) > player.ttime )
- {
- player.moveFlag = TRUE;
- player.ttime = GetTickCount();
- }
- // 如果移动标识为1,则当前方块下移
- if(player.moveFlag)
- {
- player.moveFlag = FALSE;
-
- tetrisMoveDown();
- tetrisDraw();
- }
- // 用户按键处理
- if(_kbhit())
- {
- player.key = _getch();
- tetrisKeyHandle();
- }
- // 将预生成的随机方块载入游戏地图
- if(player.newBlockFlag)
- {
- player.newBlockFlag = FALSE;
- // 将当前方块载入游戏地图
- tetrisLoadBlock();
- // 消除满行的方块
- tetrisRemove();
- // 生成新的方块
- tetrisNewBlock();
- // 判断游戏是否结束
- tetrisIsOver();
- }
- // 游戏结束处理
- if(player.gameOverFlag)
- {
- player.gameOverFlag = FALSE;
- break;
- }
-
- }
-
- }
// (每500毫秒 - 游戏等级*30毫秒)运行一次,方块下移
player.ctime = GetTickCount();
if( (player.ctime - 500 + 30*player.level) > player.ttime )
{
player.moveFlag = TRUE;
player.ttime = GetTickCount();
}
第一部分,计时部分:通过记录两个时间变量的时间差,来得到一个周期执行的标识
1.初始化时,先给变量player.ttime赋值,获得当时的时间数据;
2.每次主程序循环时,都会给另一个变量player.ctime赋值,获得最新的时间数据;
3.以默认的500ms周期为例,如果最新的时间player.ctime减去500ms,还是大于当时的时间player.ttime,说明离第一次给player.ttime赋值,已经过去了500ms,满足一个周期;
4.此时,给周期执行标识 player.moveFlag置1;表示当前方块需要下移了,将会在后面的函数处理,并将标识置0,等待下一次周期来临;
5.再给player.ttime赋值,获得当时的时间数据,开始执行下一次500ms的周期计算。
// 如果移动标识为1,则当前方块下移
if(player.moveFlag)
{
player.moveFlag = FALSE;tetrisMoveDown();
tetrisDraw();
}
第二部分,方块移动:每过一个周期,方块移动标识player.moveFlag置1,执行这部分函数
1.先将移动标识player.moveFlag置0,方便下一次周期的执行;
2.执行方块下移函数tetrisMoveDown(),对方块进行下移处理;如果方块到达游戏底部,或者下方已经存在方块,就会将生成新方块标识player.newBlockFlag置1,进行后面的处理;
3.执行绘制地图函数tetrisDraw(),画出方块下移后的画面。
// 用户按键处理
if(_kbhit())
{
player.key = _getch();
tetrisKeyHandle();
}
第三部分,按键处理:对用户的按键进行处理,控制方块的移动、游戏的进程
1._kbhit()函数,每当检测到用户按下按键时,会返回TRUE,此时if条件为真,执行if里面的代码;
2.通过_getch()函数,将用户按键值赋给变量player.key;
3.执行按键处理函数tetrisKeyHandle(),对不同的按键进行不同的处理
// 将预生成的随机方块载入游戏地图
if(player.newBlockFlag)
{
player.newBlockFlag = FALSE;
// 将当前方块载入游戏地图
tetrisLoadBlock();
// 消除满行的方块
tetrisRemove();
// 生成新的方块
tetrisNewBlock();
// 判断游戏是否结束
tetrisIsOver();
}
第四部分,新方块处理:每当当前方块到达游戏底部,或者当前方块下一行已存在方块时,会将新方块标识player.newBlockFlag置1,执行if里面的代码。
1.先把新方块标识player.newBlockFlag清0,防止重复执行;
2.当前方块已不能下移,执行tetrisLoadBlock()函数,把当前方块固定到游戏地图,不再移动;
3.固定方块后,执行tetrisRemove()函数,检测并消除满行的方块,并通过消除的行数,增加RANK分,改变level等级;
4.消除满行后,执行tetrisNewBlock()函数,将预生成的方块载入游戏,成为当前控制方块,并生成新的随机方块,载入到预生成方块地图;
5.生成新方块后,执行 tetrisIsOver()函数,判断当前控制方块是否和游戏地图有重叠,如果重叠,则游戏结束,将结束标识player.gameOverFlag置1,并让用户选择是结束游戏还是重新开始。
// 游戏结束处理
if(player.gameOverFlag)
{
player.gameOverFlag = FALSE;
break;
}
第五部分,游戏结束处理:如果用户决定结束游戏, 则退出while(1)死循环,退出程序。
上面已经解释过主函数tetrisrun(),接下来会详细解释每一个函数
初始化函数,程序会先运行初始化函数,然后再进入while(1)死循环,运行俄罗斯方块游戏;
- void tetrisInit(void)
- {
- int i,j,k;
- HWND window = initgraph(510, 620); // 初始化窗口大小
- SetWindowText(window, "俄罗斯方块 - by耒阳阿杰"); // 设置当前窗口的标题
- //SetWindowPos(window,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); // 置顶
-
- rectangle(GAMEMAP1 - 2,GAMEMAP2 - 2,GAMEMAP3 + 2,GAMEMAP4 + 2); // 绘制游戏地图范围
- rectangle(GAMEMAP5 - 2,GAMEMAP6 - 2,GAMEMAP7 + 2,GAMEMAP8 + 2); // 绘制预生成方块方位
- rectangle(GAMEGUIDE1 - 5,GAMEGUIDE2 - 5,GAMEGUIDE3 + 5,GAMEGUIDE4 + 5); // 绘制按键说明
-
- outtextxy(GAMEMAP5 + 10 ,GAMEMAP6 - 26,"下个方块");
- settextcolor(GREEN);
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 ,"W :改变形状");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 25 ,"A :方块左移");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 50 ,"S :方块右移");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 75 ,"D :方块下移");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 100 ,"R :重新开始");
- outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 125 ,"ESC:退出游戏");
-
- // 初始化游戏数据
- memset ( &player, 0, sizeof ( GAME_TETRIS ) );
- memset ( &preBlock, 0, sizeof ( GAME_PREBLOCK ) );
- memset(tetrisMap,0,sizeof(tetrisMap));
- player.ttime = GetTickCount();
-
- // 获取随机数,生成第一个随机方块
- srand((unsigned)time(NULL)); // 获取随机数,生成新的随机方块
- i = (rand() + 1) % BLOCKTYPE;
- j = rand() % BLOCKSTYLE;
- for(k = 0; k < BLOCKSPACE;k++)
- {
- preBlock.tetrisPreBlock[k] = block[i][j][k];
- }
- preBlock.blockType = i;
- preBlock.blockStyle = j;
- // 把第一个随机方块加载进游戏,并生成下一个随机方块
- tetrisNewBlock();
- }
HWND window = initgraph(510, 620); // 初始化窗口大小
SetWindowText(window, "俄罗斯方块 - by耒阳阿杰"); // 设置当前窗口的标题
//SetWindowPos(window,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); // 置顶
1.初始化窗口,定义窗口大小,设置窗口标题,屏蔽的SetWindowPos()函数是用于给游戏置顶的,置顶之后,总是会显示在WINDOWS的最顶层,类似于微信的置顶;
rectangle(GAMEMAP1 - 2,GAMEMAP2 - 2,GAMEMAP3 + 2,GAMEMAP4 + 2); // 绘制游戏地图范围
rectangle(GAMEMAP5 - 2,GAMEMAP6 - 2,GAMEMAP7 + 2,GAMEMAP8 + 2); // 绘制预生成方块方位
rectangle(GAMEGUIDE1 - 5,GAMEGUIDE2 - 5,GAMEGUIDE3 + 5,GAMEGUIDE4 + 5); // 绘制按键说明outtextxy(GAMEMAP5 + 10 ,GAMEMAP6 - 26,"下个方块");
settextcolor(GREEN);
outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 ,"W :改变形状");
outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 25 ,"A :方块左移");
outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 50 ,"S :方块右移");
outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 75 ,"D :方块下移");
outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 100 ,"R :重新开始");
outtextxy(GAMEGUIDE1 ,GAMEGUIDE2 + 125 ,"ESC:退出游戏");
2.rectangle()函数是根据你输入的四个坐标,绘制一个矩形,这里绘制了游戏地图、预生成方块地图、按键说明框;
outtextxy(x,y,string)函数是根据你输入的起点坐标,还有后面的字符串,在相应位置打印字符串内容;
settextcolor(GREEN)函数是设置打印字符串的颜色;
// 初始化游戏数据
memset ( &player, 0, sizeof ( GAME_TETRIS ) );
memset ( &preBlock, 0, sizeof ( GAME_PREBLOCK ) );
memset(tetrisMap,0,sizeof(tetrisMap));
player.ttime = GetTickCount();
3. memset()函数是重置结构或者数据的数据,将他们置0;
然后给player.ttime赋值当时的时间,方便后面用来判定500ms周期。
// 获取随机数,生成第一个随机方块
srand((unsigned)time(NULL)); // 获取随机数,生成新的随机方块
i = (rand() + 1) % BLOCKTYPE;
j = rand() % BLOCKSTYLE;
for(k = 0; k < BLOCKSPACE;k++)
{
preBlock.tetrisPreBlock[k] = block[i][j][k];
}
preBlock.blockType = i;
preBlock.blockStyle = j;
// 把第一个随机方块加载进游戏,并生成下一个随机方块
tetrisNewBlock();
4.关于随机数生成,分为伪随机和真随机,这个建议读者们自己去查阅相关资料;
通过生成的随机数,再分别取方块类型和形状(朝向)的余数,就能得到一个随机方块的数据了;
得到第一个随机方块后,再执行 tetrisNewBlock()函数,把第一个随机方块载入游戏地图,再生成新的随机方块,载入预生成方块地图。
绘制函数,根据当前游戏数据,绘制整个游戏画面。
- void tetrisDraw(void)
- {
- int i,j;
- int x,y;
- char ch[20];
-
- // 更新RANK分数和LEVEL等级
- settextstyle(20,12,"宋体"); // 设置字体和大小
- settextcolor(CYAN); // 设置字体颜色
- if(player.level < 10)
- {
- sprintf_s(ch, "%s%d","LEVEL:", player.level);
- }
- else
- { // 等级为10时,显示最大max
- sprintf_s(ch, "%s","LEVEL:MAX");
- }
- outtextxy(GAMELEVEL1,GAMELEVEL2,ch);
- settextcolor(LIGHTBLUE);
- sprintf_s(ch, "%s%d","RANK:", player.rank);
- outtextxy(GAMERANK1,GAMERANK2,ch);
-
- // 绘制预生成方块的背景板
- setfillcolor(BLACK);
- solidrectangle(GAMEMAP5,GAMEMAP6,GAMEMAP7,GAMEMAP8);
-
- // 绘制预生成的方块
- for(i = 0; i < BLOCKSPACE; i++)
- {
- switch(preBlock.tetrisPreBlock[i])
- {
- case BLOCKNONE: // 空
- continue;
- break;
- case BLOCKBLUE: // 蓝色
- setfillcolor(BLUE);
- break;
- case BLOCKGREEN: // 绿色
- setfillcolor(GREEN);
- break;
- case BLOCKCYAN: // 青色
- setfillcolor(CYAN);
- break;
- case BLOCKRED: // 红色
- setfillcolor(RED);
- break;
- case BLOCKMAGENTA: // 深红色
- setfillcolor(MAGENTA);
- break;
- case BLOCKBROWN: // 灰色
- setfillcolor(BROWN);
- break;
- case BLOCKYELLOW:
- setfillcolor(YELLOW);
- break;
- }
- // 填充相应区域
- fillrectangle(GAMEMAP5 + (i%5) * SIDELENGTH ,GAMEMAP6 + (i/5) * SIDELENGTH ,GAMEMAP5 + ((i%5)+1)*SIDELENGTH ,GAMEMAP6 + ((i/5)+1) * SIDELENGTH );
- }
-
- // 绘制游戏地图背景板
- setfillcolor(BLACK);
- solidrectangle(GAMEMAP1,GAMEMAP2,GAMEMAP3,GAMEMAP4);
-
- // 绘制当前控制方块的4个方块格
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- switch(moveBlock.blockColor)
- {
- case BLOCKNONE:
- continue;
- break;
- case BLOCKBLUE:
- setfillcolor(BLUE);
- break;
- case BLOCKGREEN:
- setfillcolor(GREEN);
- break;
- case BLOCKCYAN:
- setfillcolor(CYAN);
- break;
- case BLOCKRED:
- setfillcolor(RED);
- break;
- case BLOCKMAGENTA:
- setfillcolor(MAGENTA);
- break;
- case BLOCKBROWN:
- setfillcolor(BROWN);
- break;
- case BLOCKYELLOW:
- setfillcolor(YELLOW);
- break;
- }
- // 填充相应区域
- fillrectangle(GAMEMAP1 + y * SIDELENGTH ,GAMEMAP2 + x * SIDELENGTH ,GAMEMAP1 + (y+1)*SIDELENGTH ,GAMEMAP2 + (x+1) * SIDELENGTH );
- }
-
- // 绘制游戏实时画面
- for(i = 0; i < TETRISHEIGHT; i++)
- {
- for(j = 0; j < TETRISWIDTH; j++)
- {
- switch(tetrisMap[i][j])
- {
- case BLOCKNONE:
- continue;
- break;
- case BLOCKBLUE:
- setfillcolor(BLUE);
- break;
- case BLOCKGREEN:
- setfillcolor(GREEN);
- break;
- case BLOCKCYAN:
- setfillcolor(CYAN);
- break;
- case BLOCKRED:
- setfillcolor(RED);
- break;
- case BLOCKMAGENTA:
- setfillcolor(MAGENTA);
- break;
- case BLOCKBROWN:
- setfillcolor(BROWN);
- break;
- case BLOCKYELLOW:
- setfillcolor(YELLOW);
- break;
- }
- // 填充相应区域
- fillrectangle(GAMEMAP1 + j * SIDELENGTH ,GAMEMAP2 + i * SIDELENGTH ,GAMEMAP1 + (j+1)*SIDELENGTH ,GAMEMAP2 + (i+1) * SIDELENGTH );
- }
- }
- }
// 更新RANK分数和LEVEL等级
settextstyle(20,12,"宋体"); // 设置字体和大小
settextcolor(CYAN); // 设置字体颜色
if(player.level < 10)
{
sprintf_s(ch, "%s%d","LEVEL:", player.level);
}
else
{ // 等级为10时,显示最大max
sprintf_s(ch, "%s","LEVEL:MAX");
}
outtextxy(GAMELEVEL1,GAMELEVEL2,ch);
settextcolor(LIGHTBLUE);
sprintf_s(ch, "%s%d","RANK:", player.rank);
outtextxy(GAMERANK1,GAMERANK2,ch);
1.设置输出字符的大小和字体,再设置颜色;
等级在10级以下时,照常显示;10级及以上时,显示MAX;
// 绘制预生成方块的背景板
setfillcolor(BLACK);
solidrectangle(GAMEMAP5,GAMEMAP6,GAMEMAP7,GAMEMAP8);
2. setfillcolor(BLACK)设置填充颜色;solidrectangle(GAMEMAP5,GAMEMAP6,GAMEMAP7,GAMEMAP8) 根据四个坐标,使用设置好的填充颜色填充矩形区域,实际就是绘制一个带白色边框的黑色矩形。
// 绘制预生成的方块
for(i = 0; i < BLOCKSPACE; i++)
{
switch(preBlock.tetrisPreBlock[i])
{
case BLOCKNONE: // 空
continue;
break;
case BLOCKBLUE: // 蓝色
setfillcolor(BLUE);
break;
case BLOCKGREEN: // 绿色
setfillcolor(GREEN);
break;
case BLOCKCYAN: // 青色
setfillcolor(CYAN);
break;
case BLOCKRED: // 红色
setfillcolor(RED);
break;
case BLOCKMAGENTA: // 深红色
setfillcolor(MAGENTA);
break;
case BLOCKBROWN: // 灰色
setfillcolor(BROWN);
break;
case BLOCKYELLOW:
setfillcolor(YELLOW);
break;
}
// 填充相应区域
fillrectangle(GAMEMAP5 + (i%5) * SIDELENGTH ,GAMEMAP6 + (i/5) * SIDELENGTH ,GAMEMAP5 + ((i%5)+1)*SIDELENGTH ,GAMEMAP6 + ((i/5)+1) * SIDELENGTH );
}
3.绘制好预生成方块区域后,preBlock.tetrisPreBlock[i]是一个包含20个成员的数组,里面有16个空成员,不用管;还有4个成员就是要绘制的方块。用switch选择相应的填充颜色setfillcolor(),然后再执行 fillrectangle()函数,在相应坐标填充方块;
最后的填充函数,可能会有点复杂,这里解释一下:
预生成方块区域是一个100X80像素大小的矩形,每个方块都是20X20像素大小,所以矩形按20X20像素切割,得到一个5X4的坐标轴,包含20个方块,刚好和所有方块数据库里的方块对应。
如下图所示,只需要把数据库里20个数据中,包含方块的四个数据选出来填入,就能得到一个完整的方块了。
现在,我想要绘制一个 '----' 型方块,只需要填充2,3,4,5这4个坐标,就能得到方块;
那么它在preBlock.tetrisPreBlock[]数组中对应的数据就是
{0,1,1,1,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0};得到的最终图像就是如下所示
当preBlock.tetrisPreBlock[i]为1时,就会执行fillrectangle()函数,根据i的值,获得四个坐标值,填充这个方块;
第一个方块:i = 1, fillrectangle(GAMEMAP5 + 1 * 20,GAMEMAP6,GAMEMAP5 + 2*20,GAMEMAP6 + 1 * 20);
GAMEMAP5和GAMEMAP6就是预生成方块区域的坐上角坐标,将它视为起点坐标,忽略掉,
上面的fillrectangle() 就相当于fillrectangle( 20,0, 40,20),绘制出来就是如下图
第二个方块:i = 2,fillrectangle(GAMEMAP5 + 2 * 20,GAMEMAP6 ,GAMEMAP5 + 3*20,GAMEMAP6 + 1 * 20);
忽略起点坐标,得到fillrectangle( 40,0,60,20),绘制出来如下图
依次画出第三个方块,第四个方块,就能得到最终的图像了
// 绘制游戏地图背景板
setfillcolor(BLACK);
solidrectangle(GAMEMAP1,GAMEMAP2,GAMEMAP3,GAMEMAP4);
4.和2类似,绘制一个白色边框的纯黑矩形
// 绘制当前控制方块的4个方块格
for(i = 0; i < 4; i++)
{
x = moveBlock.blockSite[i][0];
y = moveBlock.blockSite[i][1];
switch(moveBlock.blockColor)
{
case BLOCKNONE:
continue;
break;
case BLOCKBLUE:
setfillcolor(BLUE);
break;
case BLOCKGREEN:
setfillcolor(GREEN);
break;
case BLOCKCYAN:
setfillcolor(CYAN);
break;
case BLOCKRED:
setfillcolor(RED);
break;
case BLOCKMAGENTA:
setfillcolor(MAGENTA);
break;
case BLOCKBROWN:
setfillcolor(BROWN);
break;
case BLOCKYELLOW:
setfillcolor(YELLOW);
break;
}
// 填充相应区域
fillrectangle(GAMEMAP1 + y * SIDELENGTH ,GAMEMAP2 + x * SIDELENGTH ,GAMEMAP1 + (y+1)*SIDELENGTH ,GAMEMAP2 + (x+1) * SIDELENGTH );
}
5.和3类似,变量moveBlock.blockSite[]保存了当前方块的四个方块格坐标,根据方块颜色moveBlock.blockColor,通过switch选择相应的颜色,然后fillrectangle填充,得到当前方块。
// 绘制游戏实时画面
for(i = 0; i < TETRISHEIGHT; i++)
{
for(j = 0; j < TETRISWIDTH; j++)
{
switch(tetrisMap[i][j])
{
case BLOCKNONE:
continue;
break;
case BLOCKBLUE:
setfillcolor(BLUE);
break;
case BLOCKGREEN:
setfillcolor(GREEN);
break;
case BLOCKCYAN:
setfillcolor(CYAN);
break;
case BLOCKRED:
setfillcolor(RED);
break;
case BLOCKMAGENTA:
setfillcolor(MAGENTA);
break;
case BLOCKBROWN:
setfillcolor(BROWN);
break;
case BLOCKYELLOW:
setfillcolor(YELLOW);
break;
}
// 填充相应区域
fillrectangle(GAMEMAP1 + j * SIDELENGTH ,GAMEMAP2 + i * SIDELENGTH ,GAMEMAP1 + (j+1)*SIDELENGTH ,GAMEMAP2 + (i+1) * SIDELENGTH );
}
}
6.和3、5类似,tetrisMap[]数组保存了游戏地图中已经固定下来的方块和颜色,通过switch选择颜色,然后使用fillrectangle()函数,绘制所有固定方块。
当新方块标识player.newBlockFlag为1时,会执行本函数,把预生成方块加载进游戏,成为当前控制方块;之后再获取随机数,生成新的预生成方块。
- void tetrisNewBlock(void)
- {
- int i,j,k;
-
- // 把上一个随机方块加载进当前方块数组
- k = 0;
- for(i = 0; i < BLOCKSPACE; i++)
- {
- if(preBlock.tetrisPreBlock[i])
- {
- moveBlock.blockColor = preBlock.tetrisPreBlock[i]; // 记录方块颜色
- moveBlock.blockSite[k][0] = i/5; // 记录方块格的X坐标
- moveBlock.blockSite[k][1] = 5 + i%5; // 记录方块格的Y坐标
- k++;
- }
- }
- player.blockType = preBlock.blockType; // 记录方块的类型
- player.blockStyle = preBlock.blockStyle; // 记录方块的形状(朝向)
-
- // 获取随机数,生成新的随机方块
- srand((unsigned)time(NULL));
- i = rand() % BLOCKTYPE;
- j = rand() % BLOCKSTYLE;
- for(k = 0; k < BLOCKSPACE;k++)
- {
- preBlock.tetrisPreBlock[k] = block[i][j][k];
- }
- preBlock.blockType = i;
- preBlock.blockStyle = j;
- }
// 把上一个随机方块加载进当前方块数组
k = 0;
for(i = 0; i < BLOCKSPACE; i++)
{
if(preBlock.tetrisPreBlock[i])
{
moveBlock.blockColor = preBlock.tetrisPreBlock[i]; // 记录方块颜色
moveBlock.blockSite[k][0] = i/5; // 记录方块格的X坐标
moveBlock.blockSite[k][1] = 5 + i%5; // 记录方块格的Y坐标
k++;
}
}
player.blockType = preBlock.blockType; // 记录方块的类型
player.blockStyle = preBlock.blockStyle; // 记录方块的形状(朝向)
1.preBlock.tetrisPreBlock[i]数组有16个成员为0,还有4个非0成员(方块格),检测到非0成员(方块格)时,就会记录方块颜色、坐标、类型、形状(朝向),保存到当前方块变量moveBlock。
// 获取随机数,生成新的随机方块
srand((unsigned)time(NULL));
i = rand() % BLOCKTYPE;
j = rand() % BLOCKSTYLE;
for(k = 0; k < BLOCKSPACE;k++)
{
preBlock.tetrisPreBlock[k] = block[i][j][k];
}
preBlock.blockType = i;
preBlock.blockStyle = j;
2.生成随机数,然后得到方块类型和形状(朝向),再把方块数据库中对应的20个成员值复制到preBlock.tetrisPreBlock数组中,就成为了一个新的随机方块。
当玩家按下W键后,会执行此函数,如果当前方块可改变形状(朝向),则改变形状(朝向)。
- void tetrisMoveUp(void)
- {
- int i,k;
- int bStyle;
- int ux,uy; // 改变方块朝向前后,方块格的位移矢量
- int blocksite2[4][2]; // 记录改变朝向前,4个方块的方块库坐标
- int blocksite3[4][2]; // 记录改变朝向后,4个方块的方块库坐标
- int blocksite4[4][2]; // 记录改变朝向后,4个方块的游戏地图坐标
-
- // 找到4个方块格的方块库坐标
- k = 0;
- for(i = 0; i < BLOCKSPACE; i++)
- {
- // 得到4个方块坐标后,退出循环
- if(k > 3)
- {
- break;
- }
- if(block[player.blockType][player.blockStyle][i])
- {
- blocksite2[k][0] = i / 5;
- blocksite2[k][1] = i % 5;
- k++;
- }
- }
- // 找到改变朝向后,4个方块格的方块库坐标
- k = 0;
- bStyle = (player.blockStyle + 1)%BLOCKSTYLE; // 获取改变朝向后的方块形状
- for(i = 0; i < BLOCKSPACE; i++)
- {
- // 得到4个方块坐标后,退出循环
- if(k > 3)
- {
- break;
- }
- if(block[player.blockType][bStyle][i])
- {
- blocksite3[k][0] = i / 5;
- blocksite3[k][1] = i % 5;
- k++;
- }
- }
- // 根据改变前后方块坐标的位移矢量,得到改变朝向后的当前控制方块的新坐标
- for(i = 0; i < 4; i++)
- {
- ux = blocksite3[i][0] - blocksite2[i][0]; // 获取方格的X位移矢量
- uy = blocksite3[i][1] - blocksite2[i][1]; // 获取方格的Y位移矢量
-
- blocksite4[i][0] = moveBlock.blockSite[i][0] + ux; // 得到改变朝向后的,当前控制方块格,位于游戏地图的新X坐标
- blocksite4[i][1] = moveBlock.blockSite[i][1] + uy; // 得到改变朝向后的,当前控制方块格,位于游戏地图的新Y坐标
-
- if( (blocksite4[i][0] < 0) // 判断新坐标是否超出游戏地图,超出则终止改变方块朝向
- || (blocksite4[i][1] < 0)
- || (blocksite4[i][0] > TETRISHEIGHT - 1)
- || (blocksite4[i][1] > TETRISWIDTH - 1)
- || ( tetrisMap[blocksite4[i][0]][blocksite4[i][1]] ) ) // 如果新坐标在游戏地图中已存在方块格,则终止改变方块朝向
- {
- return;
- }
- }
- // 改变方块朝向没有问题,则更新新方块的坐标
- for(i = 0;i < 4; i++)
- {
- moveBlock.blockSite[i][0] = blocksite4[i][0];
- moveBlock.blockSite[i][1] = blocksite4[i][1];
- }
- player.blockStyle = bStyle; // 更新方块格形状
-
- }
// 找到4个方块格的方块库坐标
k = 0;
for(i = 0; i < BLOCKSPACE; i++)
{
// 得到4个方块坐标后,退出循环
if(k > 3)
{
break;
}
if(block[player.blockType][player.blockStyle][i])
{
blocksite2[k][0] = i / 5;
blocksite2[k][1] = i % 5;
k++;
}
}
1.根据当前控制方块的形状(朝向),在方块数据库中找到对应的坐标,并放入数组blocksite2中。
// 找到改变朝向后,4个方块格的方块库坐标
k = 0;
bStyle = (player.blockStyle + 1)%BLOCKSTYLE; // 获取改变朝向后的方块形状
for(i = 0; i < BLOCKSPACE; i++)
{
// 得到4个方块坐标后,退出循环
if(k > 3)
{
break;
}
if(block[player.blockType][bStyle][i])
{
blocksite3[k][0] = i / 5;
blocksite3[k][1] = i % 5;
k++;
}
}
2. player.blockStyle是当前方块的形状(朝向),只要把这个变量加1,再取余方块形状数,就可以得到新的方块形状(朝向)bStyle;根据方块类型,还有新的朝向bStyle,就可以从方块数据库中得到新方块的坐标,把新方块的坐标放入blocksite3[]数组。
// 根据改变前后方块坐标的位移矢量,得到改变朝向后的当前控制方块的新坐标
for(i = 0; i < 4; i++)
{
ux = blocksite3[i][0] - blocksite2[i][0]; // 获取方格的X位移矢量
uy = blocksite3[i][1] - blocksite2[i][1]; // 获取方格的Y位移矢量blocksite4[i][0] = moveBlock.blockSite[i][0] + ux; // 得到改变朝向后的,当前控制方块格,位于游戏地图的新X坐标
blocksite4[i][1] = moveBlock.blockSite[i][1] + uy; // 得到改变朝向后的,当前控制方块格,位于游戏地图的新Y坐标
if( (blocksite4[i][0] < 0) // 判断新坐标是否超出游戏地图,超出则终止改变方块朝向
|| (blocksite4[i][1] < 0)
|| (blocksite4[i][0] > TETRISHEIGHT - 1)
|| (blocksite4[i][1] > TETRISWIDTH - 1)
|| ( tetrisMap[blocksite4[i][0]][blocksite4[i][1]] ) ) // 如果新坐标在游戏地图中已存在方块格,则终止改变方块朝向
{
return;
}
}
3.既然通过1、2步骤,得到了方块改变形状前后,位于方块数据库中的坐标,那么就可以通过把新旧坐标相减,得到旧坐标的位移矢量ux,uy;
通过位移矢量ux,uy,还有当前方块的四个方块格坐标moveBlock.blockSite,就可以得到改变形状(朝向)后,当前方块的新坐标,并把新坐标放入blocksite4[][]数组中;
有了新坐标blocksite4,就可以判断当前方块是否可以改变形状(朝向),首先判断新坐标是否超过游戏地图范围,再判断新坐标位置,是否已经存在方块;只要有一个不符合,那么本次操作无效,退出函数。
// 改变方块朝向没有问题,则更新新方块的坐标
for(i = 0;i < 4; i++)
{
moveBlock.blockSite[i][0] = blocksite4[i][0];
moveBlock.blockSite[i][1] = blocksite4[i][1];
}
player.blockStyle = bStyle; // 更新方块格形状
4.如果方块可以改变形状(朝向),那么就把方块的新坐标blocksite4,赋值给当前方块坐标moveBlock.blockSite;再把新的方块形状(朝向)bStyle,赋值给当前方块形状player.blockStyle
当方块下移标识player.moveFlag为1时,会执行本函数,控制当前方块下移。
player.moveFlag为1有两种条件
1:每个周期(默认500ms)会赋值为1。
2:用户按下S键,会赋值为1。
- void tetrisMoveDown(void)
- {
- int i;
- int x,y;
-
- // 判断当前方块是否到达地图底部
- for(i = 0; i < 4; i++)
- {
- if(moveBlock.blockSite[i][0] > TETRISHEIGHT - 2)
- {
- // 如果到达地图底部,把生成新方块标识置1
- player.newBlockFlag = TRUE;
- return;
- }
- }
- // 判断当前方块能否下移,是否会和游戏地图已存在的方块产生冲突
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0] + 1; // 获取方块下移后的新X坐标
- y = moveBlock.blockSite[i][1]; // 获取方块下移后的新Y坐标
- // 如果新坐标在游戏地图中,已经存在方块格,则方块停止移动
- if(tetrisMap[x][y])
- {
- player.newBlockFlag = TRUE;
- return;
- }
- }
- // 当前方块下移
- for(i = 0; i < 4; i++)
- {
- moveBlock.blockSite[i][0]++;
- }
-
- }
// 判断当前方块是否到达地图底部
for(i = 0; i < 4; i++)
{
if(moveBlock.blockSite[i][0] > TETRISHEIGHT - 2)
{
// 如果到达地图底部,把生成新方块标识置1
player.newBlockFlag = TRUE;
return;
}
}
1.每次方块下移时,都会先判断方块是否到达游戏地图底部,如果到达底部,会给新方块标识player.newBlockFlag赋1,然后退出本函数,当前方块不再移动。
// 判断当前方块能否下移,是否会和游戏地图已存在的方块产生冲突
for(i = 0; i < 4; i++)
{
x = moveBlock.blockSite[i][0] + 1; // 获取方块下移后的新X坐标
y = moveBlock.blockSite[i][1]; // 获取方块下移后的新Y坐标
// 如果新坐标在游戏地图中,已经存在方块格,则方块停止移动
if(tetrisMap[x][y])
{
player.newBlockFlag = TRUE;
return;
}
}
2.方块下移会改变moveBlock.blockSite[][]数组的X坐标,加一;
判断游戏地图中新坐标位置是否已存在方块,如果存在方块,会给新方块标识player.newBlockFlag赋1,然后退出本函数,当前方块不再移动。
// 当前方块下移
for(i = 0; i < 4; i++)
{
moveBlock.blockSite[i][0]++;
}
3.方块可以下移,则将当前方块的4个方块格的X坐标都加一。
每当用户按下A键,会执行本函数,控制当前方块左移。
- void tetrisMoveLeft(void)
- {
- int i;
- int x,y;
-
- // 先判断是否能左移
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- // 将Y坐标减一,再判断是否超出地图范围或引起冲突
- if( (y - 1) < 0 // 1.超出地图范围
- || tetrisMap[x][y - 1]) // 2.方块将要移动的地方已存在方块格
- {
- return; // 超出地图范围或冲突,无法左移
- }
- }
- // 左移
- for(i = 0; i < 4; i++)
- {
- moveBlock.blockSite[i][1]--;
- }
-
- }
// 先判断是否能左移
for(i = 0; i < 4; i++)
{
x = moveBlock.blockSite[i][0];
y = moveBlock.blockSite[i][1];
// 将Y坐标减一,再判断是否超出地图范围或引起冲突
if( (y - 1) < 0 // 1.超出地图范围
|| tetrisMap[x][y - 1]) // 2.方块将要移动的地方已存在方块格
{
return; // 超出地图范围或冲突,无法左移
}
}
1.方块左移,就是把方块的Y坐标减一,然后判断新的坐标是否超过游戏地图范围、新的坐标是否已经存在方块;只要有一个条件不满足,就会退出本函数,无法左移。
// 左移
for(i = 0; i < 4; i++)
{
moveBlock.blockSite[i][1]--;
}
2.可以左移,则将当前方块的四个方块格的Y坐标都减一。
每当用户按下D键,会执行本函数,控制当前方块右移。
和左移函数基本相同,就是Y坐标变为加1,因此不再过多说明。
- void tetrisMoveRight(void)
- {
- int i;
- int x,y;
- //k = 0;
- // 先判断是否能右移
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- // 将Y坐标加1,再判断是否超出地图范围或冲突
- if( ((y + 1) >= TETRISWIDTH) // 1.超出地图范围
- || (tetrisMap[x][y + 1]) ) // 2.方块将要移动的地方已存在方块格
- {
- return; // 超出地图范围或冲突,无法左移
- }
- }
- // 右移
- for(i = 0; i < 4; i++)
- {
- moveBlock.blockSite[i][1]++;
- }
-
- }
每当新方块标识player.newBlockFlag为1时,执行本函数,将当前控制方块固定在游戏地图。
- void tetrisLoadBlock(void)
- {
- int i;
- int x,y;
-
- // 将当前方块载入游戏地图
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- // 只有游戏地图坐标不为空,才会改变游戏地图
- if(!tetrisMap[x][y])
- {
- tetrisMap[x][y] = moveBlock.blockColor;
- }
- }
- }
每当新方块标识player.newBlockFlag为1时,执行本函数,判断游戏是否结束
- void tetrisIsOver(void)
- {
- int i;
- int x,y;
-
- // 将新的移动方块与游戏地图比较,如果有冲突格,则游戏结束
- for(i = 0; i < 4; i++)
- {
- x = moveBlock.blockSite[i][0];
- y = moveBlock.blockSite[i][1];
- // 如果移动方块和游戏地图在同一坐标都存在方块,则游戏结束
- if(tetrisMap[x][y])
- {
- player.gameOverFlag = TRUE;
- tetrisDraw();
- tetrisQuit();
- return;
- }
- }
- }
将预生成方块载入游戏地图时,和游戏地图比较;预生成方块和游戏地图已存在的方块重叠,则预生成方块无法载入游戏地图,游戏无法继续,判断游戏结束。
将游戏结束标识player.gameOverFlag赋1,接着执行tetrisDraw()函数,绘制重叠方块;再执行tetrisQuit()函数,由用户选择是退出游戏还是重新开始游戏。
本函数执行有两种方式,一:游戏结束,玩家已无法再继续游戏。
二:玩家按下了ESC键,想要主动退出游戏。
- void tetrisQuit(void)
- {
- int key,flag;
- flag = player.gameOverFlag;
- // 让用户选择是否退出
- key = MessageBox(NULL,"是否退出游戏?","提示",MB_YESNO| MB_SYSTEMMODAL);
- switch(key)
- {
- case IDYES:
- player.gameOverFlag = TRUE;
- break;
- case IDNO:
- player.gameOverFlag = FALSE;
- break;
- default:
- break;
- }
- // 如果游戏已无法继续,且用户不退出游戏,则强制用户选择结束游戏,或重新开始游戏
- while(flag
- && !player.gameOverFlag)
- {
- key = MessageBox(NULL,"检测到游戏已无法继续,\n请选择\"是\": 退出游戏;\n或者选择\"否\": 重启游戏;","提示",MB_YESNO| MB_SYSTEMMODAL);
- switch(key)
- {
- case IDYES:
- player.gameOverFlag = TRUE;
- break;
- case IDNO:
- tetrisInit();
- player.gameOverFlag = FALSE;
- return;
- default:
- break;
- }
- }
- CLEARKEY();
- }
1.flag = player.gameOverFlag;
// 让用户选择是否退出
key = MessageBox(NULL,"是否退出游戏?","提示",MB_YESNO| MB_SYSTEMMODAL);
switch(key)
{
case IDYES:
player.gameOverFlag = TRUE;
break;
case IDNO:
player.gameOverFlag = FALSE;
break;
default:
break;
}
1.flag标识用于区分是游戏结束,还是玩家主动结束游戏,不同方式有不同处理。
生成一个消息弹窗,MB_SYSTEMMODAL是强制弹窗置顶,功能类似于微信置顶功能。
key是用于得到用户选择“是”还是“否”,如果玩家选择退出游戏, 将游戏结束标识player.gameOverFlag置1;反之置0。
// 如果游戏已无法继续,且用户不退出游戏,则强制用户选择结束游戏,或重新开始游戏
while(flag
&& !player.gameOverFlag)
{
key = MessageBox(NULL,"检测到游戏已无法继续,\n请选择\"是\": 退出游戏;\n或者选择\"否\": 重启游戏;","提示",MB_YESNO| MB_SYSTEMMODAL);
switch(key)
{
case IDYES:
player.gameOverFlag = TRUE;
break;
case IDNO:
tetrisInit();
player.gameOverFlag = FALSE;
return;
default:
break;
}
}
CLEARKEY();
2.如果是用户主动结束游戏,那么flag为0,不会进入循环;
如果是游戏已无法继续进行,那么flag为1,会进入循环。
如果进入循环,会生成一个消息弹窗,提示用户是退出游戏,还是重新开始游戏并获取用户选择结果。
通过key获取用户选择, 如果用户选择“是”,那么再次赋值player.gameOverFlag = TRUE,接着退出此函数。
如果用户选择“否”,那么会执行初始化函数tetrisInit(),并赋值player.gameOverFlag = FALSE;
重新开始游戏。
CLEARKEY();是一个宏定义,用于清除按键输入缓冲区。
用户按键处理函数,每次用户按下相应按键后,都会执行本函数。
其中的W键改变方块形状(朝向)、A键左移、S键下移、D键右移、ESC退出键都已经在上面的函数说明了,这里就不再复述。
- void tetrisKeyHandle(void)
- {
- switch(player.key)
- {
- case 'w':
- case 'W':
- // W键,改变当前方块的朝向
- tetrisMoveUp();
- break;
- case 'a':
- case 'A':
- // A键,当前方块想左移动
- tetrisMoveLeft();
- break;
- case 's':
- case 'S':
- // S键,当前方块向下移动
- player.moveFlag = TRUE;
- player.ttime = GetTickCount();
- return;
- case 'd':
- case 'D':
- // D键,当前方块向右移动
- tetrisMoveRight();
- break;
- case ESC:
- // 退出键,退出游戏
- tetrisQuit();
- break;
- case 'r':
- case 'R':
- // R键,重置游戏进度
- tetrisReset();
- break;
- default:
- break;
- }
- // 按键之后,刷新地图
- tetrisDraw();
- }
1.就剩一个R键重新开始游戏了;
按下R键后,会执行tetrisReset()函数,进行游戏重置,函数详情会在下一个函数说明。
重置游戏函数,玩家按下R键后,可以选择是否重新开始游戏。
- void tetrisReset(void)
- {
- int key;
- key = MessageBox(NULL, "是否重新开始游戏?", "提示", MB_YESNO | MB_SYSTEMMODAL);
- CLEARKEY();
- switch (key)
- {
- case IDYES:
- tetrisInit();
- break;
- case IDNO:
- break;
- default:
- break;
- }
- }
生成一个置顶弹窗,用变量key获取用户点击的按钮(“是”“否”);
如果用户点击的是“是”,则执行tetrisInit()函数,初始化所有游戏数据,重新开始游戏。
如果用户点击的是“否”,则取消重置游戏,本次按键无效。
最后一个函数,消除满行函数,每次生成新方块标识player.newBlockFlag置1时,会执行本函数。
- void tetrisRemove(void)
- {
- int i, j, m, n;
- int flag, bnum;
- bnum = 0;
-
- // 从最下面一行开始,检测并消除满行方块
- for (i = TETRISHEIGHT - 1; i >= 0; i--)
- {
- flag = 0;
- for (j = 0; j < TETRISWIDTH; j++)
- {
- // 只要检测到空格,就不再检测本行
- if (!tetrisMap[i][j])
- {
- flag = 1;
- break;
- }
- }
- if (flag)
- {
- continue;
- }
- // 满行,消除行数加1
- bnum++;
- // 检测到满行,消除当前行
- for (j = 0; j < TETRISWIDTH; j++)
- {
- tetrisMap[i][j] = BLOCKNONE;
- }
- // 消除行上面的所有方块下移一行
- for (m = i; m > 0; m--)
- {
- for (n = 0; n < TETRISWIDTH; n++)
- {
- tetrisMap[m][n] = tetrisMap[m - 1][n];
- }
- }
- i++; // 由于消除行上面的方块下移了,所以再从当前行检测
- }
-
- // 消除行数为0,退出
- if (!bnum)
- {
- return;
- }
- // 根据消除的行数,增加RANK分数
- switch (bnum)
- {
- case 0:
- break;
- case 1:
- player.rank += 10;
- break;
- case 2:
- player.rank += 20;
- break;
- case 3:
- player.rank += 40;
- break;
- case 4:
- player.rank += 80;
- break;
- default:
- break;
- }
- // 根据rank分数换算成level
- player.level = player.rank / 100;
- if (player.level > 10)
- {
- player.level = 10;
- }
-
- }
// 从最下面一行开始,检测并消除满行方块
for (i = TETRISHEIGHT - 1; i >= 0; i--)
{
flag = 0;
for (j = 0; j < TETRISWIDTH; j++)
{
// 只要检测到空格,就不再检测本行
if (!tetrisMap[i][j])
{
flag = 1;
break;
}
}
if (flag)
{
continue;
}
// 满行,消除行数加1
bnum++;
// 检测到满行,消除当前行
for (j = 0; j < TETRISWIDTH; j++)
{
tetrisMap[i][j] = BLOCKNONE;
}
// 消除行上面的所有方块下移一行
for (m = i; m > 0; m--)
{
for (n = 0; n < TETRISWIDTH; n++)
{
tetrisMap[m][n] = tetrisMap[m - 1][n];
}
}
i++; // 由于消除行上面的方块下移了,所以再从当前行检测
}
1.从游戏地图最下面一行开始检测,依次检测到最上面一行;只要检测到一个空白格,则放弃检测本行,检测上一行。
如果当前行是满行,则消除行数bnum加一;然后把当前行清零;清零后,把当前行上面的所有方块全部下移一行;i++是因为所有方块都下移一行了,需要再次从当前行开始检测。
// 消除行数为0,退出
if (!bnum)
{
return;
}
// 根据消除的行数,增加RANK分数
switch (bnum)
{
case 0:
break;
case 1:
player.rank += 10;
break;
case 2:
player.rank += 20;
break;
case 3:
player.rank += 40;
break;
case 4:
player.rank += 80;
break;
default:
break;
}
// 根据rank分数换算成level
player.level = player.rank / 100;
if (player.level > 10)
{
player.level = 10;
}
2.如果没有检测到可消除行(bnum为0),则退出本函数。
根据消除行数bnum,增加player.rank分数:
1行加10分;2行加20分;3行加40分;4行加80。
根据player.rank分数,换算成player.level等级:
1000分以下,等级是分数/100;1000分以上,等级固定为10(MAX)。
至此,代码部分已经结束,从编写俄罗斯方块到结束,代码有经历过各种优化,bug也基本都修正了,可以说是一个比较完善的版本(基本没有BUG)。有任何疑问都可以在评论里提问,谢谢观看。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。