次のページ 前のページ 目次へ

15. ハイスコア登録処理

前章までで時間計測とダイアログまで作りましたので、 お次はゲームクリア後のハイスコア登録処理など作ってみましょう。 構成の仕方は幾通りもありますが、 ここでは名前を登録する画面と、 現在のハイスコア一覧の2つの画面を作ることにします。 力量があれば表示の仕方などいくらでも凝ることができますが、 サンプルということと筆者の都合から、 あっさりとダイアログでいきたいと思います。

15.1 記録する情報とその表現方法

ハイスコア(=クリア時間)を記録するとなると、 何の情報を保存しておくのか、 どのファイルにどのような形で記録するのか、 メモリ上ではどう表現するかなど決めねばなりません。 情報としては、クリア時間、記録者の名前、記録を出した日付、 記録を出した時刻 の4つあれば十分でしょうから、 以下のような構造体で良いでしょう。
	#define	HISCORE_FILENAME  "WST3HSCO.ZDT"
	#define	HISCORE_MAX       7

	/* ハイスコア情報構造体 */
	typedef struct {
		char	score[5+1];
		char	clrdate[10+1];
		char	clrtime[5+1];
		char	name[20+1];
	} SCORE_INFO;

	typedef struct {
		int         count;             /* 実際に構造体に登録されてる数 */
		SCORE_INFO  info[HISCORE_MAX]; /* 最大 HISCORE_MAX 件登録可能  */
	} HISCORE_INFO;

	HISCORE_INFO  hscore;  /* ハイスコア情報構造体 */
後は、この情報をゲーム終了後も保持するために ファイルに書き出しておく必要があります。 単純な方法は上記の構造体をそのまま保存することですが、 プログラム内部形式とファイル形式を一緒にするのはお勧めできません。 そのマシン・そのソフトだけで利用するものならどうにかなりますが、 バージョン違いやコンパイル時のパディングの違いなどで 微妙に変わる可能性があるからです。 そこで本ソフトでは WST3HSCO.ZDT というファイルを作成し、 カンマ区切りのテキストファイルとして保存することにしました。
	#四川省ハイスコアファイル
	#登録件数=2
	10:28,2000/06/11,22:40,登録花子
	16:31,2000/05/28,13:59,登録太郎
これなら、例え内部構造体の形式が変わってもプログラムの方で対応できますし、 PCに持っていってもそのまま読めるファイルですので汎用性があります。 繰り返しますが、プログラム内部で用いる形式はバイナリであっても何であっても構いません。 しかし外部と入出力するものは、どんな機種でも使える汎用性の高いデータにすべきです。 ワープロや表計算なども、 専用の独自フォーマットではなくどんな機種でも読めるデータの方が 何倍も利用価値が高まるというものなのですから。

15.2 ファイルからの読込&保存処理

基本的なファイル操作は前章で行いましたので、 ここでは内部構造体形式からカンマ区切りテキストへの変換出力と、 逆にファイルから構造体へ読み込む処理を作ってみます。

【保存 : write_hi_score() 】

保存はとても簡単で、上の定義で言うと HISCORE_FILENAME というファイルを開いて、 hscore->count 件だけループして hscore->info[] の内容を書き出すだけです。 カンマ区切りの文字列作成には sprintf() を使えば良いでしょう。

注意点は、ハイスコアファイルを moreソフトのある場所(本体 or カード)に作るようにしている点です。 これは、GetAplVolName() を使ってボリューム名を知り、 sprintf() で完全なファイル名を作成することで行っています。

【読込 : read_hi_score() 】

moreソフトがある側のHISCORE_FILENAMEファイルを開くのは先と同じです。 後は、次の手順で項目を切り分けつつデータを読み込み、 クリアタイムの短い順になるようソートしながら格納します。
  1. 1行読み込む
  2. カンマで区切って構造体の各メンバに値をコピーする
  3. hscore の適当な位置に今のデータを挿入する
カンマで区切って読み込むのにget_camma_str()、 読み込んだデータの挿入位置を求めるのにsearch_pofscore()、 実際の挿入処理を行うのにinsert_hi_score() という具合にサブルーチン分けしてみました。

[保存・読込処理のソース]

15.3 ハイスコア登録画面

サーチ機能を使わずにゲームクリアした場合、 それがベスト7に入るのならばこの画面で名前を入力・登録させます。

サーチを使ったか否かは、g_ewk->HF フラグで判断します。 これは、ゲーム開始時にクリアされ、サーチを使った際にセットされるように組んでおけば 今回のクリア時間がベスト7に入るかは保存・読込処理にある search_pof_score() を呼ぶことでわかります。

どちらの条件も満たすのであれば HiScore画面 を表示しましょう。 HiScore画面には、クリア時間やメッセージ等を表示するオブジェクトと、 名前を入力するためのテキストエディタが配置されています。

【ハイスコア登録画面】

HiScore画面(ハイスコア登録画面)

テキストエディタはただ配置しただけでは文字入力はできません。 入力パッドを配置しただけでもだめで、 入力パッドのイベント関数に、 どこかのテキストエディタに文字列を渡す処理を書かないといけないのです。 従って、文字入力をするためには、 テキストエディタ入力パッドの配置、 入力パッドのイベント関数の作成が必須となるわけです。

特に、テキストエディタが複数ある場合には、 現在注目しているのがどれかをプログラムで覚えておき、 それに従って入力を振り分ける事や、 注目エディタ以外はカーソル表示を停止する処理などを自前で組まねばならず、 なかなかに面倒な物となっています。

今回は複数エディタは扱いませんので、 SZABのフォームエディタの雛形から、 入力パッドとテキストエディタのある物を選んでそれを元に作りましたが、 機会があれば複数エディタの扱いも説明したいものです。

【部品の並び順】

HiScore画面の部品並び順

それから微妙な話ですが、 入力パッドは SZAB の部品一覧で上の方にないとうまく動作しない事があるので注意してください。 これはイベントの流れる順番が絡んでいます。 ザウルスでは、 一度確定した文字列をなぞって変換キーを押すことで再変換できますが、 エディタと入力パッドの位置関係が逆になると なぞって変換 ができなくなります。 コミュニケーションパルでは一部の文字が入力できなくなるという事例もありますので、 ちょっと注意してください。

【FormSetUp(), FormEnd() 時の処理】

void HiScoreFormSetUp(APLFORMPTR AplForm, MESSAGE* Message)
{
  MESSAGE  msg;
  int      no;
  char     wkstr[20];

    /* クリアタイム等を画面に表示 */
  SetCtrlProperty( HiScoreLbl2, STR_PID, pValue,
      "ゲームクリア \(^-^)/ TIME = [", AplForm->Control );
  SetCtrlProperty( HiScoreTimeStr, STR_PID, pValue,
      g_ewk->scinfo.score, AplForm->Control );

    /* 何位になるかも表示する事にした */
  no = search_pofscore(&g_ewk->scinfo);
  sprintf( wkstr, "第 %d 位", no + 1 );
  SetCtrlProperty( HiScoreLbl3, STR_PID, pValue, wkstr,
      AplForm->Control );

  /* 入力パッドのオープン処理 */
  msg.CommonMsg.MessageID = ToolOpenID;
  ControlCall( HiScoreKEYPAD00,AplForm->Control,&msg );
}
void HiScoreFormEnd(APLFORMPTR AplForm, MESSAGE* Message)
{
  MESSAGE		msg;
  char		*wkptr;


  /* 入力パッドを閉じる前にウィンドウの再表示を止める */
  EntryRedispFunc( AplForm->FormWnHandle,0,NULL,NULL );

  /* 入力パッドのクローズ処理 */
  msg.CommonMsg.MessageID = ToolCloseID;
  ControlCall( HiScoreKEYPAD00,AplForm->Control,&msg );

    /* エディタから名前の文字列を得る */
  GetCtrlProperty( HiScoreTEXTEDIT00, EDIT_BUF_TOP_PID,
      pValue, wkptr, AplForm->Control, PTR );
  strcpy( g_ewk->scinfo.name, wkptr );

  /* ソートしつつハイスコア情報構造体へ挿入 */
  insert_hi_score( &g_ewk->scinfo );

    /* ファイルへの書き込み */
  write_hi_score( HISCORE_FILENAME );
}
FormSetUp() で文字列オブジェクトの設定と入力パッドのオープンを行います。

そして、この画面を終了する際に必ず 開いていた入力パッドを閉じている ことに注意してください。 そして、登録ボタンを押そうと押すまいと、今テキストエディタに入っている 文字列を名前としてハイスコアファイルに登録している事に注意してください。

これは、仮にハイスコア登録画面が出たあと、オートパワーオフで切れた時にも 今のクリア時刻と記録日時が保存されるようにしたかったからです。 この為、登録ボタンは実際には登録処理を行っておらず、 AplForm->IsExit = true; でダイアログの終了を指示しているだけです。

ところで、ゲームクリアの文字列も FormSetUp() で設定していることに気づきましたか? これは、フォームエディタでは半角スペースを含む文字列を設定できないため、 敢えてプログラム中で設定し直しているわけです。 これに気づかないと、ビルドが正常終了しない・・・と悩む事になります。

15.4 ハイスコア画面

【ハイスコア画面】

HiScView画面(ハイスコア画面)

ハイスコアの一覧表示用に HiScView という画面を作りました。 飾りのタイトル文字はイメージで、 罫線や順位などは固定文字列で作成し、 クリア時間・記録者名・記録日時 を書き換え可能な文字列オブジェクトとして配置したものです。

情報の描画は、 この画面の FormSetUp() メソッド内で ハイスコア情報構造体 hscore の内容に従って、 各オブジェクトの文字列を変更することで行っています。 こうすることで画面デザインはフォームエディタで自由に行える上、 プログラム中の手間もさほど無くなるというメリットがうまれます。

もっとも、これだけでは画面の特殊効果などはできませんので、 より柔軟に扱いたければ、直接画面に描画した方がいいでしょう。 オフスクリーン等も組み合わせれば、 文字をスライドさせつつ描画するなど映画のような効果も可能です。
/*
	ハイスコア画面にデータを表示する処理
*/
void	HSV_SetData( APLFORMPTR AplForm )
{
  static USHORT	namearea[HISCORE_MAX] = {
    HSVName1, HSVName2, HSVName3, HSVName4, HSVName5, HSVName6, HSVName7
  };
  static USHORT	timearea[HISCORE_MAX] = {
    HSVTime1, HSVTime2, HSVTime3, HSVTime4, HSVTime5, HSVTime6, HSVTime7
  };
  int		i;
  char	*nameptr;
  char	wkbuf[32];

  for( i = 0; i < HISCORE_MAX; i++ ) {
    if ( i < hscore.count ) {
      nameptr = hscore.info[i].name;
      sprintf( wkbuf, "%s  %s %s", hscore.info[i].score,
        &hscore.info[i].clrdate[2], hscore.info[i].clrtime );
    }else{
      nameptr = "";
      wkbuf[0] = '\0';
    }

    SetCtrlProperty( namearea[i], STR_PID, pValue, nameptr, AplForm->Control );
    SetCtrlProperty( timearea[i], STR_PID, pValue, wkbuf, AplForm->Control );
  }
}
この画面は、ハイスコア登録処理が終わった後に表示する他、 ゲーム画面中のハイスコアボタンが押された時にも使える事がお判りになるかと思います。 これでようやくハイスコアボタンが活きるというものですね :-) 。


次のページ 前のページ 目次へ