ゲーム開発講座
Chapter2-1
-サウンドノベルを形だけでも作るだよの巻-
 
-はじめに- 
ゲーム開発講座の時間 
なんじゃねえの!? 
ケムニャだ。
Hey you! 
ポチだよ。 
今日は何するんだっけ?
アドベンチャーだ。 
ちょっと前に流行ったのでいうとEVEシリーズとかのジャンルだな。 
古いので言うとさんまの名探偵とかポートピア連続殺人事件だ。
全部わかんないよ。 
サウンドノベルとは違うの?
んー、基本的には同じだけどちょっと出来る事が多いんだ。 
サウンドノベルは選択肢をえらぶとそのまま進んでいくけどアドベンチャーは 
主人公の行動一つ一つを自分で選ぶことが出来るジャンルだ。 
逆転裁判とかもアドベンチャーだな。
へー。 
逆転裁判おもしろいよね
んじゃ、今回の素材だ。 
サンプルダウンロード
とりあえず作ってみた。 
ふっふっふ。 
ケムニャ、実はすでに私はゲームを一つ作ってきたのだ。 
お前は私に何かを教えようと思っているようだが 
アテが外れたなー! 
私は天才だ媚びろ媚びろぉー!
まじか! 
俺のいない間に・・・成長したな。 
俺、嬉しいよ!
サンプルにある「snple02_01.as」を起動させてくれ。 
まぁゲームといっても形を作っただけなんだけどな。
おお、やってみよう。
どお? 
ゲームじゃないけどちゃんとクリックして 
ストーリーを読んでる感じでしょ?
これは酷い。
ば、馬鹿な! 
完璧に作った力作なのに! 
ウボァーー!
いや、努力は認めるし見た感じも悪いとは言わない。 
こっちもまだ教えてなかった点とかもあるしな。
何がダメだったのよー?
まずは致命的な失敗をどうにかしようか。 
クリックを待つプログラム作ってるよな。 
ここに大きな失敗があるんだ。
な、なによー。
このプログラムの会話、実はもっと長かったんじゃないか? 
あるエラーが発生したため、こんな短さになった。 
違うかい?
なぜ・・・それを!?
16回クリックしたらエラーが出るだろ。 
これはrepeatの中にrepeatを繰り返した結果なんだ。 
repeatとloopの中で他の行に飛ぶプログラムを書いているよな。 
この描き方をするとループ文の中で他のループ文を、 
またその中で他のループ文を作るというプログラムになってしまうんだ。 
repeatは必ずloopを通り過ぎないとrepeatを完了していないものとみなされる。
repeatの中にrepeatを入れる事は出来るけどソレは16回が限度でさっきのプログラムだと
その限度を超してエラーが起きるんだ。
	;クリックを16回するとエラーが起きます
*start
	gosub *clik
	goto *start

*clik
	repeat
	stick stc,,1
	if stc=256:return	;gosubまで戻るけど、まだループの途中
	await 5
	loop
これ実行して16回クリックしたらエラーでただろ?
うぇー、どうすればいいのぉ?
そうだな、二つの方法がある。 
一つはrepeatを使わずgotoを使ってそのラベル中でループを作る。 
	;エラーは起きません
*start
	gosub *clik
	goto *start

*clik
	stick stc,,1
	if stc=256:return
	await 5
	goto clik
これはプログラムの描き方によってはちょっと面倒になるからもう一つの方法が良いと思う。 
それは 
break 
という命令で、この命令が実行されるとrepeatの回数が無限でも 
ループ回数に残りがあってもそのループを抜ける事が出来るんだ。 
この命令を使ってループを突破したら、そのループは解消されたことになるんだ。 
つまりこんな感じだ。 
	;エラーは起きません
*start
	gosub *clik
	goto *start

*clik
	repeat 
	stick stc,,1
	if stc=256:break	;クリックするとrepeatを抜ける
	await 5
	loop
	return			;gosubの所まで戻る
こんな感じでOK
こ、これで16回以上クリックできるんだね!
おうよ。 
何万回でもクリックしたれ。 
さて、他の改良点なんだが、背景とメッセージボックスを 
gosubでサブルーチンを作って何度も同じ長い文を書かないように 
作ってあるのは良い点だ。 
でもキャラクターの表示は毎回表示プログラム書いてるよな?
あ、それには理由があるんだよ。 
私だってちゃんと考えてるんだよ。 
このプログラム私の絵とちくワの絵の二種類の立ち絵が出てくるじゃない? 
でも二つの絵のサイズが違う。 
だからサブルーチンにするとサイズが違うから表示がおかしくなるんだ。
うん、そうだろうと思った。 
でもお前、大切な事わすれてるぞ。 
変数にその数値を入れておけばいいじゃないか。 
画像をロードした時、表示位置とサイズを変数に入れると 
サブルーチンで楽に表示する事が出来るだろう?
あ!そっか! 
じゃあそうしたら、背景とキャラ表示とメッセージボックス表示一個のサブルーチンに 
まとめられてスマートになる!
そうそう。 
出来るだけスマートに作ると、後で手直ししたりプログラムを読むときに便利だからな。 
あと、キャラクターを中心に表示したいようだけどちょっとズレてるよな。
うーん、どうも真ん中に絵をあわせるのが難しくて。
絵を真ん中に表示させる時は自力じゃなくて計算式でやるといいぞ。 
(画面横サイズ-中間に表示させたい画像の横サイズ)/2 
で出来る。 
Y座標の位置は 
画面の縦サイズ-表示する絵の縦サイズ 
でいい。
そうか、その手があったか! 
味な真似をしやがる!
あと、キャラクターのサイズって一々画像ソフトで開いて調べて入力してっての 
すんげー面倒くさいよな。 
でも安心してくれ、画像サイズを取得するシステム変数というのが有るんだ。
システム変数?
システム変数ってのは勝手に作られる変数で、そうだな。 
repeatつかってる時にあったcntって変数があるだろ? 
ループした回数が入ってる変数。 
そんな感じのんだ。 
自分で中身を入れるんじゃなくて、中身が用意されているのがシステム変数。 

現在指定されてる画面IDの横のサイズが格納されているシステム変数は 
winx 
縦のサイズが格納されてるシステム変数は 
winy 
指定先の画面IDが変わったら内容も変わるから変数を作ってそこに入れておいてくれ。

システム変数便利だなぁ。 
他にもあるの?
沢山あるからなぁ、まぁそのつど教える。 
あとメッセージボックス用に画像用意してるだろ、 
アレただのベタ塗りだったらbufferでサイズ指定して作った画面IDに 
boxfで色塗ってそれでコピーでいいんじゃないかな。 
buffer p1,p2,p3 
p2とp3に数値を入れることによって作る画面のサイズを決めれる。 
p2は横のサイズ、p3は縦のサイズ。 

あと、mesなんだけど、"を{でくくると改行が簡単になるぞ。 
	mes "おはよう"
	mes "こんちわ"
	mes "ばんわんこ"
	mes {"おはよう
	こんちわ
	ばんわんこ"}
	stop
 

なるほど、んじゃソレを踏まえてもう一度作ってみる! 
はい! 
snple02_02.as」実行してみて。
おお、いい感じだ。 
そう、ファイル名以外に特定のワードを入れたとき 
画像を表示しないという方法はスマートだ。 
ちゃんとノベルにもなってる・・・って、 
いい年した女の子がちんこちんこ書くなよ。 
興奮しちゃうじゃないか。
いかん、ここにも変態が!
選択肢を作ってみよう。 
ところでケムニャ。 
選択肢を作りたいんだけどさ、どうも今の知識じゃ 
不細工な作りになっちゃうんだよね。
と、言うと?
選択するのに〜をするなら→ボタン、〜をするなら↑ボタンを押してください、とか。 
選択肢の時だけボタンが表示されるようになるとか。 
そんな感じになっちゃってスマートじゃないんだ。 
よくあるゲームみたいにボタンじゃない文字をクリックして選択したいよ。
なるほど。 
それはマウスの位置を取得するシステム変数が必要になってくるんだ。 
マウスの位置のX座標が格納されているシステム変数は 
mousex 
Y座標が格納されているシステム変数は 
mousey 
コレを使うと特定の位置をクリックした時に反応するプログラムが組めるぞ。 
あと、格納されるマウスの座標はパソコンの画面全体から見た位置じゃなくて 
動かしているプログラムの画面での位置だから難しく考えずに使えるはずだ。
でもマウスの位置がわかっても、特定の位置をクリックした時に 
反応させる方法がよくわからないなぁ。
if文で四角い形の範囲を調べるんだ。 
そうだな、図であらわすとこうだ。 
 
こんな感じの画面で、赤い枠の中をクリックした時にプログラムが反応するように 
したいとするよな? 
その場合、マウスのX座標は49より大きくて、205より小さくないといけない。 
そしてマウスのY座標は65より大きくて、154より小さくないとダメだ。 
つまりこういう条件式になる 
if (mousex>49)&(mousex<205)&(mousey>65)&(mousey<154) 
これでマウスが枠内に入ったとき条件がOKになる。 
簡単なサンプルを用意してみようか。 
		;枠内でクリックすると色が変わる
	repeat
		stick stc,256
		redraw 0
		color 200,0,0:boxf 49,65,205,154
		color 0,200,0
		if (mousex>49)&(mousex<205)&(mousey>65)&(mousey<154)&(stc=256):boxf 49,65,205,154
		redraw 1
		wait 1
	loop
 
本当だ! 
さっきの式にstickで指定した変数の変化も加えて 
マウスが指定座標内+クリックされている 
という条件式が満たされた時実行されるように作ればいいんだ。
そう。 
サウンドノベルの選択風にするとこうなるな。 
			;文字をクリックする。
	sdim sen,16,2
	sen="うどん","ファミコン"
	repeat
		stick stc
		redraw 0
		color 200,200,200
		pos 0,0:mes sen.0	;灰色で文字を書く
		pos 0,16:mes sen.1
		color 0,0,0
		pos 0,0			;文字の上にマウスがあれば黒字で上書きする
		if (mousex<70)&(mousey>0)&(mousey<16):check=0:mes sen.0:if stc=256:break
		pos 0,16
		if (mousex<70)&(mousey>16)&(mousey<32):check=1:mes sen.1:if stc=256:break
		redraw 1
		wait 1
	loop
	pos 0,32:color 0,0,0
	mes "あなたが選んだのは"+sen.check+"です"
	redraw 1
	stop
マウスの位置によって変数checkの中身を変え、 
クリックするとrepeatを抜けて、抜けた先で変数checkの中身で 
何をクリックしたのかを判断するという形にすると作りやすい。
これを応用すればゲームでの選択肢を作る事が出来るね!
さて今日はここまで。
次回予告 
なるほど。 
ゲームのツールを作る・・・。 
サブルーチンを上手く使えば簡単にゲームが作れる。 
こういう事だったんだね!
・・・いや、違うぜ。
な、なんだってー!?
もっと簡単に作れるしあまりプログラムソース内に文章をだらだら入れるのは良くない。 
文章を書きにくいし、osによっては32KBくらい書くとエディタの限界でプログラムを書けなくなる。
そうなんだ。 
あれ、じゃあプログラムって32KB以内で作らないとダメってこと?
いや、エディタの読み込める文字数に限界があるだけで 
プログラム自体はいくらでも大きくてもいいから大きくなりすぎる時は他のメモ帳とか 
何個かのソースを結合させるといい。
色々大変だね。
だからプログラムはスマートにしたいんだ。 
そのほうが修正したりする時自分でも読みやすいからな。 
それで次回は外部ファイルを読み込んでそれを解析して出力する 
エンジンを作るんだ。
む、むずかしそーーー!
いや、楽勝楽勝。 
難しい事をする訳じゃないい。 
ちんこちんこ言ってるようなアホの子でも出来るって。
私みたいな淑女でも作れるのね。 
楽しみーですわー。
うん、そうだね、また次回だね。
今日はここまで。
 
 
今回のまとめ 
break 
repeat文から抜ける。
repeatは必ずリピート回数をこなしloopを通りぬけなければリピート完了したとみなされない。
gotoなどで無理やりに抜け、何度も同じrepeatを抜ける事を繰り返すと16回目でエラーを起こす。
breakはloopまでとび、リピート回数が残っていたり∞に設定されていても通り抜けリピートを完了させる事が出来る。
	mes "左クリックするとリピートを抜けます"
	repeat
		stick stc
		if stc=256:break
		wait 1
	loop
	mes "リピートを抜けちゃいました"
	stop
 
winx
winy
現在指定している画面IDのサイズが入っているシステム変数。
システム変数は直接中身を変更することは出来ない。
	picload "02_poti_01.bmp"
	color 255,255,255
	mes "この画像の解像度は"
	mes "X:"+winx+"  Y:"+winy
	stop
 
mousex
mousey
現在のマウスの位置が入っているシステム変数。
中身はwait又はawaitを通過したとき更新される。

クリックに反応するボタンを作りたい時は、
if (mousex>=ボタンの左端)&(mousex<=ボタンの右端)&(mousey>=ボタンの上側)&(mousey<=ボタンの下側)
とすると良い。

	repeat
		stick stc,256				;右クリックを押し続けれるように設定
		redraw 0
		color 255,255,255:boxf 0,0,640,480			;画面を白紙に更新
		color 0,0,0:pos 0,0:mes "X:"+mousex+"  Y:"+mousey	;マウスの座標表示
		color 200,0,0:boxf 100,100,200,200			;ボタン表示
		color 0,200,0						;ボタンを押すと反応
		if (mousex>=100)&(mousex<=200)&(mousey>=100)&(mousey<=200)&(stc=256):boxf 100,100,200,200
		redraw 1
		wait 1
	loop
 
もどる