まるまるこふこふ

数々の次元が崩壊し、全ての生命が塵と化すのを見てきた。私ほどの闇の心の持ち主でも、そこには何の喜びも無かった。

WebGL を利用して描画するまでの流れ

概要

WebGLを利用して描画する場合、描画までに実行する API のお約束が多い。

これは描画に必要なパラメータが膨大なため、 各API関数を呼び出して、グローバル変数である WebGL コンテクストの状態を変更していくことで、 描画に必要なパラメータを設定していく設計思想になっているためと思われる。

また WebGL の元となった OpenGLGPUハードウェアの制約の中で パフォーマンス向上のために API を追加し続けてきたため、 同じ描画を行う上でも、様々な方法がある(現在では推奨されないAPIもたくさん存在する)

流れ

  • GLContextの作成
var c = document.getElementById('canvas');
var gl = c.getContext('webgl');
  • シェーダーの生成

    • 頂点シェーダ
      • シェーダーの生成
        var shader = gl.createShader(gl.VERTEX_SHADER);

      • シェーダーにソースコードを割り当てる
        gl.shaderSource(shader, "shader source code");

      • シェーダーのソースコードコンパイル
        gl.compileShader(shader);

      • 正しくコンパイルできたことをチェック if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ alert(gl.getShaderInfoLog(shader)); }

    • フラグメントシェーダ
      • シェーダーの生成
        var shader = gl.createShader(gl.FRAGMENT_SHADER);
      • 以降は頂点シェーダーと同様
  • プログラムオブジェクトの生成
    プログラムオブジェクトは、各シェーダーをまとめたもの

    • プログラムオブジェクトの生成
      var program = gl.createProgram();

    • プログラムオブジェクトにコンパイルしたシェーダを割り当てる
      gl.attachShader(program, vs); gl.attachShader(program, fs);

    • シェーダをリンク
      gl.linkProgram(program);

    • シェーダのリンクが正しく行なわれたかチェック
      if(!gl.getProgramParameter(program, gl.LINK_STATUS)){ alert(gl.getProgramInfoLog(program)); }

    • プログラムオブジェクトを有効にする
      gl.useProgram(program);
  • 頂点バッファを作る
    VBOやIBOが毎フレームごとに変更される場合は、描画の際に頂点バッファを作る必要がある

    • Vertex Buffer Object(VBO)

      • バッファオブジェクトの生成
        var vbo = gl.createBuffer();
      • バッファをバインドする バッファに値を設定するときは、WebGLContext に bind → set → unbind とする必要がある
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo);

      • バッファにデータをセット
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);

      • バッファのバインドを無効化
        gl.bindBuffer(gl.ARRAY_BUFFER, null);

    • Index Buffer Object(IBO)

      • バッファオブジェクトの生成
        var ibo = gl.createBuffer();
      • バッファをバインドする
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
      • バッファにデータをセット
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), gl.STATIC_DRAW);
      • バッファのバインドを無効化
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  • VBO と IBOを登録
    シェーダー内の各変数(attribute変数、uniform変数)
    attribute変数...頂点ごとに異なるデータ
    uniform変数...頂点ごとに同じデータ

    • gl.getAttribLocation() gl.enableVertexAttribArray() gl.vertexAttribPointer() を利用してVBOを登録
    • gl.getUniformLocation() gl.uniformMatrix4fv() を利用して IBOを登録
  • 描画
    これまでの処理はプログラム開始時に1度だけ行えば良い
    描画は毎フレーム行う

    • canvasを初期化
      gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clearDepth(1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    • インデックスを用いた描画命令
      gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);

    • コンテキストの再描画
      gl.flush();

東京に来て2週間経った

部署移動のため大阪から引っ越して、東京に住んでおります。 職場の環境や人間関係、仕事内容、求められる知識が一新されて、 アワアワしております。社内転職に近い。

何をしているのか

ゲームの開発基盤作りをやってる部署に配属になりました。 部署としては、クライアントサイドのゲームエンジンや サーバーサイドや、開発する上でエンジニアやプランナーが 使うツール作りなどをしている部署です。

Ruby on Rails + Mithril で出来たWebアプリケーションを開発しているチームにアサインされました。

やったこと

主にフロントエンドの改修。 機能要件上の必要なタスクを1つ、 課題となっていたがなかなか着手できなかったタスクを複数やったりしている。 (実DOMを操作するライブラリのユニットテスト環境の整備など)

できてること

フロントエンドのキャッチアップ
もともと Mithril 触っていたというのもある

アウトプット
配属されてしばらく勉強ばかりということにはなっておらず、 何かしらアウトプットできてるのは良い。

引き続き、毎月、毎週、毎日、でも目標を立てて、それに対して成果を出していきたい。

アンラーニング
前の部署固有のドメイン知識に引っ張られることなく 現在の部署の仕事やあるいは知識に触れられている。

年末の冬休みで結構な時間を空けられたのが良かったのかもしれない。

できてないこと

社内の人とのコミュニケーション
引き続き自分が苦手だなぁと思っていること。 本来であれば、同僚や社内のキーパーソンに自らすすんで連絡を取って 交流するようしなくてはならないのだが..。

Rails のキャッチアップ
Rails tutorial やって、Rails アプリ多少作って業務にのぞんでたが全然ダメだった。

反省点は以下

全体的に Rails の学習時間が足りなかったからだと思うのだが、 Rails アプリ作るのも、環境構築に結構時間かかってたのが悪かった気がする。

今後は、新しい言語なりFWを学ぶ際は、環境構築に 大きく時間を取られることを念頭に置いておかないといけない。

すべきこと

コミュニケーション
無理をしてもお互いのためによくないので、できる範囲で。 人に対して真摯であるべきことは忘れないようしよう。

あと質問は積極的にしていこう。何事にも興味を持って。

コンテクストの学習
自分の部署は今こういうことをやっていて、それはこういう経緯があって、 誰のために今自分はシステムを作っていて etc... という情報は引き続き集めていく。

Rails の学習
この2週間の間も Rails ちゃんと調べて、以下の学びを得ました。

自分のように、別のスクリプト言語とFWの知識があって、 自分の腑に落ちるところまでAPIの挙動を把握していないとプログラできないタイプの場合、 まずは Rails のコードを読むために、Ruby メタプログラミングを学ぶのが良いですよという感じだった。 フレームワークを学習する際はソースコードレベルで理解しろ

終わりに

一緒のチームメンバーからはたくさんサポートをもらっております。 ありがとうございます。

肩肘を張っても空回りする時期ではありますが、実直にまずは 成果を積み上げて、信頼を得ていこうと思います。

2017年振り返り

リードエンジニア

2017年4月~12月末まで、エンジニア約10名規模のチームにて、 リードエンジニアという役割を頂いてました。

リードエンジニアと言っても、会社やチームによってその肩書に期待される役割はそれぞれ違います。弊社での役割は概ね以下の通りです。

  • 主に技術的な面からメンバーの開発をサポート
  • チーム全体目線でのシステムの QCD 担保

メンバーの出したプルリクエストをコードレビューしたり、 あるいは、メンバーのアサイン調整や多職種との調整をしたりしていました。 (その代わり、コードを書く量はだいぶ減った)

各案件に対してのメンバーのアサインとフォローはしっかりと 取り組んだつもりで、本人の will や can を元に、 チームがうまく回るよう考えたつもりです。

おかげで、特にチームのエース級のメンバーたちが、 その高いパフォーマンスで存分にチームに貢献できる場を作れたと思っています。 (一人は皆から認められて、今はリードエンジニアとして活躍しています)

Project Indie

2017年2月くらいから、所属する会社の社内有志メンバーで、インディーゲームを作ってリリースできないかみたいなプロジェクトを進めてました。

プロジェクトの目的は以下です。 - プロジェクトメンバーの成長 - ゲームの企画/制作のナレッジの蓄積 - インディーマーケットの開拓

ゲーム制作の能力というのは、実際にゲームを作って、何度も市場からのフィードバックを得ることで、気づきや学びを通して成長するという、自分の原体験が元です。

デジゲー博や Bit Summit に出展することが目標でしたが、 結局 1作も 2017年にはリリースできませんでした…。

イベントへの出展や、メンバーが制作に時間を当てるための社内調整より、そもそもゲームを制作することや、あるいは公の場に出すことについての、メンバーの感じている壁の高さをきちんと払拭できれば良かったなと反省しています。

Project Indie は制作の場のプラットフォームで、その中で制作チームが3チームほどある形でして、そういう観点では、プロジェクトの発起段階で、どういう人たちに参加してもらいたいかの想定を、そして立ち上がった後は、メンバーのやりたいことやスキルなどきちんと把握しながら、それに合わせたサポートをすべきだったと思います。

個人制作ゲーム

個人制作の方のゲーム制作では、今年は完成版1作体験版1作出しました。

2Dアクションパズル制作

2作目です。2017年8月に完成版。 今回もイラスト、ドット絵、音楽、シナリオなど多くの人の手を借りて、完成できました。

ゲームの全体像をしっかり考えて、その上で細部まできちんと考えられるよう、頑張っていきたいです。

探索ホラーゲーム制作

3作目です。2018年12月に完成版予定。 2作目までは、自分が中心となって、他の方々とコミュニケーションしながら制作してましたが、今回は5名で一丸となって制作してます。具体的に言うと、週1頻度でSkype チャットでMTGしてます。

たくさん反響頂いて、良いお話も頂けてるので、来年も引き続き頑張ります。

技術同人誌

技術書典というイベントで、技術同人誌を2冊頒布しました。

Emscriptoon
Webエンジニアのためのゲームプログラミング入門

※どちらも現在は Booth にてDL形式で頒布しています。

登壇

emscripten & WebAssembly night !! #5
FRONTEND CONFERENCE 2017
YAPC::Kansai 2017

ブログ

【翻訳】goroutine の仕組み

今年はてブがついたのは上記くらい。

OSSコントリビュート

今年は特になし

自分がどう変わったか

登壇とブログの量がめっきり減りました。技術同人誌を書いていたときも思ったのですが、どうやら自分は日本語書くのがヘタだと感じるようになりました。全てのことをプログラミング言語で記述したい…。

0->1 でプロダクトを作ることが好きで、その上で技術選定していくことが得意なのだとわかりました。もしかしたらエンジニア皆そうなのかもしれませんが…。

今年は(主に個人制作で)サービスリードしたり、お会社の意思決定の仕組みにちょっと関われた一方、技術がおざなりになった年でもありました。

アウトプットの質と量の向上、そのための姿勢が変わったように思います。

2018年やりたいこと

ゲーム制作

昨年1.5本だったが、もっとたくさん出したい。 完成版のリリース2つ。進行中のゲーム2つくらい進めたいな。 (数を出せばいいってものでもないけど)

作品を手に取る人にどう思って欲しいか真剣に考え、そのために作品を設計していきたい。

Web サービス

1つ出したい。アイデアだけ今ある。ちゃんとユーザーファーストに考えて、きちんと長く使われるサービスにしたい。

OSSプロダクト

1つ出したい。アイデアだけ今ある。 どういうところが新しいのか、どういう風に利用者を広げていくのか、既存のプロダクトと何が違うのかをきちんと考えてやっていきたい。

もう一つ何か新しいアウトプットしたい

何も思いつかないけど、アウトプット量として上記は少なすぎる気がする(量が多ければいいってものじゃないけど)ので 何か新しい取り組みでのアウトプットしたい。

お会社でゲームの企画書出してみようかなぁ。

3D の勉強

今、2Dしかやれてないけど、3Dも作れるようになりたい。 コンシューマーの劣化ゲーみたいにならないようにしたいなぁ。

思想/哲学/歴史の本を読む

現代は人類の歴史の中でどういう時代なのだろう。この時代を自分はどう捉えればいいのだろう、この時代に私がしなくてはならないことは?みたいなことを最近よく考える。

これらの本を読んで、何かしら自分なりに答えが出せればなと。

チーム制作 上手になる

最近、人にモノをお願いさせていただいて、一緒に制作する機会が本当に増えた。自分にできないことを人にお願いする、人ができないことを自分がやる。その結果、一人では作れないものを作ることができる。分業だ。

一緒に制作する以上、時間を奪うし、作るものに対しての向こうの期待もある。 裏切らないように、責任を持ってやっていきたい。

人を動かす/説得する
「チームワークをするときは、全員が自然に心を動かされるように話しなさい」という言葉があるけれど、その通りだと思う。ともすれば論理建てて喋ると、ロジックは納得できるが、心が動かされない言葉になりがちなので、自分も気をつけていきたい。

これを作ることで、こんな目的が達成できるんだ、という言葉は、共感してくれた人を動かす力があるので、大切にしたい。

相手を熟知することは当然として、自らのテーマ、コンセプト、問題提起が何で、ゴールイメージが何で、依頼の仕方など、ちゃんとパートナーとして認めてもらえるよう振る舞っていきたい。

あと、人の良いと思ったところはちゃんと口に出そう。

彼らが力を発揮できる環境を作る
制作の仕組みや方法を考える/実行するのはもちろんのこと、最近は、文化の違いによる支障をよく感じる。思ったことをきちんと述べることが誠実な態度に見える文化で生きてきた人もいれば、相手の気持ちを慮って時として言わないことが正の文化で生きてきた人もいる。両者に摩擦があって、制作がうまく進まないのはもったいない。文化の違いを理解して、みなが心地よく良いパフォーマンスを出せる環境を目指したい。

姿勢について

  • 適当にすまさない/ごまかさない/全力で徹底して取り組む
  • 周囲に対する感謝の心
  • 身近な人に対して真摯かつ誠実である
  • 傾聴と自己開示(耳を傾ける事/説明すること)
  • 共感する
  • コミュニケーションの場があれば、その場をお互いにとって良い場にするかを意識すること

まだ未熟ではございますが、上記のことを意識して頑張りたいと思います。

今年もまたよろしくおねがいします。

【翻訳】goroutine の仕組み

訳者による概要

Krishna Sundarram 氏の記事「How Goroutines Work」の翻訳です。

「goroutine とは軽量スレッドである」という説明に対して抱くであろう 「どのようにして並行処理を実現しているのか」「既存のスレッド処理と何が違うのか」「なぜ軽量なのか」という疑問を解消する文章です。

とても良い文章なのですが、現在リンク切れになっており、 とてももったいないことだと思ったので、日本語に翻訳しました。

原文: How Goroutines Work (2017/12/02 現在、リンク切れ)

golang の紹介

もしあなたが golang 初心者で、並行処理(Concurrency)と並列処理(Parallelism)の違いがわからなければ、Rob Pike 氏のトーク (リンク先は英語)を参照してください。約 30 分のトークですが、30分視聴するだけの価値はあります。

違いを要約すると、「人が並行処理と聞いたときに想像するのは並列処理のことであり、それらは関連はしているがまったく別物である。平行処理とは、プロセス同士が独立して実行されることであり、並列処理はたくさんの計算を同時に実行すること(場合によっては互いに影響しあいながら)です」 並行処理とは一度にたくさんのことを扱うことであり、並列処理とは一度にたくさんのことを実行することです。*1

golang を使って、我々は並行処理プログラムを書くことができます。golang は、goroutine 及びそれら goroutine 同士が通信する仕組みを提供します。本文章では、前者の goroutine に焦点を当てます。

goroutine とスレッドの違い

Java がスレッドを使うように、golang では goroutine を使います。両者の違いは何でしょうか? この違いを語る上で 3つの要素があります。「メモリ消費量」「生成と破棄に要する時間」「スイッチングに要する時間」です。

メモリ消費量

goroutine は、メモリを大量に必要としません。スタック領域では 2kB しか消費せず、必要に応じてヒープ領域を割り当てたり開放したりします。*2*3一方でスレッドはスレッド間のメモリが干渉し合わないように「スタックガードページ」と呼ばれる 1Mb(goroutineの500倍) の領域の確保から始めます。*4

それゆえに、サーバーへリクエストがくるたびに、goroutine を生成するのは何も問題がないですが、スレッドでそれをやると、深刻な OutOfMemoryError が発生します。これは Java だけの制限ではなく、並行処理で OSのスレッド機構を使う全ての言語において、この問題に直面します。

生成と破棄に要する時間

スレッドは生成と破棄のたびに OS に要求を投げて、それが完了して返ってくるのを待つため時間がかかります。この問題を回避するには、一度生成したスレッドをスレッドプールに維持しておく必要があります。一方で goroutine では、生成と破棄に関する操作を非常に低コストで行うことができます。よって、golang では、goroutine を手動で管理する方法はサポートされていません。

スイッチングに要する時間

スレッドがブロックされると、別のスレッドがスケジューリングされます。 プリエンプティブ方式*5でスレッドがスケジューリングされ、スレッドの実行がスイッチされる際にスケジューラーは全てのレジスタ、つまり 16種類の汎用レジスタ、PC(プログラムカウンタ)、SP(スタックポインタ)、16種類の XMM レジスタ、 FP co-processor の状態、16種類の AVX レジスタ、そしてモデル固有のレジスタ etc... を別の場所に保存したり、保存したそれらをレジスタに戻す処理が必要になります。これはスレッド間で迅速にスイッチングしたい場合に、無視できません。

goroutine は協調してスケジューリングされ、スイッチングが発生したときも、たった 3つのレジスタ(PC、SP、DX)しか保存したり、レジスタに戻したりしません。これは非常に低いコストです。

以前に説明したように、goroutine の数は一般的にかなり多くの数になりますが、スイッチングにかかる時間に違いはありません。これには2つの理由があります。それは、実行可能な goroutine のみ考慮され、ブロックされた goroutine は考慮されないことと、また最近のスケジューラーは O(1) なため、実行可能な goroutine の数が、スイッチングの時間に影響を与えないからです。*6

goroutine がどのように実行されるか

前述したように、goroutine は生成から破棄までランライムが管理します。 ランタイムには goroutine が多重化された少数のスレッドが割り当てられます。 いつでも、それぞれのスレッドは1つの goroutine を実行します。goroutine がブロックされると、それはスワップアウトされ、別の goroutine が代わりにスレッドによって実行されます。*7

goroutine は協調してスケジューリングされるので、ループしつづける 1つの goroutine が、同一スレッド内の他の goroutine の実行を妨げることがあります。 Go 1.2 では、関数を実行する際に、Go のスケジューラーが呼び出されることがあるため、この問題は多少緩和されました。よって、ループ内でインライン関数でない関数を呼び出しておけば、他の goroutine がスケジューリングされます。

goroutine のブロック

goroutine は低コストであり、goroutine が以下の場合でブロックされた際に、それらが多重化されているスレッドのブロックを引き起こしません。

  1. ネットワーク入力
  2. sleep 処理
  3. channel 操作
  4. sync パッケージによるプリミティブのブロック

たとえ数万個の goroutine が生成され、それらがブロックされたとしても、 ランタイムが代わりに別の goroutine をスケジューリングするため、システムのリソースは無駄にしません。

簡単にいうと、goroutine はスレッドの軽量な抽象化です。 Go プログラマはスレッドを扱わず、また同様に OS は goroutine の存在を認識していません。OSから見れば、Go のプログラムは、イベント駆動の Cプログラムのように振る舞います。(脚注 6 参照)

スレッドとプロセッサ

ランタイムが生成するスレッドの数を直接制御することはできませんが、一方でプログラムが利用するCPUプロセッサの数を決めることはできます。 これは runtime.GOMAXPROCS(n) を呼び出して、変数 GOMAXPROCS を設定することで可能です。コアの数を増やしても、設計によっては必ずしもプログラムのパフォーマンスが上がるとは限りません。プロファイリングツールを利用して、プログラムの理想的なコア数を見つけることができます。

終わりに

他の言語と同様に、複数の goroutine によって、共有リソースの同時アクセスを防止することは大切です。goroutine 間でのデータのやり取りは、channel を通して行うのが最善です。共有メモリを通してデータのやり取りをするのではなく、代わりに channel を使って、メモリを共有します。*8

最後に、C. A. R. Hoare 氏による「Communicating Sequential Processes」を確認することを強くおすすめします。彼は本当の天才でした。1978年に発行されたこの論文で、彼はプロセッサの単一コアの性能が最終的に横ばいになり、チップメーカーは代わりにコア数を増やすことを予見しました。彼のプロポーザルの偉業は、Go 言語のデザインに深い影響を与えました。

*1:Concurrency is not parallelism」by Rob Pike

*2:Effective Go: Goroutines

*3:goroutine のスタック上でのサイズは、Go 1.4 から、8kB -> 2kB に減りました。参考

*4:Five things that make Go fast」 by Dave Cheney

*5:訳注 OSがプロセッサの実行権限を管理し,タスクの実行を切り替える方式

*6:Dmitry Vyukov 氏が、 golang-nuts グループにて gorouine のスケジューリングについて述べています。参考

*7:Analysis of the Go runtime scheduler」 by Deshpande et al.

*8:Share Memory By Communicating

技術書典3 で Emscripten 本出します。

f:id:sairoutine:20171020185653p:plain:w300

10月22日(日)に秋葉原UDXで開催される技術書典3にて

『Emscriptoon』を頒布します。

techbookfest.org

内容は Emscripten という C/C++ コードを JavaScript に変換するコンパイラを初心者向けに紹介した本です。

頒布価格は 500円。 サークルスペースは「い08」です。お手洗いの近くよ。

blog.techbookfest.org

入場に関しては整理券を配布するようです。 スマホで確認できるサイトがあるのでぜひ活用してみてくださいー。

blog.techbookfest.org

戦利品を片手に休憩できるスペースもあるみたいです。 数量限定でコーヒーとミネラルウォーターがあるって。

よろしくお願いします!

emscripten で DOSBox をブラウザで動かしてみた。

はじめに

f:id:sairoutine:20170731020004p:plain

Emscriptenとは C/C++言語からLLVMを生成し、それをJavaScriptに変換するコンパイラのことです。
DOSBoxは、PC/AT互換機MS-DOS環境を再現するエミュレータです。

結果

上記ツイート内動画のように、DOS向け Bad Apple!! をブラウザで再生することができました。

再生

皆様のブラウザでも、以下のURLから再生することができます。

https://sairoutine.github.io/BadAppleJS/

起動すると「Choose sound device」と聞かれるので「3」を押して Enter してください。ロードに成功すると、「Press enter to start」と言われるので、Enter を押してください。再生が始まります。

※「Exception thrown, see JavaScript console」と表示されたらリロードしてみてください
※音ズレが発生しているのは勘弁

過程

em-dosbox という DOSBox の emscripten 移植が存在するので、それを利用しています。

https://github.com/dreamlayers/em-dosbox

DOS 向け Bad Apple!! は以下のサイトからダウンロードできます。

http://abaduaber.ru/Prog.htm

(ロシア語でわかりづらいですが、「Bad Apple, ДОС - версия」という項目がソレです。)

事前にダウンロードして解凍し、のちのち git clone してくる ./em-dosbox/src 配下に移動させておきます。

コンパイル手順は基本的に em-dosbox レポジトリの Readme に書いてある通りです。環境は、MacOS X EI Captain 10.11.6 です。

なお、emsdk を利用しています。

# emsdk のセット
git clone git@github.com:juj/emsdk.git
cd emsdk-portable
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh 

# em-dosbox のダウンロード
cd ../
git clone git@github.com:dreamlayers/em-dosbox.git

cd em-dosbox

# configure ファイルの生成
./autogen.sh

# emscripten 用 Makefile の生成
emconfigure ./configure --without-sdl2

# コンパイル
make

# DOS 向け Bad Apple!! の実行ファイルを emscripten 向けにパッケージング
./packager.py badapple badapple BADAPPLE.EXE

# http-server を起動
python -m SimpleHTTPServer 8000

# ブラウザでアクセス
open http://localhost:8000/badapple.html

以上です。

ちょっと解説

emconfigure ./configure --without-sdl2

em-dosbox はデフォルトで、SDL2 を利用してコンパイルするが、 私のMac には SDL1 しか入ってなかったので、オプション指定して SDL1 を利用しています。

SDL2 が入っていないと、以下のようなエラーになる。

f:id:sairoutine:20170731020014p:plain

./packager.py badapple badapple BADAPPLE.EXE

packager の第一引数にはパッケージ後のファイル名を、第二引数にはパッケージ対象のディレクトリを、第三引数には、DOSBox をブラウザで開いた際に、最初に起動する実行ファイル名を指定します。

なお、実行ファイルが1つしか存在しない場合、以下のように、第二引数に直接実行ファイル名の指定もできます。

./packager.py badapple BADAPPLE.EXE

終わり

描画が追いついておらず、音ズレが発生しているのは、WebAssembly を有効にすれば 解決するかもしれない。次回やってみる。

Bad Apple !!だけでなく、DOSBox では例えば Win3.1 や Windows 98 も起動できるみたいなので、うまくやれば、ブラウザ上でそれらも動かせるかもしれない。

RPG アツマールに RPG ツクール MV 製ではないゲームをアップロードしてみた

弊サークル作品の「紫と霊夢の終わらない夏」の体験版を RPG アツマールに投稿できたので、アップロードにあたって、やったことをまとめます。

ゲームの概要

「紫と霊夢の終わらない夏」は PC向け 2D アクションパズルゲームです。RPGでもなければ、RPG ツクールMV 製でもありません。

技術的には、HTML5 + javaScript で開発されており、 Electron を使って、PC 向けにビルドして頒布しております。

アップロードのやり方

RPG アツマールは RPG ツクール製のゲームがアップロードできるサイトです。PRG ツクール製ゲームのアップロードに向いていますが、Web の技術で作られたゲームであれば、RPGツクール製でないゲームでもアップロード可能です。

RPG アツマールの仕様やアップロードの仕方については、 先人の方がいて、すでにまとめられてますので、以下のURLをご参照ください。

http://qiita.com/hajimehoshi/items/2a28b16a2e587c82ac5d

やったこと

Web ブラウザ上で動くゲームならそのままアップロードできるはずですが、 アツマールの仕様上、「紫と霊夢の終わらない夏」では以下の対応を行いました。

音楽ファイルを wav から m4a と ogg に変換

RPG ツクールMVが、m4a や ogg といった音楽ファイルしか使用できない制限のため、RPG アツマールでは、wav などの一部の音楽ファイルのアップロードが制限されています。

よって、wav ファイルを m4a と ogg の両方に変換し、ゲーム側で、 ogg あるいは m4a を再生しわけるように修正しました。

(Chrome では ogg が再生できますが、safari では ogg が再生できないので、m4a を使用します。)

index.htmlに埋め込みでjavascriptが書けない

セキュリティ上の理由で、index.html に javascript を記述できないので、javascript コードは全て js ファイルに記述して、script タグで読み込むように修正しました。

safari でフォントの読み込みが終わらない

これはRPGアツマールの仕様というより、Safari の挙動が怪しい話です。 弊ゲームでは以下のようなコードで、ゲームで使用するフォントの読み込みが完了するまで、ゲームをローディング画面で待機させています。

しかし、Safari のみ、loadingdone イベントが発火しません(バージョンは10.0)

 // フォントの読み込みが完了
    if(document.fonts) {
        document.fonts.addEventListener('loadingdone', function() { game.fontLoadingDone(); });
    }
    else {
        // フォントロードに対応してなければ無視
        game.fontLoadingDone();
    }

これは、以下のように safari だけブラウザ判定して、 フォント読み込み待ちをしないことで修正しました。

 // フォントの読み込みが完了
    if(document.fonts && !navigator.userAgent.toLowerCase().indexOf("safari")) {
        document.fonts.addEventListener('loadingdone', function() { game.fontLoadingDone(); });
    }
    else {
        // フォントロードに対応してなければ無視
        game.fontLoadingDone();
    }

.gitkeep が含まれていてアップロードできない

RPG アツマールにアップロードできるファイルは、 非常に限られており、未対応のファイルをアップロードすると、 アップロードした時点で、どのファイルが未対応か教えてくれます(便利)

私の場合、.gitkeep ファイルが残ったままだったのでアップロードに失敗しました。 これは、.gitkeep を全て削除して解決しました。

おしまい

RPG アツマールでは、特に規約上でもRPG ツクールMV 製でないゲームのアップロードは禁止されていません。

「紫と霊夢の終わらない夏」のようなオリジナルゲームエンジン製のゲームをアップロードすることもできますし、例えばティラノスクリプト製のノベルゲームをアップロードすることもできます。

みんなも Let’s try!

追記

RPGアツマールのスクリーンショット機能や、画面最大化機能が使えない。canvas DOM に振ったIDが悪い気がするので調査する