2017年6月24日 星期六

俄羅斯方塊 (0) - 移動方塊

寫組譯器實在太無聊了, 整天和 elf section, x86 machine code 搏鬥, 真苦! 我寫了太多練功型的程式, 這些程式大多是幫助我理解某個概念, 實用性不高, 成就感也不大, 我決定先暫停組譯器, 來寫個自己也會用的程式。

就是你了, 皮卡丘, 阿, 不是 ... 是俄羅斯方塊。

俄羅斯方塊大家都會玩, 但不是每個人都會寫俄羅斯方塊, 稍微思考後, 覺得還蠻難的, 沒有任何突破點, 絲毫無法下手寫程式。

fig 0. 決戰俄羅斯

這個程式我 200x 年就想寫了, 不過直到最近 (201706) 我才真的動手, 大概是練功型程式我真的有點膩了, fig 0 是決戰俄羅斯, 我想寫的是這個版本, 和一般的俄羅斯方塊有什麼不同呢? 他有一些特殊方塊, 會有特殊功能, 例如可以射出子彈消掉方塊的特殊方塊。我很喜歡那些特殊功能的方塊, 能增加遊戲性, 當然還有其雙人的對戰功能, 也很有趣, 在同一個螢幕上就可以 2 人對戰, 不用透過網路。

fig 1. 大型電玩 - 俄羅斯方塊

fig 2. 軟體世界 - 決戰俄羅斯

決戰俄羅斯
英文名Face to Face
類型智育遊戲
研發蔡祈岩王功華
代理軟體世界
發行年1990
平台PC
作業系統DOS

軟體世界金磁片獎的作品, 是移植大型電玩俄羅斯方塊而來。台灣交通大學大一學生蔡祈岩與王功華製作並於 1990 年由智冠科技 (當時叫軟體世界) 出版, 加入兩人對戰及許多道具並首創與電腦對戰功能, 可以兩人對戰也可以使用特殊道具。遊戲中可以自由選擇等級及遊戲規則, 遊戲以操作流暢與合理設計將這款遊戲推向全新高度迅速風靡中港台及亞洲各國是華人自製電腦遊戲的濫觴。

有五種特殊道具 (ref figure 3):

  1. 人造衛星 (S) 可以消去方塊
  2. 小鳥 (F) 可以填補方塊
  3. 還有一個道具 (16T) 可以重壓消掉數列的方塊
  4. 炸彈 (B) 可以消去少許範圍的方塊
  5. 道具 (4) ???

(20170707 我已經寫出這前 3 種道具)

這是移植大型電玩的版本。

它有個很討厭的磁片保護, 非常煩人。

fig 3.


這個遊戲真的好玩, 要是我能在 linux 玩該有多好, 當然可以用 dos 模擬器玩, 但如果是 linux native 程式, 那就更好了, 這個念頭大概只能靠自己開發了。

再回到怎麼寫俄羅斯方塊, 俄羅斯方塊要完成好多部份, 把目標簡化很重要, 這個步驟我已經非常熟悉, 第一個想到的就是, 先來實作移動方塊吧! 這樣感覺簡單了一些, 但其實還是沒方向 ...

俄羅斯方塊有很多不同的方塊, 英文術語是 - Tetromino, 我決定先實作 z Tetromino。

  • Tetromino Z.svg Z: two stacked horizontal dominoes with the top one offset to the left.

最後的成果就是 fig 1。

fig 1. 移動 z Tetromino

這個 console mode 程式應該嚇壞你了, 怎麼這麼醜, 但他包含了整個概念, 把繪製漂亮的 UI 功能抽離出來, 這樣會比較容易專住在主要核心上, 要畫出好看的圖形可不是件容易的事情, 先不把焦點放在圖形處理上。只要 c++ 標準程式庫就可以執行了, 其中用到了 sleep, 這個可能不是標準, 但用 for loop 也可以完成 delay 的動作。

z Tetromino 可以順利的移動, 也可以旋轉, 並且不會超過邊界。這一回合就只做這件事, 感覺簡單了一些, 但實際上我在筆記本上畫了不少方塊圖, 才得以想到方法, 完成這個功能。

fig 2. z Tetromino 設計方式

一個方塊是由 4 個點構成, 只要好好的描述好這 4 個點, 就可以完成移動、旋轉。

z Tetromino 由 fig 2 那 4 個點構成, p0, p1, p2, p3:
p0: (2,3)
p1: (3,3)
p2: (3,4)
p3: (4,4)

往右移動就是在改變 p0, p1, p2, p3 這些座標, 你一定也想到要怎麼做了吧! 把所有點的 x 加 1 就搞定了。

p0: (3,3)
p1: (4,3)
p2: (4,4)
p3: (5,4)

換成程式碼就是這樣:
int right()
    {
      ++p0_.x_;
      ++p1_.x_;
      ++p2_.x_;
      ++p3_.x_;
    }

簡單到不用說明, 上、下、左也是一樣的道理。

再來要怎麼畫出畫面呢? 宣告 2X2 array container_[10][20] 來處理, 把

p0: (2,3)
p1: (3,3)
p2: (3,4)
p3: (4,4)

的座標標成 1, 其他標 0, 程式碼類似這樣:

container_[2][3] = 1;
container_[3][3] = 1;
container_[3][4] = 1;
container_[4][4] = 1;

就會輸出以下的 array:

1111111111
1000000001
1000000001
1011000001
1001100001
1000000001
1000000001
1000000001
1000000001
1000000001
1000000001
1000000001
1111111111

程式只要去檢查這個 array 所有值, 是 1 的就畫 1, 0 的就畫 0, 這樣就可以畫出整個俄羅斯方塊的畫面。

另外一個難題是碰撞偵測, 我怎麼知道方塊到底了, 外圍的 1 是我的邊框, 在 down() 的函式會更新 4 個點的座標, 檢查新座標的位置是不是 1, 若是, 就表示遇到邊框或是其他方塊, 原理就是這樣。

下次再來談談旋轉, 其實也一樣, 把 4 個點的座標改動而已。

我本來打算參考 fig 3 的書來實做俄羅斯方塊, 不過我收到時, 已經做出 2 個方塊可以移動、旋轉, 也可以消掉方塊的版本了, 儘管如此, 此書還是有不少可以參考的地方, 厄 ... 這本書是使用 trubo pascal 完成俄羅斯方塊。

不過我也不打算看別人的想法, 能自己想出來是最好的。

fig 3. 2017/06/20 09:23:17 訂購於 https://tw.bid.yahoo.com/item/100125001955, 20170623 收到 200+80

ref:
【Arduino】自己的掌機自己作(3)-俄羅斯方塊遊戲

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。