Home -> HSP講座 -> 初級編 No.8

実践の時

ついにこの日が来ましたか。初のソフト開発です!
では、その仕様を考えていきましょう。開発は、仕様を考えることから始まります。


仕様を考える

今回作るのは、なんと、なんと……数当てゲームです。(@o@!)
初級講座らしいものですね。
ちなみに、僕の処女作(初めて作る作品のこと)とほぼ同じものを作ります。

数を当てるんですから、なにか「ランダムな数(乱数)」が必要です。
レイアウトの時の講座を思い出してください。
その時説明無く紹介した、rnd関数というものを使えば、簡単に問題が作れます。(実はこの為の伏線だったり)
それともう一つ、ランダムな数を得るには、1 〜 いくつまでにするかを決めなければなりません。
大きすぎず、小さすぎない範囲で、今回は 100 とします。

次に、答える方法です。プレイヤーが何も出来ないというのは、もはやゲームじゃないので、なにか必要です。
今回は単に数値を聞くだけなので、input 命令を使用しましょう。
input から数値を受け取る方法は、前の講座でノータッチだったサンプルを見てください。

最後にもう一つ、間違っていたときのヒントの出し方です。
こういう簡素なゲームは、ソフトとプレイヤーのクロストークが必要なのです (ということにしておきましょうよ?)
という事で:

の5つにします。


step1:作業場を作る

開発をするには作業場が必要です。
最初に「作れ!」って言ったフォルダの中に、「数当てゲーム」なり、「NumberHitGame」なり、フォルダを作ってください。
そこが、この開発の作業場になります!

ちなみに、ファイルやフォルダに日本語を使うのは、あまり良いことではありません。
また、半角スペースなどは厳禁です。気をつけましょう。


step2:処理の流れを考える

開発の前に、大まかな処理の流れを考えてみます。ざっとで良いですけどね。
僕は、こう考えました。

  1. 定義
  2. 変数を用意する
  3. スクリーンを構築する
  4. 問題を作る
  5. 回答ボタンのジャンプ先 (判定)
  6. 終了する
運良く目次に出来ました。ラッキー! ('ー')ニィ
では、順に作成していきます。


step3:定義

簡潔すぎるタイトルですね……。
それはいいとして、「定義」では、主に #const などを書いておきます。
「プリプロセッサ命令」という、# から始まる命令は、必ずプログラムの先頭に書きます。

// packopt は後々……
#packopt name "数当てゲーム"
#packopt hide 1

// 定数(= const)を宣言
#const IDW_Main		0	// メイン画面のウィンドウID
#const MAX_ANSWER	100	// 答えの最大
#const ANS_LIMIT	6	// 回答できる限界

step4:変数を用意する

HSPでは本来必要のない処理ですが、僕は必ず書くようにしています。
それには、もちろん理由があります。
これを書いておくと、変数がどんな役割をしているのかが、すぐに調べられます。いわば変数表ですね。
では、今回使う変数を用意。

// 変数を用意
*SetVariable
	dim question		// 問題
	dim answer		// プレイヤーの回答
	dim nAnsCount		// 回答した回数
	
	dim ID_Edit		// input のオブジェクトID	

step5:スクリーンを構築する

次に、画面を準備します。
いつものは大きすぎるので、ちっちゃめにしましょう。
ボタンや入力ボックスなんかもここで設置します。

// スクリーンを構築する
*CreateMainWindow
	
	screen IDW_Main, 480, 320, 0		// メイン画面
	title "数当てゲーム ver.1.0"		// タイトルバーには、ゲーム名を表示させる
	
	objsize 80, 25				// ボタンの大きさを設定
	pos  20,  50 : mes "1 〜 "+ MAX_ANSWER +"までの私を当ててみよ!"
	pos  30,  80 : input answer, 120, 24	// 回答
	pos 160,  80 : button "答える", *GoAnswer	// 答え合わせ
	
	pos  50, 140		// カレントポジションを移動

step6:問題を作る

問題を事前に作らないといけないので、この辺りでします。
問題を作ると言っても、ただ単に「乱数」を発生させるだけで、あまり小難しい話じゃないです。

この前も使った、なかなか便利な rnd関数 なのですが、これは、「0 〜 (p1 - 1)」という、いわゆる0ベースの数値を返してきます。
※0ベース……0 を基準とする数値のこと。
これを「1 〜 p1」にするために、返ってきた値(返り値)を + 1 します。

// 問題を作る
*CreateQuestion
	// 0〜MAX_ANSWER-1 なので、+1 して 1〜MAX_ANSWER にする
	question = rnd(MAX_ANSWER) + 1
	
// 停止
*main
	stop

step7:回答ボタンのジャンプ先 (判定)

step5 までで、前処理は終了です。
ここでは、「答える」ボタンが押された時にする処理を書きます。

入力された数値を答えと比較して、同じなら正解、違ったら別のメッセージを表示します。

// 判定処理 ( button で飛んでくる )
*GoAnswer
	// (注意) 判定する順番は大事です。
	
	nAnsCount ++		// 答えた回数を数える
	
	if ( answer == question ) {
		// 正解
		goto *Clear	// 正解したときのラベルに飛ぶ
		
	} else : if ( (1 <= answer && answer <= MAX_ANSWER) == 0 ) {
		mes "1 〜 "+ MAX_ANSWER +" で選んでね。"
		
	} else : if ( answer * 2 < question ) {	// 問題は、回答の二倍以上
		mes "小さすぎない?"
		
	} else : if ( answer / 2 > question ) {	// 問題は、回答の半分以下
		mes "大きすぎない?"
		
	} else : if ( answer < question ) {		// 問題は、回答より大きい
		mes "もっと大きいよ"
		
	} else : if ( answer > question ) {		// 問題は、回答より小さい
		mes "もっと小さいよ"
	}
	
	// ここに来るということは、正解じゃない
	if ( nAnsCount >= ANS_LIMIT ) {	// 限界まで答えていたら
		goto *TimeUp			// 時間切れのラベル
	}
	stop

step8:終了する

ゲームが終わったときの処理を書きます。
正解したときも、失敗し続けて時間切れとなったときも、一度ここにジャンプしてきます。

ここでゲームを終わらせても良いのですが、今回は、もう一度ゲームを新たに始めるようにします。

// 正解した
*Clear
	color 0, 0, 255
	font msgothic, 50, 1		// "MS ゴシック" の代わり
	mes "正解!お見事!!"
	
	dialog "正解です!\nあなたは "+ nAnsCount +"回で正解しました", 0, "おめでとう"
	
	// 画面をリセット
	redraw 2
	color 255, 255, 255 : boxf : color
	sysfont 0		// 最初のフォント
	pos  20,  50 : mes "1 〜 "+ MAX_ANSWER +"までの私を当ててみよ!"	// もう一度書く(消されたから)
	pos  50, 140		// カレントポジションを移動
	redraw 1
	
	// 問題変更
	nAnsCount = 0
	goto *CreateQuestion
	
	stop
	
// 時間切れ
*TimeUp
	color 255, 0, 0
	font msgothic, 60, 1
	mes "タイムアップ!!"
	
	dialog "時間切れです。答えは "+ question +"でした。", 0, "残念"
	
	// 画面をリセット
	redraw 2
	color 255, 255, 255 : boxf : color
	sysfont 0		// 最初のフォント
	pos  20,  50 : mes "1 〜 "+ MAX_ANSWER +"までの私を当ててみよ!"	// もう一度書く(消されたから)
	pos  50, 140		// カレントポジションを移動
	redraw 1
	
	// 問題変更
	nAnsCount = 0
	goto *CreateQuestion
	
	stop

さぁ、これで完成です!!
動くかどうか、試してみましょう!

……おやおや……。何度実行しても答えが同じ……。
ハッ!
randomize が無いいいいいいいいぃぃぃぃぃぃぃ……。

じゃ、僕のわざとらしいミスを修正した完全版を公開して、今回は終了です。
わかんないところとかがあったら、過疎ってる某掲示板 に、遠慮無く書き込んでください。

それでは、また次回。

数当てゲームのスクリーンショット


やったーーー!!


ありゃりゃ (o-o?)

// 数当てゲーム

#packopt name "数当てゲーム"
#packopt hide 1

// 定数(= const)を宣言
#const IDW_Main	0	// メイン画面のウィンドウID
#const MAX_ANSWER	100	// 答えの最大
#const ANS_LIMIT	6	// 回答できる限界

*initialize
	randomize		// 一回だけ使えばいい
	
// 変数を用意
*SetVariable
	dim question		// 問題の答え
	dim answer		// プレイヤーの回答
	dim nAnsCount		// 回答した回数
	
	dim ID_Edit		// input のオブジェクトID	
	
// スクリーンを構築する
*CreateMainWindow
	
	screen IDW_Main, 480, 320, 0		// メイン画面
	title "数当てゲーム ver.1.0"		// タイトルバーには、ゲーム名を表示させる
	
	objsize 80, 25					// ボタンの大きさを設定
	pos  20,  50 : mes "1 〜 "+ MAX_ANSWER +"までの私を当ててみよ!"
	pos  30,  80 : input answer, 120, 24		// 回答
	pos 160,  80 : button "答える", *GoAnswer		// 答え合わせ
	
	pos  50, 140		// カレントポジションを移動
	
// 問題を作る
*CreateQuestion
	// 0〜MAX_ANSWER-1 なので、+1 して 1〜MAX_ANSWER にする
	question = rnd(MAX_ANSWER) + 1
	
// 停止
*main
	stop
	
// 判定処理 ( button で飛んでくる )
*GoAnswer
	// (注意) 判定する順番は大事です。
	
	nAnsCount ++		// 答えた回数を数える
	
	if ( answer == question ) {
		// 正解
		goto *Clear	// 正解したときのラベルに飛ぶ
		
	} else : if ( (1 <= answer && answer <= MAX_ANSWER) == 0 ) {
		mes "1 〜 "+ MAX_ANSWER +" で選んでね。"
		
	} else : if ( answer * 2 < question ) {	// 問題は、回答の二倍以上
		mes "小さすぎない?"
		
	} else : if ( answer / 2 > question ) {	// 問題は、回答の半分以下
		mes "大きすぎない?"
		
	} else : if ( answer < question ) {		// 問題は、回答より大きい
		mes "もっと大きいよ"
		
	} else : if ( answer > question ) {		// 問題は、回答より小さい
		mes "もっと小さいよ"
	}
	
	// ここに来るということは、正解じゃない
	if ( nAnsCount >= ANS_LIMIT ) {	// 限界まで答えていたら
		goto *TimeUp			// 時間切れのラベル
	}
	stop
	
// 正解した
*Clear
	color 0, 0, 255
	font msgothic, 50, 1
	mes "正解!お見事!!"
	
	dialog "正解です!\nあなたは "+ nAnsCount +"回で正解しました", 0, "おめでとう"
	
	// 画面をリセット
	redraw 2
	color 255, 255, 255 : boxf : color
	sysfont 0		// 最初のフォント
	pos  20,  50 : mes "1 〜 "+ MAX_ANSWER +"までの私を当ててみよ!"	// もう一度書く(消されたから)
	pos  50, 140		// カレントポジションを移動
	redraw 1
	
	// 問題変更
	nAnsCount = 0
	goto *CreateQuestion
	
	stop
	
// 時間切れ
*TimeUp
	color 255, 0, 0
	font msgothic, 60, 1
	mes "タイムアップ!!"
	
	dialog "時間切れです。答えは "+ question +"でした。", 0, "残念"
	
	// 画面をリセット
	redraw 2
	color 255, 255, 255 : boxf : color
	sysfont 0		// 最初のフォント
	pos  20,  50 : mes "1 〜 "+ MAX_ANSWER +"までの私を当ててみよ!"	// もう一度書く(消されたから)
	pos  50, 140		// カレントポジションを移動
	redraw 1
	
	// 問題変更
	nAnsCount = 0
	goto *CreateQuestion
	
	stop

追伸:このスクリプトを完璧に理解する必要はありません。今はまだ、「だいたい」の感じが分かったらそれでいいのです。


by 上大

第七章へ   第九章へ