CoRでゲームをつくってみよう / 第07回 より面白くするために
投稿者: aoihikawa 投稿日:2022/08/18 19:03
CoRでゲームをつくってみよう
第07回 より面白くするために
こんにちは。
フリーデザイナープログラマー(自称)の
簸川 葵(ひかわ あおい)と申します。
第06回 ではタイトル画面やゲームクリア画面など、
シューティングゲームとして完成するまでのお話でした。
第07回は、いよいよ最終回。
より面白くするために、様々な工夫の方法を紹介していきます。
07-01 敵に弾を発射させる
キャラクターが攻撃できるのに、
敵キャラクターが攻撃できないのは不公平ですね。
敵キャラクターにも弾を発射させてみましょう。
基本的な仕組みは、キャラクターの弾を発射させたときと同じです。
今回は、弾にアニメーションも付けてみましょう。
今回もまた、恒例のサンプルの素材を準備いたしました。
第01回を参考に、クリップからリソースへの登録まで行い、
すぐにスクリプトで利用できるように、準備してください。
敵弾の画像を読み込むために
画像の定義、素材のロードを行います。
#_/_/_/_/_/_/ 素材の定義 _/_/_/_/_/_/ #----- 画像の定義 ----- #メイン背景 sprite 'spr_bg_00' do image 'img_bg_00' origin :left_top end #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #敵弾 sprite 'spr_enemy_tama' do image 'img_enemy_tama' origin :left_top animation 'wait', [0], 60, true animation 'move', [0, 1, 2], 5, true end #---------- ここまで ----------
preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #----- 画像 ----- #メイン背景 image 'img_bg_00', id: 76800 #プレイヤーキャラクター image 'img_char', id: 76793, frame_size: [64, 64] #プレイヤー弾 image 'img_char_tama', id: 77342 #敵キャラクター image 'img_enemy', id: 77127, frame_size: [64, 64] #---------- ここから ---------- #敵弾 image 'img_enemy_tama', id: 77349, frame_size: [16, 16] #---------- ここまで ----------
ローカル変数の定義、初期化を行います。
scene 'start' do #_/_/_/ ローカル変数の定義 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #敵キャラクターオブジェクト obj_enemy_spr = [] obj_enemy_pos_x = []; obj_enemy_pos_y = [] obj_enemy_size_w = nil; obj_enemy_size_h = nil obj_enemy_speed = nil; obj_enemy_speed_rnd = nil obj_enemy_pos_x_old = []; obj_enemy_pos_y_old = [] obj_enemy_speed_r_x = []; obj_enemy_speed_r_y = [] obj_enemy_w_max = nil; obj_enemy_h_max = nil obj_enemy_hit_time = [] obj_enemy_invincible_time = nil obj_enemy_hit_x = nil; obj_enemy_hit_y = nil obj_enemy_hit_w = nil; obj_enemy_hit_h = nil obj_enemy_anime = [] obj_enemy_max = nil obj_enemy_next = nil obj_enemy_next_rnd = nil obj_enemy_next_time = nil #---------- ここから ---------- obj_enemy_tama_next = nil obj_enemy_tama_next_time = [] #敵弾オブジェクト obj_enemy_tama_spr = [] obj_enemy_tama_pos_x = []; obj_enemy_tama_pos_y = [] obj_enemy_tama_size_w = nil; obj_enemy_tama_size_h = nil obj_enemy_tama_speed = nil obj_enemy_tama_speed_r_x = []; obj_enemy_tama_speed_r_y = [] obj_enemy_tama_pos_x_old = []; obj_enemy_tama_pos_y_old = [] obj_enemy_tama_w_max = nil; obj_enemy_tama_h_max = nil obj_enemy_tama_hit_x = nil; obj_enemy_tama_hit_y = nil obj_enemy_tama_hit_w = nil; obj_enemy_tama_hit_h = nil obj_enemy_tama_anime = [] obj_enemy_tama_max = nil #---------- ここまで ----------
敵弾のローカル変数のみではなく、
敵にも次に敵弾を発射するまでの時間を設定する
新規に作成しています。
定義したローカル変数を初期化します。
#敵キャラクターオブジェクト obj_enemy_size_w = 64; obj_enemy_size_h = 64 obj_enemy_w_max = (800 - obj_enemy_size_w) obj_enemy_h_max = (600 + obj_enemy_size_h) obj_enemy_speed = 3; obj_enemy_speed_rnd = 2 obj_enemy_invincible_time = (60 * 1) obj_enemy_hit_x = 20; obj_enemy_hit_y = 20 obj_enemy_hit_w = 44; obj_enemy_hit_h = 55 obj_enemy_max = 5 obj_enemy_next = (60 * 4) obj_enemy_next_rnd = 60 obj_enemy_next_time = (60 * 3) #---------- ここから ---------- obj_enemy_tama_next = (60 * 2) #---------- ここまで ---------- i = 0; ilen = obj_enemy_max while i < ilen do obj_enemy_pos_x[i] = 0; obj_enemy_pos_y[i] = ((-64) * 2) obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i] obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i] obj_enemy_speed_r_x[i] = 0; obj_enemy_speed_r_y[i] = 0 #---------- ここから ---------- obj_enemy_anime[i] = 'wait' #---------- ここまで ---------- obj_enemy_hit_time[i] = (-1) obj_enemy_tama_next_time[i] = obj_enemy_tama_next i += 1 end #---------- ここから ---------- #敵弾オブジェクト obj_enemy_tama_size_w = 16; obj_enemy_tama_size_h = 16 obj_enemy_tama_speed = 5 obj_enemy_tama_w_max = (800 + (obj_enemy_tama_size_w * 2)) obj_enemy_tama_h_max = (600 + (obj_enemy_tama_size_h * 2)) obj_enemy_tama_hit_x = 3; obj_enemy_tama_hit_y = 3 obj_enemy_tama_hit_w = 13; obj_enemy_tama_hit_h = 13 obj_enemy_tama_max = 10 i = 0; ilen = obj_enemy_tama_max while i < ilen do obj_enemy_tama_pos_x[i] = 0 obj_enemy_tama_pos_y[i] = ((-64) * 2) obj_enemy_tama_speed_r_x[i] = 0 obj_enemy_tama_speed_r_y[i] = 0 obj_enemy_tama_pos_x_old[i] = obj_enemy_tama_pos_x[i] obj_enemy_tama_pos_y_old[i] = obj_enemy_tama_pos_y[i] obj_enemy_tama_anime[i] = 'wait' i += 1 end #---------- ここまで ----------
敵弾画像オブジェクトを生成します。
#_/_/_/ 素材の初期化 _/_/_/ #---------- ここから ---------- #敵弾 i = 0; ilen = obj_enemy_tama_max while i < ilen do obj_enemy_tama_spr[i] = put_sprite 'spr_enemy_tama' do position obj_enemy_tama_pos_x[i], obj_enemy_tama_pos_y[i] frame_index 0 end i += 1 end #---------- ここまで ----------
自機狙い弾を発射するために
ユーザ定義関数を用意しておきます。
scene 'start' do #_/_/_/_/_/_/ ユーザ関数の定義 _/_/_/_/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #自機狙い弾 def jikinerai_tama(char_x, char_y, ememy_x, ememy_y, speed) r = 0; x = 0; y = 0 if char_x == ememy_x if char_y > ememy_y y = (speed * (-1)) elsif char_y < ememy_y y = speed end else r = (Math.atan2((ememy_y - char_y), (ememy_x - char_x))) x = (Math.cos(r) * speed).to_f y = (Math.sin(r) * speed).to_f end ret_data = createArray() ret_data[0] = x ret_data[1] = y return ret_data end #---------- ここまで ----------
内容はarrp版の自機狙い弾と同じものですが
新CoR向けに、三角関数関連の命令が一部変更されています。
敵キャラクターが敵弾を発射するようにします。
#敵キャラクターの行動ループ wrk_enemy_count = 0 #~~~~~~~~~~ 中略 ~~~~~~~~~~ #敵キャラクターのオブジェクトを移動する if (obj_enemy_pos_x_old[i] != obj_enemy_pos_x[i]) || (obj_enemy_pos_y_old[i] != obj_enemy_pos_y[i]) obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i] obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i] obj_enemy_spr[i].position obj_enemy_pos_x[i], obj_enemy_pos_y[i] end #---------- ここから ---------- #敵弾の発射は画面内に入ってから if obj_enemy_pos_x[i] > 0 #敵弾の発射カウントダウン if obj_enemy_tama_next_time[i] > (-1) obj_enemy_tama_next_time[i] -= 1 end #敵弾の発射 if obj_enemy_tama_next_time[i] < 0 obj_enemy_tama_next_time[i] = obj_enemy_tama_next j = 0; jlen = obj_enemy_tama_max while j < jlen do #待機状態の敵弾を探す if obj_enemy_tama_anime[j] == 'wait' #敵弾を移動状態にする obj_enemy_tama_pos_x[j] = obj_enemy_pos_x[i] + ((obj_enemy_size_w - obj_enemy_tama_size_w) / 2) - 10 obj_enemy_tama_pos_y[j] = obj_enemy_pos_y[i] + obj_enemy_size_h - 10 #敵弾の移動方向を決める wrk_p = [] wrk_p = jikinerai_tama((obj_char_pos_x + (obj_char_size_w / 2)), (obj_char_pos_y + (obj_char_size_h / 2)), (obj_enemy_tama_pos_x[j] + (obj_enemy_tama_size_w / 2)), (obj_enemy_tama_pos_y[j] + (obj_enemy_tama_size_h / 2)), obj_enemy_tama_speed) obj_enemy_tama_speed_r_x[j] = wrk_p[0] obj_enemy_tama_speed_r_y[j] = wrk_p[1] wrk_p.clear obj_enemy_tama_anime[j] = setChangeAnime(obj_enemy_tama_spr[j], obj_enemy_tama_anime[j], 'move') #ループを終了させる j = jlen end j += 1 end end end #---------- ここまで ---------- #プレイヤーキャラクターとの当たり判定
敵弾の発射位置が、敵キャラクターの銃口付近になるよう
若干の座標調整をしています。
敵弾の移動方向を決める処理で
先程のユーザ関数、jikinerai_tamaを使用しており、
戻り値の受け取りにwrk_pという配列変数を用意して、
obj_enemy_tama_speed_r_x、obj_enemy_tama_speed_r_yに値渡した後
配列変数を開放しています。
敵弾を動かす処理を追加します。
#ゲームクリア if (enemy_zan == 0) && (wrk_enemy_count == 0) gameclear_flg = true end #---------- ここから ---------- #--- 敵弾 --- #敵弾の移動 i = 0; ilen = obj_enemy_tama_max while i < ilen do if obj_enemy_tama_anime[i] == 'move' #敵弾の座標値を移動させる obj_enemy_tama_pos_x[i] -= obj_enemy_tama_speed_r_x[i] obj_enemy_tama_pos_y[i] -= obj_enemy_tama_speed_r_y[i] #プレイヤーキャラクターとの当たり判定 wrk_char_hit_flg = false if (obj_char_hit_time < 0) && ((obj_char_pos_x + obj_char_hit_x) < (obj_enemy_tama_pos_x_old[i] + obj_enemy_tama_hit_w)) && ((obj_char_pos_x + obj_char_hit_w) > (obj_enemy_tama_pos_x_old[i] + obj_enemy_tama_hit_x)) && ((obj_char_pos_y + obj_char_hit_y) < (obj_enemy_tama_pos_y_old[i] + obj_enemy_tama_hit_h)) && ((obj_char_pos_y + obj_char_hit_h) > (obj_enemy_tama_pos_y_old[i] + obj_enemy_tama_hit_y)) #プレイヤーキャラクターの残機を変更 char_zan -= 1 #プレイヤーキャラクターに無敵時間を設定 obj_char_hit_time = obj_char_invincible_time wrk_char_hit_flg = true end #敵弾の移動範囲制限 if wrk_char_hit_flg || (obj_enemy_tama_pos_x[i] < (obj_enemy_tama_size_w * (-2))) || (obj_enemy_tama_pos_x[i] > (obj_enemy_tama_w_max)) || (obj_enemy_tama_pos_y[i] < (obj_enemy_tama_size_h * (-2))) || (obj_enemy_tama_pos_y[i] > (obj_enemy_tama_h_max)) obj_enemy_tama_pos_x[i] = 800; obj_enemy_tama_pos_y[i] = 600 obj_enemy_tama_anime[i] = setChangeAnime(obj_enemy_tama_spr[i], obj_enemy_tama_anime[i], 'wait') end #敵弾のオブジェクトを移動する if (obj_enemy_tama_pos_x_old[i] != obj_enemy_tama_pos_x[i]) || (obj_enemy_tama_pos_y_old[i] != obj_enemy_tama_pos_y[i]) obj_enemy_tama_pos_x_old[i] = obj_enemy_tama_pos_x[i] obj_enemy_tama_pos_y_old[i] = obj_enemy_tama_pos_y[i] obj_enemy_tama_spr[i].position obj_enemy_tama_pos_x[i], obj_enemy_tama_pos_y[i] end end i += 1 end #---------- ここまで ---------- #--- 背景 --- #背景のスクロール
プレイヤーと敵弾の当たり判定に
wrk_char_hit_flgを用意しておき
当たっていた場合、wrk_char_hit_flgをtrueにすることで
敵弾の移動範囲制限と同様に
敵弾を待機状態に戻しています。
敵キャラクターが倒されたとき
敵弾の発射時間をリセットするようにします。
#ダメージ状態の敵キャラクターを探す if obj_enemy_anime[i] == 'damage' wrk_enemy_count += 1 #敵キャラクターの無敵時間をカウント if obj_enemy_hit_time[i] > (-1) obj_enemy_hit_time[i] -= 1 #無敵時間の場合プレイヤーキャラクターを点滅表示する if obj_enemy_hit_time[i] == 0 setAlpha(obj_enemy_spr[i], 1) #無敵時間が終了したら待機状態に戻す obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'wait') obj_enemy_speed_r_x[i] = 0; obj_enemy_speed_r_y[i] = 0 obj_enemy_pos_x[i] = 0; obj_enemy_pos_y[i] = ((-64) * 2) #---------- ここから ---------- obj_enemy_tama_next_time[i] = obj_enemy_tama_next #---------- ここまで ---------- #敵キャラクターのオブジェクトを移動する
シーン移動時の配列の開放を追加します
#配列を開放する 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 #---------- ここから ---------- obj_enemy_tama_pos_x.clear obj_enemy_tama_pos_y.clear obj_enemy_tama_speed_r_x.clear obj_enemy_tama_speed_r_y.clear obj_enemy_tama_pos_x_old.clear obj_enemy_tama_pos_y_old.clear obj_enemy_tama_anime.clear obj_enemy_tama_next_time.clear #---------- ここまで ----------
ここまでで、
敵キャラクターが敵弾を発射するスクリプトが出来ました。
画面上部メニューにある、「保存をして実行」を押して
実際のゲーム画面を確認してみましょう。
07-02 敵にAIを搭載する
敵キャラクターの動きがワンパターンでは、
やっぱり物足りない感じがしてしまいます。
今度は、簡単なAIを搭載して、
動きを変化させてみることにしましょう。
今回は敵キャラクターが一定時間ごとに
直線移動、斜め移動の右方向、左方向の3種類へ
ランダムで切り替わるAIを実装します。
ローカル変数の定義、初期化を行います。
obj_enemy_tama_next = nil obj_enemy_tama_next_time = [] #---------- ここから ---------- obj_enemy_ai = [] obj_enemy_ai_next = nil obj_enemy_ai_next_time = [] #---------- ここまで ---------- #敵弾オブジェクト obj_enemy_tama_spr = []
obj_enemy_aiは現在のAIの種類。
obj_enemy_ai_next、obj_enemy_ai_next_timeは
次のAIに切り替わるまでの時間を管理します。
定義したローカル変数を初期化します。
#敵キャラクターオブジェクト obj_enemy_size_w = 64; obj_enemy_size_h = 64 obj_enemy_w_max = (800 - obj_enemy_size_w) obj_enemy_h_max = (600 + obj_enemy_size_h) obj_enemy_speed = 3; obj_enemy_speed_rnd = 2 obj_enemy_invincible_time = (60 * 1) obj_enemy_hit_x = 20; obj_enemy_hit_y = 20 obj_enemy_hit_w = 44; obj_enemy_hit_h = 55 obj_enemy_max = 5 obj_enemy_next = (60 * 4) obj_enemy_next_rnd = 60 obj_enemy_next_time = (60 * 3) obj_enemy_tama_next = (60 * 2) #---------- ここから ---------- obj_enemy_ai_next = (60 * 1.5) #---------- ここまで ---------- i = 0; ilen = obj_enemy_max while i < ilen do obj_enemy_pos_x[i] = 0; obj_enemy_pos_y[i] = ((-64) * 2) obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i] obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i] obj_enemy_speed_r_x[i] = 0; obj_enemy_speed_r_y[i] = 0 obj_enemy_anime[i] = 'wait' obj_enemy_hit_time[i] = (-1) obj_enemy_tama_next_time[i] = obj_enemy_tama_next #---------- ここから ---------- obj_enemy_ai[i] = 'wait' obj_enemy_ai_next_time[i] = obj_enemy_ai_next #---------- ここまで ---------- i += 1 end
敵の出現時にランダムにAIを切り替えるようにします。
#--- 敵キャラクター --- #敵キャラクターの出現カウントダウン 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 #敵キャラクターを行動状態にする 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) #---------- ここから ---------- wrk_rnd = rand(3) case wrk_rnd when 0 then obj_enemy_ai[i] = 'left' when 1 then obj_enemy_ai[i] = 'right' else obj_enemy_ai[i] = 'straight' end #---------- ここまで ---------- #アニメーションの開始 obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'move') #ループを終了させる i = ilen end i += 1 end end
AIパターンの分岐処理にcase文を使用しています。
敵キャラクターが一定時間ごとに
ランダムでAIを変更するようにします。
#敵キャラクターの行動ループ wrk_enemy_count = 0 i = 0; ilen = obj_enemy_max while i < ilen do #移動状態の敵キャラクターを探す if obj_enemy_anime[i] == 'move' wrk_enemy_count += 1 #---------- ここから ---------- #敵キャラクターのAI切り替えカウントダウン obj_enemy_ai_next_time[i] -= 1 #カウントダウンが0以下になったらAIをランダムに切り替える if obj_enemy_ai_next_time[i] < 0 obj_enemy_ai_next_time[i] = obj_enemy_ai_next wrk_rnd = rand(3) case wrk_rnd when 0 then obj_enemy_ai[i] = 'left' when 1 then obj_enemy_ai[i] = 'right' else obj_enemy_ai[i] = 'straight' end end #---------- ここまで ---------- #敵キャラクターの座標値を移動させる
AIパターンによって、敵キャラクターの移動方向を切り替えます。
#敵キャラクターの座標値を移動させる #---------- ここから変更 ---------- case obj_enemy_ai[i] when 'left' then obj_enemy_pos_x[i] -= obj_enemy_speed_r_x[i] when 'right' then obj_enemy_pos_x[i] += obj_enemy_speed_r_x[i] else end #---------- ここまで変更 ---------- obj_enemy_pos_y[i] += obj_enemy_speed_r_y[i] #敵キャラクターの移動範囲制限 if obj_enemy_pos_x[i] < 0 obj_enemy_pos_x[i] = 0 #移動方向を反転させる #---------- ここから変更 ---------- #obj_enemy_speed_r_x[i] = obj_enemy_speed_r_x[i] * (-1) obj_enemy_ai[i] = 'right' #---------- ここまで変更 ---------- end if obj_enemy_pos_x[i] > obj_enemy_w_max obj_enemy_pos_x[i] = obj_enemy_w_max #移動方向を反転させる #---------- ここから変更 ---------- #obj_enemy_speed_r_x[i] = obj_enemy_speed_r_x[i] * (-1) obj_enemy_ai[i] = 'left' #---------- ここまで変更 ---------- end if obj_enemy_pos_y[i] > obj_enemy_h_max #画面外まで移動したら待機状態に戻す obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'wait') obj_enemy_speed_r_x[i] = 0; obj_enemy_speed_r_y[i] = 0 #---------- ここから ---------- obj_enemy_ai[i] = 'wait' #---------- ここまで ---------- end #敵キャラクターのオブジェクトを移動する if (obj_enemy_pos_x_old[i] != obj_enemy_pos_x[i]) || (obj_enemy_pos_y_old[i] != obj_enemy_pos_y[i]) obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i] obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i] obj_enemy_spr[i].position obj_enemy_pos_x[i], obj_enemy_pos_y[i] end
obj_enemy_pos_xの座標移動値が
obj_enemy_speed_r_x直接の値から
obj_enemy_aiによる切り替えに変更されています。
敵キャラクターの移動範囲制限も、
obj_enemy_speed_r_x直接の変更から
obj_enemy_aiの切り替えに変更されています。
敵キャラクターがプレイヤー弾に当たったあと
待機状態に戻すときに少し処理を追加します。
#ダメージ状態の敵キャラクターを探す if obj_enemy_anime[i] == 'damage' wrk_enemy_count += 1 #敵キャラクターの無敵時間をカウント if obj_enemy_hit_time[i] > (-1) obj_enemy_hit_time[i] -= 1 #無敵時間の場合プレイヤーキャラクターを点滅表示する if obj_enemy_hit_time[i] == 0 setAlpha(obj_enemy_spr[i], 1) #無敵時間が終了したら待機状態に戻す obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'wait') obj_enemy_speed_r_x[i] = 0; obj_enemy_speed_r_y[i] = 0 obj_enemy_pos_x[i] = 0; obj_enemy_pos_y[i] = ((-64) * 2) obj_enemy_tama_next_time[i] = obj_enemy_tama_next #---------- ここから ---------- obj_enemy_ai[i] = 'wait' #---------- ここまで ---------- #敵キャラクターのオブジェクトを移動する
シーン移動時の配列の開放を追加します
#配列を開放する #~~~~~~~~~~ 中略 ~~~~~~~~~~ obj_enemy_anime.clear #---------- ここから ---------- obj_enemy_ai.clear obj_enemy_ai_next_time.clear #---------- ここまで ---------- obj_enemy_tama_pos_x.clear obj_enemy_tama_pos_y.clear
ここまでで敵キャラクターのAIを
ランダムで切り替えるスクリプトが出来ました。
画面上部メニューにある、「保存をして実行」を押して
実際のゲーム画面を確認してみましょう。
07-03 ボスを登場させる
同じ敵だけではなく、他の種類の敵も登場させてみましょう。
最後の1体がいなくなったとき、ボスが出現するようにします。
今回もまた、恒例のサンプルの素材を準備いたしました。
第01回を参考に、クリップからリソースへの登録まで行い、
すぐにスクリプトで利用できるように、準備してください。
画像素材の定義、素材のロードを行います。
preload do #----- ゲームロード時に実行される処理 ----- #_/_/_/ 素材のロード _/_/_/ #----- 画像 ----- #~~~~~~~~~~ 中略 ~~~~~~~~~~ #敵弾 image 'img_enemy_tama', id: 77349, frame_size: [16, 16] #---------- ここから ---------- #ボスキャラクター image 'img_boss', id: 78549 #ボス弾 image 'img_boss_tama', id: 77649 #---------- ここまで ---------- #~~~~~~~~~~ 中略 ~~~~~~~~~~ #_/_/_/_/_/_/ 素材の定義 _/_/_/_/_/_/ #----- 画像の定義 ----- #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #ボスキャラクター sprite 'spr_boss' do image 'img_boss' origin :left_top end #ボス弾 sprite 'spr_boss_tama' do image 'img_boss_tama' origin :left_top end #---------- ここまで ---------- #----- 文字の定義 -----
ローカル変数の定義、初期化を行います。
#********** startシーン ここから ********** scene 'start' do #_/_/_/ ローカル変数の定義 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #システム関連 gameclear_flg = nil gameover_flg = nil score = nil; score_view = nil enemy_score = nil #---------- ここから ---------- boss_score = nil #---------- ここまで ---------- char_zan = nil; char_zan_view = nil enemy_zan = nil; enemy_zan_view = nil #---------- ここから ---------- boss_zan = nil #---------- ここまで ---------- #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #ボスキャラクターオブジェクト obj_boss_spr = nil obj_boss_pos_x = nil; obj_boss_pos_y = nil obj_boss_size_w = nil; obj_boss_size_h = nil obj_boss_pos_x_old = nil; obj_boss_pos_y_old = nil obj_boss_speed = nil obj_boss_speed_r_x = nil; obj_boss_speed_r_y = nil obj_boss_w_max = nil obj_boss_hit_time = nil obj_boss_invincible_time = nil obj_boss_hit_x = nil; obj_boss_hit_y = nil obj_boss_hit_w = nil; obj_boss_hit_h = nil obj_boss_ai = nil obj_boss_ai_next_y = nil obj_boss_ai_count = nil #ボス弾オブジェクト obj_boss_tama_spr = [] obj_boss_tama_pos_x = []; obj_boss_tama_pos_y = [] obj_boss_tama_size_w = nil; obj_boss_tama_size_h = nil obj_boss_tama_scale_x = []; obj_boss_tama_scale_y = [] obj_boss_tama_scale_count = [] obj_boss_tama_speed = nil obj_boss_tama_pos_x_old = []; obj_boss_tama_pos_y_old = [] obj_boss_tama_h_max = nil obj_boss_tama_hit_x = nil; obj_boss_tama_hit_y = nil obj_boss_tama_hit_w = nil; obj_boss_tama_hit_h = nil obj_boss_tama_flg = [] obj_boss_tama_max = nil obj_boss_tama_next = nil obj_boss_tama_next_time = nil #---------- ここまで ---------- #~~~~~~~~~~ 中略 ~~~~~~~~~~ create do #----- シーンロード時に実行される処理 ----- #_/_/_/ 変数の初期化 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #ボスキャラクターオブジェクト obj_boss_pos_x = 800; obj_boss_pos_y = 600 obj_boss_size_w = 256; obj_boss_size_h = 160 obj_boss_pos_x_old = obj_boss_pos_x obj_boss_pos_y_old = obj_boss_pos_y obj_boss_speed = 3 obj_boss_speed_r_x = 0; obj_boss_speed_r_y = 0 obj_boss_w_max = (800 - obj_boss_size_w) obj_boss_hit_time = (-1) obj_boss_invincible_time = (60 * 1) obj_boss_hit_x = 60; obj_boss_hit_y = 50 obj_boss_hit_w = 196; obj_boss_hit_h = 140 obj_boss_ai = 'wait' obj_boss_ai_next_y = 60 obj_boss_ai_count = 0 #ボス弾オブジェクト obj_boss_tama_size_w = 16; obj_boss_tama_size_h = 64 obj_boss_tama_speed = 6 obj_boss_tama_hit_x = 1; obj_boss_tama_hit_y = 0 obj_boss_tama_hit_w = 15; obj_boss_tama_hit_h = 64 obj_boss_tama_h_max = (600 + obj_boss_tama_size_h) obj_boss_tama_max = 10 obj_boss_tama_next = (60 * 0.75) obj_boss_tama_next_time = 0 obj_boss_tama_next_type = 'wait' i = 0; ilen = obj_boss_tama_max while i < ilen do obj_boss_tama_pos_x[i] = 0 obj_boss_tama_pos_y[i] = ((-64) * 2) obj_boss_tama_scale_x[i] = 1; obj_boss_tama_scale_y[i] = 0 obj_boss_tama_scale_count[i] = 0 obj_boss_tama_pos_x_old[i] = obj_boss_tama_pos_x[i] obj_boss_tama_pos_y_old[i] = obj_boss_tama_pos_y[i] obj_boss_tama_flg[i] = false i += 1 end #---------- ここまで ----------
画像オブジェクトを生成します。
#_/_/_/ 素材の初期化 _/_/_/ #~~~~~~~~~~ 中略 ~~~~~~~~~~ #アニメーションの開始 obj_char_spr.start_animation('neutral') #---------- ここから ---------- #ボスキャラクター obj_boss_spr = put_sprite 'spr_boss' do position obj_boss_pos_x, obj_boss_pos_y src_rect 0, 0, obj_boss_size_w, obj_boss_size_h end #---------- ここまで ---------- #プレイヤー弾 i = 0; ilen = obj_char_tama_max while i < ilen do #~~~~~~~~~~ 中略 ~~~~~~~~~~ #---------- ここから ---------- #ボス弾 i = 0; ilen = obj_boss_tama_max while i < ilen do obj_boss_tama_spr[i] = put_sprite 'spr_boss_tama' do position obj_boss_tama_pos_x[i], obj_boss_tama_pos_y[i] src_rect 0, 0, 16, 64 end obj_boss_tama_spr[i].scale obj_boss_tama_scale_x[i], obj_boss_tama_scale_y[i] i += 1 end #---------- ここまで ----------
ボスキャラクターの上を弾の表示が通過するように
スクリプトの順序を組み立てているところがポイントです。
ゲームクリア処理としていた部分を
ボスの登場に変更します。
#---------- ここから変更 ---------- #ボスの出現 if (enemy_zan == 0) && (wrk_enemy_count == 0) && (obj_boss_ai == 'wait') obj_boss_ai = 'start' obj_boss_pos_x = (800 - obj_boss_size_w) / 2 obj_boss_pos_y = (0 - obj_boss_size_h) end #---------- ここまで変更 ----------
ボスキャラクターの行動処理を追加します。
#---------- ここから ---------- #--- ボスキャラクター --- if obj_boss_ai != 'wait' #AIによってボスの移動パターンを変更 case obj_boss_ai when 'left' then #左移動中 obj_boss_pos_x -= obj_boss_speed when 'right' then #右移動中 obj_boss_pos_x += obj_boss_speed when 'bomb' obj_boss_pos_y -= (obj_boss_speed / 3) else #登場シーン obj_boss_pos_y += (obj_boss_speed / 2) end #ボスキャラクターの移動範囲制限 if obj_boss_pos_x < 0 obj_boss_pos_x = 0 obj_boss_ai = 'right' end if obj_boss_pos_x > obj_boss_w_max obj_boss_pos_x = obj_boss_w_max obj_boss_ai = 'left' end if obj_boss_pos_y > obj_boss_ai_next_y obj_boss_pos_y = obj_boss_ai_next_y obj_boss_ai = 'right' end #プレイヤーキャラクターとの当たり判定 if (obj_char_hit_time < 0) && ((obj_char_pos_x + obj_char_hit_x) < (obj_boss_pos_x_old + obj_boss_hit_w)) && ((obj_char_pos_x + obj_char_hit_w) > (obj_boss_pos_x_old + obj_boss_hit_x)) && ((obj_char_pos_y + obj_char_hit_y) < (obj_boss_pos_y_old + obj_boss_hit_h)) && ((obj_char_pos_y + obj_char_hit_h) > (obj_boss_pos_y_old + obj_boss_hit_y)) #プレイヤーキャラクターの残機を変更 char_zan -= 1 #プレイヤーキャラクターに無敵時間を設定 obj_char_hit_time = obj_char_invincible_time end #ボスキャラクターのオブジェクトを移動する if (obj_boss_pos_x_old != obj_boss_pos_x) || (obj_boss_pos_y_old != obj_boss_pos_y) obj_boss_pos_x_old = obj_boss_pos_x obj_boss_pos_y_old = obj_boss_pos_y obj_boss_spr.position obj_boss_pos_x, obj_boss_pos_y end #ボスキャラクターの無敵時間をカウント if (obj_boss_hit_time > (-1)) || (obj_boss_ai == 'bomb') obj_boss_hit_time -= 1 if obj_boss_hit_time < (-1) obj_boss_hit_time = obj_boss_invincible_time end #無敵時間の場合プレイヤーキャラクターを点滅表示する if obj_boss_hit_time == 0 setAlpha(obj_boss_spr, 1) elsif ((obj_boss_hit_time % 10) == 0) setAlpha(obj_boss_spr, 1) elsif ((obj_boss_hit_time % 5) == 0) setAlpha(obj_boss_spr, 0) elsif ((obj_boss_hit_time % 3) == 0) setAlpha(obj_boss_spr, 0.5) end end end #---------- ここまで ----------
ボス弾の行動処理を追加します。
#---------- ここから ---------- #--- ボス弾 --- #ボス弾の発射カウントダウン if obj_boss_tama_next_time > (-1) && ((obj_boss_ai == 'left') || (obj_boss_ai == 'right')) obj_boss_tama_next_time -= 1 end #ボス弾の発射 if obj_boss_tama_next_time < 0 obj_boss_tama_next_time = obj_boss_tama_next #2発同時に発射するカウンター wrk_start_count = 0 i = 0; ilen = obj_boss_tama_max while i < ilen do #待機状態のボス弾を探す if !obj_boss_tama_flg[i] #ボス弾を移動状態にする if wrk_start_count < 1 obj_boss_tama_pos_x[i] = obj_boss_pos_x + ((obj_boss_size_w - obj_boss_tama_size_w) / 2) - 27 obj_boss_tama_pos_y[i] = obj_boss_pos_y + obj_boss_size_h - 20 else obj_boss_tama_pos_x[i] = obj_boss_pos_x + ((obj_boss_size_w - obj_boss_tama_size_w) / 2) + 27 obj_boss_tama_pos_y[i] = obj_boss_pos_y + obj_boss_size_h - 20 end obj_boss_tama_scale_x[i] = 1; obj_boss_tama_scale_y[i] = 0 obj_boss_tama_scale_count[i] = 0 obj_boss_tama_flg[i] = true #ループを終了させる wrk_start_count += 1 if wrk_start_count > 1 i = ilen end end i += 1 end end #ボス弾の移動 i = 0; ilen = obj_boss_tama_max while i < ilen do if obj_boss_tama_flg[i] #ボス弾の座標値を移動させる if obj_boss_tama_scale_y[i] < 1 case obj_boss_ai when 'left' then #左移動中 obj_boss_tama_pos_x[i] -= obj_boss_speed when 'right' then #右移動中 obj_boss_tama_pos_x[i] += obj_boss_speed else end obj_boss_tama_scale_count[i] += 1 obj_boss_tama_scale_y[i] = (obj_boss_tama_speed * obj_boss_tama_scale_count[i]) / obj_boss_tama_size_h if obj_boss_tama_scale_y[i] > 1 obj_boss_tama_scale_y[i] = 1 end else obj_boss_tama_pos_y[i] += obj_boss_tama_speed end #プレイヤーキャラクターとの当たり判定 wrk_char_hit_flg = false if (obj_char_hit_time < 0) && ((obj_char_pos_x + obj_char_hit_x) < (obj_boss_tama_pos_x_old[i] + obj_boss_tama_hit_w)) && ((obj_char_pos_x + obj_char_hit_w) > (obj_boss_tama_pos_x_old[i] + obj_boss_tama_hit_x)) && ((obj_char_pos_y + obj_char_hit_y) < (obj_boss_tama_pos_y_old[i] + obj_boss_tama_hit_h)) && ((obj_char_pos_y + obj_char_hit_h) > (obj_boss_tama_pos_y_old[i] + obj_boss_tama_hit_y)) #プレイヤーキャラクターの残機を変更 char_zan -= 1 #プレイヤーキャラクターに無敵時間を設定 obj_char_hit_time = obj_char_invincible_time wrk_char_hit_flg = true end #ボス弾の移動範囲制限 if wrk_char_hit_flg || (obj_boss_tama_pos_y[i] > obj_boss_tama_h_max) obj_boss_tama_pos_x[i] = 800; obj_boss_tama_pos_y[i] = 600 obj_boss_tama_flg[i] = false obj_boss_tama_scale_x[i] = 1; obj_boss_tama_scale_y[i] = 0 obj_boss_tama_scale_count[i] = 0 end #ボス弾のオブジェクトを移動する if (obj_boss_tama_pos_x_old[i] != obj_boss_tama_pos_x[i]) || (obj_boss_tama_pos_y_old[i] != obj_boss_tama_pos_y[i]) obj_boss_tama_pos_x_old[i] = obj_boss_tama_pos_x[i] obj_boss_tama_pos_y_old[i] = obj_boss_tama_pos_y[i] obj_boss_tama_spr[i].position obj_boss_tama_pos_x[i], obj_boss_tama_pos_y[i] obj_boss_tama_spr[i].scale obj_boss_tama_scale_x[i], obj_boss_tama_scale_y[i] end end i += 1 end #---------- ここまで ----------
ボスキャラクターとプレイヤー弾の
当たり判定を追加します。
#プレイヤー弾の移動 #~~~~~~~~~~ 中略 ~~~~~~~~~~ #プレイヤー弾のサイズ値を変更する if obj_char_tama_scale_y[i] < 1 obj_char_tama_scale_count[i] += 1 obj_char_tama_scale_y[i] = (obj_char_tama_speed * obj_char_tama_scale_count[i]) / obj_char_tama_size_h if obj_char_tama_scale_y[i] > 1 obj_char_tama_scale_y[i] = 1 end end #---------- ここから ---------- #ボスキャラクターとの当たり判定 wrk_boss_hit_flg = false if ((obj_boss_ai == 'left') || (obj_boss_ai == 'right')) && (obj_boss_hit_time < 0) && ((obj_boss_pos_x + obj_boss_hit_x) < (obj_char_tama_pos_x_old[i] + obj_char_tama_hit_w)) && ((obj_boss_pos_x + obj_boss_hit_w) > (obj_char_tama_pos_x_old[i] + obj_char_tama_hit_x)) && ((obj_boss_pos_y + obj_boss_hit_y) < (obj_char_tama_pos_y_old[i] + obj_char_tama_hit_h)) && ((obj_boss_pos_y + obj_boss_hit_h) > (obj_char_tama_pos_y_old[i] + obj_char_tama_hit_y)) wrk_boss_hit_flg = true #ボスキャラクターの残ライフを変更 boss_zan -= 1 if boss_zan < 1 #スコアの加算 score += boss_score obj_boss_ai = 'bomb' end #ボスキャラクターに無敵時間を設定 obj_boss_hit_time = obj_boss_invincible_time end #---------- ここまで ---------- #プレイヤー弾の移動範囲制限
ゲームクリアの条件を追加します。
#---------- ここから ---------- #ゲームクリア if (obj_boss_ai == 'bomb') && (obj_boss_pos_y < (0 - obj_boss_size_h)) gameclear_flg = true end #---------- ここまで ----------
ボス討伐など大きなスコアを獲得した場合の
表示処理を変更します。
#スコア表示の変更 if score_view < score #---------- ここから変更 ---------- if (score - score_view) > 1000 score_view += 39 else score_view += 17 end #---------- ここまで変更 ---------- if score_view > score score_view = score end
シーン移動前に画像素材、配列を開放する処理を追加します。
#画像素材を開放する #~~~~~~~~~~ 中略 ~~~~~~~~~~ i = 0; ilen = obj_enemy_tama_max while i < ilen do obj_enemy_tama_spr[i].destroy i += 1 end #---------- ここから ---------- obj_boss_spr.destroy i = 0; ilen = obj_boss_tama_max while i < ilen do obj_boss_tama_spr[i].destroy i += 1 end #---------- ここまで ---------- #~~~~~~~~~~ 中略 ~~~~~~~~~~ obj_enemy_tama_anime.clear obj_enemy_tama_next_time.clear #---------- ここから ---------- obj_boss_tama_pos_x.clear obj_boss_tama_pos_y.clear obj_boss_tama_scale_x.clear; obj_boss_tama_scale_y.clear obj_boss_tama_scale_count.clear obj_boss_tama_pos_x_old.clear obj_boss_tama_pos_y_old.clear obj_boss_tama_flg.clear #---------- ここまで ----------
ゲームの終了時に
アクティビティフィードを出力できるようにします。
obj_boss_tama_flg.clear #---------- ここから ---------- #アクティビティフィードの送信 wrk_str = 'SCORE ' + (score).to_s wrk_result = send_activity_feed(wrk_str) #---------- ここまで ---------- if gameclear_flg #ゲームクリア画面に移動 game_clear
他、仕上げに
音楽や効果音を追加して
ゲーム全体の雰囲気を盛り上げます。
(今回までのスクリプト全体参照)
ここまででボスの登場と
ゲーム全体を仕上げるスクリプトが出来ました。
画面上部メニューにある、「保存をして実行」を押して
実際のゲーム画面を確認してみましょう。
07-04 おわりに
いかがでしたでしょうか。
今回のシリーズではシューティングゲームの
基本的なところをつくりましたが、
敵の種類を増やしてみたり、
キャラクターを強化するアイテムを登場させてみたり
まだまだアレンジをしてみることができます。
また、他のジャンルのゲームも、基本的なポイントは同じであり、
キャラクターなどの動きや当たり判定の方法を変更していけば、
つくってみることもできるでしょう。
是非いろいろなゲーム制作に挑戦してみてください。
今回までのスクリプト全体
CoRでゲームをつくってみよう / 第07回
第01回 CoRの開発準備をしよう
第02回 画面に背景やキャラクターを描画する
第03回 背景やキャラクターを動かす
第04回 敵キャラクターを登場させる
第05回 弾を発射する
第06回 ゲームとして必要な機能を追加する
第07回 より面白くするために
コメントする
コメントするには、ログインする必要があります。
ボス戦への移り変わりなど、
ゲーム内で場面が切り替わるようなものは多分作ったことないですが
単純に変数を駆使してゲームに動きをつけるというイメージができました。
様々な基準を取る方法がありますが
いずれも、変数の応用で
組み上げることが可能です。