本物の golang を... 本物の Gopher を、お見せしますよ。

  • 797
    いいね
  • 4
    コメント

事の始まり

それはD言語くんへの嫉妬から始まった。

D言語くんの繁殖についての仮説

lsを間違えてdlと入力してしまったときに、D言語くんが通り過ぎるコマンド

くっ悔しい...

そしてショボいAAで2番煎じ。
lsを間違えてgolと入力してしまったときに、Gopherが通り過ぎるコマンド書いた。

こんなはずじゃない!
僕らの Gopher 君はこんなチープじゃない!

明日来てください。本物の Gopher をお見せしますよ。
— mattn (@mattn_jp) December 15, 2015

(本当はもうちょっと前から作ってましたが)

本物のGopher君とは

そして今回、これを公開するに至った。

https://github.com/mattn/gopher

まずはこれをご覧頂きたい。

Gopher君

!!!!!!!!!!!!1

20110824233828.jpg

こいつ・・・ 動くぞ・・・

golang で書いたデスクトップマスコットです。起動すると画面のタスクバーの上をウロウロします。たまに方向転換したりジャンプしたりします。かわいいですね!
プログラムは .NET 等を使わない Windows のネイティブアプリ、Windows API を叩いています。CGOを一切使用していない Full Pure Golangです。

どうやって動いているのか

gopher コマンドは data フォルダにある png ファイルをassetsバイナリとしてexeファイルに埋め込んでいます。ですのでexeファイル1つあればどこでも起動します。またランタイムも必要としません。起動直後にこのassetsのpngファイルを読み取り、RGBAから透明度を得てウィンドウのリージョンを作成しています。

    files := []string{
        "data/out01.png",
        "data/out02.png",
        "data/out03.png",
        "data/waiting.png",
    }

    // make scene 1, 2, 3, and schene waiting
    for i, fname := range files {
        img[i], err = loadImage(fname)
        if err != nil {
            return nil, err
        }
        hBitmap[i], err = hBitmapFromImage(img[i])
        if err != nil {
            return nil, err
        }

        // create region for window
        hRgn[i] = winapi.CreateRectRgn(0, 0, 0, 0)
        for y := img[i].Bounds().Min.Y; y != img[i].Bounds().Max.Y; y++ {
            for x := img[i].Bounds().Min.X; x != img[i].Bounds().Max.X; x++ {
                _, _, _, a := img[i].At(x, y).RGBA()
                // combine transparent colors
                if a > 0 {
                    mask := winapi.CreateRectRgn(int32(x), int32(y), int32(x+1), int32(y+1))
                    winapi.CombineRgn(hRgn[i], mask, hRgn[i], winapi.RGN_OR)
                    winapi.DeleteObject(winapi.HGDIOBJ(mask))
                }
            }
        }
    }

使っているコマは以下の3つ

out01.png out02.png out03.png

GIMPを使ってチマチマと手と足を切り取っては回転させ、色を補完しながら仕上げました。またオリジナル画像の周りの輪郭がボケていて透明部分が切り出し辛くだいぶん苦労しました。おそらく今回作った成果物の中で一番時間を掛けてしまったかもしれません。

これらの画像を Windows のタイマーイベントを使って、各アニメーションモードに従った座標の移動とウィンドウリージョンの適用を行っています。
尚、golang は標準でビルドするとコンソールアプリが生成されますが今回はコンソールを持たない Windows 実行ファイルです。お手数ですが、go get ではなくリポジトリ上で mingw32-make を実行して下さい。go build に -ldflags="-H windowsgui" というオプションが付与され、コンソールの無いexeファイルが生成されます。
また Makefile を見てもらえると分かる通り、mingw のリソースコンパイラを使い、exeファイルにアイコンを付与しています。go build はカレントディレクトリに syso という拡張子のオブジェクトファイルを置いておくと一緒にリンクしてくれるので go ファイルのビルド前に syso ファイルを生成しておきます(この動作は各プラットフォームで同じです)。

IMAGES = $(wildcard data/*)

all : gopher.exe

gopher.exe : main.go bindata.go Makefile gopher.syso
    go build -ldflags="-H windowsgui"

bindata.go : $(IMAGES) main.go
    go-bindata data

gopher.syso : gopher.rc
    windres gopher.rc gopher.syso

clean :
    -rm *.syso *.exe

以下、この gopher コマンドを使用して説明しますので、パスの通ったディレクトリに gopher.exe をコピーしておいて下さい。

これだけじゃないぞ!

コマンド引数に -sl を付けると、「ls コマンドを間違って sl にタイプミスした時用の sl モード」になります。Gopher君が画面を倍速で走り抜けます。

SLモード

速い! そして デカい!

いっぱい起動したらどうなんの?

Windows アプリなのでコンソールを取りません。いっぱい起動するとどうなるか確かめたくなりますよね。ではお見せしましょう。

いっぱい

うわぁーーーーーーーーっ!(小並感)

画面が豊かになりましたね。
いっぱい起動してウザくなる人も若干ながら居るかと思いますが、どうかタスクマネージャで強制終了といった可哀想な事はしないで下さい。リポジトリに同梱している gopherc というクライアントソフトを使い、以下の様に実行して下さい。

gopherc -x

画面上の Gopher が一括で終了します。この gopherc コマンドは gopher プロセスと WM_COPYDATA によるプロセス間通信を行い、外部から Gopher の挙動の幾つかを変えられる様になっています。

そしてこの gopherc コマンドにはもう一つ秘密があるのです。

おしゃべりGopher君

gopherc -m Hello

-m フラグを指定して実行するとGopher君が吹きだしを表示してくれます。

なにそれすごい!(よく分からない)

さらに

gopherc -j

でGopher君がロングジャンプしてくれます。

すごいすごいよ!(さらによく分からない)

Vim でおしゃべり Gopher

リポジトリの misc/vim に Vim plugin を同梱してあります。

:HeyGopher おなかすいた

と実行するとGopher君があなたの気持ちを代弁してくれます。

heygopher.png

これで深夜の勤務でも寂しくない!

ニュース読み上げGopher君

実は gopherc コマンドは全て gopher パッケージに構築されたプロセス間通信を行う Gopher API を使って実装されています。

gopherObj.Message("Hello!", "http://www.google.com")

上記の様に実行すると、Gopher君が「Hello」と表示し、クリックするとブラウザでGoogleが開きます。応用例ですが、リポジトリに gopherfeed というコマンドを用意しました。gopher コマンドを実行してデスクトップをウロウロさせた後、gopherfeed コマンドを実行してみて下さい。

ニュース読み上げGopher

Gopher君がニュースを読んでくれ、クリックすると RSS フィードの URL がブラウザで開きます。

これは便利!?(おそらく気のせい)

リアルタイムチャットで Gopher君

もう一つ応用例をお見せします。リポジトリに chat というコマンドがあります。Websocket を使ったチャットサーバです。Websocket はクライアントからの接続イベントをフックする事が出来る為、そこで Gopher君を起動させてやる事が出来ます。もちろん接続が切れたら Gopher君を消します。
上記のメッセージ Gopher API をチャットシステムと連携すれば...

chat.png

Gopher君がリアルタイムに会話するチャットシステムの出来上がり!誰かが JOIN してくるとその度に Gopher君が増え、数が多いとブラウザでテキストを打つのも一苦労です!

なにそれ怖い!

まとめ

本物の Gopher は如何でしたか。皆さんのデスクトップにもぜひ1匹常駐させてみては如何でしょうか。

※ gopher の画像は Renee French さんによって作成された画像を使用させて頂きました。

追記: Linux版を公開しました(Go言語じゃないです)。