前回:
[テキストだけのエロゲーを作るvol.2 - 111のデジ同人感想]
次回:
[テキストだけのエロゲーを作るvol.4 - 111のデジ同人感想]

手触りへの労力を惜しんではいけないのだ


前回の調子で、今回は「カメと知り合った後、竿竹を売ってるとランダム確率でカメが登場、今度は悪巧みをささやく」を実装しようと思った。

だがここで問題が発生。
前回の、バズーカを振る→カメと知り合うというパターンでは問題なかったのだが、竿竹売りの場合、0.5秒ほど待って「うれねー」か「まぁまぁ売れた!」という結果が出る。

そこにカメの悪巧みの文章がかち合うことが判明した。



つまり、
1.「竿竹を売るにゃ」
2.「カメがあらわれた」
3.「まあまあ売れた!」
という具合になってしまう。これでは意味がわからないね。

プログラムをしてると、こんな予想外の事ばかりである。

これを他と同じく、すぐさま結果表示するようにすれば、何の問題もない。
その時点で解決だし、それが賢い場合もあるだろう。

だが"僅かな手触り"に凝ることで、ゲームは全然違うものになる(事がある)。
それはテキストオンリーゲーでも変わらないし、むしろそれ故にもっと顕著である。

許されるならば、ツールであれプログラムであれ、こだわりたいものだ。
どんな手触りを経て、どんな想いをさせたいのか…、そこにゲーム体験は眠るのだから。

世界は自分の頭で作れるんだ! プログラミング・ロジックの魅力を5分で伝えてみるテスト


という訳で、手触りを実現するため、プログラムのロジック再び考える。
今の形は
message("竿竹を売るにゃ");
setTimeout(function(){message("まあまあ売れた!")} , 1000);
message("カメがあらわれた");

こんな感じ。

なぜこれだと、文章が前後してしまうか。
それは前回も書いた通り、JavaScriptは「1秒後に"まあまあ売れた!"というメッセージは出すけど、それはそれとして、先に進んじゃう」非同期処理が基本だから。

なぜそんな仕組みなんだ…と思うかもだが、まあ元々はwebページ用なので…。
例えばこのブログを表示する時、

1.ブログの文章読み込み(コンマ数秒で終わる)
2.サイドパーツの人気記事一覧とか読み込み(3,4秒は掛かる)
3.ブログの画像とか読み込み(コンマ数秒で終わる)

を順に実行してると、実際にブログが表示されるまでにかなり時間が必要で、イライラするね。
ここは「時間の掛かるサイドパーツはまぁ後から読むとして、とりあえずブログを真っ先に表示する」というのが欲しい。
その為にJavaScriptは非同期が基本となってます。

(じゃあそもそも、そんなプログラム言語をゲーム制作に使うのはおかしいんじゃねってのは…、まぁそうだね…。
でも今や、ツクールMVもティラノスクリプトもUnityもJavaScriptを採用してるので…。
勿論、それぞれ欠点を克服すべくアレコレしてるんだろうけど)


今回の場合、早い話、
message("竿竹を売るにゃ");
wait(1秒待つ);
message("まあまあ売れた!");
message("カメがあらわれた");


と書いたら、ちゃんとwaitで1秒待って、順に表示してくれる、これが理想の形であろう。
(プログラム言語は新しい命令(関数)を定義できるのだから、
ロジックさえ自分で作れば、普通にwaitという命令を使えるようになる。
言い替えれば、ありものを組み合わせるゲーム制作ツールと違い、自分自身をプログラムで拡張できる…)

だがJavaScriptはデフォルトでは、そんな事はできない。
できない…が、ここは考えどころだ。

setIntervalという、「◯秒ごとに処理を実行し続ける(setTimeoutの繰り返し版)」がある。
これ何か、使えそうじゃないですかね…

count = 0;
setInterval(function(){
count += 1;
if(count == 1000)message("1000ミリ秒たった");
},1);


setIntervalが1(1ミリ秒)ごとにループしており、その中でcountという変数を一つずつ増やす。
つまりcountが1000になった時は、1000ミリ秒、1秒が経った時だ。
(実際にはブラウザの性能次第で1ミリ秒より遅くなるみたいだけど、まあ細かい話は抜きで…)

なんとか、自分の頭で、自分の発想で、「時間を測る」事ができた。
こんな一つ一つの小さな実験、一つ一つの些少な理論を築き上げて、お目当ての処理を作っていく。
それがロジックになる。


例えば、筒に3つの命令が入ってると考える。
筒 = [message("竿竹を売るにゃ") , message("まあまあ売れた!") , 
message("カメがあらわれた")]

こんな感じだ。

これが、こんな風に取り出されるとしたら?
count = 0;
setInterval(function(){
count += 1;
if(count == 0)筒の1個め実行
if(count == 500)筒の2個め実行
if(count == 500)筒の3個め実行
},1);


これはきちんと順番に表示される。
"まあまあ売れた"もちゃんと0.5秒待った後に表示されるし、カメもその直後に現れる。

"時間を指定して、順にメッセージを表示する"が出来た。
こうやってプログラムのあちこちで、命令と時間を、筒に入れていけばいいのだ…。

111先生の作例


そういうアレコレがあって、今回はここまで進みましたよ。

WM2233806
クリックでゲームに飛びます


追加したもの
*バズーカを振ってカメを仲間にした後、竿竹売ってると「アフィ活動」を教えてくれるようになった


一応、実際のプログラムコード部分はこう。

ループしてる部分
setInterval(function(){
if(MIP.length > 0){
if(MIP[0]())MIP.shift();
}
}, 1);

setIntervalでMIP(筒)を常に監視、追加されたらすぐにその中にある命令を取り出す。
"終わったよ"という確認が取れるまで、常にその命令は繰り返される。

即座に表示するものは即座に"終わったよ"というメッセージを返す。
「◯秒待つ」なら◯秒後に終わったよメッセージを、「クリックされるまで待つ」はクリックされた時に…と、かなり広く対応できた。

MIP.writeText("さおだけー さおだけー
さおonly");
MIP.wait(500);
MIP.clickWait("「おっ、なんだネコバじゃねえか、
まだそんなショボイ仕事してんのか");

MIPには、プログラムのどこからでも突っ込める。
突っ込んだ途端、すぐさま取り出して命令実行が始まる。


なぜか選択肢が無限に出たりしつつ…("終了したよ"メッセージを送るのを忘れて、ずっと繰り返しになってた)

かなり簡潔にできたと思うのだけど、実際にはこの形になるまで、2回くらい考え直しちゃあ、書き直してる。
(それで一週間経った)


どうですかね、「こうやらないといけない」なんて形は決まってなくて、自分の考えたように書けばいいし、それでちゃんとゲームとして耐えうる物になるぞ…っていう、このダイナミズム。
伝わりましたかね…。

まさに俺俺システム、俺の考えた仕組みで世の中に牙を剥ける!
これがプログラムの醍醐味なんだね。たぶんきっと。知らんけど。

…うんまぁ、
ティラノスクリプトとか使えば、そんな余計な苦労しなくても、同じJavaScript上で、もっとちゃんと出来るじゃん。アホ?(たぶん、waitだって初めから揃ってると思う…)」
っていうのも分かる。
(テキストゲーが終わったら、そういうツールで作る回だってやりたいし…)

でもこれが極まれば、
例えば同人ゲームでも[Dragon Mahjongg Evolution]とか、一度作った俺俺システムを拡張しつつ作ってるし、
確か[モモコ百烈拳]の方も、そんな感じの自作アクションエンジンを使ってたハズ。

あと商業同人だと[風雲!オークキャッスル 〜恥辱の発情戦乙女達]とかも、吉里吉里上で構築して何作も作ってるね。
あのマップを一歩一歩自動で、てこてこ歩くやつ。

悪意あるネコバカット

今回はただテキストを順に表示するだけだけど、ここから少しずつ肉付けしていって、色んな処理を作っていける、色んなゲームのテンプレートになれるんですよ。
それはロジック次第なんだ。

世界の設計を、ただ俺の頭一つで構築する、という意味でそれは等しいはず。
…うん。


ちなみに実際のコードを見ると、ほとんど『ツクールのイベントコマンドを不自由にしただけ』になってます…。
それは自分の頭が悪いから…、自分のロジックが狭いんだから、仕方ないね…。

詳しい人はzipで実際のコードを確認するも良し。
http://kirara111.sakura.ne.jp/js_test/simple_text_2016_3_05.zip

今回はこれでおしまい。ゲーム作りのダイナミズムと熱を学んだら、もう失わないようにセーブして、次回を待とう。
(というかプログラムに四苦八苦しただけだった気もするが)


興味が出たら、
ドットインストール
ゼロから始める「ゲームの作り方」入門
とかで勉強してみよう。