スクリプト/Rmakeで自由なゲームをつくろう / 第06回 より面白くするために(履歴ID:109)
最終投稿者: aoihikawa
更新:2011/08/30 09:50:45
Rmakeで自由なゲームをつくろう
第06回 敵キャラクターを登場させる
こんにちは。
フリーデザイナープログラマー(自称)の
簸川 葵(ひかわ あおい)と申します。
第05回 では弾を発射させるなど、
シューティングゲームとして完成するまでのお話でした。
第06回は、いよいよ最終回。
より面白くするために、様々な工夫の方法を紹介していきます。
06-01 敵に弾を発射させる
キャラクターが攻撃できるのに、
敵キャラクターが攻撃できないのは不公平ですね。
敵キャラクターにも弾を発射させてみましょう。
基本的な仕組みは、キャラクターの弾を発射させたときと同じです。
今回は、弾にアニメーションも付けてみましょう。
今回もまた、恒例のサンプルの素材を準備いたしました。
第02回を参考に、クリップからリソースへの登録まで行い、
すぐにスクリプトで利用できるように、準備してください。
それでは、まずは関数の準備から。
#ここから↑は省略 #敵キャラクターの表示内容を変更する関数 def setEnemySpritePattern(no, i) img_enemy_name = "img_enemy" get_x = 0; get_y = 0; get_w = 64; get_h = 64 set_x = 0; set_y = 0; set_w = 64; set_h = 64 if no == 1 get_x = 0; get_y = 0 elsif no == 2 get_x = 64; get_y = 0 elsif no == 3 get_x = 128; get_y = 0 elsif no == 4 get_x = 192; get_y = 0 else get_w = 0; get_h = 0 set_w = 0; set_h = 0 end setSpriteRect(getVariable(img_enemy_name)[i], get_x, get_y, get_w, get_h, set_x, set_y, set_w, set_h) end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクター弾の表示内容を変更する関数 def setEnemyTamaSpritePattern(no, i) img_enemy_tama_name = "img_enemy_tama" get_x = 0; get_y = 0; get_w = 16; get_h = 16 set_x = 0; set_y = 0; set_w = 16; set_h = 16 if no == 1 get_x = 0; get_y = 0 elsif no == 2 get_x = 16; get_y = 0 elsif no == 3 get_x = 32; get_y = 0 else get_w = 0; get_h = 0 set_w = 0; set_h = 0 end setSpriteRect(getVariable(img_enemy_tama_name)[i], get_x, get_y, get_w, get_h, set_x, set_y, set_w, set_h) end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
続いて、定数の設定
#ここから↑は省略 #敵キャラクターの設定 max_enemy = 3 enemy_speed = 5 enemy_baratuki = 20 enemy_w_max = 800 - 64; enemy_h_min = -64 enemy_anime_change = 2 enemy_hit = createArray() enemy_hit[x] = 20; enemy_hit[y] = 20 enemy_hit[w] = 24; enemy_hit[h] = 35 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクター弾の設定 max_enemy_tama = 6 enemy_tama_speed = 15 enemy_tama_w_max = 800 - 16 enemy_tama_anime_change = 2 enemy_tama_hassya_pos = createArray() enemy_tama_hassya_pos[0] = 50 enemy_tama_hassya_pos[1] = 190 enemy_tama_hit = createArray() enemy_tama_hit[x] = 3; enemy_tama_hit[y] = 3 enemy_tama_hit[w] = 10; enemy_tama_hit[h] = 10 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
「enemy_tama_hassya_pos」は敵キャラクターがこの設定値よりも
下に移動したとき、攻撃を行うボーダーラインの設定です。
次に、画像の設定。
#ここから↑は省略 #敵キャラクターの画像の設定 img_no = 77127 img_enemy_name = "img_enemy" get[x] = 0; get[y] = 0; get[w] = 64; get[h] = 64 set[x] = 0; set[y] = 0; set[w] = 64; set[h] = 64 set_z = 5 pos_enemy = createArray() i = 0 while i < max_enemy pos_enemy[i] = createArray() pos_enemy[i][x] = 800; pos_enemy[i][y] = 600 i = i + 1 end setCreateSprite(img_enemy_name, img_no, get, set, set_z, pos_enemy, max_enemy) #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクター弾の画像の設定 img_no = 77349 img_enemy_tama_name = "img_enemy_tama" get[x] = 0; get[y] = 0; get[w] = 16; get[h] = 16 set[x] = 0; set[y] = 0; set[w] = 16; set[h] = 16 set_z = 4 pos_enemy_tama = createArray() i = 0 while i < max_enemy_tama pos_enemy_tama[i] = createArray() pos_enemy_tama[i][x] = 800; pos_enemy_tama[i][y] = 600 i = i + 1 end setCreateSprite(img_enemy_tama_name, img_no, get, set, set_z, pos_enemy_tama, max_enemy_tama) #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
大体、パターンも覚えてきましたでしょうか。
次は、変数の設定です。
#ここから↑は省略 #敵キャラクター enemy_anime_count = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_tama_hassya_count = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ i = 0 while i < max_enemy enemy_anime_count[i] = -1 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_tama_hassya_count[i] = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ i = i + 1 end enemy_syutugen_count = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクター弾 enemy_tama_anime_count = createArray() i = 0 while i < max_enemy_tama enemy_tama_anime_count[i] = -1 i = i + 1 end enemy_tama_syutugen_count = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #キャラクターの非ダメージ char_damage = false #キャラクターの当たり判定範囲 char_atari = createArray() char_atari[x] = pos_char[x] + char_hit[x] char_atari[y] = pos_char[y] + char_hit[y] char_atari[w] = char_atari[x] + char_hit[w] char_atari[h] = char_atari[y] + char_hit[h] #キャラクター弾の発射間隔カウント char_tama_interval_count = 0 #キャラクター弾の当たり判定範囲 char_tama_atari = createArray() #敵キャラクターの当たり判定範囲 enemy_atari = createArray() i = 0 while i < max_enemy enemy_atari[i] = createArray() i = i + 1 end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクター弾の当たり判定範囲 enemy_tama_atari = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
先ほど説明しました、ボーダーラインを超えた数のカウントに
「enemy_tama_hassya_count」という変数を準備しています。
それでは、メインループ内のスクリプトへ。
まずは、敵キャラクター弾の発射から。
#ここから↑は省略 #敵キャラクターの当たり判定範囲 enemy_atari[i][x] = pos_enemy[i][x] + enemy_hit[x] enemy_atari[i][y] = pos_enemy[i][y] + enemy_hit[y] enemy_atari[i][w] = enemy_atari[i][x] + enemy_hit[w] enemy_atari[i][h] = enemy_atari[i][y] + enemy_hit[h] #当たり判定のチェック if ((char_atari[w]) > (enemy_atari[i][x])) && ((char_atari[h]) > (enemy_atari[i][y])) && ((char_atari[x]) < (enemy_atari[i][w])) && ((char_atari[y]) < (enemy_atari[i][h])) char_damage = true mainloop = false end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #弾の発射 j = enemy_tama_hassya_count[i] jlen = getArrayLength(enemy_tama_hassya_pos) if j < jlen if pos_enemy[i][y] > enemy_tama_hassya_pos[j] enemy_tama_syutugen_count = enemy_tama_syutugen_count + 1 #出現カウント k = 0 while k < max_enemy_tama if enemy_tama_anime_count[k] < 0 pos_enemy_tama[k][x] = pos_enemy[i][x] + 13 pos_enemy_tama[k][y] = pos_enemy[i][y] + 50 enemy_tama_anime_count[k] = 0 #アニメーションをリセット enemy_tama_hassya_count[i] = enemy_tama_hassya_count[i] + 1 k = max_enemy_tama end k = k + 1 end end end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
「getArrayLength」関数は、配列の長さを調べます。
発射した回数が、発射するボーダーラインの設定数に達しているかどうか
比較してスクリプトを分岐させています。
次のif文は敵キャラクターの位置と、ボーダーラインの比較ですね。
while文は、画面外に待機している弾の画像、
つまり「enemy_tama_anime_count」が「-1」になっている画像を探しています。
見つかったところで、発射状態の設定を行い、このループを抜けています。
発射時のX座標とY座標に微妙な数値を加算しているのは、
敵キャラクターの所持している、光線銃の場所から
発射しているように見せるための調整値です。
最後に弾のアニメーション、移動、当たり判定。
これは、敵キャラクターを追加したときと内容はほとんど一緒ですね。
アニメーションが3枚のループになっている点に気をつけましょう。
#ここから↑は省略 k = max_enemy_tama end k = k + 1 end end end end end i = i + 1 end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #----- 敵キャラクター弾のアニメーション ----- i = 0 while i < max_enemy_tama if enemy_tama_anime_count[i] > -1 #アニメーション用カウンター enemy_tama_anime_count[i] = enemy_tama_anime_count[i] + 1 if enemy_tama_anime_count[i] == (enemy_tama_anime_change * 3) enemy_tama_anime_count[i] = 0 #アニメーションをリセット end if enemy_tama_anime_count[i] < enemy_tama_anime_change setEnemyTamaSpritePattern(1, i) elsif enemy_tama_anime_count[i] < (enemy_tama_anime_change * 2) setEnemyTamaSpritePattern(2, i) else setEnemyTamaSpritePattern(3, i) end #敵キャラクター弾の移動 pos_enemy_tama[i][y] = pos_enemy_tama[i][y] + enemy_tama_speed if pos_enemy_tama[i][y] > 600 #敵キャラクター弾を初期値に戻す enemy_tama_syutugen_count = enemy_tama_syutugen_count - 1 #出現カウント pos_enemy_tama[i][x] = 800 pos_enemy_tama[i][y] = 600 enemy_tama_anime_count[i] = -1 end setSpritePos(img_enemy_tama_name, pos_enemy_tama, i) #敵キャラクター弾の当たり判定範囲 enemy_tama_atari[x] = pos_enemy_tama[i][x] + enemy_tama_hit[x] enemy_tama_atari[y] = pos_enemy_tama[i][y] + enemy_tama_hit[y] enemy_tama_atari[w] = enemy_tama_atari[x] + enemy_tama_hit[w] enemy_tama_atari[h] = enemy_tama_atari[y] + enemy_tama_hit[h] #当たり判定のチェック if ((char_atari[w]) > (enemy_tama_atari[x])) && ((char_atari[h]) > (enemy_tama_atari[y])) && ((char_atari[x]) < (enemy_tama_atari[w])) && ((char_atari[y]) < (enemy_tama_atari[h])) char_damage = true mainloop = false end end i = i + 1 end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #----- キャラクター弾のアニメーション ----- i = 0 while i < max_char_tama #ここから↓は省略
ここまでで、敵キャラクターが弾を発射してくるようになりました。
完成したら、テストプレーを行ってみましょう。
06-02 敵にAIを搭載する
敵キャラクターの動きがワンパターンでは、
やっぱり物足りない感じがしてしまいます。
今度は、簡単なAIを搭載して、
動きを変化させてみることにしましょう。
まずは定数の準備から。
#ここから↑は省略 #敵キャラクターの設定 max_enemy = 3 enemy_speed = 5 enemy_baratuki = 20 enemy_w_max = 800 - 64; enemy_h_min = -64 enemy_anime_change = 2 enemy_hit = createArray() enemy_hit[x] = 20; enemy_hit[y] = 20 enemy_hit[w] = 24; enemy_hit[h] = 35 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_ai_pattern = 3 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
「enemy_ai_pattern」には、AIの種類を設定しておきます。
次は変数の準備。
現在のAIの状態を保管しておく変数を準備しておきます。
#ここから↑は省略 #アニメーション用カウンター #キャラクター char_anime_count = 0 #キャラクター弾 char_tama_anime_count = createArray() i = 0 while i < max_char_tama char_tama_anime_count[i] = -1 i = i + 1 end char_tama_syutugen_count = 0 #敵キャラクター enemy_anime_count = createArray() enemy_tama_hassya_count = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_ai = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ i = 0 while i < max_enemy enemy_anime_count[i] = -1 enemy_tama_hassya_count[i] = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_ai[i] = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ i = i + 1 end enemy_syutugen_count = 0 #ここから↓は省略
メインスクリプト。
敵キャラクターの登場時にAIをランダムで決定、
移動のスクリプトを関数に渡して行ってもらい、
結果を配列で受けとっています。
#ここから↑は省略 #----- 敵キャラクターのアニメーション ----- i = 0 while i < max_enemy #敵キャラクターを出現させる if (enemy_syutugen_count < max_enemy) && (enemy_anime_count[i] < 0) if rand(enemy_baratuki) == 0 #出現カウントが最大値より少なく、アニメーションがマイナス(初期値)の場合 enemy_syutugen_count = enemy_syutugen_count + 1 #出現カウント pos_enemy[i][x] = rand(enemy_w_max) pos_enemy[i][y] = enemy_h_min enemy_anime_count[i] = 0 #アニメーションをリセット enemy_tama_hassya_count[i] = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_ai[i] = rand(enemy_ai_pattern) #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ end end #中略 #敵キャラクターの移動 #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ ret_data = retEnemyAI(pos_enemy[i], enemy_speed, enemy_ai[i], enemy_w_max) pos_enemy[i] = ret_data[0] enemy_ai[i] = ret_data[1] #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ if pos_enemy[i][y] > 600 #敵キャラクターを初期値に戻す enemy_syutugen_count = enemy_syutugen_count - 1 #出現カウント pos_enemy[i][x] = 800 pos_enemy[i][y] = 600 enemy_anime_count[i] = -1 end setSpritePos(img_enemy_name, pos_enemy, i) #ここから↓は省略
最後に、AIによって移動を切り替えて実行する関数の作成。
今回は直線移動、斜め移動の右方向、左方向の3種類を実装します。
#ここから↑は省略 #敵キャラクター弾の表示内容を変更する関数 def setEnemyTamaSpritePattern(no, i) img_enemy_name = "img_enemy_tama" get_x = 0; get_y = 0; get_w = 16; get_h = 16 set_x = 0; set_y = 0; set_w = 16; set_h = 16 if no == 1 get_x = 0; get_y = 0 elsif no == 2 get_x = 16; get_y = 0 elsif no == 3 get_x = 32; get_y = 0 else get_w = 0; get_h = 0 set_w = 0; set_h = 0 end setSpriteRect(getVariable(img_enemy_name)[i], get_x, get_y, get_w, get_h, set_x, set_y, set_w, set_h) end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクターのAI実行関数 def retEnemyAI(pos_enemy, enemy_speed, enemy_ai, enemy_w_max) x = 0; y = 1 if enemy_ai == 0 #直線移動 pos_enemy[y] = pos_enemy[y] + floor(enemy_speed * 1.5) elsif enemy_ai == 1 #右下へ移動 pos_enemy[x] = pos_enemy[x] + (enemy_speed * 3) pos_enemy[y] = pos_enemy[y] + enemy_speed if pos_enemy[x] > enemy_w_max #右端に到達 pos_enemy[x] = enemy_w_max enemy_ai = 2 #AIの切り替え end else #左下へ移動 pos_enemy[x] = pos_enemy[x] - (enemy_speed * 3) pos_enemy[y] = pos_enemy[y] + enemy_speed if pos_enemy[x] < 0 #左端に到達 pos_enemy[x] = 0 enemy_ai = 1 #AIの切り替え end end ret_data = createArray() ret_data[0] = pos_enemy ret_data[1] = enemy_ai return ret_data end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #----- 定数の設定 ----- #ここから↓は省略
「floor」は小数点以下を切り捨てる関数です。
右下、左下へ移動するAIの場合、画面外へ消えていってしまわないよう、
端に到達したときにAIを切り替えるスクリプトにしています。
ここまでで、敵キャラクターにAIが搭載されました。
完成したら、テストプレーを行ってみましょう。
06-03 ボスを登場させる
同じ敵だけではなく、他の種類の敵も登場させてみましょう。
最後の1体になったとき、ボスが出現するようにします。
今回もまた、恒例のサンプルの素材を準備いたしました。
第02回を参考に、クリップからリソースへの登録まで行い、
すぐにスクリプトで利用できるように、準備してください。
それでは、関数の追加から。
#ここから↑は省略 #敵キャラクター弾の表示内容を変更する関数 def setEnemyTamaSpritePattern(no, i) img_enemy_tama_name = "img_enemy_tama" get_x = 0; get_y = 0; get_w = 16; get_h = 16 set_x = 0; set_y = 0; set_w = 16; set_h = 16 if no == 1 get_x = 0; get_y = 0 elsif no == 2 get_x = 16; get_y = 0 elsif no == 3 get_x = 32; get_y = 0 else get_w = 0; get_h = 0 set_w = 0; set_h = 0 end setSpriteRect(getVariable(img_enemy_tama_name)[i], get_x, get_y, get_w, get_h, set_x, set_y, set_w, set_h) end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #ボスキャラクターの表示内容を変更する関数 def setBossSpritePattern(no) img_boss_name = "img_boss" get_x = 0; get_y = 0; get_w = 256; get_h = 160 set_x = 0; set_y = 0; set_w = 256; set_h = 160 if no == 1 get_x = 0; get_y = 0 else get_w = 0; get_h = 0 set_w = 0; set_h = 0 end setSpriteRect(getVariable(img_boss_name), get_x, get_y, get_w, get_h, set_x, set_y, set_w, set_h) end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #敵キャラクターのAI実行関数 def retEnemyAI(pos_enemy, enemy_speed, enemy_ai, enemy_w_max) x = 0; y = 1 if enemy_ai == 0 #直線移動 pos_enemy[y] = pos_enemy[y] + floor(enemy_speed * 1.5) elsif enemy_ai == 1 #右下へ移動 pos_enemy[x] = pos_enemy[x] + (enemy_speed * 3) pos_enemy[y] = pos_enemy[y] + enemy_speed if pos_enemy[x] > enemy_w_max #右端に到達 pos_enemy[x] = enemy_w_max enemy_ai = 2 #AIの切り替え end #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ elsif enemy_ai == 2 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #左下へ移動 pos_enemy[x] = pos_enemy[x] - (enemy_speed * 3) pos_enemy[y] = pos_enemy[y] + enemy_speed if pos_enemy[x] < 0 #左端に到達 pos_enemy[x] = 0 enemy_ai = 1 #AIの切り替え end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ elsif enemy_ai == 30 #直線移動 pos_enemy[y] = pos_enemy[y] + enemy_speed if pos_enemy[y] > 20 enemy_ai = (rand(2) + 31) end elsif enemy_ai == 31 pos_enemy[x] = pos_enemy[x] + floor(enemy_speed * 1.5) if pos_enemy[x] > enemy_w_max #右端に到達 pos_enemy[x] = enemy_w_max enemy_ai = 32 #AIの切り替え end else pos_enemy[x] = pos_enemy[x] - floor(enemy_speed * 1.5) if pos_enemy[x] < -96 #左端に到達 pos_enemy[x] = -96 enemy_ai = 31 #AIの切り替え end end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ ret_data = createArray() ret_data[0] = pos_enemy ret_data[1] = enemy_ai return ret_data end #ここから↓は省略
ボスの表示を切り替える関数の追加と、
AIの関数にボスの動きで使用する30番台を追加しています。
それでは、定数の準備。
#ここから↑は省略 #敵キャラクター弾の設定 max_enemy_tama = 6 enemy_tama_speed = 15 enemy_tama_w_max = 800 - 16 enemy_tama_anime_change = 2 enemy_tama_hassya_pos = createArray() enemy_tama_hassya_pos[0] = 50 enemy_tama_hassya_pos[1] = 190 enemy_tama_hit = createArray() enemy_tama_hit[x] = 3; enemy_tama_hit[y] = 3 enemy_tama_hit[w] = 10; enemy_tama_hit[h] = 10 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #ボスキャラクターの設定 boss_speed = 8 boss_max_life = 30 boss_w_max = 800 - 160 boss_hit = createArray() boss_hit[x] = 60; boss_hit[y] = 50 boss_hit[w] = 136; boss_hit[h] = 90 #ボスキャラクター弾の設定 max_boss_tama = 6 boss_tama_interval = 9 boss_tama_speed = 20 boss_tama_hit = createArray() boss_tama_hit[x] = 1; boss_tama_hit[y] = 0 boss_tama_hit[w] = 14; boss_tama_hit[h] = 64 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #残撃破数の設定 gekiha_max = 30 #音楽・効果音の設定 bgm_main = 77253 bgm_vol = 0.7 se_hit = 63622 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ se_hit2 = 78638 se_bomb = 78639 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ se_vol = 1 #ここから↓は省略
「boss_max_life」はボスの最大ライフ、
「boss_tama_interval」はボスの攻撃間隔を設定しています。
また、新規に効果音を2つ追加しています。
続いて画像の設定
#ここから↑は省略 #敵キャラクター弾の画像の設定 img_no = 77349 img_enemy_tama_name = "img_enemy_tama" get[x] = 0; get[y] = 0; get[w] = 16; get[h] = 16 set[x] = 0; set[y] = 0; set[w] = 16; set[h] = 16 set_z = 4 pos_enemy_tama = createArray() i = 0 while i < max_enemy_tama pos_enemy_tama[i] = createArray() pos_enemy_tama[i][x] = 800; pos_enemy_tama[i][y] = 600 i = i + 1 end setCreateSprite(img_enemy_tama_name, img_no, get, set, set_z, pos_enemy_tama, max_enemy_tama) #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #ボスキャラクター画像の設定 img_no = 78549 img_boss_name = "img_boss" get[x] = 0; get[y] = 0; get[w] = 256; get[h] = 160 set[x] = 0; set[y] = 0; set[w] = 256; set[h] = 160 set_z = 5 pos_boss = createArray() pos_boss[x] = 800; pos_boss[y] = 600 setCreateSprite(img_boss_name, img_no, get, set, set_z, pos_boss) #ボスキャラクター弾の画像の設定 img_no = 77649 img_boss_tama_name = "img_boss_tama" get[x] = 0; get[y] = 0; get[w] = 16; get[h] = 64 set[x] = 0; set[y] = 0; set[w] = 16; set[h] = 64 set_z = 4 pos_boss_tama = createArray() i = 0 while i < max_boss_tama pos_boss_tama[i] = createArray() pos_boss_tama[i][x] = 800; pos_enemy_tama[i][y] = 600 i = i + 1 end setCreateSprite(img_boss_tama_name, img_no, get, set, set_z, pos_boss_tama, max_boss_tama) #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
次は変数の設定
#ここから↑は省略 #敵キャラクター弾 enemy_tama_anime_count = createArray() i = 0 while i < max_enemy_tama enemy_tama_anime_count[i] = -1 i = i + 1 end enemy_tama_syutugen_count = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #ボスキャラクター boss_anime_count = -1 boss_ai = 0 boss_life = boss_max_life #ボスキャラクター弾 boss_tama_anime_count = createArray() i = 0 while i < max_boss_tama boss_tama_anime_count[i] = -1 i = i + 1 end boss_tama_syutugen_count = 0 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #中略 #敵キャラクター弾の当たり判定範囲 enemy_tama_atari = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #ボスキャラクターの当たり判定範囲 boss_atari = createArray() #ボスキャラクター弾の発射間隔カウント boss_tama_interval_count = 0 #ボスキャラクター弾の当たり判定範囲 boss_tama_atari = createArray() #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #残撃破数の設定 gekiha_count = gekiha_max #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ enemy_zan_syutugen_count = max_enemy #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
「enemy_zan_syutugen_count」は最後の1体でボスを登場させるため
通常の敵キャラクターの出現調整に使用します。
効果音の準備
#ここから↑は省略 #効果音の事前準備 se_id = playSound(se_hit); setSoundVolume(se_id, 0) #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ se_id = playSound(se_hit2); setSoundVolume(se_id, 0) se_id = playSound(se_bomb); setSoundVolume(se_id, 0) #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #音楽の再生開始 playBGM(bgm_main); setMusicVolume(bgm_vol) #ここから↓は省略
メインループ、ボスキャラクターと発射する弾のスクリプト
#ここから↑は省略 #敵キャラクター弾の当たり判定範囲 enemy_tama_atari[x] = pos_enemy_tama[i][x] + enemy_tama_hit[x] enemy_tama_atari[y] = pos_enemy_tama[i][y] + enemy_tama_hit[y] enemy_tama_atari[w] = enemy_tama_atari[x] + enemy_tama_hit[w] enemy_tama_atari[h] = enemy_tama_atari[y] + enemy_tama_hit[h] #当たり判定のチェック if ((char_atari[w]) > (enemy_tama_atari[x])) && ((char_atari[h]) > (enemy_tama_atari[y])) && ((char_atari[x]) < (enemy_tama_atari[w])) && ((char_atari[y]) < (enemy_tama_atari[h])) char_damage = true mainloop = false end end i = i + 1 end end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #----- ボスキャラクターのアニメーション ----- if boss_anime_count > 2 boss_anime_count = boss_anime_count + 1 if (boss_anime_count % 2) == 0 setBossSpritePattern(1) else setBossSpritePattern(0) end if (boss_anime_count % 3) == 0 #効果音 se_id = playSound(se_bomb); setSoundVolume(se_id, se_vol) end if boss_anime_count > 30 gekiha_count = 0 #残撃破が0になったらゲームクリア mainloop = false end elsif boss_anime_count > 0 boss_anime_count = boss_anime_count - 1 if (boss_anime_count % 2) == 0 setBossSpritePattern(1) else setBossSpritePattern(0) end #ボスキャラクターの移動 ret_data = retEnemyAI(pos_boss, boss_speed, boss_ai, boss_w_max) pos_boss = ret_data[0] boss_ai = ret_data[1] setSpritePos(img_boss_name, pos_boss) elsif boss_anime_count > -1 #ボスキャラクターの移動 ret_data = retEnemyAI(pos_boss, boss_speed, boss_ai, boss_w_max) pos_boss = ret_data[0] boss_ai = ret_data[1] setSpritePos(img_boss_name, pos_boss) #敵キャラクターの当たり判定範囲 boss_atari[x] = pos_boss[x] + boss_hit[x] boss_atari[y] = pos_boss[y] + boss_hit[y] boss_atari[w] = boss_atari[x] + boss_hit[w] boss_atari[h] = boss_atari[y] + boss_hit[h] #当たり判定のチェック if ((char_atari[w]) > (boss_atari[x])) && ((char_atari[h]) > (boss_atari[y])) && ((char_atari[x]) < (boss_atari[w])) && ((char_atari[y]) < (boss_atari[h])) char_damage = true mainloop = false end boss_tama_interval_count = boss_tama_interval_count + 1 if (boss_tama_interval_count > boss_tama_interval) && (boss_tama_syutugen_count < max_boss_tama) boss_tama_interval_count = 0 boss_tama_syutugen_count = boss_tama_syutugen_count + 2 #弾の発射 i = 0 tama_count = 0 while i < max_boss_tama if boss_tama_anime_count[i] < 0 pos_boss_tama[i][x] = pos_boss[x] + 95 + (tama_count * 50) pos_boss_tama[i][y] = pos_boss[y] + 90 boss_tama_anime_count[i] = 0 tama_count = tama_count + 1 if tama_count > 1 i = max_char_tama end end i = i + 1 end end end #----- ボスキャラクター弾のアニメーション ----- if boss_tama_syutugen_count > 0 i = 0 while i < max_boss_tama if boss_tama_anime_count[i] > -1 #キャラクター弾の移動 pos_boss_tama[i][y] = pos_boss_tama[i][y] + boss_tama_speed if pos_boss_tama[i][y] > 600 #弾を初期値に戻す boss_tama_syutugen_count = boss_tama_syutugen_count - 1 #出現カウント pos_boss_tama[i][x] = 800 pos_boss_tama[i][y] = 600 boss_tama_anime_count[i] = -1 end setSpritePos(img_boss_tama_name, pos_boss_tama, i) #キャラクター弾の当たり判定範囲 boss_tama_atari[x] = pos_boss_tama[i][x] + boss_tama_hit[x] boss_tama_atari[y] = pos_boss_tama[i][y] + boss_tama_hit[y] boss_tama_atari[w] = boss_tama_atari[x] + boss_tama_hit[w] boss_tama_atari[h] = boss_tama_atari[y] + boss_tama_hit[h] #当たり判定のチェック if ((char_atari[w]) > (boss_tama_atari[x])) && ((char_atari[h]) > (boss_tama_atari[y])) && ((char_atari[x]) < (boss_tama_atari[w])) && ((char_atari[y]) < (boss_tama_atari[h])) char_damage = true mainloop = false end end i = i + 1 end end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
ボスキャラクターの動きは「boss_anime_count」の状態が
「-1」で出現前、「0」で出現中、「1~2」ダメージ中、「3以降」が撃破後
の動きになっています。
「3以降」は「30」になるまでカウントし、点滅表示や爆発音の再生を行っています。
「30」になったとき、メインループを抜けて、エンディング画面に移動します。
次に、敵キャラクターの出現制限と、ボスキャラクターの登場。
敵キャラクターを撃破したときのスクリプトに少し追加します。
#ここから↑は省略 #弾を初期値に戻す char_tama_syutugen_count = char_tama_syutugen_count - 1 #出現カウント pos_char_tama[i][x] = -64 pos_char_tama[i][y] = 600 char_tama_anime_count[i] = -1 setSpritePos(img_char_tama_name, pos_char_tama, i) #撃破カウント gekiha_count = gekiha_count - 1 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ if gekiha_count == 4 enemy_zan_syutugen_count = 2 elsif gekiha_count == 2 enemy_zan_syutugen_count = 1 elsif gekiha_count == 1 enemy_zan_syutugen_count = 0 #ボスキャラクターの登場 if boss_anime_count == -1 pos_boss[x] = ((800 - 256) / 2) pos_boss[y] = -160 boss_ai = 30 boss_life = boss_max_life boss_anime_count = 0 end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ elsif gekiha_count == 0 #残撃破が0になったらゲームクリア #mainloop = false #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ end #ここから↓は省略
「gekiha_count」の値によって
「enemy_zan_syutugen_count」を変更しています。
「gekiha_count」が残り1となったとき、
「enemy_zan_syutugen_count」を「0」にして
通常の敵キャラクターの登場をストップさせ、
同時にボスキャラクターを登場させています。
ボスを倒したとき、エンディングに移動するようになったため、
これまでのスクリプトをコメントにすることで無効化しています。
「enemy_zan_syutugen_count」によって
通常の敵キャラクターが登場する数を調整します。
スクリプトの位置は、若干上に戻ります。
#ここから↑は省略 #----- 敵キャラクターのアニメーション ----- i = 0 while i < max_enemy #敵キャラクターを出現させる #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ if (enemy_syutugen_count < enemy_zan_syutugen_count) && (enemy_anime_count[i] < 0) #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ if rand(enemy_baratuki) == 0 #出現カウントが最大値より少なく、アニメーションがマイナス(初期値)の場合 enemy_syutugen_count = enemy_syutugen_count + 1 #出現カウント #ここから↓は省略
最後に、ボスキャラクターとキャラクター弾との
当たり判定を行います。
#ここから↑は省略 #効果音 se_id = playSound(se_hit); setSoundVolume(se_id, se_vol) j = max_enemy end end j = j + 1 end #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ if boss_anime_count == 0 #当たり判定のチェック if ((char_tama_atari[w]) > (boss_atari[x])) && ((char_tama_atari[h]) > (boss_atari[y])) && ((char_tama_atari[x]) < (boss_atari[w])) && ((char_tama_atari[y]) < (boss_atari[h])) #弾を初期値に戻す char_tama_syutugen_count = char_tama_syutugen_count - 1 #出現カウント pos_char_tama[i][x] = -64 pos_char_tama[i][y] = 600 char_tama_anime_count[i] = -1 setSpritePos(img_char_tama_name, pos_char_tama, i) #ボスの残りHPを減算 if boss_life > 0 boss_life = boss_life - 1 boss_anime_count = 2 #効果音 se_id = playSound(se_hit2); setSoundVolume(se_id, se_vol) else boss_anime_count = 3 end end end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ end i = i + 1 end #----- 残撃破数の表示 ----- #ここから↓は省略
ボスキャラクターは敵キャラクターと異なり、
キャラクター弾に当たったとき、「boss_life」が減少するスクリプトに
変更しています。
「boss_life」が「0」になっている時の場合、
「boss_anime_count」を「3」、つまりボスキャラクターが「撃破後」の
状態に変更しています。
ここまでで、ボスキャラクターが登場するようになりました。
完成したら、テストプレーを行ってみましょう。
06-04 フレームスキップを実装する
さまざまな要素を追加していくと、少しずつスクリプトの動きが
重くなってきます。
特に、複雑な動きや、表示する内容の数を追加すると
局所的に重くなることもあります。
前者はスクリプトの改善を行うことで、軽くしていきますが、
表示する内容については減らしたくない場合もあります。
これを解決する方法として、「フレームスキップ」という手段があります。
「フレーム」とは、1秒あたりに何回描画を実行するかのことで、
重くなってきたときにこの描画をスキップ、飛ばしてしまうわけです。
フレームスキップも何を基準とするかによって、様々な方法がありますが、
今回は スクリプト/コツ/フレームスキップスクリプト で紹介しております
時間を基準に実装する方法で行います。
なお、変更箇所のみ記載いたしますので、
詳細の解説は、フレームスキップスクリプトのブログ記事を、参照して頂けると幸いです。
まずは定数の設定から。
同時に、フレームスキップが発生するか確認しやすくするために、
フレームスキップの規定値を低めに設定し、敵キャラクターの数を増加させています。
#ここから↑は省略 #----- 定数の設定 ----- x = 0; y = 1; w = 2; h = 3 #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #FPS管理の設定 draw_setting = 35 #ゲームのメイン処理実行タイミングを設定(ミリ秒) #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #キャラクターの設定 #中略 #敵キャラクターの設定 #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ max_enemy = 6 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ enemy_speed = 5 enemy_baratuki = 20 enemy_w_max = 800 - 64; enemy_h_min = -64 enemy_anime_change = 2 enemy_hit = createArray() enemy_hit[x] = 20; enemy_hit[y] = 20 enemy_hit[w] = 24; enemy_hit[h] = 35 enemy_ai_pattern = 3 #敵キャラクター弾の設定 #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ max_enemy_tama = 12 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ enemy_tama_speed = 15 enemy_tama_w_max = 800 - 16 enemy_tama_anime_change = 2 #中略 #残撃破数の設定 #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ gekiha_max = 50 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #ここから↓は省略
フレームスキップを実行するための事前スクリプトを追加します。
#ここから↑は省略 #画面の更新 drawCanvas() setCanvasVisible(true) #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ setBaseTime() #時間計測の開始 #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ startInput() #入力受付の開始 #メインループの開始 mainloop = true while mainloop #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/ #----- FPSの計測と判定 ----- timer = getTime() #差分の時間を取得 fps = fps + 1 #FPSのカウント fpscount = timer - oldfpstime if fpscount < (draw_setting * fps) draw_flg = true #最低限のFPSを満たしている場合描画OK else #最低限のFPSを満たしていない場合、前回描画したかどうか if draw_flg draw_flg = false else draw_flg = true end end if fpscount > 999 #1秒を超えたらFPSのカウントをリセットする fps = 0 oldfpstime = timer fpscount = fpscount % 1000 end #----- ゲームのメイン処理実行判定 ----- draw_count = timer - olddrawtime #メイン処理実行タイミングのカウント if draw_setting < draw_count #ゲームのメイン処理実行タイミングになっていたら、カウントをリセットする olddrawtime = timer draw_count = draw_count % draw_setting #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ #キー入力の判定 #ここから↓は省略
最後に、フレームスキップを実行するスクリプトを追加します。
#ここから↑は省略 #----- 残撃破数の表示 ----- str = "残り撃墜数 " if gekiha_count < 10 str = str + "0" end str = str + gekiha_count setText(text_zan, str) #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/ #----- 画面の更新 ----- if draw_flg drawCanvas() #描画OKならキャンバスを更新 end else waitTime(1) #ゲームのメイン処理実行タイミングになるまで保留 end #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/ end #ここから↓は省略
ここまでで、フレームスキップの機能が実装されました。
完成したら、敵の数が増えたときに描画がスキップされるか
テストプレーを行ってみましょう。
スクリプト全体(一部、少し整理とフレームスキップの値を調整しています)
これで、一通り完成です。
保存、終了をして、テストプレーを行い、
確認してみましょう。
06-05 オープニングやエンディングを設定する
ゲームの内容は一通り完成しましたが、
ゲームを遊んでもらうためには、外見、つまり「タイトル画面」は
重要な要素のひとつです。
完成したゲームは公開をする前に、
タイトル画面、エンディング画面、バッドエンディング画面を
設定しておきましょう。
今回もまた、恒例のサンプルの素材を準備いたしました。
音楽素材は、助教授さまと、rerofumiさまの音楽素材を利用いたします。
クリップをしたら、ゲームエディタ画面で「OP:ED:全滅」を押します。
オープニング画面の項目の、「クリップした画像を設定する」を押し、
設定する画像の「設定(追加)する」を押します。
同様に、エンディング画面、ゲームオーバー画面も設定しましょう。
画像を設定したら、次は画面の下のほうにある
オープニング音楽、エンディング音楽、ゲームオーバー音楽を
設定しましょう。
操作は画像のときと同じです。
これで、設定が完了しました。
テストプレーを行い、確認してみましょう。
テストプレーでしっかりと確認ができたら
ゲームを公開しましょう。
まず、メインエディタに戻ります。
公開したいゲームの右側にある「公開します」を押します。
「上記を確認したので、ゲームを公開します」を押します。
これで、ゲームの公開が完了しました。
06-06 おわりに
いかがでしたでしょうか。
今回のシリーズではシューティングゲームの
基本的なところをつくりましたが、
敵の種類を増やしてみたり、
キャラクターを強化するアイテムを登場させてみたり
まだまだアレンジをしてみることができます。
また、他のジャンルのゲームも、基本的なポイントは同じであり、
キャラクターなどの動きや当たり判定の方法を変更していけば、
つくってみることもできるでしょう。
なお、今回のシリーズで完成したサンプルのゲームを
公開しておりますので、実際にプレイしてみたい方は
是非、遊んでみてください。
シューティングサンプルゲーム - 【ノベルゲーム】
第01回 スクリプトって何?
第02回 画面にキャラクターを描画する
第03回 キャラクターをキー入力で操作する
第04回 敵キャラクターを登場させる
第05回 弾を発射させる
第06回 より面白くするために
この記事についてご質問等がありましたら
こちらのブログ記事のコメントへご投稿、
よろしくお願いいたします。