Help us understand the problem. What is going on with this article?

ターミナルで遊べるブロック崩しをGo言語で作る

More than 3 years have passed since last update.

この記事はGo (その2) Advent Calendar 2016の12日目の記事です。

みなさん、サンタさんには何をお願いしましたか?
PS4ですか?

でもクリスマスまであと何日かありますよね。PS4はしばらくお預けですよね。
PS4がまだ無いとすると、手元にあるCUIのターミナルで遊ぶしかないですよね。

というわけで、ターミナルで遊べるブロック崩しをGo言語で作ってみました。

Untitled9.gif

WindowsでもMacでもLinuxでも遊べます。
残念ながらPS3では遊べません

技術解説

Go言語界隈ではわりとおなじみのtermbox-goというライブラリを利用しています。

これを使うと

  • 任意の座標への文字の書き込み
  • 画面のクリア
  • キーイベントの取得

が行えます。

画面表示はこんな風に行います。

draw.go
//画面を初期化
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
//10列目15行目にAと表示
termbox.SetCell(10, 15, []rune("A")[0], termbox.ColorDefault, termbox.ColorDefault)
//画面に反映
termbox.Flush()

とっても簡単ですね。
座標を指定して、文字列渡すだけ。
オプションで背景色や文字色も指定できます。

キー入力はこのように取得します。

key.go
for {
    switch ev := termbox.PollEvent(); ev.Type {
    case termbox.EventKey:
        switch ev.Key {
        case termbox.KeyArrowLeft:
            //左キーを押された時の処理
        case termbox.KeyArrowRight:
            //右キーを押された時の処理
        default:
        }
    default:
    }
}

ぐるぐるループを回しながらキーイベントを待つ感じです。


今回のブロック崩しは

  • キーイベントの取得(プレイヤーのバーを動かす)
  • タイマーの取得(時間経過でボールを動かす)
  • 当たり判定などのゲームコントロール
  • 画面描画

大きく分けて4つの処理で成り立っています。

この中の「キーイベント」と「タイマー」は同時に別々に動かす必要があるため、goroutineで並行して実行しています。

しかし気をつけて実装しないと・・・

zu2.png

複数のgoroutineがひとつのデータを同時に編集しようとしてクラッシュします。

ただの変数なら「いつかクラッシュするかも」というレベルですが、termbox-goのようにIOが絡んでくると起動して数十秒でクラッシュすることもあります。

というわけで、このような構成にしてみました。

zu.png

キーの取得とタイマーを別々のgoroutineとして動かし、それらの整合性はchannelでゲームコントロール関数に一任。画面描画関数を呼び出せるのをゲームコントロール関数だけに限定し、複数のgoroutineから同時に画面を弄るようなことはしない、という作りです。左下の猫に深い意味はありません。

このあたりの並列/並行処理のバグは非常に厄介で、試しに動かしてみたら普通に動くけど、長時間動かすと途中でクラッシュする、というような再現の難しい問題に直面します。

そういったバグを事前にチェックする機能がGo言語には備わっているので、goroutineを利用するプログラムを作る際はぜひチェックしましょう。

Go1.1 の Race Detector
http://jxck.hatenablog.com/entry/20130530/1369928762

まとめ

ソースコードはこちらです。
https://github.com/kurehajime/kuzusi

余談ですが、
今回のブロック崩しに似たプログラムで「pongコマンド」というのも過去に作りましたので、ぜひこちらもご覧頂ければと思います。

Go言語でpongコマンドを実装する
http://qiita.com/kurehajime/items/f9d225fab5eaa736913b

そして誰か、自分の代わりにpongコマンドの並行処理バグを直してくれると大変助かります。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away