青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C/C++圖形圖像的世界

圖形與游戲編程

常用鏈接

統(tǒng)計

積分與排名

Blog

最新評論

[原創(chuàng)] 88行代碼實現(xiàn)俄羅斯方塊游戲(含講解)

在正式閱讀本文之前,請你記得你應該用娛樂的心態(tài)來看,
本代碼所使用到的技巧,在工作了的人眼里會覺得很糾結(jié),很蛋疼,很不可理喻,很丑,
注意,是你蛋疼,不關我的事

通常,寫一個俄羅斯方塊,往往動不動就幾百行,甚至上千行,而這里只有88行
正所謂頭腦風暴,打破常規(guī)。這里將使用很多不平常的手段來減少代碼

以下是Win-TC可以成功編譯并執(zhí)行的代碼(代碼保證單行長度不超過80字符,如果你是Win7系統(tǒng),那請看后文):
#include "graphics.h"
#include <conio.h>
#include <stdlib.h>
int gcW = 20, gcColor[] = {DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN,
    LIGHTRED, LIGHTMAGENTA,MAGENTA, YELLOW};
struct tetris {
    int _pool[16][32], (*pool)[32], tmap[8][4][16];
    int x, y, s, st, t;
}gt;

void trsInit() {
    int sp[8][4] = {{15,4369},{23,785,116,547},{71,275,113,802},
        {39,305,114,562},{54,561},{99,306},{51,51},{-1}};
    int *p, i, j, b;
    for (p = sp[0]; *p >= 0; ++p) if ( *p == 0 ) *p = p[-2];
    gt.pool = &gt._pool[4];
    for (j = 0; j < 7; ++j)
        for (i = 0; i < 4; ++i)
            for (b = 0; b < 16; ++b)
                gt.tmap[j+1][i][b] = (sp[j][i] & 1) * (j + 1),
                sp[j][i] >>= 1;
    memset(gt._pool, -1, sizeof(gt._pool));
    for (i = 0; i < 10; ++i)
        memset(&gt.pool[i], 0, sizeof(int[21]));
    return ;
}

int trsCopy(int sp[], int x, int y, int c) {
    int m[] = {0,32,64,96,1,33,65,97,2,34,66,98,3,35,67,99}, i, cx, cy;
    for (i = 0; i < 16; ++i) if (sp[i]) {
        cx = x + (m[i] >> 5), cy = y + (m[i] & 31);
        if (gt.pool[cx][cy]) if (c == 2) gt.pool[cx][cy] = 0; else return 0;
        if (c==1) gt.pool[cx][cy] = sp[i];
    }
    return 1;
}

int trsScene() {
    int x, y = 0;
    gt.s = random(7) + 1, gt.st = gt.t = 0;
    gt.x = 4, gt.y = 0;
    for (--gt.t ; ; delay(10), --gt.t) {
        int k = 0;
        while (kbhit()) {
            k = getch();
            if (k == 27) return 0;
            if (k == 'A' || k == 'a') {
                if (trsCopy(gt.tmap[gt.s][gt.st], gt.x-1, gt.y, 0)) --gt.x;
            } else if (k == 'D' || k == 'd') {
                if (trsCopy(gt.tmap[gt.s][gt.st], gt.x+1, gt.y, 0)) ++gt.x;
            } else if (k == 'W' || k == 'w') {
                if (trsCopy(gt.tmap[gt.s][(gt.st+1) % 4], gt.x, gt.y, 0))
                    gt.st = (gt.st+1) % 4;
            }
        }
        if (k == 'S' || k == 's' || gt.t < 0) {
            if (trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y+1, 0))++gt.y,gt.t=50;
            else {
                trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 1);
                for (--y; y > 0; --y) {
                    for (x = 0; gt.pool[x][y] > 0; ++x);
                    if (gt.pool[x][y] < 0)
                        for (k = y++; k > 0; --k)
                            for (x = 0; gt.pool[x][0] >= 0; ++x)
                                gt.pool[x][k] = gt.pool[x][k-1];
                }
                return 1;
            }
        }
        trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 1);
        for (x = 0; gt.pool[x][0] >= 0; ++x) {
            for (y = 1; gt.pool[x][y] >= 0; ++y) {
                setfillstyle(1, gcColor[gt.pool[x][y]]);
                bar(201 + x*gcW, 1 + y*gcW, 200 + gcW + x*gcW, gcW + y*gcW);
            }
        }
        trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 2);
    }
}

int main() {
    int g = DETECT, m = 0;
    initgraph(&g, &m, "");
    randomize();
    trsInit();
    while (trsScene());
    return 0;
}

 

如果你沒有Win-TC,或者你是Win7系統(tǒng),可以用這個能用VC6編譯的工程包:
http://m.shnenglu.com/Files/misakamm/tetris.zip

以上是圖形界面版本,顯示看起來好看一些
但為了能更通用,還有一份控制臺版本的代碼,同樣是88行,直接復制到VC即可編譯:
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <conio.h>
#include <stdlib.h>
char gcText[] = " 1LJTSZ#";
struct tetris {
    int _pool[16][32], (*pool)[32], tmap[8][4][16];
    int x, y, s, st, t;
}gt;

void trsInit() {
    int sp[8][4] = {{15,4369},{23,785,116,547},{71,275,113,802},
        {39,305,114,562},{54,561},{99,306},{51,51},{-1}};
    int *p, i, j, b;
    for (p = sp[0]; *p >= 0; ++p) if ( *p == 0 ) *p = p[-2];
    gt.pool = &gt._pool[4];
    for (j = 0; j < 7; ++j)
        for (i = 0; i < 4; ++i)
            for (b = 0; b < 16; ++b)
                gt.tmap[j+1][i][b] = (sp[j][i] & 1) * (j + 1),
                sp[j][i] >>= 1;
    memset(gt._pool, -1, sizeof(gt._pool));
    for (i = 0; i < 10; ++i)
        memset(&gt.pool[i], 0, sizeof(int[21]));
    return ;
}

int trsCopy(int sp[], int x, int y, int c) {
    int i, cx, cy;
    for (i = 0; i < 16; ++i) if (sp[i]) {
        cx = x + (i & 3), cy = y + (i >> 2);
        if (gt.pool[cx][cy])
            if (c == 2) gt.pool[cx][cy] = 0; else return 0;
        if (c==1) gt.pool[cx][cy] = sp[i];
    }
    return 1;
}

int trsScene() {
    int x, y = 0;
    COORD pos = {0};
    gt.s = rand() % 7 + 1, gt.st = gt.t = 0;
    gt.x = 3, gt.y = 0;
    for (--gt.t; ; Sleep(1), --gt.t) {
        int k = 0;
        while (kbhit()) {
            k = getch();
            if (k == 27) return 0;
            if (k == 'A' || k == 'a') {
                if (trsCopy(gt.tmap[gt.s][gt.st], gt.x-1, gt.y, 0)) --gt.x;
            } else if (k == 'D' || k == 'd') {
                if (trsCopy(gt.tmap[gt.s][gt.st], gt.x+1, gt.y, 0)) ++gt.x;
            } else if (k == 'W' || k == 'w') {
                if (trsCopy(gt.tmap[gt.s][(gt.st+1) % 4], gt.x, gt.y, 0))
                    gt.st = (gt.st+1) % 4;
            }
        }
        if (k == 'S' || k == 's' || gt.t < 0) {
            if (trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y+1, 0))++gt.y,gt.t=50;
            else {
                trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 1);
                for (--y; y > 0; --y) {
                    for (x = 0; gt.pool[x][y] > 0; ++x);
                    if (gt.pool[x][y] < 0)
                        for (k = y++; k > 0; --k)
                            for (x = 0; gt.pool[x][0] >= 0; ++x)
                                gt.pool[x][k] = gt.pool[x][k-1];
                }
                return 1;
            }
        }
        trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 1);
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
        for (y = 1; gt.pool[0][y] >= 0; ++y,putchar(10)) {
            for (x = 0; gt.pool[x][0] >= 0; ++x) {
                putchar(gcText[gt.pool[x][y]]);
            }
        }
        trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 2);
    }
}

int main() {
    srand((unsigned)time(NULL));
    for (trsInit(); trsScene(); );
    return 0;
}

區(qū)別僅僅是繪畫用的函數(shù)不同而已,不過控制臺版顯示效果自然會差很多了
當你玩下去,你如果堆放到最頂,輸了的話,程序就會以最為華麗的方式:Crash(程序崩潰) 謝幕


======================================華麗的分割線========================================
以下是對代碼的壓縮方法進行分析

首先,通常我們需要準備7種方塊,4個方向的形狀表,相當多的俄羅斯方塊程序就是在開頭寫了這樣一個很長的數(shù)組定義,
有的光這個定義就直接超100行了,這個程序是怎么實現(xiàn)的呢?

其實這個程序,同樣是使用一個7*4*16的數(shù)組來保存這個形狀表,但是,它沒有直接初始化,見這個數(shù)組的定義:
int sp[8][4] = {{15,4369},{23,785,116,547},{71,275,113,802},
        {39,305,114,562},{54,561},{99,306},{51,51},{-1}};
這個莫名其妙的數(shù)組的值是什么意思呢?其實很好猜的,我們嘗試把這些數(shù)化為二進制:
15 = 1111
4369 = 1000100010001

合理地四位四位拆開,從低位到高位,從左到右,從上到下排列一下:
1111
0000
0000
0000

1000
1000
1000
1000

你終于發(fā)現(xiàn),這就是長條方塊的兩個形狀
后面類似

然后你會發(fā)現(xiàn),這個數(shù)組并不完整,有的只定義了兩個形狀,有的是四個形狀,沒定義的數(shù)會默認置0的,這個怎么解釋?
看這個數(shù)組定義的下面第二行:
for (p = sp[0]; *p >= 0; ++p) if ( *p == 0 ) *p = p[-2];
意思是找出這個數(shù)組為0的元素,用它前面的元素值填上即*p = p[-2]
而數(shù)組中最后一個元素值-1起監(jiān)督頭的作用,用于讓這個循環(huán)跳出
雖然可以把這些常數(shù)全直接寫在數(shù)組里,但常數(shù)太多顯得不太好,就這樣寫了

之后你看到這行代碼:
gt.pool = &gt._pool[4];
為什么定義兩個pool呢?因為我們需要在原來的pool的界外用-1值填充,以便后面做碰撞檢測減少不必要的代碼
但如果直接用原來的_pool,那每次訪問都要加上一個偏移常數(shù),不美觀且顯得代碼長,就用另一個指針直接指向開始的位置

然后,后面的三重循環(huán)就是解開那個位壓縮數(shù)組以初始化gt.tmap數(shù)組,這個數(shù)組就是記錄7*4種形狀的數(shù)組
再下面三行,就是初始化pool,游戲區(qū)為0,界外為-1
而其中,i < 10決定了游戲池的寬度為10,sizeof(int[21])決定了游戲池的高度是20 (0我們不使用,這一行有特殊作用,后文會講)
用memset也是為了免寫二重循環(huán)而已。整個初始化流程就到這里了

然后,是一個trsCopy函數(shù),這個函數(shù)綜合了碰撞檢測,復制到游戲池和反復制,行為由參數(shù)c (是control縮寫字母)控制
c為0就單純的碰撞檢測,c為1是復制,c為2就是反復制,細心分析一下,這個函數(shù)功能就清楚了,這里不詳細展開

好了,到了trsScene函數(shù),整個游戲的主邏輯流程就在這里了
我們先看第75行的那個二重循環(huán),只有那個地方是根據(jù)pool保存的值來輸出
所以,這個時候,你應該明白為什么trsCopy函數(shù)還要復制和反復制了,
它把你正在控制的方塊,復制到pool里,統(tǒng)一輸出,這樣就不需要另加一個函數(shù)來繪畫你的控制塊了

而繪圖之前,就是鍵盤處理等的邏輯控制,這里就沒有什么復雜難懂的代碼了,
唯一要講講的是,if (k == 'S' || k == 's' || gt.t < 0)
這一段是判斷下落鍵的按下,和是否到時間強制下落
里面for (--y; y > 0; --y)開始是消行計算
你可能會奇怪這個y沒有明顯的初始值,直接就來一個 --y,初始從哪里來?
其實就在之前講的輸出繪畫那個循環(huán)里,循環(huán)結(jié)束后,y的值一定是最后一行+1
所以我們只要--y就得到最底下一行,因為消行計算,從下往上,只要一次就解決了,代碼較少

好了,現(xiàn)在解釋之前說的,為什么不是從0,而是從1開始
消行計算這里,每消除一行,最頂?shù)囊恍芯蛻撚?填充,但如果你因為這個多寫一個for循環(huán)就不值得了
我們改成從1開始,那么把第0行的內(nèi)容復制到第一行,就完成0填充了,就可以少寫一個for

好了,差不多接近尾聲了,最后說說trsScene的返回值
trsScene返回值的意思很簡單,如果是1就繼續(xù)循環(huán),如果是0就退出
所以你可以在代碼里看到,當按下ESC(值為27)的時候才返回0
而方塊落下一個的時候,返回1,讓主函數(shù)重新調(diào)用它,就能再次初始化當前控制塊的位置和形狀了,
達到免除狀態(tài)管理的代碼的作用

最后,在主循環(huán)除了初始化,只要華麗的一行for (trsInit(); trsScene(); ); 就可以玩這個游戲了


看不懂?說明你也是個正常人
看得懂?說明你已經(jīng)腦殘了。。。

posted on 2011-01-02 23:12 御坂美琴 閱讀(1197) 評論(0)  編輯 收藏 引用 所屬分類: 頭腦風暴


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜日韩福利| 在线视频精品一区| 亚洲欧美影院| 亚洲影音先锋| 亚洲欧美成人精品| 午夜精品网站| 久久久久国产一区二区三区| 久久都是精品| 欧美成在线观看| 亚洲激情电影在线| 亚洲电影免费| 在线一区二区三区四区| 亚洲欧美在线高清| 久久亚洲欧美国产精品乐播| 美女视频黄a大片欧美| 欧美精品三级| 国产美女搞久久| 在线观看亚洲精品视频| 野花国产精品入口| 久久久999精品免费| 亚洲国产成人在线视频| 亚洲图片在区色| 麻豆成人综合网| 国产精品视频一| 亚洲最快最全在线视频| 久久久亚洲精品一区二区三区| 美腿丝袜亚洲色图| 亚洲午夜一区| 欧美理论片在线观看| 国产性做久久久久久| 一区二区三区国产精华| 麻豆国产精品va在线观看不卡 | 国产欧美精品va在线观看| 亚洲国产经典视频| 欧美呦呦网站| 99视频有精品| 欧美黄色网络| 亚洲大片在线| 久久久噜噜噜久久中文字免| 亚洲高清久久| 欧美一二三区精品| 亚洲日本无吗高清不卡| 久久久人成影片一区二区三区| 欧美日韩在线视频一区| 亚洲国产一二三| 美国十次了思思久久精品导航| 一区二区三区视频在线观看| 麻豆精品在线播放| 在线观看不卡| 鲁鲁狠狠狠7777一区二区| 午夜精品免费视频| 国产精品久久激情| 一本久久知道综合久久| 亚洲激情婷婷| 欧美精品国产一区二区| 亚洲欧洲久久| 亚洲国产高清一区| 麻豆成人在线播放| 亚洲欧洲午夜| 亚洲国产欧美在线人成| 欧美成人一区二免费视频软件| 精品福利av| 欧美成人一区二区三区在线观看| 欧美在线free| 影音先锋久久精品| 欧美成人一区二区三区在线观看| 久久夜色精品国产噜噜av| 一区二区在线免费观看| 久久亚洲综合| 免费久久99精品国产自| 91久久国产精品91久久性色| 欧美成人精品在线播放| 欧美777四色影视在线| 99国产精品国产精品久久| 亚洲精品欧美日韩| 国产精品日韩欧美| 久久久999国产| 免费成人网www| 这里是久久伊人| 99天天综合性| 国产一区二区观看| 欧美承认网站| 欧美色欧美亚洲另类七区| 亚洲女爱视频在线| 久久国产精品毛片| 亚洲乱码一区二区| 亚洲一区二区在线播放| 韩国成人理伦片免费播放| 欧美激情一区二区三区不卡| 欧美日韩成人一区二区| 欧美一区二区私人影院日本 | 在线国产亚洲欧美| 亚洲黄色一区二区三区| 国产精品久久久亚洲一区 | 亚洲精选一区二区| 亚洲一区二区三区免费在线观看| 国产亚洲激情视频在线| 亚洲美女在线一区| 亚洲影音先锋| 亚洲日本成人女熟在线观看| 99伊人成综合| 亚洲国产一区二区三区高清| 中文精品一区二区三区| 激情av一区| 亚洲午夜小视频| 亚洲精品一线二线三线无人区| 亚洲一区二区三区视频| 亚洲精品欧美专区| 久久久久久久97| 午夜日韩av| 国产精品家教| 99ri日韩精品视频| 亚洲另类视频| 麻豆av一区二区三区久久| 久久久99久久精品女同性| 欧美日韩黄色大片| 欧美激情一区二区久久久| 狠狠久久婷婷| 午夜精品久久久久久久蜜桃app | 亚洲六月丁香色婷婷综合久久| 在线视频免费在线观看一区二区| 又紧又大又爽精品一区二区| 亚洲网址在线| 9l国产精品久久久久麻豆| 久久嫩草精品久久久精品| 亚洲欧美视频在线观看| 欧美日本一区二区高清播放视频| 久久一区二区三区超碰国产精品| 国产精品白丝av嫩草影院 | 久久久99国产精品免费| 先锋影音久久久| 国产精品乱看| 亚洲午夜久久久久久久久电影院| av成人免费观看| 欧美男人的天堂| 亚洲人成网站999久久久综合| 伊人久久综合97精品| 久久精品视频在线免费观看| 午夜精品一区二区三区电影天堂| 欧美先锋影音| 亚洲免费在线| 久久久www成人免费毛片麻豆| 国产欧美日本一区二区三区| 亚洲免费在线视频| 久久久久国产一区二区三区四区| 国产精品久久久久久久久婷婷| 一区二区三区四区五区精品| 亚洲欧美国产日韩中文字幕| 欧美人牲a欧美精品| 日韩亚洲一区二区| 午夜精品久久| 激情久久婷婷| 欧美成人官网二区| 日韩午夜激情电影| 午夜精品一区二区在线观看 | 欧美中文在线观看| 日韩视频―中文字幕| 欧美激情亚洲精品| 日韩视频第一页| 欧美亚洲日本网站| 在线看无码的免费网站| 欧美成人dvd在线视频| 夜夜嗨av色综合久久久综合网 | 久久亚洲视频| 亚洲美女视频网| 国产精品私拍pans大尺度在线| 午夜精品久久久久久久久| 欧美sm视频| 亚洲欧美日韩在线| 亚洲电影成人| 欧美日韩一区二区在线播放| 亚洲欧美激情一区| 欧美激情视频一区二区三区在线播放 | 亚洲一区二区毛片| 牛牛国产精品| 香蕉成人啪国产精品视频综合网| 国产综合激情| 欧美午夜精彩| 久久综合亚州| 亚洲欧美日韩成人| 亚洲精品久久久久久一区二区 | 国内精品模特av私拍在线观看| 美女露胸一区二区三区| 国产精品99久久久久久www| 久热精品视频在线观看| 亚洲一区二区三区乱码aⅴ蜜桃女 亚洲一区二区三区乱码aⅴ | 久久精品国产免费观看| 亚洲卡通欧美制服中文| 女同性一区二区三区人了人一 | 欧美高清在线| 欧美影院精品一区| 夜夜爽www精品| 亚洲国产黄色| 免费一区二区三区| 久久精品视频在线| 午夜欧美不卡精品aaaaa| 日韩一级黄色av| 最近看过的日韩成人| 悠悠资源网久久精品| 国产亚洲精品久|