armos devlog 3f1b057 and 6aab220

github.com

以下の機能がarmosのdev branchに取り込まれた.

  • CLIでのarmos generateコマンドによるコード生成
  • glslifyによるShaderのprecompile

また,今回の変更によりarmosの動作にはnpmを要求するようになった.

(この解説では便宜上,プロジェクトのルートディレクトリを/として表記する)

armos generateコマンド

$ armos generate <target>

いくつかの種類のディレクトリやソースコードを自動生成する.generateの部分はgに省略可能. <target>は以下がサポートされている.

  • project
  • material
  • glslsource(glslsources)

project target

$ armos generate project [<projectpath>] [<options...>]

armosコマンドの<target>projectを指定した場合,新規に指定したパス<projectname>にarmosのプロジェクトを生成する. <projectname>を省略した場合,現在のワーキングディレクトリにプロジェクトが生成される(dub initと同様の挙動と考えて良い).

このコマンドは以下の処理を行う.

  1. dub initの実行によるプロジェクトの生成,
  2. armosのアプリケーションの雛形となるMainApp classとそのエントリーポイントを含んだコードをsource/app.dへ上書き.
  3. glslifyがnpmのglobalに存在しない場合,インストールを行う.

以下のoptionにより,デフォルトで生成されるapp.dに追加するコンポーネントを指定できる.

  • --defaultcamera string

他のコンポーネントについてのoptionは今後追加していく予定.

--defaultcamera string

armos.graphics.camera.DefaultCameraを追加する.このoptionはインスタンスの名前を指定するために文字列の値を設定する必要がある.

material target

$ armos generate material <ClassName> [<path>] [<options...>]

armos.graphics.materialを継承したクラスの定義が書かれたコードを生成する.<ClassName>には生成するクラスの名称を指定する.pathを指定しないこと(e.g. foo/BoxMaterial). 生成されたコードは/source/<projectname>/materials/<classname>.dとして保存される.

以下のoptionが使用可能.

glslsource (glslsources) target

ここでは機能が似ている2つのtargetについて説明する.

$ armos generate glslsource <filepath> [<options...>]

glslsourceは一つのglslファイルを生成する.<filepath>に指定したファイルを/shadersディレクトリ内に生成する. 生成されるファイルがvertex shaderかfragment shaderか,あるいはgeometry shaderかは,<filepath>で指定された文字列の拡張子により判別される. 拡張子は以下を用いること.

  • .vert vertex shader
  • .frag fragment shader
  • .geom geometry shader

optionには以下を使用できる.

$ armos generate glslsources <dirpath> [<options...>]

glslsourcesは vertex shader, fragment shader, geometry shaderの3つのglsl sourceを含んだディレクトリを/shadersディレクトリ内に<dirpath>として生成する. 以下のoptionが使用できる.

  • --no-vert vertex shaderを生成しない
  • --no-geom geometry shaderを生成しない
  • --no-frag fragment shaderを生成しない
  • --path string /ディレクトリからの相対パスで生成先を指定.dirpathより優先される..

今後は--typeoptionにより様々な種類のglsl sourceを生成できるようにしていく予定. .

glslify Shader Precompile

armos.graphics.shaderでglsl sourceをコンパイルする前に行われるソースコードの展開(precompile)にnpmのパッケージであるglslifyを使用するようにした.

この変更により,以下の機能が提供される.

  • glsl sourceのモジュール化と読み込み
  • npmによるglsl-*系パッケージの手軽な利用

詳細は以下の記事を参照.

qiita.com

なお,dlangのソースコードにハードコードされたglsl sourceをarmos.graphics.Shader.loadSourcesに渡した場合, そのコードは/にあると見なされる.glslifyの相対パスによるmodule読み込みの際には注意すること.

引っ越しした

山奥から札幌に引っ越しした.色々と落ち着いてきたのでこの記事を書いている.出自が野蛮な男子寮なので(夜中に人間の鳴き声が聞こえる等.スズメがドン引きするレベル),世間の常識的にどこまで騒いでいいのかよくわからずビクビクしながら静かに生活している.

自炊

f:id:ttata:20170125224143j:plain:w500

朝はシリアルで軽く食べて,昼と夜はスパゲティとかスープ系とかを作って食べている.今日は舞茸とキャベツのペペロンチーノを作った.具が多すぎて野菜炒めみたいになってしまったが,キャベツのやさしい味がして美味しかった.あとシチューとかもこの前作った.ふたり分作ってしまって残りは冷蔵庫に突っ込んでおけるので楽.また,米については炊飯器は買わずに普通の鍋で炊く予定だったが,ここ数日美味しいごはんの食べたみが出てきたので,つい先ほど土鍋と米を買ってしまった.土鍋は頑丈そうで米も炊けそうな銀峯 花三島の8号ってやつを選んだ.ちょっと大きめなので誰かと鍋をつつくのにも使えると思う. これで生活の文明レベルが弥生時代まで急激に発達した.土鍋×ガスの最高のごはん体験楽しみ.とりあえずこの後は,土鍋を調理に使う前に,目止めというならし作業を行うので,実際にごはんを炊くのは明日以降になると思う.

インターネット

さて,引っ越してから1週間が経過して家具や家電は概ね揃ったが,未だに不足しているインフラがある.インターネットだ.今は無線の容量制限付きの回線でなんとかしのいでいるが,半身をwebに置いているような人間なので正直そろそろ息苦しい.予定では2/1には使えるようになるので,それまでに届くよう無線ルーターもポチった.NEC Aterm WG1800HP2ってやつ.回線が整い次第本気出しますよろしくお願いします. 

キリンガラナ500ml缶

この記事は苫小牧高専 Advent Calendar 2016 23日目の記事です。

 冷蔵庫からキリンガラナ500ml缶(以下ガラナ)を取り出した.この記事を書くときに飲もうと取っておいた最後の一缶だ.できるだけ体温で温度が上がらないよう,上面の縁をつまむようにして机へ運ぶ.下面に書かれた製造番号は「NA/1EI59」."NA"が製造工場の識別番号で,スラッシュの後ろがロットになる.この500ml缶は全て,岩内町にある「日本アスパラガス」という工場で生産されていると友人から聞いた.恐らく識別番号は"Nihon Asparagus"の頭文字をとったのだろう.この工場は缶詰の製造ノウハウを清涼飲料水のパッケージングに転用したとかなんとか.さて,ロット違いのものが他にあれば飲み比べもできるが今回はこの一缶だけ.プルタブを引き起こす.炭酸の勢い良く漏れる音と共に鼻の奥を優しく刺激するフルーティーな香りが漂う.最初の一口,喉で味わう.いつもより炭酸は控えめで甘めの味付けだ.冷蔵庫で冷やしただけなので舌触りはサラッとした感触.凍る直前まで冷やすとまろやかになるが,一歩間違えると破裂する恐れがあるので最近はやっていない.高専の寮にいた時は,冬の朝に二重窓の間に置いておいたガラナが破裂し,窓が飴色に染まったのを思い出す――

 僕が寮にいた5年間で一体何本のガラナを飲んだだろうか.一年のうち2/3は寮で生活していたとすると,一日に一本は飲んでいたので,大体1200本は飲んだことになる.いつも買う寮の食堂の前のアホみたいな品揃えの自販機はガラナを100円で販売していたので120000円分ガラナに注ぎ込んだ計算になる.まじか.ドン引きなんだけど.多分計算間違いだと思う.入学したばかりのころはそこまで飲んでいなかったような気がするし.

f:id:ttata:20161223223359j:plain

食堂前,アホみたいな品揃えの自販機(なお周波数の都合で一部点灯してないように見えるがテスト期間につき全て売り切れ)

 授業が終わり,一度寮へ帰る.部活へ行く途中,食堂の前の自販機でガラナを買う.すぐにでも飲みたいが,外の空気に触れると味が変わってしまうので開けずに部室まで縁をつまんで持っていく.未だに不思議なのが,屋内の空気と触れるだけではそこまで味が変わらない点だ.開封したまま外を歩くと,どうしても埃っぽい味になってしまう.まあ,その季節その時間の空気の香りをガラナと一緒に楽しむことができる,という考え方もあるかもしれない.夜は寮の風呂から上がった後に食堂の前の自販機でガラナを買う.そのまま缶を片手に自分の部屋に戻ったり,誰かの部屋に遊びに行ったり.基本的に1日1本だけどテスト期間だと2本目に手を出すことがある.で,そういう時期には寮の自販機のガラナが売り切れたりする.

 卒研室の冷蔵庫には常にガラナが入っていた.というのも,当時の僕を含めた卒研室の5年生はほとんどがガラナ飲みで,いつも机に500ml缶を置きながら研究に励んでいた.あといつの間にか卒研担当の先生もガラナにハマっていた.こうしてそれぞれ買ってきたガラナを冷蔵庫で冷やすようになった.

 ガラナについてのある仮説が提唱されたのもこの場所だった気がする.

ガラナの味が違う」

半分冗談だったけど.甘さや香り,炭酸の強さが,飲む度に微妙に異なることに気がついたのだ.ここでいくつかの仮説が立てられた.

  1. 体調説
  2. ロット説
  3. 経年劣化(熟成)説

まず,体調説の検証は難しそうなのでパス.でも体調で味覚が左右される話はよく聞くので,可能性としては大いにあると思う.また,ロット説については,研究室のメンバーが異なる複数のロットのものを仕入れるため,それぞれ別のルート,寮の食堂前の自販機,学生会館の購買等からガラナを入手し飲み比べをした.確か味が異なっていた記憶がある.要追実験.最後に,経年劣化(熟成)説は,事前に僕が,食堂前の自販機のガラナが売り切れた際の戦略備蓄として,自分の部屋の机の引き出しに保存しておいた,購入から1年が経過したガラナをサンプルとして利用し,検証する予定だった.でも結局,なかなか開封するタイミングがつかめずに卒業してしまった.あの熟成ガラナは当時の卒研室のメンバーだった僕の友人に譲渡した気がする.今もまだあるのだろうか.

 ガラナのアレンジは,他のジュースと混ぜるあたりでやめておいたほうが良いのかもしれない.ガラナを少し飲んだ後にレッドブルを混ぜたガラナブルはテスト期間等切羽詰っている時にお世話になった.あとレモンを絞ると美味しいらしい.これは友人から聞いただけで実はまだ一度も試せてない.ポッカレモンよりも生のレモンが良いとか.

 問題はここからで,ある時ふと魔が差して固形物のガラナを食べたくなってしまって,フライパンでガラナを煮詰めてガラナ飴を作った.いい感じに箸に巻きつけて,それっぽい見た目にすることには成功した.ただ,どうにも若干火加減が強かったらしく,焦げてしまったらしい.ほろ苦い大人向けの仕上がりになってしまった.もともとの液体の色がキャラメル色なので,判断が難しいんだと思う.誰かこの失敗を活かして美味しいガラナ飴を作って欲しい.

f:id:ttata:20161223224247j:plain

ガラナ飴 苦い

 で,最悪だったのがホットガラナ.元のガラナが美味しいだけに,これは本当に驚いた.コニカルビーカーに入れて湯煎したので見た目に凄みがあったのも大きいかもしれない.僕と,共犯の1人は口に含んだ直後に吐き出した.なお別の共犯者は普通に飲んでたので個人差があるのかもしれない.まあ,あれは本当に最悪のエクスペリエンスだった.簡単にできるのでこの記事を読んだ人はぜひ実践していただきたい.

f:id:ttata:20161223224345j:plain

吐き気を催す邪悪

 大事な話をするのを忘れていたんだけど,キリンガラナって,容器によって味が微妙に異なる.これは僕のまわりのガラナ飲みからコンセンサスが得られてるんだけど,500ml缶が至高.ペットボトルだと味に雑味が入る.アルミのボトルタイプのものも同様.どちらもフタ付きで飲みきりではないので何らかの保存料が追加で含まれているのかもしれない.ただこれだと190ml,350ml缶の味が500ml缶に劣る理由が説明できない.なんでだろう.誰か調べてみてほしい.(あとキリンガラナの他にもコアップとか色々な種類のガラナがあるけどキリンガラナが一番美味しいと思います)

 そろそろ開けたガラナも無くなりそうなのでこの記事もこのへんでまとめていこうと思う.昔からガラナについて何か記事を書いておこうと考えてはいたけどタイミングが見つけられなかった.そこで今回,苫高専AdventCalendar23日目という機会を頂いたので,ポエムを献上させて頂いた次第.しかしこうして昔のことを思い返すと僕も友人たちも本当に脳にガラナが回ってたんじゃないかと不安になる.まあ,在校していた当時から,卒業して今に至るまで,ガラナを本当に沢山の人と飲みながら,下らないことから大事なことまで色々な話をしたし,きっとこれからも,昔の友人と会うときはガラナで乾杯するのだろう.

ガラナはいいぞ.

f:id:ttata:20161223232431j:plain:w340

明日,24日の記事はhanaken_nさんの「クリスマスイブデートを断って後輩たちに捧げるポエムです。それでは聴いてください。『あえて言おう、mkは休学すると』」です.僕もmkくんは無傷で専攻科を卒業できるとは思っていないのでとても楽しみにしてます.

D言語でクリエイティブコーディングのためのフレームワークarmosを開発している話

はじめに

 この記事はD言語 Advent Calendar 2016クリエイティブコーディング Advent Calendar 2016の記事です.

 1年ほど前からopenFrameworksprocessingのようなフレームワークD言語で開発しています.この記事では,ざっくりですがその紹介をしていきたいを思います.なお現在のarmosの仕様は暫定的なもので,これから大きく変更される可能性があります.

armos

f:id:ttata:20161206230838p:plain

github.com

 armosはクロスプラットフォームのクリエイティブコーディングフレームワークを目指して開発されました.言語は,ネイティブコンパイル言語の処理速度と,軽量言語の書きやすさを兼ね備えたD言語を採用しており,シンプルなプロトタイピングから,複雑でスピードを要求されるようなアプリケーションまで柔軟な記述が可能です.画像や音声等の複数のライブラリを統一的なIFでラップしており,開発者はD言語のコードからそれぞれの機能を簡単に扱うことができます.

 現在のarmosについては,動作環境については,Linuxと一部のWindowsで確認しており,Macについては未確認となっています.一部グラボによっては描画が正しく行われない,等の環境依存があるようです.機能については,openGLによる描画処理,Assimpによる3Dモデルの読み込み,openALによる3次元音声処理,GLFWによるウィンドウ管理と各種入力デバイスのサポート等が実装されています.これらは工数の兼ね合いから,ライブラリの全機能のラッピングよりも主要な部分の実装が優先されており,あまり重要ではない機能やユーテリティは後回しとなっています.また,今後は動画やフォント,パスの描画等の機能を実装していく予定です.

機能の追加やバグフィックス等がありましたら是非気軽にContributionお願いします:)

サンプルコード

 moduleの数がそれなりに多く網羅的な説明をこの記事で行うのは困難なので,armosの基本的なアプリケーションの記述方法を紹介していきたいと思います.

// armosの機能を使うためのimport文.
// コード中のどの部分がarmosの機能なのかを明示するためにstaticをつけている.
static import ar = armos;

// oFと同様にBaseAppを継承してアプリケーションのclassを記述していく.
// 基本的なメンバ関数は以下の3つがある.
// setup  実行時の最初に一度だけ呼ばれる
// update 毎フレーム呼び出される.メンバの更新処理を記述する
// draw   毎フレームupdateの直後に呼び出され,描画処理を記述する

class TestApp : ar.app.BaseApp{
    override void setup(){
        // アルファブレンディングを有効にするため,BlendModeを指定する.
        ar.graphics.blendMode = ar.graphics.BlendMode.Alpha;
        
        // Lenaの画像を扱うImage classのインスタンスを生成し,画像ファイルを読み込む.
        // 読み込みの処理はFreeImageを使用.
        _imageLena = (new ar.graphics.Image).load("lena_std.tif");
        
        // 同様にD-man(D言語くん)の画像を読み込む.
        // また,ここでは拡大した際にぼけないよう,テクスチャのフィルタの設定も行っている.
        // このように,armosで実装されているほとんどのclassやstructはメソッドチェーンで処理を書いていくことができる.
        _imageDman = (new ar.graphics.Image).load("d-man.png")
                                            .minMagFilter(ar.graphics.TextureMinFilter.Nearest, ar.graphics.TextureMagFilter.Nearest);
    }
    
    override void draw(){
        // Lenaの画像の一部分を表示.
        // 第一引数と第二引数は表示位置,それ以降の引数で切り抜く範囲のピクセル座標を指定する.
        _imageLena.drawCropped(512, 512, 256, 256, 512, 512);
        // Lenaの画像を0,0の位置に表示.
        _imageLena.draw(0, 0);
        
        // oFやp5にある同名の関数と同様,Model行列を保存(stackにpush)する.
        ar.graphics.pushMatrix;
            // Model行列のx, y座標を10倍に拡大する.
            ar.graphics.scale(10, 10, 1);
            // 今のModel行列が適応されるので10倍のサイズのD言語くんが表示される.
            _imageDman.draw(14, 5);
        // 保存しておいたModel行列を再び読み出す(stackからpop).
        ar.graphics.popMatrix;
    }
    
    private{
        // 画像を読み込み,表示するためのImage.
        ar.graphics.Image _imageLena;
        ar.graphics.Image _imageDman;
    }
}

// D言語の標準のエントリーポイント.
void main(){
    // 上で実装したアプリケーションを実行する.
    ar.app.run(new TestApp);
}

このコードを実行することで,以下のような表示を行うアプリケーションが動作します.

f:id:ttata:20161206231226p:plain

 armosには各機能の動作を紹介するサンプルプロジェクトが同梱されているので,詳細はそちらを参照してください.

armos/examples at dev · tanitta/armos · GitHub

特徴

 いくつか紹介したいと思います.

oFライクなイベント

 armosを用いたアプリケーションを開発する際に継承するクラスarmos.app.BaseAppは,openFrameworksのofBaseAppと同様なメソッドを用意しています.キーボード入力は,現在のキーの状態をすぐに確認できるhasPressedKey, hasHeldKey, hasReleasedKeyが実装されています.   https://github.com/tanitta/armos/blob/dev/source/armos/app/baseapp.d

Vector

 ベクトルを表すstructです.要素の型と次元をtemplate引数として指定します.各種オペレータのオーバーロードが実装されており簡単にベクトルの計算ができます.

auto v = Vector!(float, 3);

また,Vector Swizzleが実装されており,GLSLのvector.xzのような記法でのプロパティへのアクセスが可能です.

auto vec = Vector3f(2.0,4.0,6.0);
vec.yx = Vector2f(0.0,1.0);
assert (vec == Vector3f(1.0,0.0,6.0));

他にもVectorを元にしたMatrixやQuaternion等が実装されています.

Shader

 openGLのShaderを扱うclassです.基本的なインターフェースはoFと似たものとなっていますが,Shaderのプログラムのattributeやuniformにデータを渡す関数は,D言語の強力なコンパイルメタプログラミング機能により,データの要素の型や要素数を意識することなく扱うことが可能です.

int d = 1;
shader.uniform("distance", d);
shader.uniform("position", ar.math.Vector2f(1.0,2.0));

Material

 ポリゴンの材質を表す,Shaderとプロパティをまとめたinterfaceで,複数の材質の切り替えやパラメータの管理等を容易に行えます.また,このinterfaceを元にオリジナルのMaterialを作成することができます.

AutoLoadMaterial

 上のMaterial interfaceを元にしたMaterialで,読み込んでいるShaderのソースファイルが更新された際に自動的に変更を検知し,再読み込み,コンパイルを行います.これにより,GLSLを用いたライブコーディングが可能となっております.

2Dデータ

 2DのデータはImage, Bitmap, Textureの3種類があります.簡単に画像を扱うためのImage classは,ファイルの読み込みから画面への描画をサポートします.画像の読み込みはFreeImageにより行うため,様々な形式の画像ファイルに対応しています.Bitmap structは画像を表す単純なデータ構造で,サイズ分のピクセル情報を持ちます.拡張機能として,ndsliceへの変換が可能なため,複雑な画像処理でも高速で行うことができます.Texture classは,openGL側で画像を扱うためのもので,Bitmapからの変換が可能です.

3Dデータ

 armosでの3Dのデータは階層構造になっています.

  • 形状を表すMesh class
  • Meshと材質を表すMaterialを束ねたEntity class
  • 複数のEntityを束ねたModel class

なおModelはファイル名を指定することで外部ファイルからデータを読み込む機能も実装されています(Assimpを使用).また,MeshとEntityはGPU側で高速に扱うためのBufferMesh,BufferEntityが存在します.これらは,openGLのVBOを用いてデータを管理しており,元のMeshやEntityから簡単に変換することができます(CinderのBatchのような感じ).

Filter機能

 Fbo classのメンバ関数FilteredByを使うことで,表示結果にフィルタをかけていくことができます.引数にはMaterialを指定します.

fbo.filteredBy(invert)
   .filteredBy(offRegistrationFilter);

D言語でクリエイティブコーディングをするときの便利なパッケージ

 D言語で色々やっていくために書きました.

easing

github.com

 よくあるeasing関数がまとめられたパッケージです.関数を直接扱う際は定義域,値域共に(0,1)ですが,付属のmap関数を用いることで,それらを自由に変更することができます.実装されているeasing関数はパッケージのREADME.mdを参照してください.

import easing;
auto output = input.linear;
//                  |
// easing function -+

auto output = input.map!linear(0.0, 10.0, 0.0, 1.0);
//                      |      |    |     |    |
// easing function -----+      |    |     |    |
// min of input ---------------+    |     |    |
// max of input --------------------+     |    |
// min of output -------------------------+    |
// max of output ------------------------------+

osc-d

github.com

 おなじみOpen Sound Control(OSC)プロトコルD言語実装です.外部のシーケンサ等からarmosのアプリケーションを操作することができるようになります.

実際のところD言語でクリエイティブコーディングってどうなの

 D言語の仕様については問題なく快適にコードが書けます.ビルド速度も高速で,試行錯誤のサイクルをガンガン回すことができ,テンプレートをゴリゴリ使ってもそれほど遅くなりません.hppとcppでコードを分ける必要も無く,module機能が実装されているのでincludeの依存関係で悩む必要も無いため,ソースコードの取り回しが非常に楽です,また,昔のD言語はアップデートが派手だったらしいのですが,最近のD言語はそのような破壊的な変更も無く安定しています.言語仕様が洗練されているため学習コストも低く,特にC++erなら非常に楽に学べると思います.

 エコシステムに関しては,モダンな言語でよくあるパッケージマネージャとしてdubがあり,プロジェクトと要求パッケージのバージョン依存を管理をしてくれます.ライブラリ周りについては,品揃えはそこそこ充実してきたのですが,どうしてもクリエイティブコーディングのような用途で要求されるような特殊なものは不足してしまうところがあります.また,D言語はCで書かれたコードについては互換性がありますが,一方でC++はそのへんが難しいらしく,そのため,openCVKinectのようなライブラリがC++で記述されたものについては,一度Cでラッパを書いてそこから呼び出す,等の方法をとる必要があるようです.(なお,openCVについては,同様の画像処理ライブラリとして現在dcvが開発されており,今後が非常に楽しみです)

 このように,ライブラリついては若干不安がありますが,言語自体は非常に優秀です.足りないライブラリはガンガン実装してコミュニティに貢献していきましょう!

My First Game Jam: Summer Editionに参加した

 久しぶりにゲームジャムやりたいなと思ってIndie Game Jamsを眺めていたら,My First Game Jamっていう初心者向けのゆるそうなイベントを見つけたので参加してきた.

itch.io

 自分は以前にGlobal Game Jamに参加したこと(参照)があるので"My First Game Jam"ってわけじゃないんだけど,今回使ったprocessingでゲームを作るのは始めてだったのでまあ初心者ってことで.

My First Game Jamとは

  • 初心者向けのゲームジャム
  • ルールはかなりゆるい
  • 期間は2週間
  • 一人で開発してもよし,チームを組んでもよし
  • 普通のゲームジャムと同様,開催直後に発表されるテーマに沿って開発する.

開催までの色々

 一人で作るのも寂しかったので,普段から素晴らしい楽曲を書いているOtObOx先生をサウンド回り担当として誘った.「やる?」「やる」的な二つ返事でコトが進んだ記憶がある.フットワークが軽くて素敵だと思う.というわけで,自分がプログラミングとグラフィック担当,OtObOx先生がサウンド担当って感じでチームが決まった.

開催後前半

 どんなゲームを作っていくか,SlackとTeamSpeak3で作戦を練った.今回発表されたテーマは"a spin on a popular story/myth".スピンオンってなんだ.ググりまくった記憶がある.とりあえず日本の昔話系をリストアップした.自分はゲーム作りやすそうだったので因幡の白うさぎをゴリ押しした気がする.サメから落ちたらゲームオーバーみたいな.最終的に竹取物語ベースのシューティングを作ることになった.この時はまだ,月からの使者を迎撃する普通のインベーダ的なゲームを想定していたのであった...

開催後後半

 1週間が経過した.「そろそろつくろっか.まあ1週間もあれば余裕っしょ.ハンデハンデ笑」という気持ちで開発が始まった.とりあえず2日間ぽちぽちドットを打ち,もくもくコードを書いて叩き台が完成.設計や実装の美しさを無視した,とりあえず動けばいいコードを乱暴に書き上げていく作業は,背徳感とスピード感があってとても気持ちが良かった.あとは楽曲や効果音を組み込みつつ,難易度を下げる方向に調整していった.

 最終日は,時間ギリギリまでテストプレイのフィードバックでクオリティを上げていく作業をした.朝ごはんとして温めた角煮肉まんを電子レンジから取り出す暇が無いほどエクストリームだった.(テスターのみなさんありがとうございました!)13時の提出直前は,バージョンを一つ戻すかどうかで決断を迫られる体験ができた.git rebaseのコマンドをド忘れして激焦った.提出も,イベントのページと別でアカウントが管理されている都合,無事にアップロードできてるのか分からなくて激ヤバだった.

 最後は,すっかり冷えきった角煮肉まんをもう一度レンチンしなおして笑顔でおいしく頂けたのでよかった.

できあがったもの

f:id:ttata:20160817153702p:plain

tanitta.itch.io

github.com

 月から地球にやってくる使者のウサギから,かぐや姫を守るシューティングゲーム.前半1週間でOtObOx先生が「弓飛ばそう弓」と言ってた気がするが,実際に実装されたのは,タケヤリにロケットブースタをポン付けした星間ミサイルと,それに作用する重力場であった.射出後に加速するタケヤリミサイルを地球の軌道に上手く乗せて,飛来するウサギを迎撃していく.真上に打ち上げるだけだと,重力が作用してすぐに落下してしまうため慣れが必要.また,タケヤリの残弾数は地上のタケを刈り取ることで回復できる.WindowsLinux対応.(Macは適当にprocessingでビルドして動かして下さい.)なお,開発途中で名前が"taketori war"から"taketori wars"に変わったため,表記ゆれが非常に激しい.あとdision氏のスコアがオーバーフローしたプレイ動画乗せておきます.

www.youtube.com

得られた知見

  • 相手の作業風景を直接見れないのでリモート難しい.くだらない内容でも良いので連絡をこまめにとると,お互いの開発状況がなんとなくわかって安心.
  • 少ないメンバーで迅速な意思決定ができたのでよかった.多くても3人とかがよさ気?
  • 実際に作業する人手が不足している.自分がプログラミングとグラフィック両方やるのはちょっと厳しい.どちらかできる人がもう一人いれば....
  • ゲームの難易度は,開発者自身が実装の過程で慣れてしまうため,調整が難しい.自分が思っている以上に下げる,あるいはコアメンバ以外の人にテストプレイをしてもらう必要がある.
  • 爆発エフェクトは白黒の点滅を入れると視覚的に威力が上がる.
  • 適当なバネモデルで画面を揺らすと激しい肌触りになる.
  • 早めの提出

ある日の環境構築

まとめ

 linuxで,Radeon(HD5850)+xf86-video-atiでKMSが有効な状態でstartxを実行すると画面が真っ暗になって落ちる,そういうときは,カーネルパラメータにradeon.dpm=0を指定すると解決する場合がある.

ポエム

 ある日のこと,メインの開発機のArchでyaourt -Syuでアップデートを行った後,dlangで書いている自前のプロジェクトのビルドを終え,実行したところ以下のエラーが出た.

GLまわりのエラーのようなので,とりあえず可能性として以下の原因が思い浮かんだ.

  • グラフィックドライバまわりのエラー
  • glfwのライブラリのリンクまわりの不具合

 出力の前半にDRIまわりの警告があったため,まず,グラフィックドライバについて調べた.この環境では,プロプライエタリcatalyst-testをドライバとして使用している.導入の際,要求される他のパッケージやデーモンの設定等で苦労した記憶があるため,このあたりが怪しいと判断した.そこで,オープンソースドライバであるxf86-video-atiによるcatalyst-testの置き換えを試みたが,パッケージの依存性の解決が難しそうだったため,予備として用意していた,グラフィックドライバやxorgを導入する前まで設定を済ませておいた別のパーティションのArchlinuxで,オープンソースドライバのxf86-video-atiを用いた新しい環境を立ち上げることにした.

 ところで,今回問題が発生したメインの環境でcatalyst-testを使用していたのは,最初の環境構築の際に,他のドライバの,catalyst,xf86-video-atiでは上手くRadeon HD5850が動作しなかったためであり,また,今のcatalyst-testの導入後に何度か他のドライバでの動作を試みたが全て失敗していた.そのため,今回の試みも正直ダメな予感がしていた.

 さて,さっそく新しい環境を整える.まずは,arch wikiにある通り,カーネルパラメータにnomodesetを設定してKMSを無効化,xf86-video-atiを入れる.ここまでは順調だが,その後,KMSを有効にした状態でstartxによりXWindowを立ち上げると,スクリーンに何も表示されなくなる(情弱感).また,キーボードのcaps lockのランプも,普段は切り替えを行うと点滅するのだが,その反応もなくなってしまう.これまで何度か試みた際もこの挙動が原因でドライバの導入を諦めており,フォーラムを覗いても同様の症状のスレッドはxorg.cfgまわりに原因があるものばかりで,XWindowまわりが怪しいんだろうなーと予想していた.ところが,生成されたXorg.0.logを眺めていると,どうやらnomodesetでKMSが無効になった状態で起動を試みていることを示すメッセージを見つけた.これはnomodesetが指定されていた時に誤ってstartxを実行してしまった時のログであり,タイムスタンプを確認すると,KMSが有効な状態での起動に失敗する以前のものだった.つまり,それが上書きされずに残っている,ということは,startxのログが生成される以前で何らかの障害が発生している,あるいは,startxの処理の中でエラーログが生成されないような派手な落ち方をしている,この2つに原因を絞り込むことができる.そもそも,linuxではシステムがいきなり停止するような場合,ハードウェアに原因があることが多く,また,上で書いたcaps lockのランプが反応しなくなるのも,システムがコケていることを示し,startx後に画面に何も表示されなくなった際にハードに近い部分が不具合を引き起こしている説を補強する.

 そこで,カーネルパラメータまわりについてフォーラムを検索したところ,radeon.dpmについて設定すると上手く起動する,とのポストを見つけた.このオプションは,"Dynamic Power Management"と呼ばれるGPUの使用率にあわせて動的に周波数と電圧を変更する機能についてのもので,radeon.dpm=0を設定するとあっさり動いた.最初にxf86-video-atiの導入を試してから2年近くが経過していており,正直なんともいえない気持ちになった.あと,余談だが最新のcatalystcatalyst-testを置き換えるのも依存が大変なことになったが成功した.ただ,プロプラなので更新が遅く,さらに最近のオープンソースドライバも熟成してきたので,個人的にはxf86-video-atiの方に分があると思う.

 無事に念願のドライバが導入できたところで,そもそもの今回の環境構築のきっかけを思い出したい.それは,自前のプロジェクトが実行時にグラフィック回りの警告とエラーが出た,というものであった.この新しい環境でコンパイラや依存ライブラリを整え,実行すると,警告は消えたが同じエラーが表示された.どうやら,グラフィックドライバとは別の,もうひとつの可能性であるglfwまわりについても考えねばならないらしい.ところが,こちらはドライバの問題よりずっとスムーズに解決したので,事の顛末は以下のツイートをもって代えさせていただきたい.

これと同様の対応を元々の環境で行ったが,エラーは表示されず上手く動いた.早急にこのPRがmergeされることを祈る.

結局のところ,問題を解決するために新規に開発環境を立ち上げる必要は無かった,という話です.

Global Game Jam Sapporo 2016に参加した

夜にはレッドブルおねーさんが徘徊する会場で,初めて会う人達とチームを組んで,48時間以内にゲームをつくる,そんな素敵なイベントのGlobal Game Jamに,2ヶ月前,参加してきた.

ggjsap.doorkeeper.jp

きっかけ

GGJは去年あたりにツイッターで見かけて興味を持った.本当はその年のGGJ2015に参加するつもりだったが,自分のスキルセットが中途半端で見送り.それから一年が経過して,ある程度簡単な言語やライブラリ等を要求されても1周間くらいの学習期間が確保できればそこそこ使える感じになってきたので今回は参加することにした.

できたもの

Roque

githubリポジトリはこちら

GGJのサイトはこっち

Roque | Global Game Jam&reg;

 ゲームとしてはローグライクっぽい方向を目指した.カーソルキーでロボットを操作して,バッテリーを取りながら右下のゴールに到達するとゲームクリア.デザインは,移動や敵との接触でバッテリーが減少するリスクと,マップに散らばるバッテリーを集めることで残量が増加するメリットとのジレンマが生じるデザインにした.

チームの決定

 GGJ Sapporoでは,申し込みをする際,手元の開発環境と主なスキルセットをアンケートに入力して提出し,それを元に運営の方がチームを決定する.自分は普段Arch Linuxを使用しているため,共同で開発するとなるとクロスプラットフォームな何かに縛られてしまうのが不安であった.神頼みでアンケートを記入して提出,チームの発表日を待った.

 チーム分けが発表されると,自分は「UNIX☆Webチーム」に配属された.キャプションには"OSS好きやオールラウンダーが織り成すUnix衆、ここに結成! その可能性、外部からは予測不能!"と記されていた.

開発

 今回はgithubを軸に開発を行った.全員が既にアカウントを所有し普段から使用していたためぴったり.自分は,作業のルートとなる,ゲームとしてギリギリ遊べるレベルの叩き台をマッハででっち上げる作業をした.プロトタイプを開発するのが昔から好きなので,この作業は本当に楽しかった.その後は,新機能の実装,バグ潰し,ドット絵をぽちぽち打つなどをしていた.他のメンバーについては,ちゃんとスタートからゴールまでたどり着ける迷路生成とゲーム機能,細かいバグのfixなどはyassu氏やnasa9084氏が,レベルデザインといくつかの効果音はhomomaid氏,ランキング等の処理を行うsinatraのバックエンドはmktakuya氏とtosiemon18氏,GGJ終了後も耳に残っていた印象的なBGMと効果音はmanzyun氏が制作.全員に良い具合にタスクが割り当たり,チームとしてガンガン進捗を叩き出せたのでスピーディーで楽しかった.

 ドット絵は最近界隈でアツいらしいasepriteというエディタを使用.普通のペイントソフトには無いような,ドット打つのに特化した機能が沢山実装されている.購入に際して,Windows/Mac版で提供されるバイナリは有料だが,よく調べたら自前でgithubからcloneしてビルドする分には無料.正直購入する気満々だったのでdonateしたい.そのくらいオススメ.

会場の様子

自分のチームは部屋がひとつそのまま割り振られた(部屋によっては2チームで共用のところも).部屋には電源タップが大量に用意されており,タップ持って行こうか迷っていたので安心.ネットワーク環境はそこそこ速かったので良かった.ciscoの機材が転がっており,運営のエンジニアの方曰く,チューンを煮詰めればまだ速度を上げられるらしい.

 なお,毎晩レッドブルガールが出現し,缶を開封した状態のレッドブルがもらえる.そのため,背中に羽が生えた状態での作業を余儀なくされ,開発が大変捗った.ちなみに余談だが,それでも会場の自販機のレッドブルは売り切れになっていた.

まとめ

チームが最高で楽しかった.ぜひ来年も参加してみたい.