「Ajaxでエロゲーを作るブログ」[ゲーム][DHTML][XML][ねこみみか](2)/XMLの連結
ねこみみか第2話。
- サンプル:ねこみみか(2)/XMLの連結
複数XMLファイルへの対応を行いました。
- XMLの接続
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <character>Lecan03.gif</character> <background>BG03.jpg</background> <text>ねこみみか (2)</text> </page> <!-- 略 --> <page> <character>Lecan01.gif</character> <text>レカン:わらわの名はレカンじゃ。この名も、そなたの知る女性に似せて付けられたのであろう。心証を悪くするでないぞ。</text> <next>00000001.xml</next> </page> </pages>
「次のXML」を<next>タグで指定。
これがセットされていたらJavaScriptでこのXMLファイルを読み込むようにしました。
main.js
// ... // <next>の中身を取得します。 if( pageElement.getElementsByTagName( "next" ).length != 0 ) { page.nextXmlUrl = pageElement.getElementsByTagName( "next" )[0].childNodes[0].nodeValue; } else { page.nextXmlUrl = null; } // インデックスナンバーを進めます。 page.nextIndex = index + 1; if( page.nextXmlUrl != null ) { page.nextIndex = 0; } else if( page.nextIndex == ajax.responseXML.documentElement.getElementsByTagName( "page" ).length ) { page.nextIndex = 0; } // ... // 「読み込むXML」を格納するグローバル変数。 var nextXmlUrl = "00000000.xml"; // ... // 次の読み込み先。 if( page.nextXmlUrl != null ) { nextXmlUrl = page.nextXmlUrl; }
これで、シーン毎にXMLファイルを分けられるようにしました。
分岐とかもこの辺で分けられるようにしたいな。
あともうひとつ、キャラクターの非表示時に、一度透明GIFに置き換えるようにしました。
main.js
// offの時は非表示に。 characterObj.src = "Opa.gif"; characterObj.style.visibility = "hidden";
そうしないと、次の表示時に前のイメージが出ちゃうんで。
次はメッセージウィンドウの非表示化だな。
なんせ、次は一枚絵が出てくるんで……。
(1)/キャラ非表示/キー入力
「ねこみみか」というシリーズものを開始しました。
- サンプル:ねこみみか(1)/キャラ非表示/キー入力
技術的には、キャラの非表示と、キー入力に対応しました。
- キャラクターの非表示
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <!-- 略 --> <page> <character>off</character> <background>BG02.jpg</background> <text>そして恋歌は家に帰り、俺は誰もいない家に着く。</text> </page> <!-- 略 --> </pages>
<character>タグでoffを指定すると、キャラを消せるようにしました。
これと同時に背景を一枚絵にすると、一枚絵の表示になるとゆー。
キャラクターの表示・非表示は、対象オブジェクトのstyle.visibilityプロパティにvisible/hiddenをセットすることで行えます。
main.js
// キャラ。 if( page.characterUrl != null ) { // イメージ置き換え先の取得。 var characterObj = document.getElementById( characterObjId ); if( page.characterUrl.indexOf( "off" ) == 0 ) { // offの時は非表示に。 characterObj.style.visibility = "hidden"; } else { // イメージを置き換えます。 characterObj.src = page.characterUrl; characterObj.style.visibility = "visible"; } }
つか、JavaScriptって、JavaのString#equals()に当たるメソッドってないんか?(汗)
indexOf()で比較したけど、前方一致だからちょっと不安だな。うーむ。
- キー入力すると進むようにする。
スペースキー、←、→を押すと進むようにしました。
なんかこれがえらいめんどかった。
main.js
/** * キーが押された時に呼び出されるイベントハンドラです。 */ function onKeyPressNext( e ) { var keyCode = null; if(document.all) { // IE6の場合。 keyCode = event.keyCode; } else { // FireFoxの場合。 keyCode = e.which; } // スペースキー、←、→の場合に次へとスキップします。 if( ( keyCode == 32 ) || ( keyCode == 37 ) || ( keyCode == 39 ) ) { next(); return false; } } // イベントハンドラとしてセットします。 document.onkeypress = onKeyPressNext;
まずイベントハンドラのセットは、document.onkeypressプロパティにイベントハンドラとなるメソッドを渡すことで行います。
そうすると、キー入力時に指定したメソッドが呼ばれます。
メソッドでは引数ひとつ持たせます……が、この引数というか、キー入力の内容が格納されている変数がIE6とFireFoxとでことなるので、そのあたりを吸収しています。
よくわからんが、document.allがあるとIE6らしい?
あと、このイベントハンドラでfalseを返せば、ブラウザ上での処理はされません。普通ならスペースキーを押すと下にスクロールするけど、それもされないです。
IMEっぽい処理をしてるプログラムは、こういうふうにしてるんかな。
とりあえずこれでかなりゲームっぽい感じに。
他にしたいのはこんなとこかな。
- メッセージウィンドウの表示・非表示切り替え。
- 分岐まわり。
分岐まわりは結構大変そうだなぁ。ウィンドウ表示はできるけど、そのあたりをXML側で定義するのが面倒そう。
背景の置き換え。
背景も置き換えられるようにしました。
- サンプル:背景の置き換え。
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <character>g.gif</character> <background>BG01.jpg</background> <text>恋歌:外……。</text> </page> <page> <text>恋歌:あっという間に……。</text> </page> <page> <character>e.gif</character> <background>BG02.jpg</background> <text>恋歌:玄関!</text> </page> </pages>
<character>タグでキャラクターの画像を、<background>タグで背景画像を指定するようにしました。
これを、キャラの画像と同じ方法で置き換えています。
つか、今回はCSSでの細かい調整がメイン。
- クリック用の「トップスクリーン」が、IE6だと機能しない
クリック用の「トップスクリーン」が、IE6だとちゃんと機能しなかった。
「何もない」とダメだったみたいで、背景色を指定して、その上で透明度を最大に。
main.css
/** トップスクリーン(クリック用) */ div.topscreen { position: absolute; left: 20px; top: 0px; width: 600px; height: 400px; filter: alpha( style=0, opacity=00 ); -moz-opacity: 0.00; background: #FFFFFF; z-index: 50; overflow: visible; }
これで、IE6でも、ゲーム画面のどこをクリックしても進むようになりました。
- メッセージフレームがIE6とFireFoxで大きくずれる。
IE6がpaddingをwidthに含むのに対して、FireFoxは含まずwidth+paddingが実際の横幅になるんで、paddingを使用せず、内側の実際にテキストを出力する部分にmarginをセット。
- 背景の出力位置がずれる。
背景の出力位置の基準がIE6とFireFoxでこれまたずれてた。
absoluteにするとちゃんとうまくいくんで、横線以下も<div>で囲んで全部absoluteに(爆)。
ここまでやって、だいぶIE6とFireFoxとで近づきました。
微妙に違う所もあるけど、まぁこのくらいなら問題ないでしょ。
当面の課題。
各画像のサイズ合わせたりとかが思いの外面倒なことに気付き始めた……。
CSSで透明度変更。
エロゲーっぽくしてみました。
- サンプル:CSSで透明度変更。
スタイルシートをいじってエロゲーっぽい構成に。
index.html
<DIV class="background"> </DIV> <DIV class="caracter"> <IMG ID="character" SRC="e.jpg"><BR> </DIV> <DIV class="message_window_background"> </DIV> <DIV class="message_window_frame"> <DIV ID="maintext">このへんクリックしてね</DIV><BR> </DIV> <DIV class="topscreen" onClick="next( 'character', 'maintext' ); return false;"> </DIV>
メッセージウィンドウの透明度は、IEとFireFoxで違うので両方設定。
main.css
/** メッセージウィンドウ(背景) */ div.message_window_background { position: absolute; left: 20px; top: 300px; width: 600px; height: 100px; filter: alpha( style=0, opacity=70 ); -moz-opacity: 0.70; z-index: 2; overflow: visible; background: #FFFFFF; }
IEはfilterで、FireFoxは-moz-opacityで設定。
あと、「ゲーム画面全体のどこでクリックしてもテキストが進む」ように、<DIV class="topscreen">を全体にはっつけました。
main.css
/** トップスクリーン(クリック用) */ div.topscreen { position: absolute; left: 0px; top: 0px; width: 600px; height: 400px; z-index: 5; overflow: visible; }
これをonClickにしてるんで、ゲーム画面のどこをクリックしても進みます。将来的にはキーを押した時にも進めるようにしたいな。
スタイルシートで背景とキャラを重ねる。
- サンプル:レイヤーで背景とキャラを重ねる。
スタイルシートを使って、レイヤーのように背景の上にキャラを重ねてみました。
index.html
<DIV class="background"> <IMG ID="background" SRC="1.jpg" BORDER="0"><BR> </DIV> <DIV class="caracter"> <IMG ID="character" SRC="2.gif"><BR> </DIV>
背景、キャラ共に<DIV>で囲んであります。
んでこれをスタイルシートで重ねます。
main.css
/** キャラクター */ div.caracter { position: absolute; left: 100px; top: 0px; z-index: 1; overflow: visible; } /** 背景 */ div.background { position: relative; left: 0px; top: 0px; z-index: 0; overflow: visible; }
背景の方はpositionをrelativeでかつz-indexを0に。
キャラの方はpositionをabsoluteでかつz-indexを1に。
これで重なります。
ただ、キャラの画像は透過GIFにしないとまわりを透明にできないです。
PNGでも試したんだけど、IE6だと透過しないです。FireFoxならちゃんと透過されるんだけど。IE7ではサポートされるみたいだけど、IE7が浸透するまで待つ……のは無理なんで、とりあえずGIFしかないなー。アンチエイリアシングまわりが面倒そうだ……。
XML内にエレメントがない場合の処理。
- サンプル:XML内にエレメントがない場合の処理。
今回は以下のような修正をしました。
- XMLの情報を変数として返す。
- <image>タグがない場合にはこれまでの画像をそのままセットする。
オブジェクト指向っぽく、と、XML記述を楽にするために、ってことで。
まず、XMLの方はこんな感じ。
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <image>f.jpg</image> <text>恋歌:むかつくー!!</text> </page> <page> <text>恋歌:むかつくむかつくむかつくー!!</text> </page> <!-- 略 --> </pages>
2番目の<page>タグには、<image>タグがありません。
こういう「省略記法」ができるように、というのが今回の修正の理由。
<image>タグがあるかどうかのチェックはこんな感じ。
main.js
function getPage( ajax, index ) { var page = new Object(); // <page>を取得します。 var pageElement = ajax.responseXML.documentElement.getElementsByTagName( "page" )[index]; // <image>の中身を取得します。 if( pageElement.getElementsByTagName( "image" ).length != 0 ) { page.imageUrl = pageElement.getElementsByTagName( "image" )[0].childNodes[0].nodeValue; } else { page.imageUrl = null; } // ... return page; }
タグがなければgetElementsByTagName()メソッドの戻り値の配列が、要素数0になるんでそれをチェック。
それにしても、JavaScriptって不思議だなぁ……。
とりあえず、メソッドなしの構造体みたいなオブジェクトを作る場合は、次のようにするらしい。
- new Object()してとりあえずオブジェクトを作る。
- プロパティは宣言の必要なし。アクセスすれば作られる。
- 別に指定しなくても関数は戻り値を返せる。
……うう、「オブジェクト」を「インスタンス」、「プロパティ」を「フィールド」って言いてぇ(汗)。
まぁとりあえずこれでタグの有無をチェックできることがわかったんで、たとえば<next_page>ってタグを作って00000001.xmlみたいに書いておくと次はそっちを読むとかできるな。
さらに、背景用タグとか、選択肢用のタグ、画面エフェクト用タグもあとで追加するようにしていきましょう。