實訓:俄羅斯方塊

本來是一天上傳一點的,結果一次性上傳了( ̄▽ ̄)",尷尬。

HANDLE Output;
void printPrompting();                                                  //顯示提示信息
void gotoxyWithFullwidth(short x,short y);                              //進行全角定位
void printScore(const Manager *manager);                                //顯示分數
void printPoolBorder();                                                 //顯示遊戲池邊界
void initGame(Manager *manager,Control *control);                       //初始化遊戲
void startGame(Manager *manager,Control *control);                      //開始遊戲
void printNextTetris(const Manager *manager);                           //顯示下一個和下下一個方塊
void printTetrisPool(const Manager *manager,const Control *control);    //顯示遊戲池
void initTetris(Manager *manager);                                      //方塊初始化,構造當前方塊
void insertTetris(Manager *manager);                                    //把當前方塊插入遊戲池中
void setPoolColor(const Manager *manager,Control *control);             //設置顏色
void printCurrentTetris(const Manager *manager,const Control *control); //顯示當前方塊
bool checkCollision(const Manager *manager);                            //碰撞檢測
void runGame(Manager *manager,Control *control);                        //運行遊戲
void moveDownTetris(Manager *manager,Control *control);                 //向下移動方塊
void removeTetris(Manager *manager);                                    //移去方塊
bool checkErasing(Manager *manager,Control *control);                   //檢測消行
void horzMoveTetris(Manager *manager,Control *control);                 //左右移動
void rotateTetris(Manager *manager,Control *control);                   //旋轉方塊
void keydownControl(Manager *manager,Control *control,int key);         //鍵入指令
void dropDownTetris(Manager *manager,Control *control);                 //消行
bool ifPlayAgain();                                                     //重新遊戲

這是所有的函數。

 

#include <stdio.h>
#include <stdlib.h>
#include"day8.h"
int main()
{
    Manager manager;
    Control control;
    //初始化函數
    initGame(&manager,&control);
    //initTetris(&manager);
    //runGame(&manager,&control);
    //初始化結構體
   // Output=GetStdHandle(STD_OUTPUT_HANDLE);



    do
    {   printPrompting();
        //printScore(&manager);
        printPoolBorder();
        // printNextTetris(&manager);//顯示下一個和下下一個方塊
        // printTetrisPool(&manager,&control);//顯示遊戲池
        // setPoolColor(&manager,&control);
        // insertTetris(&manager);
        // setPoolColor(&manager,&control);
        runGame(&manager,&control);
        if(ifPlayAgain())
        {
            SetConsoleTextAttribute(Output,0x7);
            system("cls");//清屏
            startGame(&manager,&control);
        }
        else
        {
            break;
        }

    }while(1);

}



//進行全角定位
void gotoxyWithFullwidth(short x,short y)
{
        static COORD cd;
        cd.X=(x*2);
        cd.Y=y;
        SetConsoleCursorPosition(Output,cd);
}



//顯示提示信息
void printPrompting()
{
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(26,10);
    printf("■控制:");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,12);
    printf("□向左移動:← A 4");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,13);
    printf("□向右移動:→ D 6");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,14);
    printf("□向下移動:↓ S 2");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,15);
    printf("□順時針轉:↑ W 8");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,16);
    printf("□逆時針轉:0");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,17);
    printf("□直接落地:空格");
    SetConsoleTextAttribute(Output,11);
    gotoxyWithFullwidth(27,18);
    printf("□暫停遊戲:回車");

}



//顯示分數
void printScore(const Manager *manager)
{
    static const char *tetrisbName="ITLJZSO";
  int i;
  SetConsoleTextAttribute(Output,14);
  gotoxyWithFullwidth(2,2);
  printf("■得分:%u",manager->score);
  //顯示消行總數
  gotoxyWithFullwidth(1,6);
  printf("■消行總數:%u",manager->erasedTotal);
  for(i=0;i<4;++i)
  {
      gotoxyWithFullwidth(2,8+i);
      printf("□消%d:%u",i+1,manager->erasedCount[i]);
  }
  //輸出方塊總數
  gotoxyWithFullwidth(1,15);
  printf("■方塊總數:%u",manager->tetrisTotal);
  //輸出每一行方塊數
  for(i=0;i<7;++i)
  {
     gotoxyWithFullwidth(2,17+i);
     printf("□%c形:%u",tetrisbName[i],manager->tetrisCount[i]);
  }

}



//顯示遊戲池邊界
void printPoolBorder()
{   int j;
    //背景高亮白     11110000
    SetConsoleTextAttribute(Output,0xf0);
/*  //顯示縱線
for(i=1;i<24;++i)
    {
       gotoxyWithFullwidth(10,i);
       printf("%2s","");

       gotoxyWithFullwidth(23,i);
       printf("%2s","");
    }
    //顯示橫線
    for(j=0;j<12;++j)
    {gotoxyWithFullwidth(11+j,23);
    printf("%2s","");
    }
*/
for(j=4;j<26;++j)
    {
        //顯示縱線
       gotoxyWithFullwidth(10,j-3);
       printf("%2s","");

       gotoxyWithFullwidth(23,j-3);
       printf("%2s","");
    }
        //顯示橫線

    gotoxyWithFullwidth(10,j-3);
    printf("%28s","");


}



//初始化遊戲
void initGame(Manager *manager,Control *control)
{
    //設置一個光標隱藏變量並初始化
    CONSOLE_CURSOR_INFO cursorInfo={1,FALSE};
    //獲取控制檯輸入句柄
    Output=GetStdHandle(STD_OUTPUT_HANDLE);
    //設置光標隱藏
    SetConsoleCursorInfo(Output,&cursorInfo);
    //設置控制檯標題
    SetConsoleTitle("俄羅斯方塊");
    //調用一個遊戲開始函數
    startGame(manager,control);
}



//開始遊戲
void startGame(Manager *manager,Control *control)
{
    //初始化結構體
    memset(manager,0,sizeof(Manager));
    memset(control,0,sizeof(Control));
    //初始化遊戲池
    memcpy(manager->pool,gs_uInitialTetrisPool,sizeof(unsigned int[28]));
    //設置隨機數種子
    srand((unsigned)time(NULL));
    //初始化下一個方塊
    manager->type[1]=rand()%7;
    manager->orientation[1]=rand()%4;
    //初始化下下一個方塊
    manager->type[2]=rand()%7;
    manager->orientation[2]=rand()%4;
    memset(control,0,sizeof(Control));
    //初始化遊戲
    initTetris(manager);//給下一個方塊
    //設置顏色
    setPoolColor(manager,control);
}



//顯示下一個和下下一個方塊
void printNextTetris(const Manager *manager)
{
    unsigned int tetris;
    int i;
    //邊框
    SetConsoleTextAttribute(Output,15);
    gotoxyWithFullwidth(26,1);
    printf("■■■■■■■■■■■");
    gotoxyWithFullwidth(26,2);
    printf("■%8s■%8s■","","");
    gotoxyWithFullwidth(26,3);
    printf("■%8s■%8s■","","");
    gotoxyWithFullwidth(26,4);
    printf("■%8s■%8s■","","");
    gotoxyWithFullwidth(26,5);
    printf("■%8s■%8s■","","");
    gotoxyWithFullwidth(26,6);
    printf("■■■■■■■■■■■");
     //顯示下一個方塊
     tetris=TetrisTable[manager->type[1]][manager->orientation[1]];
     SetConsoleTextAttribute(Output,manager->type[1]|8);
     for(i=0;i<16;++i)
     {
         gotoxyWithFullwidth((i&3)+27,(i>>2)+2);
         ((tetris>>i)&1)?(printf("■")):printf("%2s","");
     };
     //顯示下下一個方塊
     tetris=TetrisTable[manager->type[2]][manager->orientation[2]];
     SetConsoleTextAttribute(Output,manager->type[2]|8);
     for(i=0;i<16;++i)
     {
         gotoxyWithFullwidth((i&3)+32,(i>>2)+2);
         ((tetris>>i)&1)?(printf("■")):printf("%2s","");
     };
     gotoxyWithFullwidth(50,27);
     printf("by:yaoe");


}


//顯示遊戲池  gotoxyInPool(2,4)等價於gotoxyWithFullwidth(11,1)
#define gotoxyInPool(x,y) gotoxyWithFullwidth(x+9,y-3)
void printTetrisPool(const Manager *manager,const Control *control)
{
    int x,y;
    for (y=4;y<=25;++y)
    {
        gotoxyInPool(2,y);//把光標打到每行的開頭
        for(x=2;x<=13;++x)
        {
            if((manager->pool[y]>>x)&1)//將每一行都遍歷一遍
            {
                //用相應顏色,顯示一個實心方塊
                SetConsoleTextAttribute(Output,control->color[y][x]);
                printf("■");
            }
            else//沒有方塊,顯示空白
            {
                SetConsoleTextAttribute(Output,0);
                printf("%2s","");
            }
        }
    }

}



//方塊初始化,構造當前方塊
void initTetris(Manager *manager)
{
    unsigned int tetris;
    manager->type[0]=manager->type[1];//下一個方塊變成當前方塊
    manager->orientation[0]=manager->orientation[1];

    manager->type[1]=manager->type[2];//下下一個方塊變成當前方塊
    manager->orientation[1]=manager->orientation[2];

    manager->type[2]=rand()%7;//隨機生成下下下一個方塊
    manager->orientation[2]=rand()%4;
    tetris=TetrisTable[manager->type[0]][manager->orientation[0]];//當前方塊
    manager->y=0;
    manager->x=6;
    if(checkCollision(manager))
    {
        manager->dead=true;
    }
    else
    {
        insertTetris(manager);//將當前方塊加入遊戲池
    }
    ++manager->tetrisTotal;//方塊總數
    ++manager->tetrisCount[manager->type[0]];//對應方塊數
    printScore(manager);
    printNextTetris(manager);//顯示下一個方塊

}



//把當前方塊插入遊戲池中
void insertTetris(Manager *manager)
{
    unsigned int tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
    //當前方塊每4位取出,位或到遊戲池相應位置,即完成插入方塊
    manager->pool[manager->y+0]|=(((tetris>>0x0)&0x000f)<<manager->x);//取方塊的最低4位,放入遊戲池中,取4
    manager->pool[manager->y+1]|=(((tetris>>0x4)&0x000f)<<manager->x);//取方塊的次低4位,放入遊戲池中,取3
    manager->pool[manager->y+2]|=(((tetris>>0x8)&0x000f)<<manager->x);//取方塊的最高4位,放入遊戲池中,取2
    manager->pool[manager->y+3]|=(((tetris>>0xc)&0x000f)<<manager->x);//取方塊的最高4位,放入遊戲池中,取1
}



//設置顏色
void setPoolColor( const Manager *manager, Control *control)
{
    int i,x,y;
    //當前方塊
    unsigned int tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
    for(i=0;i<16;++i)
    {
        y=(i>>2)+manager->y;//待設置的列
            if(y>26)//超過底部限制
        {
            break;
        }
        x=(i&3)+manager->x;//待設置的行
            if((tetris>>i)&1)//檢測的到消方格屬於當前方塊區域
        {
            control->color[y][x]=(manager->type[0]|8);//設置顏色

        }
    }

}



//顯示當前方塊
void printCurrentTetris(const Manager *manager,const Control *control)
{
    int x,y;
    y=(manager->y>4)?(manager->y-1):4;//向上擴展一行
    for(;y<26&&y<manager->y+4;++y)
    {
        x=(manager->x>2)?(manager->x-1):2;//向左擴展一列
        for(;x<14&&x<manager->x+5;++x)
        {
            gotoxyInPool(x,y);
            if((manager->pool[y]>>x)&1)
            {
                SetConsoleTextAttribute(Output,control->color[y][x]);
                printf("■");
            }
            else
            {
                SetConsoleTextAttribute(Output,0);
                printf("%2s","");
            }
        }
    }

}



//碰撞檢測
bool checkCollision(const Manager *manager)
{
    unsigned int tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
    unsigned int dest=0;//存放我們在新的位置取出來的16位數
    //取dest的最低4位
    dest|=(((manager->pool[manager->y+0]>>manager->x)<<0x0)&0x000f);
    //取dest的次低4位
    dest|=(((manager->pool[manager->y+1]>>manager->x)<<0x4)&0x00f0);
    //取dest的次高4位
    dest|=(((manager->pool[manager->y+2]>>manager->x)<<0x8)&0x0f00);
    //取dest的最高4位
    dest|=(((manager->pool[manager->y+3]>>manager->x)<<0xc)&0xf000);
    return((dest&tetris)!=0);

}



//運行遊戲
void runGame(Manager *manager,Control *control)
{
    clock_t clockLast,clockNow;//這裏的clock_t爲長整型,clock_t是用來保存時間
    clockLast=clock();//計時
    printTetrisPool(manager,control);//顯示遊戲池
    while(!manager->dead)//沒掛
    {
        while(_kbhit())//有鍵按下
        {
            keydownControl(manager,control,getch());//處理按鍵
        }
        if(!control->pause)//未暫停
        {
            clockNow=clock();//計時
            //兩次計時的間隔超過0.45秒
            if(clockNow-clockLast>0.45F*CLOCKS_PER_SEC)//CLOCKS_PER_SER爲常量,值爲1000
            {
               clockLast=clockNow;
               moveDownTetris(manager,control);
            }
        }
    }
}



//向下移動方塊
void moveDownTetris(Manager *manager,Control *control)
{
    int y=manager->y;
    removeTetris(manager);//移去當前方塊
    ++manager->y;
    if(checkCollision(manager))
    {
        manager->y=y;
        insertTetris(manager);//放入當前方塊,不需要設置顏色
        if(checkErasing(manager,control))
        {
            printTetrisPool(manager,control);
        }
    }
    else
    {
        insertTetris(manager);
        setPoolColor(manager,control);
        printCurrentTetris(manager,control);

    }


}



//移去方塊
void removeTetris(Manager *manager)
{
    //當前方塊
    unsigned int tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
    //當前方塊每4位取出,按位取反後位與到遊戲池相應位置,即完成移除方塊
    manager->pool[manager->y+0]&=~(((tetris>>0x0)&0x000F)<<manager->x);
    manager->pool[manager->y+1]&=~(((tetris>>0x4)&0x000F)<<manager->x);
    manager->pool[manager->y+2]&=~(((tetris>>0x8)&0x000F)<<manager->x);
    manager->pool[manager->y+3]&=~(((tetris>>0xc)&0x000F)<<manager->x);
}



bool checkErasing(Manager *manager,Control *control)
{
    static const unsigned scores[5]={0,10,30,90,150};
    int count=0;//本次的消行數
    int y=manager->y+3;//從下往上檢測
    do
    {
        if(y<26&&manager->pool[y]==0xffff)//有效區域內
        {
            ++count;//
            memmove(manager->pool+1,manager->pool,sizeof(unsigned int )*y);
            memmove(control->color[1],control->color[0],sizeof(int [16])*y);
        }
        else
        {
            --y;
        }
    }while(y>=manager->y);
    manager->erasedTotal+=count;//消行總分
    manager->score+=scores[count];//得分
    if(count>0)
    {
        ++manager->erasedCount[count-1];//消行
    }
    initTetris(manager);//初始化方塊
    setPoolColor(manager,control);//設置顏色
    return(count>0);

}



void horzMoveTetris(Manager *manager,Control *control)
{
    int x=manager->x;//記錄原列位置
    removeTetris(manager);//在原來的位置移除方塊
    control->direction==0?(--manager->x):(++manager->x);//選擇移動
    if(checkCollision(manager))
    {
        manager->x=x;//恢復原來的位置
        insertTetris(manager);//放入當前方塊,由於位置未變,不需要設置顏色
    }
    else
    {
        insertTetris(manager);//在新位置放入方塊
        setPoolColor(manager,control);//設置顏色
        printCurrentTetris(manager,control);//顯示當前方塊
    }
}



void rotateTetris(Manager *manager,Control *control)
{
    int ori=manager->orientation[0];//記錄原旋轉狀態
    removeTetris(manager);//
    manager->orientation[0]=(control->clockwise)?((ori+1)&3):((ori+3)&3);
    if(checkCollision(manager))
    {
        manager->orientation[0]=ori;//恢復原來的位置
        insertTetris(manager);//放入當前方塊,由於位置未變,不需要設置顏色
    }
    else
    {
        insertTetris(manager);//在新位置放入方塊
        setPoolColor(manager,control);//設置顏色
        printCurrentTetris(manager,control);//顯示當前方塊
    }
}


void keydownControl(Manager *manager,Control *control,int key)
{
    if(key==13)//暫停或解除暫停
    {
        control->pause=!control->pause;
    }
    if(control->pause)//暫停狀態,不作處理
    {
        return;
    }
    switch(key)
    {
    case 72://上
        rotateTetris(manager,control);//旋轉方塊
        break;
    case 80://下
        moveDownTetris(manager,control);//向下移動方塊
        break;
    case 75://左
        control->direction=0;
        horzMoveTetris(manager,control);//水平移動方塊
        break;
    case 77://右
        control->direction=1;
        horzMoveTetris(manager,control);//水平移動方塊
        break;
    case ' '://直接落地
        dropDownTetris(manager,control);
        break;
    default:
        break;
    }

}



void dropDownTetris(Manager *manager,Control *control)
{
    removeTetris(manager);//移走當前方塊
    for(;manager->y<26;++manager->y)
    {
        if(checkCollision(manager))//檢測到碰撞
        {
            break;
        }
    }
    --manager->y;
    insertTetris(manager);
    setPoolColor(manager,control);
    checkErasing(manager,control);
    printTetrisPool(manager,control);
}


//重玩一次
bool ifPlayAgain()
{
    int ch;
    SetConsoleTextAttribute(Output,0xf0);
    gotoxyWithFullwidth(15,10);
    printf("遊戲結束");
    gotoxyWithFullwidth(13,11);
    printf("按Y重玩,按N退出");
    do
    {
        ch=_getch();
        if(ch=='Y'||ch=='y')
        {
            return true;
        }
        else if(ch=='N'||ch=='n')
        {
            return false;
        }

    }while(1);

}

容我偷回懶O(∩_∩)O

 

 

#ifndef DAY8_H_INCLUDED
#define DAY8_H_INCLUDED
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include<time.h>
#include<conio.h>
#include<windows.h>
#include<stdbool.h>

typedef struct TetrisManager
{
    unsigned int pool[28];                                              //遊戲池                                             //遊戲池
    int x;                                                              //當前方塊橫座標,此處座標爲X軸左上角橫座標
    int y;                                                              //當前方塊縱座標,此處座標爲Y軸左上角縱座標
    int type[3];                                                        //當前、下一個和下下一個方塊的類型
    int orientation[3];                                                 //當前、下一個和下下一個方塊的旋轉狀態
    unsigned score;                                                     //得分
    unsigned erasedCount[4];                                            //消行數
    unsigned erasedTotal;                                               //消行總數
    unsigned tetrisCount[7];                                            //消方塊數
    unsigned tetrisTotal;                                               //方塊總數
    bool dead;                                                          //遊戲是否結束
}Manager;

typedef struct TetrisControl
{
    bool pause;          //暫停
    bool clockwise;      //旋轉方向:順時針爲true
    int direction;       //移動方向:0向左運動,1向右運動
    int color[28][16];
}Control;

static const unsigned int TetrisTable[7][4]=
{
    {0x00f0,0x2222,0x00F0,0x2222},                                      //I型
    {0x0072,0x0262,0x0270,0x0232},                                      //T型
    {0x0223,0x0074,0x0622,0x0170},                                      //L型
    {0x0226,0x0470,0x0322,0x0071},                                      //J型
    {0x0063,0x0264,0x0063,0x0264},                                      //Z型
    {0x006C,0x0462,0x006c,0x0462},                                      //S型
    {0x0660,0x0660,0x0660,0x0660}                                       //O型
};


static const unsigned int gs_uInitialTetrisPool[28]=                    //初始狀態的遊戲池,還沒有插入方塊
{
    0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
    0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
    0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
    0xc003,0xc003,0xc003,0xc003,0xc003,0xffff,0xffff
};

HANDLE Output;
void printPrompting();                                                  //顯示提示信息
void gotoxyWithFullwidth(short x,short y);                              //進行全角定位
void printScore(const Manager *manager);                                //顯示分數
void printPoolBorder();                                                 //顯示遊戲池邊界
void initGame(Manager *manager,Control *control);                       //初始化遊戲
void startGame(Manager *manager,Control *control);                      //開始遊戲
void printNextTetris(const Manager *manager);                           //顯示下一個和下下一個方塊
void printTetrisPool(const Manager *manager,const Control *control);    //顯示遊戲池
void initTetris(Manager *manager);                                      //方塊初始化,構造當前方塊
void insertTetris(Manager *manager);                                    //把當前方塊插入遊戲池中
void setPoolColor(const Manager *manager,Control *control);             //設置顏色
void printCurrentTetris(const Manager *manager,const Control *control); //顯示當前方塊
bool checkCollision(const Manager *manager);                            //碰撞檢測
void runGame(Manager *manager,Control *control);                        //運行遊戲
void moveDownTetris(Manager *manager,Control *control);                 //向下移動方塊
void removeTetris(Manager *manager);                                    //移去方塊
bool checkErasing(Manager *manager,Control *control);
void horzMoveTetris(Manager *manager,Control *control);
void rotateTetris(Manager *manager,Control *control);
void keydownControl(Manager *manager,Control *control,int key);         
void dropDownTetris(Manager *manager,Control *control);
bool ifPlayAgain();

#endif // DAY8_H_INCLUDED

頭文件   ↑

暫且寫這些以後再改(o゚v゚)ノ

2018.6

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章