文書の過去の版を表示しています。
ハイハイスクールアドベンチャー Web版
あらすじ
2019年神奈山県立ハイ高等学校は 地盤が弱く校舎の老朽化も進んだため、 とうとう廃校にする以外方法がなく なってしまった。
ところで大変な情報を手に入れた。 それは、
「ハイ高校にATOMIC BOMBが仕掛けられている。」
と、いうものだ。 どうやらハイ高が廃校になった時、 気が狂った理科の先生がATOMIC BOMBを 学校のどこかに仕掛けてしまったらしい。
お願いだ。我が母校のコナゴナになった 姿を見たくはない。 早くATOMIC BOMBを取り除いてくれ……!!
行動は英語で、“<動詞>” 或いは、“<動詞>”+“<目的語>“のように入れていただきたい。 例えば、”look room”と入れれば部屋の様子を見ることが出来るという訳だ。
それでは Good Luck!!!…………
概要
PalmOS版を作ったときに、勢いで、HTML5バージョンを作ってしまえ、と、当時1)はやり始めていた HTML5に対応したバージョンを作成し始めた。
当時は、JavaScriptによるオブジェクトの取り扱いなどが今2)とは大きく異なっていたため、現在のバージョンとは全くと言って異なるコードになっていた。
しかも当時の Canvas への描画は遅く、ダブルバッファなどの使い方を追求する気もさらさらなかったため、グラフィックスの描画はサーバ側に置いたCGIで行い、JavaScriptからはこのCGIへのパラメータを生成してリクエストを投げるだけというスタイルで動作していた。
その後放置していたら、CGIが使用している Boost::Gil の仕様が変わっているわ、JavaScriptも大きく変わっているわで全く動かなくなってしまった。
そのまま放置でもいいかな、と思ったが、ググってみると旧Twitter3)でこれに言及している人がいたのを見つけてしまったので、なんとなく動かさないといけないような気がして、一気にコードを修正した。
なお、今現在4)、ゲームのセーブとロードに使っていた WebSQLが廃止されていたために、コードの修正中でセーブとロードが行えない。
また、画面に関するエフェクトも後回しにしている。5)
細かなバグが残っていて突然振り出しに差し戻されてしまうこともあるような気がする。 AsIs でシャレの分かる人のみプレイしてみてほしい。
あれこれ
画面の描画
上にも書いた通り、画像の生成には HTML5 の canvas 要素を使用している。 そもそも2012年ごろ公開したバージョンでも、実は、描画用のコード自体は存在していたのだが、テストしたらあまりに遅くて使い物にならなかったので、使用を取りやめて CGI方式にした。
とはいえ、ブラウザに搭載されたJavaScriptエンジンも高速化し続けているので、そろそろ行けるんじゃないかと思ったけれど、そのままでは行けなかった。
書き込みはそこそこいける。
正直ハイハイスクールアドベンチャーくらいのゲームなら十分だ。
だが、読み出しが入るとどうにもならないくらい遅くなる。 このゲームの画像描画の肝はペイントルーチンにあるといっても過言ではない。
そのペイントは境界検出のために画面データをなめまくるのだ。 じゃあ、メモリ上に置いといて、書き込みは処理が終わってまとめてやればいいんじゃないかということになるが、画像を RGBA形式で保持していると、結局読み出しが遅いのだ。
そもそもそんなに色数使わないので、8bitのインデックスを作ってペイントバッファとしてそれを使えばいいんじゃないかということに気づいてそのようにした。
なお、当初は、普通に一枚の canvasでやりくりしてたし、速度的には十分だったが、下に書くように、画面の表示領域をネイティブのサイズより大きくしたかったので、画面の canvas要素へ拡大転送するための canvasを作成して、ネイティブサイズ6)の画像はそこに描画されている。
画像を拡大せよ
このゲームのネイティブな画像サイズは 256×152 ピクセルしかない。 昔のPCなら十分な広さだ。 だが、今時のPCの画面にはさみしすぎる。 せめて倍で表示させたい。7)
ウェブページ上に 512×3048)で canvasを用意して、プログラム中ではネイティブサイズのダミーの canvas に書き込みを行い、倍サイズの表示領域に拡大転送することでこれを実現している。
this.zctx = document.getElementById("HHSAdv").getContext('2d'); this.zctx.imageSmoothingEnabled = true; this.zctx.mozImageSmoothingEnabled = true; this.zctx.webkitImageSmoothingEnabled = true; this.zctx.msImageSmoothingEnabled = true; this.width = 256; this.height = 152; this.canvas = document.createElement("canvas"); this.canvas.width = this.widht; this.canvas.height = this.height; this.bitmap = new Bitmap(this.width * this.height); // 描画用バッファ ... this.context.putImageData(this.bitmap, 0, 0); // バッファの内容をネイティブサイズの canvasに書いてから this.zctx.drawImage(this.canvas, 0, 0, this.width, this.height, 0, 0, this.zctx.canvas.width, this.zctx.canvas.height); // それを拡大して画面に書き込む
クラスとかラムダ式とか
2011年ごろの JavaScript によるオブジェクト指向プログラミングというと、クラスも何もなくて、普通の変数の宣言を利用してやっていたのが実態であった。
var Klass = function() { this.member = "abc"; this.hello = function() { console.log("Hello World!"); }; } var k = new Klass(); k.hello();
こんな感じのコードで、まあコードの管理も大変だった。 しかも、いつの間にかエラー吐いて動かなくなっちゃったし。
今時は普通に class を使うということなので全面的に書き直した。
なお、もうひとつ大きな変更としてはXMLHttpRequestが非推奨になっちまってたこと。 基本的にデータファイルも、CGIで描画させた画像もこの枠組みを使ってやりとりしていたので、これも大きかった。
var req = new XMLHttpRequest(); req.open('GET', 'cgi/loadB64.rb?name=" + name, true); req.onload = function() { ... }; req.send();
みたいなことをしていたのだが、今時はこれも fetch()でやるのが正しいらしいのでそのようにする。 しかも、xxx = function(){} みたいなのも古いらしい。 これはラムダ式を使うのが今風なんだと。
fetch('data/xxx.dat').then((res) => res.blob()).then((blob) => blob.arrayBuffer()).then((abuf) => { var buf = new Uint8Array(abuf); // arrayBuffer型はそのままでは利用できないので適当な形式にする。 ... });
みたいなコードになる。 本当は resを受け取ったら、res.ok かどうかを検証するべきなんだけれど、ファイルの読み取りエラーはなしってことでサボってる。 .then().then() って続いているのは、それぞれ、非同期通信になるので、値がちゃんとやってきてから次段へ進むためにこうなってる。 全部をひとまとまりでやろうとするとうまく動かない。
fetch('data/xxx.dat').then((res) => { if (res.ok) { var blob = res.blob(); var abuf = blob.arrayBuffer(); var buf = new Uint8Array(abuf); ... } });
このコードは同期がとれてないので動かない。 というかbufに中身は入ってこないのだ。