ゲームにはとても重要なスコアを表示したいと思います。
敵を撃墜した得点を加算するスコアと
一番良かったときのスコアを残すハイスコアの表示を行います。
テキストツールを使って「SCORE」「HI-SCORE」ついでに「敵残機」のテキストを
作成します。
まず、テキストを表示するレイヤーを選択します。
スコア ゲームオーバー のレイヤーをクリックしましょう。
ツールの中からテキストツールをクリックします。
テキストが選択されていない状態でプロパティを開きます。
プロパティから静止テキストを選びます。
そして、サイズを 20 pt、カラーは白に設定します。
静止テキストはプログラム側から制御せず、ただ表示する時に使います。
「SCORE:」「HI-SCORE:」「敵残機:」を画面の上部に作ります。
座標は適当でかまいません。
次は、実際に得点を表示する部分を作ります。
プログラム側から得点を変更する訳ですから、こちらはダイナミックテキストを使います。
テキストツールを選び、他のテキストを選んでいない状態でプロパティを開きます。
そして、ダイナミックテキストに設定します。
段落の行揃えは、左揃えの設定にしておきます。
スコア、ハイスコア、敵残機のそれぞれにダイナミックテキストで表示するエリアを作ります。
作った所が分かり易いように、とりあえず0でも入れておきます。
上の画像では作ったエリアが見えるように、3つとも選択した状態です。
1つ1つエリアを作成している時に、このような見え方はしません。
プログラム側から値を変更できるように、インスタンス名を付けます。
1つずつ選択してプロパティから設定しましょう。
スコア「sc_txt」
ハイスコア「hi_txt」
敵残機「nokori_txt」
ちなみに、インスタンス名に「_txt」と付けていますが、これを付けなくてはいけない
ルールはありません。
プログラミングするとき、または、作成してからしばらくして見たとき
「これは何だろう?」
となる場合があると思います。
そんな時に「ああ、これはダイナミックテキストのインスタンス名だな」と
思い出し易いようにするためです。
このように名前を付けるときには、名前付けのルールを決めておくと
プログラミングのメンテナンス効率があがります。
これでスコアを表示するための材料は揃いました。
今の段階でスコアを表示するプログラミングをしても、もしかしたら表示されないかも
しれません。
次のようなメッセージを見たことありませんか?
これは
「ダイナミックテキストを使ったとき、フォントを埋め込まないと表示されないかも」
と忠告してくれているのです。
Flash 側では、実行ファイル(swfファイル)の中に、すべてのフォントを
持たないようにしています。
その理由は、すべてのフォントを持っていたらファイルサイズが巨大になるからです。
では、使用するフォントを必ず表示するにはどうするのか?
それにはフォントの埋め込みを行います。
これからフォントの埋め込み方を説明します。
スコア「sc_txt」のプロパティを開いて下さい。
そして、フォントファミリーの右下にある埋め込みボタンをクリックします。
次の画面が開きます。
文字の範囲の中の数字 [0..9] (11/11文字) にチェックを入れます。
OKをクリックすれば、これでフォントの埋め込みが完了します。
実行ファイルの中に数字が埋め込まれたことになります。
スコア、ハイスコア、敵残機、どれも同じフォントを指定していれば、この作業だけでOKです。
余談になりますが、数字って0から1,2,3~9まで、全10文字ですよね。
埋め込んだ数字は (11/11文字) となっています。
不思議なことに1文字多いです。
これはピリオド(.)小数点が含まれているからなんです。
確かにピリオドがなければ困りますよね。
実際に動いている所を確認してみましょう。
敵を撃墜したとき 10 点入るようになってます。
確認ポイントは
・撃墜したときスコアに 10 点加算されているか
・リトライしたとき、ハイスコアよりスコアが高ければハイスコアが更新されるか
の2点です。
次のようにプログラムを変更します。
const LINE_MAX = 6; // 宝と敵の段数 var enemyArr:Array = []; var gemArr:Array = []; var turn:Vector.<int> = new Vector.<int>(LINE_MAX,true); var state:Vector.<int> = new Vector.<int>(LINE_MAX,true); var delcnt:Vector.<int> = new Vector.<int>(LINE_MAX,true); var beamFlg:int = 0; var xSpeed:Number = 0; var retCnt:int = 0; var retryWait:int = 0; var score:int = 0; var hisc:int = 0; var nokori:int = 0; initFunc(); //---------------------------------------------------- // システム関連の初期化 function initFunc() { trace("initFunc ---"); for( var i=0; i < LINE_MAX; i++ ){ enemyArr[i] = new enemy(); // 敵の作成 enemyArr[i].stop(); gemArr[i] = new gem(); // 宝石の作成 disp.addChild(enemyArr[i]); // ステージに表示 disp.addChild(gemArr[i]); } hisc = 0; hi_txt.text = hisc.toString(); initStart(); initGame(); // 毎フレームイベントの登録 stage.addEventListener(Event.ENTER_FRAME, mainloop); // マウスイベント 左ボタン押下のイベント登録 stage.addEventListener(MouseEvent.MOUSE_DOWN, m_down); } //---------------------------------------------------- // 毎フレーム処理 function mainloop(event:Event):void { // マウスの座標を取得して自機を動かす player_mc.x += (player_mc.mouseX / 5); if( beamFlg == 0 ){ // 0:未発射 1:発射中 // 未発射なら自機と動きを同期させる beam_mc.x = player_mc.x; } else { // 発射中のとき弾を移動する beam_mc.y -= 10; if( beam_mc.y < -30 ){ // 画面外へ弾が出たとき beamFlg = 0; beam_mc.x = player_mc.x; beam_mc.y = player_mc.y - 25; } } moveEnemy(); // 敵の移動 if( retCnt == LINE_MAX ){ // 全ての宝石を奪われた gameover_txt.visible = true; // ゲームオーバーを表示 if( !retry_txt.visible ){ retryWait++; if( retryWait > 120 ){ retry_txt.visible = true; // リトライ表示 } } } } //---------------------------------------------------- // 敵の移動 function moveEnemy() { var ex:int; var ey:int; for( var i=0; i < LINE_MAX; i++ ){ // 爆発中 if( state[i] == 2 ){ delcnt[i]--; if( delcnt[i] == 0 ){ state[i] = 0; // 0:待機中 enemyArr[i].x = 530; enemyArr[i].gotoAndStop(1); } } // 出現中のみ以下の処理を行う if( !(state[i] == 1) ) continue; // 敵の移動処理 if( turn[i] == 0 ){ enemyArr[i].x -= xSpeed; // 宝石と接触したら引き返す if( (gemArr[i].x + 36) > enemyArr[i].x ){ turn[i] = 2; } // 左際まできたら右移動へ変更 if( enemyArr[i].x < 20 ){ turn[i] = 1; } } else { enemyArr[i].x += xSpeed; if( turn[i] == 2 ){ // 宝を連れて行く gemArr[i].x = enemyArr[i].x - 36; } // 画面外へ出たら待機中にする if( enemyArr[i].x > 580 ){ state[i] = 0; // 0:待機中 retCnt++; // 宝石を盗った回数 } } ex = enemyArr[i].x; ey = enemyArr[i].y; // 敵と弾との当たり判定の範囲を、見た目で調整する if( (beam_mc.x > ex-20) && (beam_mc.x < ex+20) && (beam_mc.y > ey-20) && (beam_mc.y < ey+20) ){ state[i] = 2; // 2:爆発中 delcnt[i] = 18; // 消滅までのカウント beamFlg = 0; // 0:未発射 1:発射中 enemyArr[i].play(); beam_mc.x = player_mc.x; beam_mc.y = player_mc.y - 25; score += 10; sc_txt.text = score.toString(); } } if( Math.random() < 0.015 ){ // 敵の出現率 // 出現位置 var rnd:int = Math.floor(Math.random()*LINE_MAX); for( i=0; i < LINE_MAX; i++ ){ var lno = (rnd + i) % LINE_MAX; if( !(state[lno] == 0) ) continue; if( gemArr[lno].x > 530 ) continue; state[lno] = 1; // 1:出現中 turn[lno] = 0; // 0:左移動 enemyArr[lno].x = 530; break; } } } //---------------------------------------------------- // ゲーム関連の初期化 function initGame() { trace("initGame ---"); gameover_txt.visible = false; // ゲームオーバーを非表示 retry_txt.visible = false; // リトライを非表示 beamFlg = 0; // 0:未発射 1:発射中 xSpeed = 2.0; // 敵の初期移動速度 retCnt = 0; // 宝石を盗った回数 retryWait = 0; // リトライ表示までの時間 sc_txt.text = score.toString(); player_mc.y = 360; // 自機のy座標(固定) beam_mc.x = player_mc.x; beam_mc.y = player_mc.y - 25; // 弾の表示(半分 自機と重ねる) for( var i=0; i < LINE_MAX; i++ ){ // 敵の初期設定 enemyArr[i].x = 530; enemyArr[i].y = (i*42) + 60; // 宝石の初期設定 gemArr[i].x = 40; gemArr[i].y = (i*42) + 60; turn[i] = 0; // 0:左移動 1:右移動 2:右(宝付き) state[i] = 0; // 0:待機中 1:出現中 2:爆発中 } } //---------------------------------------------------- // ゲーム開始前の初期化 function initStart() { score = 0; } //---------------------------------------------------- // マウス左ボタン押されたとき function m_down(event:MouseEvent):void { if( retry_txt.visible ){ // リトライが表示中の時 if( hisc < score ){ hisc = score; } hi_txt.text = hisc.toString(); initStart(); // ゲーム開始前の初期化 initGame(); // ゲーム関連の初期化 return; } if( beamFlg == 1 ) return; // 0:未発射 1:発射中 beamFlg = 1; // 自機の位置に弾を表示する beam_mc.x = player_mc.x; beam_mc.y = player_mc.y - 25; }
変更点を見ていきます。
12-14行目、スコア・ハイスコア・敵残機のための変数を宣言しています。
33行目、変数 hisc の内容をハイスコアとして表示しています。
ハイスコア hi_txt.text に代入することで、ステージ上の表示が変わるのです。
なお、hi_txt.text は文字列のみ代入できます。
よって、変数 hisc に .toString() を付けて文字列に変換する必要があります。
35行目、新しく関数 initStart() を作りました。
ゲームを開始するときの初期化をする関数です。
ゲーム開始前に行う初期化をここにまとめます。
174行目、スコア sc_txt.text に代入して、ステージ上の表示を変えています。
ここで不思議に思う人もいるかもしれませんね。
initStart() と initGame() の違いは何か・・・
このプログラムでは次のように分けています。
initStart() ... ゲームを初めてプレイ、または、リプレイ直後に呼ぶ
initGame() ... ゲームを始める直前に呼ぶ。ステージのあるゲームならステージ開始前に呼ぶ。
どんなプログラムでも初期化の関数は、割と重要な働きをします。
初期化の関数の作り方によって、プログラム全体の流れが変わってくるので
しっかりと考えて作りましょう。
138-139行目、スコアをカウントして、ステージに反映させています。
この処理は、敵と弾が当たった時に実行されます。
204-205行目、ハイスコアよりスコアが良いとき、ハイスコアを更新しています。
208行目、関数 initStart() を入れてゲーム開始前の初期化をしています。
先ほど説明したように、リプレイ直後には initStart() と initGame()
どちらも必要になります。
変更点は以上です。
今、見直してみると 33 行目と 207行目は削除して、initStart() の中に入れても
良かったなと思います。
敵残機の表示は、ステージ構成を作るときに対応します。
次[ ステージ構成にする その1 ]へ進む