Ja
va
Sc
ri
pt

←戻る

 
2007年5月13日 (日) : 対応ブラウザ拡大

昨日Opera9.2とNetscape8.1、Mozilla Firefox2をネカフェで頂いてきたので、まずは手始めにOpera9.2から動作チェックを 始めてみました。
結果、どのスクリプトも問題なく(ショートカットキーの干渉の問題は8と変わりありませんが)動作しました。
// しかしホンマぷよぷよもどきの動作が早いなあ……IEは使えん。

一つだけ気になったのは、神経衰弱のメッセージとクリア時間が重なってしまったことかな。
これは不具合というよりも、作ったのが4年前だからWeb標準に準拠できていないことが原因だと思う。
モダンブラウザはどんどんCSSや(X)HTMLについて標準志向になってますしね。

機会があれば直しておきます。そろそろ出勤なので……@8:10。
次はFirefox2で全スクリプトを検証予定。

 
2007年4月25日 (水) : 息抜き

仕事もだんだんと忙しくなり、ゲームのネタを出す余裕がなくなってきたので、過去に作ったスクリプトで「ぐるぐるメニュー」 というのをリメイクしてみました。

この「ぐるぐるメニュー」というのは、その名の通り、コンテンツメニューを 円周率(Math.PI)とサイン(Math.sin())、コサイン(Math.cos())を用いて円状に並べたものを 画面の隅に置き、回転させることにより見えない部分を見える部分まで移動させてくるという、 当サイト史上最悪のユーザビリティといわれたスクリプトです。

「ぐるぐるメニュー」が搭載された当サイトバージョン8のトップページのキャプチャ
▲さあ、御存知のひとは思い出し笑いをするがよい!(何

これを、発想を転換して、メニューに用いるのではなく、一種のヴィジュアル・エフェクトとして再利用できない かということで、今回は「画面の外から中心に円が寄り集まってくる」というスクリプトに書き換えてみることに しました。
JavaScriptゲームのページ最下部「JavaScript小ネタ集」に追加していますので、実際の挙動はそちらでご確認ください。

原理は「ぐるぐるメニュー」と同じ。
違うのは、「ぐるぐるメニュー」では回転運動の半径が一定だったのに対し、今回のスクリプトでは、回転運動が 行われるごとに半径が縮まっていくということです。もちろん、こういった仕様にしないと、円は中心には 寄り集まってこない。

ぐるぐると回って中心に寄り集まったところで、最初は円が重ならないなどの不具合がありましたが、それは 「最後に余りが出たらその余りのぶんだけ回転運動の半径を縮め、どんな場合でも最終的に0にする」ことで解決しました。
あとは、今までお情けで対応ブラウザに含めていたNN6で動かないのがちょっと気がかりですね。
たぶん、clientWidthとかに対応していないのだろう。

 
2007年4月22日 (日) : どうなのやら

新作ゲーム「アルファベットを撃て!」。
Great!とかGood!とかMiss!とか挙動はビーマニそのものですけど。
ただ、それぞれのレーンで押すキーが決まっているわけじゃないから、そこらへんが難しいかもね。

僅差判断の追加など、いろいろとバグフィックスはしたんですが、たとえばbが落ちてきたときに、bを押そうとして間違ってbとvを 同時に押してしまったりすると、次のアルファベットがvでなかった場合にタイプミスになります(もちろんですが)。タ イピングに不慣れな方にとっては日常茶飯事なんだろうけど、そのあたりはこのゲームがタイピングの腕にも依存するという ことで、敢えて補正しておりません。「Wrong typing!」と表示されてなかなか点数が伸びない場合は、まだまだ タイピングのスキルが甘いなということでご理解くださいませ。

まあ、仕様を直そうとすれば直せるんだけどね(ぉ

ちなみに、俺自身は落下速度が「速」までだとパーフェクトが出せます。が、「激速」になると、途端に最高得点 が360点に…(汁
激速でパーフェクトが出せた方はご一報ください(笑

* * *

ここからは開発の話にちょっと踏み込みます。
降ってくるアルファベットの色を変える処理に関しては、もちろん onkeydown イベントが発生したときにいちばん近いアルファベット が表示されるコンテナのスタイルシートにおける top を取得して、ラインとの距離で正確さを判断しています。
このラインとの距離が、各ブラウザでけっこう差が出てくるんじゃないかなー、と心配してはいたんですが、どうやらNN6以外は 割と正確に(言い換えれば、IEと同じように)判断してくれるようで。NN6もそれほどズレてはいないので、説明書きの 部分にちょっと注釈をつける形で対応させていただきました。まあ、あんまりNN6でプレイするひとなんていないと思うけど。

いちばん近いアルファベットと書きましたが、最初はこれだけだと不都合があったんです。
たとえば、aとbが降ってきて、それぞれ落下速度にバラつきが現れるように作っていますから、当然、運動会のかけっこの ようにaとbが僅差でラインに到達することがあるわけです。
そのときに、aがラインまで20px、bがラインまで10pxだとすると、プレイヤーの目にはその差がほとんど分かりません。 そのため、aがbよりも左のレーンで落下している場合、本能的に、aから押そうとします。(俺もそうだった)
こうなると、ラインにいちばん近いアルファベットを撃つように当初は設計されていたため、aにはなんの反応も起こら ず、bがタイプミスということになってしまいます。

これではいかんということで、「僅差判断」というものを追加しました。
僅差判断というのは、その名の通り、ラインにいちばん近いアルファベットと2番目に近いアルファベットが僅差で ラインに到達するときにのみ、どちらから押しても反応するようにするための処理のことです。
5つのレーンのアルファベットとラインとの距離は、onkeydown イベントが発生するごとに、色が変わっていないもののみ 毎回取得しています。その距離の配列を予め昇順にソートしておき、いちばん距離が近いアルファベットと、 2番目に距離が近いアルファベットとの距離を算出、それが30px(移動3回分)以内なら僅差判断を行うことにしています。

これで、さきほどのaとbの例の場合に、aを先に押してもアルファベットの色が変わるようになりました。
が、これではまだまだ不十分。
たとえば、僅差で落ちてきた2つのアルファベットが、aとaのように同じだった場合はどうでしょうか?
1レーン目のaがラインまで30px、2レーン目のaがラインまで10pxのときに、2レーン目のaから先に反応させたいのに1レーン 目のaが先に反応してしまいます(1レーン目から順に判断しているため)。
この不都合には、僅差判断をする文字が同じ文字だった場合には僅差判断を避けるようにすることで対処しました。

まだまだ課題はあります。
4つまたは5つのアルファベットが僅差で落ちてきた場合には、反応しないことがあるかもしれません。
まあ、それはレアケースということで。そうなった場合は、単に運が悪かっただけと思ってリプレイするか、 意地でも短い間隔で4つまたは5つのキーを押してくださいw

 
2007年4月18日 (水) : 本日の修正

「ぷよぷよもどき」でゲームをリトライしたときに、落下速度が戻らなかった不具合を修正。

* * *

同じく「ぷよぷよもどき」に連鎖時のイベントボイスを挿入。
IEでしか鳴りません。萌えるならIEで!(でも動作激遅

 
2007年4月17日 (火) : Firefoxの奇蹟

1160行もある「ぷよぷよもどき」のスクリプトにDOMの条件分岐を加えるのは非常に手間がかかるので、 テキストエディタで document.all[] の部分を document.getElementById() にさくっと置き換えてNN版を作りました。

DOMの変更以外にも、例えばNN7/FirefoxはDHTML+CSSでカラーコード(例えば赤なら#ff0000)をスタイルシートの値に代入した ときに、カラーコードをそのまま返すんじゃなくて、rgb(赤,[半角スペース]青,[半角スペース]緑) の形(例えば 赤なら rgb(255, 0, 0))の形で返したり。それがNN6だと、半角スペースが無い(rgb(255,0,0)など)。だから、それもテキストエディタで 置き換えてやることで、NN6用のJSと、NN7/Firefox用のJSができたわけです。

で、完成したFirefox版をMozilla Firefox 1.0を起動させてプレイしてみる。
START!ボタンを押したあとに一度表示領域をクリックしなければならないという壁はあるものの、それを越えれば 連鎖の処理時間などがIEよりも格段に速い!
正直、同じCPU、同じメモリにもかかわらず、ブラウザのJS処理方法でこんなにも処理時間に差が現れるものかと、驚きま した。

同じく「ウンベーダー」もNN/Firefoxに対応させようとしたのですが、こちらはなんとIEと比べて逆に、1度目の プレイをしたあと急激にブラウザのレスポンスが悪くなるという結果が。筆者の環境では、なんとエクスプローラにまで とばっちりが来て、ファイルをデスクトップのアイコンにD&Dして開くことができなくなるまでにモタりました。
これはちょっと処理を見直す必要があるかもしれぬ。

* * *

モタりの原因は opacity プロパティだったことが判明。
ステージクリア/ゲームオーバー画面の半透明をなくし、点数が見えるようコンテナの高さを縮めたのはいいものの、 今度は「Start Game」ボタンを押したときに disabled にすると表示ペインをクリックしてアクティブにしないと弾丸も 出ないし機体も動かなくなった。disabled にしない場合はアクティブにしなくてもいいみたいだけど……。

今日はNN対応で1日が潰れたので、またの機会にアクティブにしなくてもキープレスが有効になる方法を模索してみます。

* * *

なんとか今日中にNN系ブラウザにおけるキープレスの問題も解決。
disabled が true になると非アクティブ状態でのキープレスが無効になるっぽいので、disabled は false のままで、 ゲームスタートボタンを押したときの関数呼び出しを許すか許さないかのトグルスイッチを新たに追加して対応しました。

ウンベーダーでも、ぷよぷよもどきでもこの問題は解決しています。

 
2007年4月16日 (月) : 「ウンベーダー」および「ぷよぷよもどき」の開発が一段落ついて

合計で2000行。いやホントに疲れました。
オカンからも「なんで最近ゲームをよく作るようになったん?」と言われる始末。
JavaScripterですから、とハッキリ答えるわけにもいかないので、昔取った杵柄とだけ説明しましたけど^^;

表の日記にも書いてあるんですが、最近ソースの書き方で大きな変化が現れたのは、関数を積極的に定義するように なったということ。
ひとつのゲームは、数種類から数十種類の機能で構成されています。その機能の一つ一つを作るのが、JSでは関数。
人間の営みで言えば、小学校の大掃除の時間に、床に油を引く作業と、雑巾で窓を拭く作業、黒板を消す作業、トイレを 掃除する作業……というように、いろいろな作業があります。その中で、最初の3つは教室という空間を共有していたり、 後半の3つはともに洗面所を使用する作業であったり……と、各作業に関わり合いができることがあります。これも、JSの 関数を組んでいるとよく起こること。ある関数からある関数へ、花を移動するミツバチのように、引数という連絡手段 を用いて、関数内で処理された変数が渡されたりします。

また、関数にはPerlのサブルーチン同様、ローカル変数といって、その関数の中でしか効力を持たない変数があり、 全体に作用するが、関数内での優先順位は後回しになるグローバル変数というのも別にあります。その2つをうまく 使い分けたり、ローカル/グローバルにこだわらない配列変数を参照したりすることにより、実行の フローチャートのようなものが以前よりも明瞭になったように感じます。

この関数を、俺は3年前同じ「ぷよぷよもどき」を作っていたときに有効に活用することができませんでした。
Perlのサブルーチンとは訳の違う、「なにかよくわからないもの」として関数を見ていたのです。

でも、関数は結局はサブルーチンと同じようなもの。
何度も行う処理を機能別に定義しておいて、あとから関数名を書いて実行する。
それをソースコードの中で積極的に行うだけでも、飛躍的に開発の能率はアップします。
3年前はふんづまったが、今は同じものを3日で作り上げている俺が言うのだから間違いなし(ぁ

まあ、そんなわけで、関数を使うことにより、なによりソースコードの可読性が大幅に改善され、実際の実行場面との 対比が明瞭になりました。これを教訓に、機能の分化したプログラムについては、積極的に関数を定義する姿勢で 今後もソースコードを組んでいきたい所存です。

* * *

関数もさることながら、もうひとつソースコードの可読性を高めたのは、変数の名前の付け方でしょうか。
たとえば、「ぷよぷよもどき」のソースコードから抜粋すると、上から出てくる2つの玉のうち、上側の玉の場所IDには upperTamaID 、下側には lowerTamaID という変数名が割り当てられています。なにを格納している変数のなのかが、 一目瞭然ですね。

以前はこの変数名に、アンダースコアをよく用いていました。
たとえば、lower_tama とか、 upper_tama とか。
これでもわからなくはないんだけど、関数名には setShadow など、単語の区切れ目で大文字を使うことが多いから、 表記を統一させてやろうと。別に変数名に大文字を使っても、中身が関数でない限りは関数と誤認されることはないしね。(心配であれば、typeof() で 中身の型を確認してみましょう)

で、以前よくあった、やたら略された変数名。たとえば、さきほどの upperTamaID を略して、uptid とか書いたり。
これは最近やってません。可読性を低くする原因になるから。
rensaGroup(連鎖でできた玉の場所IDのグループ)、allowGroupCheckLeft(左側の玉をグループとしてチェックするかどうか)などのように、 読んだ瞬間意味がわかるように変数名を付けてやるのがいいと思います。
変数なんて、宣言しているうちに余裕で50個、100個とできてしまうものだからね。