CoRでゲームをつくってみよう / 第06回 ゲームとして必要な機能を追加する
投稿者: aoihikawa
投稿日:2022/08/15 22:33
CoRでゲームをつくってみよう
第06回 ゲームとして必要な機能を追加する
こんにちは。
フリーデザイナープログラマー(自称)の
簸川 葵(ひかわ あおい)と申します。

第05回 では、弾の表示と当たり判定
音楽や効果音の再生方法までスクリプトを実装しました。
第06回はスコアや残機など文字を表示する方法、
タイトル画面やゲームクリアの作り方など
ゲームとして必要な機能を実装する方法についてやっていきますね。
06-01 文字を表示しよう
ゲームには画像の表示だけでなく
文字の表示も大事な要素となっています。
まずは、文字オブジェクトを生成して
スコアや残機を表示させるところまでつくってみましょう。

新CoRでは、文字オブジェクトも
画像オブジェクトのように、素材を定義して使用します。
定義の項目は異なりますが、それ以降の内容は
画像オブジェクトのスクリプトの書き方と似ているので
arrpと比較して、扱いやすくなっています。
それでは、文字の定義から。
スクリプトの最後、画像素材の定義より後に
文字の定義を行います。
プレイヤーキャラクターには
待機状態のアニメーションが存在しなかったため、
こちらの定義も追加しておきます。
#_/_/_/_/_/_/ 素材の定義 _/_/_/_/_/_/ #----- 画像の定義 ----- #メイン背景 sprite 'spr_bg_00' do image 'img_bg_00' origin :left_top end #プレイヤーキャラクター sprite 'spr_char' do image 'img_char' origin :left_top #---------- ここから ---------- animation 'wait', [3], 60, true #---------- ここまで ---------- animation 'neutral', [0, 3], 10, true animation 'left', [1, 4], 10, true animation 'right', [2, 5], 10, true end #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #----- 文字の定義 ----- text 'spr_txt_info' do origin :left_top font_size 18 color '#FFFFFF' end #---------- ここまで ----------
文字の場合、定義の命令がspriteからtextに変更されます。
originは画像のときと同様に
画面上に表示するときの基準点を決めています。
font_sizeは表示する文字のフォントサイズ。
colorは表示する文字の色をカラーコードで指定しています。
カラーコードについては
WEB色見本などの情報を参考にすると分かりやすいです。
文字オブジェクトで表示する値の
ローカル変数を定義します。
scene 'start' do #_/_/_/ ローカル変数の定義 _/_/_/ #キー入力用のフラグ key_flg_up_st = nil; key_flg_up_do = nil; key_flg_up_en = nil key_flg_down_st = nil; key_flg_down_do = nil; key_flg_down_en = nil key_flg_left_st = nil; key_flg_left_do = nil; key_flg_left_en = nil key_flg_right_st = nil; key_flg_right_do = nil; key_flg_right_en = nil key_flg_z_st = nil; key_flg_z_do = nil; key_flg_z_en = nil #---------- ここから ---------- #システム関連 score = nil; score_view = nil enemy_score = nil char_zan = nil; char_zan_view = nil enemy_zan = nil; enemy_zan_view = nil #---------- ここまで ----------
score、score_viewは現在のスコア表示。
enemy_scoreは敵キャラクターを倒したときに獲得するスコア値。
char_zan、char_zan_viewは残機表示。
enemy_zan、enemy_zan_viewは残り敵キャラクター出現数表示に使用します。
文字オブジェクトを格納するローカル変数を定義します。
scene 'start' do #_/_/_/ ローカル変数の定義 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ obj_enemy_next = nil obj_enemy_next_rnd = nil obj_enemy_next_time = nil #---------- ここから ---------- #文字オブジェクト obj_minienemy_spr = nil obj_txt_enemyzan_spr = nil; obj_txt_enemyzan_no_spr = nil obj_txt_score_spr = nil; obj_txt_score_no_spr = nil obj_minichar_spr = nil obj_txt_charzan_spr = nil; obj_txt_charzan_no_spr = nil #---------- ここまで ---------- #音楽オブジェクト obj_bgm_main = nil #効果音オブジェクト obj_se_hit00 = nil
obj_minienemy_sprは縮小した敵キャラクター画像
obj_txt_enemyzan_spr、obj_txt_enemyzan_no_sprは
残り敵キャラクター出現数表示。
obj_txt_score_spr、obj_txt_score_no_sprはスコア表示。
obj_minichar_sprは縮小したプレイヤーキャラクター表示
obj_txt_enemyzan_spr、obj_txt_enemyzan_no_sprは
残機数表示に使用します。
文字オブジェクトで表示する値の
ローカル変数を初期化します。
create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #キー入力用のフラグ key_flg_up_st = false; key_flg_up_do = false; key_flg_up_en = false key_flg_down_st = false; key_flg_down_do = false; key_flg_down_en = false key_flg_left_st = false; key_flg_left_do = false; key_flg_left_en = false key_flg_right_st = false; key_flg_right_do = false; key_flg_right_en = false key_flg_z_st = false; key_flg_z_do = false; key_flg_z_en = false #---------- ここから ---------- #システム関連 score = 0; score_view = score enemy_score = 500 char_zan = 5; char_zan_view = char_zan enemy_zan = 20; enemy_zan_view = enemy_zan #---------- ここまで ----------
文字オブジェクトを生成します。
まずは、敵キャラクターの残り出現数から表示してみましょう。
#_/_/_/ 素材の初期化 _/_/_/ #メイン背景 obj_bg_00_spr = put_sprite 'spr_bg_00' do position obj_bg_pos_x, obj_bg_pos_y src_rect 0, 0, 800, 600 end #~~~~~~~~~~ 中略 ~~~~~~~~~~ #敵キャラクター i = 0; ilen = obj_enemy_max while i < ilen do obj_enemy_spr[i] = put_sprite 'spr_enemy' do position obj_enemy_pos_x[i], obj_enemy_pos_y[i] frame_index 0 end #アニメーションの開始 obj_enemy_spr[i].start_animation('wait') i += 1 end #---------- ここから ---------- #残敵数 obj_minienemy_spr = put_sprite 'spr_enemy' do position 16, 0 frame_index 0 end #アニメーションの開始 obj_minienemy_spr.start_animation('wait') #サイズの変更 obj_minienemy_spr.scale (32 / obj_enemy_size_w), (32 / obj_enemy_size_h) obj_txt_enemyzan_spr = put_text 'spr_txt_info' do position 52, 6 end obj_txt_enemyzan_spr.text '×' obj_txt_enemyzan_no_spr = put_text 'spr_txt_info' do position 78, 6 end obj_txt_enemyzan_no_spr.text (format('%02d',enemy_zan_view)).to_s #---------- ここまで ----------
obj_minienemy_sprは敵キャラクターの画像オブジェクトを生成し
scaleで縮小して表示しています。
obj_txt_enemyzan_spr、obj_txt_enemyzan_no_sprが文字オブジェクトの生成。
put_textでオブジェクトを生成し、
各オブジェクトに対してtextを指定することで
表示するテキストを書き換えています。
なお、obj_txt_enemyzan_no_sprのテキストで使用されている
format関数は、数値型の変数を特定の長さの0で埋め、
文字型の変数に変更しています。
数値、文字列の0埋め
スコア、プレイヤーの残機の文字オブジェクトも同様に生成します。
#残敵数 obj_minienemy_spr = put_sprite 'spr_enemy' do position 16, 0 frame_index 0 end #アニメーションの開始 obj_minienemy_spr.start_animation('wait') #サイズの変更 obj_minienemy_spr.scale (32 / obj_enemy_size_w), (32 / obj_enemy_size_h) obj_txt_enemyzan_spr = put_text 'spr_txt_info' do position 52, 6 end obj_txt_enemyzan_spr.text '×' obj_txt_enemyzan_no_spr = put_text 'spr_txt_info' do position 78, 6 end obj_txt_enemyzan_no_spr.text (format('%02d',enemy_zan_view)).to_s #---------- ここから ---------- #スコア obj_txt_score_spr = put_text 'spr_txt_info' do position 320, 6 end obj_txt_score_spr.text 'SCORE' obj_txt_score_no_spr = put_text 'spr_txt_info' do position 400, 6 end obj_txt_score_no_spr.text (format('%06d',score_view)).to_s #残機 obj_minichar_spr = put_sprite 'spr_char' do position 696, 4 frame_index 0 end #アニメーションの開始 obj_minichar_spr.start_animation('wait') #サイズの変更 obj_minichar_spr.scale (32 / obj_char_size_w), (32 / obj_char_size_h) obj_txt_charzan_spr = put_text 'spr_txt_info' do position 732, 6 end obj_txt_charzan_spr.text '×' obj_txt_charzan_no_spr = put_text 'spr_txt_info' do position 758, 6 end obj_txt_charzan_no_spr.text (format('%02d',char_zan_view)).to_s #---------- ここまで ----------
残敵キャラクター数、スコア、プレイヤー残機に変更があった場合
文字オブジェクトのテキストを書き換える処理を追加します。
#--- 背景 --- #背景のスクロール obj_bg_pos_y += obj_bg_speed #背景のスクロールをループさせる if obj_bg_pos_y > 600 obj_bg_pos_y -= 600 end #背景のオブジェクトを移動する obj_bg_00_spr.position obj_bg_pos_x, obj_bg_pos_y obj_bg_01_spr.position obj_bg_pos_x, (obj_bg_pos_y - 600) #---------- ここから ---------- #--- 残敵数 --- if enemy_zan < 0 enemy_zan = 0 end if enemy_zan != enemy_zan_view enemy_zan_view = enemy_zan obj_txt_enemyzan_no_spr.text (format('%02d',enemy_zan_view)).to_s end #--- スコア --- #スコアの最大値 if score > 999999 score = 999999 end #スコア表示の変更 if score_view < score score_view += 17 if score_view > score score_view = score end obj_txt_score_no_spr.text (format('%06d',score_view)).to_s end #--- 残機 --- if char_zan < 0 char_zan = 0 end if char_zan != char_zan_view char_zan_view = char_zan obj_txt_charzan_no_spr.text (format('%02d',char_zan_view)).to_s end #---------- ここまで ----------
スコア表示の変更では
一度に表示スコアを変更するのではなく、
実際のスコアに表示スコアが徐々に近づいていくように
換算する処理を加えることで、演出を上げているところがポイントです。
メインループ内、各条件が整ったとき
残り敵キャラクター数、スコア、プレイヤー残機が変更されるよう
処理を追加します。
#--- 敵キャラクター --- #敵キャラクターの出現カウントダウン obj_enemy_next_time -= 1 #カウントダウンが0以下になったら敵を出現させる if obj_enemy_next_time < 0 obj_enemy_next_time = obj_enemy_next + rand(obj_enemy_next_rnd) i = 0; ilen = obj_enemy_max while i < ilen do #待機状態の敵キャラクターを探す if obj_enemy_anime[i] == 'wait' #---------- ここから ---------- #敵キャラクターの残数を変更 enemy_zan -= 1 #---------- ここまで ---------- #敵キャラクターを行動状態にする obj_enemy_pos_x[i] = rand(obj_enemy_w_max) obj_enemy_pos_y[i] = (obj_enemy_size_h * (-2)) obj_enemy_speed_r_x[i] = obj_enemy_speed * (1 + ((-2) * rand(1))) obj_enemy_speed_r_y[i] = obj_enemy_speed - obj_enemy_speed_rnd + rand(obj_enemy_speed_rnd) #アニメーションの開始 obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'move') #ループを終了させる i = ilen end i += 1 end end #~~~~~~~~~~ 中略 ~~~~~~~~~~ #プレイヤーキャラクターとの当たり判定 if (obj_char_hit_time < 0) && ((obj_char_pos_x + obj_char_hit_x) < (obj_enemy_pos_x_old[i] + obj_enemy_hit_w)) && ((obj_char_pos_x + obj_char_hit_w) > (obj_enemy_pos_x_old[i] + obj_enemy_hit_x)) && ((obj_char_pos_y + obj_char_hit_y) < (obj_enemy_pos_y_old[i] + obj_enemy_hit_h)) && ((obj_char_pos_y + obj_char_hit_h) > (obj_enemy_pos_y_old[i] + obj_enemy_hit_y)) #---------- ここから ---------- #プレイヤーキャラクターの残機を変更 char_zan -= 1 #---------- ここまで ---------- #プレイヤーキャラクターに無敵時間を設定 obj_char_hit_time = obj_char_invincible_time end #プレイヤー弾との当たり判定 j = 0; jlen = obj_char_tama_max while j < jlen do #移動状態のプレイヤー弾を探す if obj_char_tama_flg[j] && ((obj_char_tama_pos_x[j] + obj_char_tama_hit_x) < (obj_enemy_pos_x_old[i] + obj_enemy_hit_w)) && ((obj_char_tama_pos_x[j] + obj_char_tama_hit_w) > (obj_enemy_pos_x_old[i] + obj_enemy_hit_x)) && ((obj_char_tama_pos_y[j] + obj_char_tama_hit_y) < (obj_enemy_pos_y_old[i] + obj_enemy_hit_h)) && ((obj_char_tama_pos_y[j] + obj_char_tama_hit_h) > (obj_enemy_pos_y_old[i] + obj_enemy_hit_y)) #効果音を再生する obj_se_hit00.play() #---------- ここから ---------- #スコアの加算 score += enemy_score #---------- ここまで ---------- #敵キャラクターに無敵時間を設定 obj_enemy_hit_time[i] = obj_enemy_invincible_time
ここまでで、
画面上にスコアや残機を表示するスクリプトが出来ました。
画面上部メニューにある、「保存をして実行」を押して
実際のゲーム画面を確認してみましょう。

06-02 オープニングやエンディングを設定しよう
ゲームの内容は一通り完成しましたが、
ゲームを遊んでもらうためには、外見、つまり「タイトル画面」は
重要な要素のひとつです。
また、このまま無限に遊び続けられるのも良いですが
ゲームの終了となる、ゲームクリアやゲームオーバーもつくってみましょう。

今回もまた、恒例のサンプルの素材を準備いたしました。
音楽素材は、助教授さまと、rerofumiさまの音楽素材を利用いたします。
クリップをしたら、ゲームエディタ画面で「OP,ED,全滅時設定」を押します。
オープニング画面の項目の、「クリップした画像を設定する」を押し、
設定する画像の「設定する」を押します。

同様に、エンディング画面も設定します。
新CoRでは、ゲームオーバー画面が存在しないため、
ここまで設定できたら、COREシーン一覧からCOREシーンエディタに戻ります。

新CoRでは、上記の設定だけだと
ゲーム一覧にはオープニング画面が反映されますが
実際のゲーム内では表示されません。
そのため、タイトル画面、ゲームオーバー画面は
スクリプトで実装する必要があります。
COREシーンエディタのリソースに
先ほどの素材の中から、
タイトル画面、ゲームオーバー画面、
2種類の音楽素材を追加しておきましょう。

ここからstart.rb内に、タイトル用のシーンを追加することもできますが、
今回は、ゲームメイン画面と、タイトル画面でソースファイルを分け
スクリプトが見やすくなるようにつくってみましょう。
ソースファイル一覧に戻り。
タイトル画面用のソースファイルを作成します。
ソースファイル一覧横の新規作成を押します。

タイトル画面用のソースファイル名を入力し、
「新規作成する」を押します。

ソースファイル一覧にtitle.rbという
ソースファイルが追加されました。

「start.rb」を押して、スクリプトの編集画面を開きます。
画面の一番右に、先ほどと同様にtitle.rbが追加されています。
編集したいスクリプトを切り替える際は、
この一覧からクリックすることでも切り替えることができます。

ソースファイルを作成しただけでは、
他のソースファイルのスクリプトを読み込んでくれません。
まずは「start.rb」から「title.rb」を読み込んでもらえるよう
外部ソースファイルの読み込み設定を行います。
#--------------------------------------- #シューティングサンプルゲーム(新CoR) #--------------------------------------- #_/_/_/_/_/_/ 外部ソースファイルの読み込み _/_/_/_/_/_/ #---------- ここから ---------- require_code 'title.rb' #---------- ここまで ----------
これで、外部ソースファイルの読み込みの準備が完了しました。
画面上部メニューの「保存する」押してから
「title.rb」のスクリプト編集画面に移動します。
全く何も書かれていないスクリプトが表示されますので、
第01回を参考に、空のスクリプトを作成します。
このとき、title.rb側では、
外部ソースファイルの読み込み、ゲームロード後最初のシーンを開始する、という箇所は
必要ないので削除しておきましょう。
#---------- ここから ---------- #--------------------------------------- #シューティングサンプルゲーム(新CoR) #--------------------------------------- #_/_/_/_/_/_/ グローバル変数の定義 _/_/_/_/_/_/ #_/_/_/_/_/_/ ユーザ関数の定義 _/_/_/_/_/_/ #********** titleシーン ここから ********** scene 'title' do #_/_/_/ ローカル変数の定義 _/_/_/ preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #_/_/_/ 素材の初期化 _/_/_/ end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #_/_/_/ メイン処理 _/_/_/ end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** titleシーン ここまで ********** #********** gameoverシーン ここから ********** scene 'gameover' do #_/_/_/ ローカル変数の定義 _/_/_/ preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #_/_/_/ 素材の初期化 _/_/_/ end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #_/_/_/ メイン処理 _/_/_/ end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** gameoverシーン ここまで ********** #_/_/_/_/_/_/ 素材の定義 _/_/_/_/_/_/ #---------- ここまで ----------
titleシーンはそこまで大きなスクリプトにはならないため
同じソースファイルにgameoverシーンも追加しています。
このように、ソースファイルを分けずに
複数のシーンを実装する方法もあります。
titleシーンとgameoverシーンに
メイン画像オブジェクトを表示します。
これまでのおさらいもかねて
一気に実装してみましょう。
#********** titleシーン ここから ********** scene 'title' do #_/_/_/ ローカル変数の定義 _/_/_/ #---------- ここから ---------- #タイトル背景オブジェクト obj_bg_title_spr = nil #文字オブジェクト obj_txt_title_spr = nil #---------- ここまで ---------- preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #---------- ここから ---------- #----- 画像 ----- #タイトル背景 image 'img_bg_title', id: 78741 #---------- ここまで ---------- end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #_/_/_/ 素材の初期化 _/_/_/ #---------- ここから ---------- #タイトル背景 obj_bg_title_spr = put_sprite 'spr_bg_title' do position 0, 0 src_rect 0, 0, 800, 600 end #タイトル文字 obj_txt_title_spr = put_text 'spr_txt_title' do position 400, 550 end obj_txt_title_spr.text 'PLEASE PUSH Z KEY' #---------- ここまで ---------- end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #_/_/_/ メイン処理 _/_/_/ end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** titleシーン ここまで ********** #********** gameoverシーン ここから ********** scene 'gameover' do #_/_/_/ ローカル変数の定義 _/_/_/ #---------- ここから ---------- #タイトル背景オブジェクト obj_bg_gameover_spr = nil #---------- ここまで ---------- preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #---------- ここから ---------- #----- 画像 ----- #ゲームオーバー背景 image 'img_bg_gameover', id: 78769 #---------- ここまで ---------- end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #_/_/_/ 素材の初期化 _/_/_/ #---------- ここから ---------- #ゲームオーバー背景 obj_bg_gameover_spr = put_sprite 'spr_bg_gameover' do position 0, 0 src_rect 0, 0, 800, 600 end #---------- ここまで ---------- end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #_/_/_/ メイン処理 _/_/_/ end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** gameoverシーン ここまで ********** #_/_/_/_/_/_/ 素材の定義 _/_/_/_/_/_/ #----- 画像の定義 ----- #---------- ここから ---------- #タイトル背景 sprite 'spr_bg_title' do image 'img_bg_title' origin :left_top end #ゲームオーバー背景 sprite 'spr_bg_gameover' do image 'img_bg_gameover' origin :left_top end #----- 文字の定義 ----- text 'spr_txt_title' do origin :center font_size 18 color '#FFFFFF' end #---------- ここまで ----------
素材の定義は、全てのソースファイルで共通のため
同じ名前が重複して使用されいように注意しましょう。
titleシーンとgameoverシーンに
音楽が再生されるようにします。
#********** titleシーン ここから ********** scene 'title' do #_/_/_/ ローカル変数の定義 _/_/_/ #タイトル背景オブジェクト obj_bg_title_spr = nil #文字オブジェクト obj_txt_title_spr = nil #---------- ここから ---------- #音楽オブジェクト obj_bgm_title = nil #---------- ここまで ---------- preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #----- 画像 ----- #タイトル背景 image 'img_bg_title', id: 78741 #---------- ここから ---------- #----- 音楽 ----- #メイン音楽 music 'bgm_title', id: 63621 #---------- ここまで ---------- end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #_/_/_/ 素材の初期化 _/_/_/ #タイトル背景 obj_bg_title_spr = put_sprite 'spr_bg_title' do position 0, 0 src_rect 0, 0, 800, 600 end #タイトル文字 obj_txt_title_spr = put_text 'spr_txt_title' do position 400, 550 end obj_txt_title_spr.text 'PLEASE PUSH Z KEY' #---------- ここから ---------- #音楽 obj_bgm_title = add_music('bgm_title') volBGM(obj_bgm_title, 0.5) #音楽の再生を開始する obj_bgm_title.play() #---------- ここまで ---------- end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #_/_/_/ メイン処理 _/_/_/ end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** titleシーン ここまで ********** #********** gameoverシーン ここから ********** scene 'gameover' do #_/_/_/ ローカル変数の定義 _/_/_/ #タイトル背景オブジェクト obj_bg_gameover_spr = nil #---------- ここから ---------- #音楽オブジェクト obj_bgm_gameover = nil #---------- ここまで ---------- preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #----- 画像 ----- #ゲームオーバー背景 image 'img_bg_gameover', id: 78769 #---------- ここから ---------- #----- 音楽 ----- #メイン音楽 music 'bgm_gameover', id: 48990 #---------- ここまで ---------- end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #_/_/_/ 素材の初期化 _/_/_/ #ゲームオーバー背景 obj_bg_gameover_spr = put_sprite 'spr_bg_gameover' do position 0, 0 src_rect 0, 0, 800, 600 end #---------- ここから ---------- #音楽 obj_bgm_gameover = add_music('bgm_gameover') volBGM(obj_bgm_gameover, 0.5) #音楽の再生を開始する obj_bgm_gameover.play() #---------- ここまで ---------- end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #_/_/_/ メイン処理 _/_/_/ end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** gameoverシーン ここまで **********
タイトル画面でZキーの入力を受け付けるようにします。
#********** titleシーン ここから ********** scene 'title' do #_/_/_/ ローカル変数の定義 _/_/_/ #---------- ここから ---------- #キー入力用のフラグ key_flg_z_st = nil; key_flg_z_do = nil; key_flg_z_en = nil change_scene_flg = nil #---------- ここまで ---------- #タイトル背景オブジェクト obj_bg_title_spr = nil #文字オブジェクト obj_txt_title_spr = nil #音楽オブジェクト obj_bgm_title = nil preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #----- 画像 ----- #タイトル背景 image 'img_bg_title', id: 78741 #----- 音楽 ----- #メイン音楽 music 'bgm_title', id: 63621 end create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #---------- ここから ---------- #キー入力用のフラグ key_flg_z_st = false; key_flg_z_do = false; key_flg_z_en = false change_scene_flg = false #---------- ここまで ---------- #_/_/_/ 素材の初期化 _/_/_/ #タイトル背景 obj_bg_title_spr = put_sprite 'spr_bg_title' do position 0, 0 src_rect 0, 0, 800, 600 end #タイトル文字 obj_txt_title_spr = put_text 'spr_txt_title' do position 400, 550 end obj_txt_title_spr.text 'PLEASE PUSH Z KEY' #音楽 obj_bgm_title = add_music('bgm_title') volBGM(obj_bgm_title, 0.5) #音楽の再生を開始する obj_bgm_title.play() end update do #----- シーンのメインループ処理 ----- #_/_/_/ 入力の判定 _/_/_/ #---------- ここから ---------- #キー入力判定 if keyboard.down?('Z') key_flg_z_st = true else key_flg_z_st = false key_flg_z_do = false end #---------- ここまで ---------- #_/_/_/ メイン処理 _/_/_/ #---------- ここまで ---------- #--- キー入力処理 --- #Zキー if (key_flg_z_st && !key_flg_z_do) key_flg_z_do = true #--- 押された時に実行する処理 --- change_scene_flg = true elsif key_flg_z_do key_flg_z_en = true #--- 押されつづけている時に実行する処理 --- elsif key_flg_z_en key_flg_z_en = false #--- 離された時に実行する処理 --- end #---------- ここまで ---------- end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end end #********** titleシーン ここまで **********
Zキーの入力を受け付けた場合、
ローカル変数のchange_scene_flgがtrueになります。
change_scene_flgがtrueになったとき
ゲームメイン画面のstartシーンに移動するようにします。
#********** titleシーン ここから ********** scene 'title' do #~~~~~~~~~~ 中略 ~~~~~~~~~~ #_/_/_/ メイン処理 _/_/_/ #--- キー入力処理 --- #Zキー if (key_flg_z_st && !key_flg_z_do) key_flg_z_do = true #--- 押された時に実行する処理 --- change_scene_flg = true elsif key_flg_z_do key_flg_z_en = true #--- 押されつづけている時に実行する処理 --- elsif key_flg_z_en key_flg_z_en = false #--- 離された時に実行する処理 --- end #---------- ここから ---------- #シーンの移動 if change_scene_flg #音楽の再生を停止する obj_bgm_title.stop() #画像素材を開放する obj_bg_title_spr.destroy obj_txt_title_spr.destroy #startシーンに移動 change_scene "start" end #---------- ここまで ----------
現在のシーンを終了する前に
使用した画像素材をdestroyの指示で開放します。
今回のような短いゲームでは
画像の開放をしていなくても影響はほぼありませんが、
長編のゲームになった場合
ゲーム自体がフリーズしてしまう恐れがあるためです。
change_sceneで別のシーンに移動します。
移動先はシーン名の文字列で指定します。
ゲーム開始時にタイトル画面から始まるように
ゲームロード後最初のシーンを変更します。
title.rbを保存してから、start.rbに移動しましょう。
start.rbのスクリプトの最後にある
ゲームロード後最初のシーンを書き換えます。
#_/_/_/_/_/_/ ゲームロード後最初のシーンを開始する _/_/_/_/_/_/ start_scene 'title' #------- 変更
ゲームメイン画面で特定の条件を満たしたとき、
ゲームクリア画面、ゲームオーバー画面に移動するように
処理を追加します。
まずは、ゲームクリア、ゲームオーバーを判定する
ローカル変数の定義から行います。
#********** startシーン ここから ********** scene 'start' do #_/_/_/ ローカル変数の定義 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #システム関連 #---------- ここから ---------- gameclear_flg = nil gameover_flg = nil #---------- ここまで ---------- score = nil; score_view = nil enemy_score = nil char_zan = nil; char_zan_view = nil enemy_zan = nil; enemy_zan_view = nil
定義したローカル変数を初期化します。
create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #システム関連 #---------- ここから ---------- gameclear_flg = false gameover_flg = false #---------- ここまで ---------- score = 0; score_view = score enemy_score = 500 char_zan = 5; char_zan_view = char_zan enemy_zan = 20; enemy_zan_view = enemy_zan
プレイヤーキャラクターの残機がなくなった場合
入力操作を停止するようにします。
#--- プレイヤーキャラクター --- #プレイヤーキャラクター移動方向のフラグによって処理を分岐 if (obj_char_flg_up && obj_char_flg_left) && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'left') #プレイヤーキャラクターの座標を変更 obj_char_pos_x -= obj_char_speed_r_x; obj_char_pos_y -= obj_char_speed_r_y elsif (obj_char_flg_down && obj_char_flg_left) && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'left') #プレイヤーキャラクターの座標を変更 obj_char_pos_x -= obj_char_speed_r_x; obj_char_pos_y += obj_char_speed_r_y elsif (obj_char_flg_up && obj_char_flg_right) && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'right') #プレイヤーキャラクターの座標を変更 obj_char_pos_x += obj_char_speed_r_x; obj_char_pos_y -= obj_char_speed_r_y elsif (obj_char_flg_down && obj_char_flg_right) && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'right') #プレイヤーキャラクターの座標を変更 obj_char_pos_x += obj_char_speed_r_x; obj_char_pos_y += obj_char_speed_r_y elsif obj_char_flg_up && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'neutral') #プレイヤーキャラクターの座標を変更 obj_char_pos_y -= obj_char_speed elsif obj_char_flg_down && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'neutral') #プレイヤーキャラクターの座標を変更 obj_char_pos_y += obj_char_speed elsif obj_char_flg_left && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'left') #プレイヤーキャラクターの座標を変更 obj_char_pos_x -= obj_char_speed elsif obj_char_flg_right && (char_zan > 0) #------- 変更 #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'right') #プレイヤーキャラクターの座標を変更 obj_char_pos_x += obj_char_speed else #プレイヤーキャラクターのアニメーションを変更 obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'neutral') end
プレイヤーキャラクターがダメージを受けている間は
弾の発射が行えないようにします。
#プレイヤー弾の発射 if obj_char_tama_flg_z && (obj_char_tama_next_time < 0) && (obj_char_hit_time < 0) #------- 変更 obj_char_tama_next_time = obj_char_tama_next i = 0; ilen = obj_char_tama_max while i < ilen do #待機状態のプレイヤー弾を探す if !obj_char_tama_flg[i] #プレイヤー弾を移動状態にする obj_char_tama_pos_x[i] = obj_char_pos_x + ((obj_char_size_w - obj_char_tama_size_w) / 2) obj_char_tama_pos_y[i] = obj_char_pos_y obj_char_tama_scale_x[i] = 1; obj_char_tama_scale_y[i] = 0 obj_char_tama_scale_count[i] = 0 obj_char_tama_flg[i] = true #ループを終了させる i = ilen end i += 1 end end
ゲームオーバーの条件が揃ったら
ゲームオーバーのフラグをtrueにします。
#プレイヤー弾のオブジェクトを移動する if (obj_char_tama_pos_x_old[i] != obj_char_tama_pos_x[i]) || (obj_char_tama_pos_y_old[i] != obj_char_tama_pos_y[i]) obj_char_tama_pos_x_old[i] = obj_char_tama_pos_x[i] obj_char_tama_pos_y_old[i] = obj_char_tama_pos_y[i] obj_char_tama_spr[i].position obj_char_tama_pos_x[i], obj_char_tama_pos_y[i] obj_char_tama_spr[i].scale obj_char_tama_scale_x[i], obj_char_tama_scale_y[i] end end i += 1 end #---------- ここから ---------- #ゲームオーバー if (char_zan == 0) && (obj_char_hit_time < 0) gameover_flg = true end #---------- ここまで ---------- #--- 敵キャラクター --- #敵キャラクターの出現カウントダウン obj_enemy_next_time -= 1
残り敵キャラクター出現数が0になったら
次の敵キャラクターを出現させないようにします。
#--- 敵キャラクター --- #敵キャラクターの出現カウントダウン obj_enemy_next_time -= 1 #カウントダウンが0以下になったら敵を出現させる if obj_enemy_next_time < 0 && enemy_zan > 0 #------- 変更 obj_enemy_next_time = obj_enemy_next + rand(obj_enemy_next_rnd) i = 0; ilen = obj_enemy_max while i < ilen do #待機状態の敵キャラクターを探す if obj_enemy_anime[i] == 'wait' #敵キャラクターの残数を変更 enemy_zan -= 1
ゲームクリア条件を追加するため
敵キャラクターが全ていなくなったか判定する処理を追加します。
#敵キャラクターの行動ループ #---------- ここから ---------- wrk_enemy_count = 0 #---------- ここまで ---------- i = 0; ilen = obj_enemy_max while i < ilen do #移動状態の敵キャラクターを探す if obj_enemy_anime[i] == 'move' #---------- ここから ---------- wrk_enemy_count += 1 #---------- ここまで ---------- #敵キャラクターの座標値を移動させる obj_enemy_pos_x[i] += obj_enemy_speed_r_x[i] obj_enemy_pos_y[i] += obj_enemy_speed_r_y[i] #~~~~~~~~~~ 中略 ~~~~~~~~~~ #ダメージ状態の敵キャラクターを探す if obj_enemy_anime[i] == 'damage' #---------- ここから ---------- wrk_enemy_count += 1 #---------- ここまで ---------- #敵キャラクターの無敵時間をカウント if obj_enemy_hit_time[i] > (-1) obj_enemy_hit_time[i] -= 1
wrk_enemy_countというカウンター変数を用意して
敵キャラクターがmoveまたはdamageの行動状態が存在した場合
カウンターを追加しています。
敵キャラクターの行動を全て確認したとき
カウンターが0のままであれば、
全ての敵キャラクターがいなくなったと判断しています。
ゲームクリアの条件が揃ったら、
ゲームクリアのフラグをtrueにします。
#敵キャラクターのオブジェクトを移動する obj_enemy_spr[i].position obj_enemy_pos_x[i], obj_enemy_pos_y[i] elsif ((obj_enemy_hit_time[i] % 10) == 0) setAlpha(obj_enemy_spr[i], 1) elsif ((obj_enemy_hit_time[i] % 5) == 0) setAlpha(obj_enemy_spr[i], 0) elsif ((obj_enemy_hit_time[i] % 3) == 0) setAlpha(obj_enemy_spr[i], 0.5) end end end i += 1 end #---------- ここから ---------- #ゲームクリア if (enemy_zan == 0) && (wrk_enemy_count == 0) gameclear_flg = true end #---------- ここまで ----------
ゲームクリアフラグまたはゲームオーバーフラグがtrueの場合
シーンを移動する処理を追加します。
#--- 残機 --- if char_zan < 0 char_zan = 0 end if char_zan != char_zan_view char_zan_view = char_zan obj_txt_charzan_no_spr.text (format('%02d',char_zan_view)).to_s end #---------- ここから ---------- #シーンの移動 if gameclear_flg || gameover_flg #音楽の再生を停止する obj_bgm_main.stop() #画像素材を開放する obj_bg_00_spr.destroy; obj_bg_01_spr.destroy obj_char_spr.destroy i = 0; ilen = obj_char_tama_max while i < ilen do obj_char_tama_spr[i].destroy i += 1 end i = 0; ilen = obj_enemy_max while i < ilen do obj_enemy_spr[i].destroy i += 1 end obj_minienemy_spr.destroy obj_txt_enemyzan_spr.destroy; obj_txt_enemyzan_no_spr.destroy obj_txt_score_spr.destroy; obj_txt_score_no_spr.destroy obj_minichar_spr.destroy obj_txt_charzan_spr.destroy; obj_txt_charzan_no_spr.destroy #配列を開放する obj_char_tama_spr.clear obj_char_tama_pos_x.clear; obj_char_tama_pos_y.clear obj_char_tama_scale_x.clear; obj_char_tama_scale_y.clear obj_char_tama_scale_count.clear obj_char_tama_pos_x_old.clear; obj_char_tama_pos_y_old.clear obj_char_tama_flg.clear obj_enemy_spr.clear obj_enemy_pos_x.clear; obj_enemy_pos_y.clear obj_enemy_pos_x_old.clear; obj_enemy_pos_y_old.clear obj_enemy_speed_r_x.clear; obj_enemy_speed_r_y.clear obj_enemy_hit_time.clear obj_enemy_anime.clear if gameclear_flg #ゲームクリア画面に移動 game_clear else #gameoverシーンに移動 change_scene "gameover" end end #---------- ここまで ---------- end render do #----- シーンのメイン描画処理 ----- #_/_/_/ 描画の変更 _/_/_/ end
シーンを移動する前に
destroyで画像素材の開放と、clearで配列の開放を行っています。
配列の開放も画像素材の開放と同様に
ゲーム自体がフリーズしてしまう恐れがあるため
必ず行うようにしておきましょう。
素材を開放すると、当然ながら
素材を扱う処理がこの後に存在しているとエラーとなってしまいますので
メインループ内の途中ではフラグを立てておき
updateの一番最後で、シーンを移動するように順番を組み立てています。
game_clearはゲームクリア画面に移動します。
この命令で、Rmakeのゲームクリア条件も達成したことになります。
ゲームオーバーの場合は
title.rb内に作成したgameoverシーンに移動しています。
ここまでで、タイトル画面、ゲームクリア画面、ゲームオーバー画面を
表示するスクリプトが出来ました。
画面上部メニューにある、「保存をして実行」を押して
実際のゲーム画面を確認してみましょう。

06-03 おわりに
いかがでしたでしょうか。
これで、立派にゲームとして必要な要素が揃いました。
さて、次回は、いよいよ最終回。
「より面白くするために」と題しまして、
更なるテクニックをご紹介します。
今回までのスクリプト全体
CoRでゲームをつくってみよう / 第06回
第01回 CoRの開発準備をしよう
第02回 画面に背景やキャラクターを描画する
第03回 背景やキャラクターを動かす
第04回 敵キャラクターを登場させる
第05回 弾を発射する
第06回 ゲームとして必要な機能を追加する
第07回 より面白くするために
コメントする
コメントするには、ログインする必要があります。
タイトル画面をスクリプトで作る機会ってRmakeでは
あんまり無かったと思うので助かるなと思いました。
シーンの移り方も分かってありがたいです。
Rubyと同じ仕組みを利用しています。
CoRはRubyをベースに拡張したつくりになっているため
一部のRuby関数は同様に利用することができるのです。