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回 より面白くするために
コメントする
コメントするには、ログインする必要があります。
ボス戦への移り変わりなど、
ゲーム内で場面が切り替わるようなものは多分作ったことないですが
単純に変数を駆使してゲームに動きをつけるというイメージができました。
様々な基準を取る方法がありますが
いずれも、変数の応用で
組み上げることが可能です。