スクリプト/Rmakeで自由なゲームをつくろう / 第06回 より面白くするために
最終投稿者:
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回 より面白くするために
この記事についてご質問等がありましたら
こちらのブログ記事のコメントへご投稿、
よろしくお願いいたします。
コメントする
コメントするには、ログインする必要があります。
コメント一覧
コメントはありません。