C++實(shí)現(xiàn)俄羅斯方塊
本文實(shí)例為大家分享了C++實(shí)現(xiàn)俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
工具:vc++2010,圖庫(kù):EasyX
先看效果圖片

純手寫(xiě),沒(méi)有面向?qū)ο笏枷?看全部源碼
#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;//下一個(gè)方塊種類
int BlockIndex = -1;//當(dāng)前方塊種類
int score = 0;//分?jǐn)?shù)
int rank = 0;//等級(jí)
int visit[30][15];//訪問(wèn)數(shù)組
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(){
//初始化畫(huà)布
initgraph(550,660);
//設(shè)置窗口標(biāo)題
HWND window = GetHWnd();//獲取窗口
SetWindowText(window,_T("俄羅斯方塊 GWF"));//設(shè)置窗口標(biāo)題
//設(shè)置文本字體樣式
setfont(0,30,_T("微軟雅黑"));
setcolor(YELLOW);
outtextxy(150,200,_T("俄羅斯方塊"));
setfont(0,10,_T("微軟雅黑"));
outtextxy(175,300,_T("IT編程從俄羅斯方塊開(kāi)始"));
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("下一個(gè)"));
setcolor(RED);
outtextxy(405,280,_T("分?jǐn)?shù)"));
sprintf(str,"%d",score);
outtextxy(415,310,str);
outtextxy(405,375,_T("等級(jí)"));
sprintf(str,"%d",rank);
outtextxy(415,405,str);
setcolor(LIGHTBLUE);
outtextxy(390,475,"操作說(shuō)明");
outtextxy(390,500,"↑:旋轉(zhuǎn)");
outtextxy(390,525,"↓:下降");
outtextxy(390,550,"→:向右");
outtextxy(390,575,"←:向左");
outtextxy(390,600,"空格:暫停");
}
void drawBlock(int x,int y){//右上角畫(huà)出方塊
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){//按索引畫(huà)出什么方塊指定位置方塊指定方向
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);//清除右上角方塊
//隨機(jī)選擇一種方塊
srand(time(NULL));//時(shí)間函數(shù)的返回值產(chǎn)生隨機(jī)數(shù)種子
NextIndex = rand()%BLOCK_COUNT;
drawBlock(391,71);//畫(huà)出方塊
}
//如果在指定位置可以向方向移動(dòng)
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(){//游戲是否結(jié)束
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;
}
}
}//判斷當(dāng)前方向是否可以轉(zhuǎn)到指定方向
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,"■");
}
}
}
//清除最頂層那一行,就是行標(biāo)位0的哪一行
setcolor(BLACK);
for(int j = 0;j<15;j++){
visit[0][j] = 0;
outtextxy(20*j+minX,minY,"■");
}
}
void updataGrade(){
//更新等級(jí)提示
//假設(shè):50分一級(jí)
char str[10];
rank = score/50;
sprintf(str,"%d",rank);
outtextxy(425,405,str);
//更新速度,等級(jí)越高速度越快,speed越小
//最慢是500,最快是50
speed = 500-rank*50;
if(speed<=0){
speed = 50;
}
}
void addScore(int lines){//更新分?jǐn)?shù),line表示消除的行數(shù)
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++);
//執(zhí)行到此處有兩種情況,
//1.第I行沒(méi)有滿,即表示有空位,此時(shí)j<15
//2.第i行已經(jīng)滿了,j就大于等于15
if(j>=15){
//此時(shí)第i行已經(jīng)滿了,就需要消除第i行
clear_down(i);//清除第i行,并把上面的行都下移動(dòng)
i++;
clearLines++;
}
}
//更新分?jǐn)?shù)
addScore(clearLines);
//更新等級(jí)
updataGrade();
}
void move(){
int x = START_X;
int y = START_Y;
int k = 0;
int curSpeed = speed;
block_dir_t blockDir = BLOCK_UP;
//檢查游戲是否結(jié)束
failCheck();
while(1){
if(kbhit()){
int key = getch();
if(KEY_SPACE == key){
getch();
}
}
//清除當(dāng)前方塊
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){//鄉(xiāng)下加速
curSpeed = 50;
}else if(KEY_RIGHT == key){//右移動(dòng)
if(moveable(x,y+k+20,MOVE_RIGHT,blockDir)){
x+=20;
}
}else if(KEY_LEFT == key){//左移動(dòng)
if(moveable(x,y+k+20,MOVE_LEFT,blockDir)){
x-=20;
}
}
}
k+=20;
//繪制當(dāng)前方塊
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;
//繪制方塊從頂部掉下來(lái)
drawBlock(START_X,START_Y);
//新出現(xiàn)的方塊等一下
Sleep(100);
//右上角繪制下一個(gè)方塊
nextblock();
//向下降落的動(dòng)作
move();
}
int main (void){
welcome();
initGameScene();
//產(chǎn)生新方塊
nextblock();
Sleep(500);
memset(visit,0,sizeof(visit));
while(1){
newblock();
//消除滿行,并更新分?jǐn)?shù)和速度
check();
}
system("pause");
closegraph();
return 0;
}
分析項(xiàng)目:
1.必須要有歡迎界面
2.搭建合理的邊界,就是游戲范圍
3.邏輯1:先出現(xiàn)右上方的方塊樣式,等待一段時(shí)間,將右上方的樣式在游戲區(qū)打印出
4.邏輯2,方塊降落,要擦除原先印記,將1改為0
5.邏輯3,熱鍵控制移動(dòng)方向,暫停及變形,且不能移動(dòng)出界,判斷方塊是否還能移動(dòng)
6.邏輯4,方塊凝固在下方不出界
7.邏輯5,最下面一行方塊疊滿了,消去它并把上面的行都下移(分兩種情況),并且再次檢查這一行
8.邏輯6,計(jì)算消除行數(shù)次數(shù),統(tǒng)計(jì)分?jǐn)?shù),控制休眠時(shí)間長(zhǎng)度
9.邏輯7,每次移動(dòng)先判斷是否能移動(dòng),默認(rèn)結(jié)束程序,在合理游戲區(qū)返回false,結(jié)束界面



總結(jié):從界面開(kāi)始到完整的架構(gòu),功能后實(shí)現(xiàn),一步一步,邏輯嚴(yán)謹(jǐn),思路清晰,注釋在代碼里。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)音樂(lè)播放器的示例代碼
這篇文章主要和大家分享了一個(gè)C語(yǔ)言的小DEMO,可以實(shí)現(xiàn)音樂(lè)播放器功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-02-02
OpenCV圖像旋轉(zhuǎn)Rotate的詳細(xì)介紹
這篇文章主要介紹了OpenCV圖像旋轉(zhuǎn)Rotate,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
C++ 項(xiàng)目引入lib和dll的區(qū)別與使用實(shí)戰(zhàn)
靜態(tài)鏈接庫(kù)與動(dòng)態(tài)鏈接庫(kù)都是共享代碼的方式,本文主要介紹了C++項(xiàng)目引入lib和dll的區(qū)別與使用實(shí)戰(zhàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
C++實(shí)現(xiàn)第K順序統(tǒng)計(jì)量的求解方法
這篇文章主要介紹了C++實(shí)現(xiàn)第K順序統(tǒng)計(jì)量的求解方法,很有借鑒價(jià)值的算法,需要的朋友可以參考下2014-08-08
C++?使用?new?創(chuàng)建二維數(shù)組實(shí)例
這篇文章主要介紹了C++?使用?new?創(chuàng)建二維數(shù)組實(shí)例的相關(guān)資料,需要的朋友可以參考下2023-01-01
C語(yǔ)言實(shí)現(xiàn)BST二叉排序樹(shù)的基本操作
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)BST二叉排序樹(shù)的基本操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
C++實(shí)現(xiàn)景區(qū)旅游信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)景區(qū)旅游信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

