スクリプト/Rmakeで自由なゲームをつくろう / 第04回 敵キャラクターを登場させる

最終投稿者:Cdv30200 aoi icon mini aoihikawa 更新:2011/08/11 23:07:26
Rmakeで自由なゲームをつくろう

 第04回 敵キャラクターを登場させる


  こんにちは。
 フリーデザイナープログラマー(自称)の
 簸川 葵(ひかわ あおい)と申します。


 第03回 ではキャラクターをキー操作で動かすまでのお話でした。
 第04回は、これまでつくってきたものに、ちょっとずつ手を加えながら
 敵キャラクターを登場させるところまで、やっていきますね。



04-01 背景を動かそう


  敵キャラクターを登場させる前に、前回のおさらいも兼ねて、
 背景を動かしてみましょう。

  背景を動かすためには、縦に長ーい画像を準備する方法もありますが、
 今回は、1枚の絵を2枚使用して、これをループさせて表示します。


  さて、2枚同じものを表示するには、
 背景に関連しているスクリプトを、コピーして増やすこともできますが、
 スクリプトがどんどん長くなってしまいます。

  そこで、「配列」というものを使います。
 配列とは、変数を分割し縦に長い箱にしたものです。
 縦方向の場所を区別するときは、番号を使用します。

#変数
pos_bg_x = 0

#変数の配列化
pos_bg_x = createArray()   #変数を配列にする関数
                           #これ以降、「pos_bg_x」は配列になります
pos_bg_x[0] = 0            #配列は「変数[番号]」で場所を区別します
pos_bg_x[1] = 800

basyo = 2
pos_bg_x[basyo] = 1600     #番号に入れる数値は、変数でも使用できます


  配列の各番号の場所を、さらに配列にすることもできます。
 これを「2次元配列」と呼びます。
  変数が、リバーシゲームの升目のようになった感じですね。
pos_bg = createArray()     #変数を配列にします
                           #0番目を1枚目の背景、1番目を2枚目の背景とします。

pos_bg[0] = createArray()  #配列の中身をさらに配列にします(2次元配列)
pos_bg[1] = createArray()  #次の場所も同じように

x = 0;  y = 1              #分かりやすくするために定数を準備しておきます

pos_bg[0][x] = 0           #1枚目の背景のX座標とY座標
pos_bg[0][y] = 0

pos_bg[1][x] = 0           #2枚目の背景のX座標とY座標
pos_bg[1][y] = 0

  これを繰り返すことで、3次元配列、とか4次元配列、などという
 感じのものも作ることができてしまいます。
  ただ、これ以降場合、「多次元配列」という呼び方で
 まとめてしまうことが多いです。



  それでは、この配列を利用して、
 表示する背景を2枚に増やしてみましょう。
#ここから↑は省略

#_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
#----- 画像の設定 -----
get = createArray()
set = createArray()
x = 0;    y = 1;    w = 2;    h = 3

#キャラクター画像の設定
img_no = 76793
img_char_name = "img_char"

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 = 7
pos_char = createArray()
pos_char[x] = 368;            pos_char[y] = 500

setCreateSprite(img_char_name, img_no, get, set, set_z, pos_char)


#背景画像の設定
img_no = 76800
img_bg_name = "img_bg"

get[x] = 0;    get[y] = 0;    get[w] = 800;  get[h] = 600
set[x] = 0;    set[y] = 0;    set[w] = 800;  set[h] = 600
set_z = 1
pos_bg = createArray()
pos_bg[0] = createArray()
pos_bg[0][x] = 0;             pos_bg[0][y] = 0
pos_bg[1] = createArray()
pos_bg[1][x] = 0;             pos_bg[1][y] = -600

setCreateSprite(img_bg_name, img_no, get, set, set_z, pos_bg, 2)
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#ここから↓は省略

  setCreateSpriteの引数に含まれている配列に番号が振られていません。
 このように、配列に番号が振られていない場合、
 その配列の集合全体を意味します。
  つまり、「get」は「get[x]~get[h]」を纏めた状態で
 関数に渡しているわけです。



  それでは、受け取る方の関数も配列に対応してあげましょう。
#メニュー項目等の表示OFF
setMenuItemVisible(getMenuBackLog(), false)
setMenuItemVisible(getMenuSave(), false)
setMenuItemVisible(getMenuLoad(), false)
setHelpVisible(false)

#キャンバスの初期化
setCanvasVisible(false)
deleteAllSprite()
drawCanvas()

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#----- 関数の設定 -----

#スプライトの表示位置を変更する関数
def setSpritePos(img_name, pos, i)
    if i
        setSpritePosition(getVariable(img_name)[i],
                          pos[i][0], pos[i][1])
    else
        setSpritePosition(getVariable(img_name),
                          pos[0], pos[1])
    end
end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
#画像を設定する関数
def setCreateSprite(img_name, img_no, get, set, set_z, pos, ilen)
    x = 0;    y = 1;    w = 2;    h = 3
    if ilen
        setVariable(img_name, createArray())
        
        i = 0
        while i < ilen
            getVariable(img_name)[i] = createSprite(img_no)
            setSpriteRect(getVariable(img_name)[i],
                          get[x], get[y], get[w], get[h],
                          set[x], set[y], set[w], set[h])
            setSpriteZOrder(getVariable(img_name)[i], set_z)
            setSpritePos(img_name, pos, i)
            i = i + 1
        end
    else
        setVariable(img_name, createSprite(img_no))
        setSpriteRect(getVariable(img_name),
                      get[x], get[y], get[w], get[h],
                      set[x], set[y], set[w], set[h])
        setSpriteZOrder(getVariable(img_name), set_z)
        setSpritePos(img_name, pos)
    end
end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#ここから↓は省略

  1つめのsetSpritePosという関数はsetSpritePositionを
 簡単に利用するために纏めた関数になっています。
  引数の「i」は配列の場所を受け取る仕組みになっています。
 もし、場所が指定されていない場合、
 通常の変数として扱うように処理を分岐させています。


  2つめのsetCreateSpriteという関数は先ほどの
 「get」、「set」、「pos」という配列に対応するように
 変更されています。

  また、渡された値が配列だった場合、
 配列の長さだけループさせて、画像を設定するように
 変更されています。



  背景を動かす定数を準備します。
#ここから↑は省略

#定数の設定
char_speed = 10
char_w_max = 800 - 64;      char_h_max = 600 - 64
char_anime_change = 3
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
bg_speed = 3
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#変数の設定
char_anime_count = 0

#ここから↓は省略

  「bg_speed」には、背景の移動速度が入ります。


  準備した配列や関数などを利用して、
 キャラクターの移動の変更点と
 背景を動かす処理のスクリプトを書きます。
#ここから↑は省略

    #----- ゲームのメイン処理を入れる場所 -----
    #(ゲームの終了時はmainloopをfalseに)
    
    #----- キャラクターの移動 -----
    #_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
    if key_flg_left
        #左
        pos_char[x] = pos_char[x] - char_speed
        if pos_char[x] < 0
            pos_char[x] = 0
        end
        setSpritePos(img_char_name, pos_char)
    elsif key_flg_right
        #右
        pos_char[x] = pos_char[x] + char_speed
        if pos_char[x] > char_w_max
            pos_char[x] = char_w_max
        end
        setSpritePos(img_char_name, pos_char)
    end
    
    if key_flg_up
        #上
        pos_char[y] = pos_char[y] - char_speed
        if pos_char[y] < 0
            pos_char[y] = 0
        end
        setSpritePos(img_char_name, pos_char)
    elsif key_flg_down
        #下
        pos_char[y] = pos_char[y] + char_speed
        if pos_char[y] > char_h_max
            pos_char[y] = char_h_max
        end
        setSpritePos(img_char_name, pos_char)
    end
    #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
    
    #----- キャラクターのアニメーション -----
    
    #アニメーション用カウンター
    char_anime_count = char_anime_count + 1
    if char_anime_count == (char_anime_change * 2)
        char_anime_count = 0
    end
    
    #キャラクターの表示を切替
    if key_flg_left
        if char_anime_count < char_anime_change
            setCharSpritePattern(2)
        else
            setCharSpritePattern(5)
        end
    elsif key_flg_right
        if char_anime_count < char_anime_change
            setCharSpritePattern(3)
        else
            setCharSpritePattern(6)
        end
    else
        if char_anime_count < char_anime_change
            setCharSpritePattern(1)
        else
            setCharSpritePattern(4)
        end
    end
    
    #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
    #----- 背景のスクロール -----
    i = 0
    while i < 2
        pos_bg[i][y] = pos_bg[i][y] + bg_speed
        if pos_bg[i][y] > 600
            pos_bg[i][y] = (pos_bg[i][y] % 600) - 600
        end
        setSpritePos(img_bg_name, pos_bg, i)
        i = i + 1
    end
    #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
    
    #----- 画面の更新 -----
    drawCanvas()
    
    waitTime(30)
end

endInput()     #入力受付の終了
goEnding()     #ゲームのクリア


  ここまでで、背景がスクロールするようになりました。
 完成したら、テストプレーを行ってみましょう。



04-02 敵キャラクターを表示しよう



  今回も、お手軽にスクリプトの作成までできるよう、
 敵キャラクターのサンプルの素材を準備いたしました。


  第02回を参考に、クリップからリソースへの登録まで行い、
 すぐにスクリプトで利用できるように、準備してください。



  それでは、敵キャラクター用の関数から。
 ベースはキャラクター用の関数を利用します。
#ここから↑は省略

#キャラクターの表示内容を変更する関数
def setCharSpritePattern(no)
    img_char_name = "img_char"
    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 = 0;    get_y = 64
    elsif no == 5
        get_x = 64;   get_y = 64
    elsif no == 6
        get_x = 128;  get_y = 64
    else
        get_w = 0;    get_h = 0
        set_w = 0;    set_h = 0
    end
    
    setSpriteRect(getVariable(img_char_name),
                  get_x, get_y, get_w, get_h,
                  set_x, set_y, set_w, set_h)
end

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#敵キャラクターの表示内容を変更する関数
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
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#ここから↓は省略




  作成した関数のすぐ下に、ばらばらな箇所でつくっていた定数を纏めながら
 敵キャラクター用の定数も定義します。
  定数を一纏めにしておく方が、後でちょっと値を変更したくなった時、
 分かりやすいからです。
  さらに、どういった意味の定数なのか、コメントも付けておきますね。
#ここから↑は省略
    setSpriteRect(getVariable(img_enemy_name)[i],
                  get_x, get_y, get_w, get_h,
                  set_x, set_y, set_w, set_h)
end

#_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
#----- 定数の設定 -----
x = 0;    y = 1;    w = 2;    h = 3

#キャラクターの設定
char_speed = 10
char_w_max = 800 - 64;      char_h_max = 600 - 64
char_anime_change = 3

#背景の設定
bg_speed = 3
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#敵キャラクターの設定
max_enemy = 3
enemy_speed = 5
enemy_baratuki = 20
enemy_w_max = 800 - 64;     enemy_h_min = -64
enemy_anime_change = 2
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

  「max_enemy」は敵キャラクターの数、
 「enemy_speed」は敵キャラクターの移動速度、
 「enemy_baratuki」は敵キャラクターを出現させるときのばらつき具合、
 「enemy_w_max」と「enemy_h_min」は後で使用する
 敵キャラクターの出現位置となるX座標の最大値とY座標を設定しています。



  続いて、画像の設定です。
 こちらも、キャラクターの設定をベースにしながら、
 敵キャラクターの数だけ、配列で増やします。
#ここから↑は省略
enemy_anime_change = 2


#----- 画像の設定 -----
get = createArray()
set = createArray()

#キャラクター画像の設定
img_no = 76793
img_char_name = "img_char"

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 = 7
pos_char = createArray()
pos_char[x] = 368;            pos_char[y] = 500

setCreateSprite(img_char_name, img_no, get, set, set_z, pos_char)


#背景画像の設定
img_no = 76800
img_bg_name = "img_bg"

get[x] = 0;    get[y] = 0;    get[w] = 800;  get[h] = 600
set[x] = 0;    set[y] = 0;    set[w] = 800;  set[h] = 600
set_z = 1
pos_bg = createArray()
pos_bg[0] = createArray()
pos_bg[0][x] = 0;             pos_bg[0][y] = 0
pos_bg[1] = createArray()
pos_bg[1][x] = 0;             pos_bg[1][y] = -600

setCreateSprite(img_bg_name, img_no, get, set, set_z, pos_bg, 2)

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#敵キャラクターの画像の設定
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)
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#ここから↓は省略

  敵キャラクターの初期座標が画面外になっています。
 これは登場するシーンがくるまで、舞台袖で待っていてもらうのと
 同じ仕組みになっています。



  変数も同様に、キャラクターの設定をベースにしながら、
 敵キャラクターの数だけ、配列で増やします。
#ここから↑は省略
setCreateSprite(img_enemy_name, img_no, get, set,
                set_z, pos_enemy, max_enemy)

#----- 変数の設定 -----

#キー入力フラグの設定
key_flg_left  = false;      key_flg_right = false
key_flg_up    = false;      key_flg_down  = false
key_flg_z     = false

#アニメーション用カウンター
#キャラクター
char_anime_count = 0

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/

#敵キャラクター
enemy_anime_count = createArray()
i = 0
while i < max_enemy
    enemy_anime_count[i] = -1
    i = i + 1
end
enemy_syutugen_count = 0
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#画面の更新
drawCanvas()
setCanvasVisible(true)
#ここから↓は省略

  「enemy_syutugen_count」は敵キャラが画面上に何体出現しているか
 カウントするために使用します。
  後でこれを利用することで、敵キャラクターを出現させる
 スクリプトの実行を分岐させます。



  最後に、敵キャラクターを登場、アニメーションさせる
 スクリプトを書きます。
#ここから↑は省略
    
    #----- 背景のスクロール -----
    i = 0
    while i < 2
        pos_bg[i][y] = pos_bg[i][y] + bg_speed
        if pos_bg[i][y] > 600
            pos_bg[i][y] = (pos_bg[i][y] % 600) - 600
        end
        setSpritePos(img_bg_name, pos_bg, i)
        i = i + 1
    end
    
    #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
    #----- 敵キャラクターのアニメーション -----
    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                     #アニメーションをリセット
            end
        end
        
        if enemy_anime_count[i] > -1
            #アニメーション用カウンター
            enemy_anime_count[i] = enemy_anime_count[i] + 1
            if enemy_anime_count[i] == (enemy_anime_change * 4)
                enemy_anime_count[i] = 0                     #アニメーションをリセット
            end
            
            #敵キャラクターの表示を切替
            if enemy_anime_count[i] < enemy_anime_change
                setEnemySpritePattern(1, i)
            elsif  enemy_anime_count[i] < (enemy_anime_change * 2)
                setEnemySpritePattern(2, i)
            elsif  enemy_anime_count[i] < (enemy_anime_change * 3)
                setEnemySpritePattern(3, i)
            else
                setEnemySpritePattern(2, i)
            end
            
            #敵キャラクターの移動
            pos_enemy[i][y] = pos_enemy[i][y] + enemy_speed
            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)
        end
        
        i = i + 1
    end
    #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
    
    #----- 画面の更新 -----
    drawCanvas()
    
    waitTime(30)
end

endInput()     #入力受付の終了
goEnding()     #ゲームのクリア

  こちらも、基本的にはキャラクターのスクリプトをベースにしていますが、
 いくつか、異なっている箇所があります。

  説明用に、先ほどの一部を抜粋します。
i = 0
while i < max_enemy
    #敵キャラクターを出現させる
    if (enemy_syutugen_count < max_enemy) && (enemy_anime_count[i] < 0)

  まず、while文で敵キャラクターの最大数まで、処理をループさせています。

  次にif文が入っていますが、ここで新しい記号が登場しています。
 実は、while文やif文の条件式は、ひとつの条件式の中に、
 同時に複数の条件を組み合わせることができます。

  「(条件1) && (条件2)」AND関数と呼び、
 条件1と条件2の両方が成立したときだけ、成立と判断されます。

  「(条件1) || (条件2)」OR関数と呼び、
 条件1と条件2のどちらか片方でも成立したら、成立と判断されます。

  なお、while文、if文などの途中で、この条件式を繋ぐ記号が行の最後だった場合
 関数の「,」の時のように、次の行もスクリプトでは同じ行として判断されます。
#次の2つは同一
if (enemy_syutugen_count < max_enemy) && (enemy_anime_count[i] < 0)
    
end
#--------------------------------------------------
if (enemy_syutugen_count < max_enemy) && 
   (enemy_anime_count[i] < 0)
    
end


  また、ちょっと特殊なもので、
  「!(条件1) 」NOT関数と呼び、
 条件1が不成立なら成立、成立なら不成立、と判断されるものもあります。


  説明用に、先ほどの一部を抜粋します。
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                     #アニメーションをリセット
end

  次のif文では、第01回で登場した、rand関数が使用されています。
 「0~enemy_baratuki」の間でランダムで値を決定してもらい、
 この値が「0」となったときだけ、出現させるスクリプトに移動するようになっています。

  if文の中身については、出現数のカウントと
 出現させた時の変数の初期値の設定を行っています。
  X座標もまた、毎回異なる場所に出現するように、
 「0~enemy_w_max」でX座標を決定してもらうように、rand関数が使用されています。


  説明用に、先ほどの一部を抜粋します。
if enemy_anime_count[i] > -1
    #アニメーション用カウンター
    enemy_anime_count[i] = enemy_anime_count[i] + 1
    if enemy_anime_count[i] == (enemy_anime_change * 4)
        enemy_anime_count[i] = 0                     #アニメーションをリセット
    end
    
    #敵キャラクターの表示を切替
    if enemy_anime_count[i] < enemy_anime_change
        setEnemySpritePattern(1, i)
    elsif  enemy_anime_count[i] < (enemy_anime_change * 2)
        setEnemySpritePattern(2, i)
    elsif  enemy_anime_count[i] < (enemy_anime_change * 3)
        setEnemySpritePattern(3, i)
    else
        setEnemySpritePattern(2, i)
    end

  続いて、敵キャラクターのアニメーション。
 「enemy_anime_count」が初期値になっているかどうか判断することで、
 出現している状態のときのみ実行されるようになっています。
  また、アニメーションが耳をぱたぱたさせる動きとなる、
 1→2→3→2の繰り返しとなるよう変更されています。


  説明用に、先ほどの一部を抜粋します。
    #敵キャラクターの移動
    pos_enemy[i][y] = pos_enemy[i][y] + enemy_speed
    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)
end

  最後に、敵キャラクターの移動と座標の移動。
 if文で、画面外まで敵キャラクターが移動したとき、
 使用していた変数を初期化する仕組みになっています。



  ここまでで、敵キャラクターが表示されるようになりました。
 完成したら、テストプレーを行ってみましょう。



04-03 当たり判定を付けよう




  さて、敵キャラクターが登場しただけでは少し物足りないですね。
 キャラクターが敵キャラクターに当ったとき、ミスになるように
 キャラクターと敵キャラクターに当たり判定を付けてみましょう。


  まずは当たり判定の設定から。
 キャラクターの座標をそのまま利用することも出来ますが、
 今回は、それより内側の位置に当たり判定を設定します。


  キャラクターの座標から当たり判定までの
 差分の値を定数で設定します。
#ここから↑は省略
#----- 定数の設定 -----
x = 0;    y = 1;    w = 2;    h = 3

#キャラクターの設定
char_speed = 10
char_w_max = 800 - 64;      char_h_max = 600 - 64
char_anime_change = 3
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
char_hit = createArray()
char_hit[x] = 25;           char_hit[y] = 20
char_hit[w] = 14;           char_hit[h] = 30
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#背景の設定
bg_speed = 3

#敵キャラクターの設定
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
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#ここから↓は省略



  差分から、当たり判定を算出して保存しておく変数を準備します。
#ここから↑は省略

#アニメーション用カウンター
#キャラクター
char_anime_count = 0

#敵キャラクター
enemy_anime_count = createArray()
i = 0
while i < max_enemy
    enemy_anime_count[i] = -1
    i = i + 1
end
enemy_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]

#敵キャラクターの当たり判定範囲
enemy_atari = createArray()
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#画面の更新
drawCanvas()
setCanvasVisible(true)

#ここから↓は省略

  「char_damage」には、敵に当たったかどうかの
 スイッチを設定します。



  キャラクター、敵キャラクターの移動ごとに、
 当たり判定の再計算を行います。
#ここから↑は省略
            setCharSpritePattern(4)
        end
    end
    
    #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
    #キャラクターの当たり判定範囲
    if key_flg_left || key_flg_right || key_flg_up || key_flg_down
        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]
    end
    #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
    
    #----- 背景のスクロール -----
#ここから↓は省略


#ここから↑は省略
            #敵キャラクターの移動
            pos_enemy[i][y] = pos_enemy[i][y] + enemy_speed
            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)
            
            #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
            #敵キャラクターの当たり判定範囲
            enemy_atari[x] = pos_enemy[i][x] + enemy_hit[x]
            enemy_atari[y] = pos_enemy[i][y] + enemy_hit[y]
            enemy_atari[w] = enemy_atari[x] + enemy_hit[w]
            enemy_atari[h] = enemy_atari[y] + enemy_hit[h]
            #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        end
        
        i = i + 1
    end
#ここから↓は省略




  最後に、実際に当たったかどうかの判定を行い、
 当たってしまうとメインループを終了させ、ゲームを終了します。

  当たったかどうかの判定は、キャラクターと敵キャラクターの
 上下左右、それぞれの位置が超えているかどうか比較することで
 判断します。

#ここから↑は省略
            #敵キャラクターの移動
            pos_enemy[i][y] = pos_enemy[i][y] + enemy_speed
            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)
            
            #敵キャラクターの当たり判定範囲
            enemy_atari[x] = pos_enemy[i][x] + enemy_hit[x]
            enemy_atari[y] = pos_enemy[i][y] + enemy_hit[y]
            enemy_atari[w] = enemy_atari[x] + enemy_hit[w]
            enemy_atari[h] = enemy_atari[y] + enemy_hit[h]
            
            #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
            #当たり判定のチェック
            if ((char_atari[w]) > (enemy_atari[x])) && 
               ((char_atari[h]) > (enemy_atari[y])) &&
               ((char_atari[x]) < (enemy_atari[w])) && 
               ((char_atari[y]) < (enemy_atari[h]))
               
               char_damage = true
               mainloop = false
            end
            #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        end
        
        i = i + 1
    end
    
    #----- 画面の更新 -----
    drawCanvas()
    
    waitTime(30)
end

endInput()     #入力受付の終了
#_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
if char_damage
    goBadEnding()  #ゲームオーバー
else
    goEnding()     #ゲームのクリア
end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

  当たってしまったとき、「char_damage」をオンに変更してから、
 「mainloop」をオフに変更してゲームのメインループを抜けています。

  最後に、「char_damage」を比較することで、
 ゲームクリアか、ゲームオーバーか分岐させています。

  なお、新しく登場したgoBadEndingは、
 ゲームオーバー画面に移動する関数です。



  スクリプト全体(一部、少し整理しています)

  これで、一通り完成です。
 保存、終了をして、テストプレーを行い、
 敵キャラクターに当たると、ゲームオーバーになるかどうか、
 確認してみましょう。




04-04 おわりに


  いかがでしたでしょうか。
 大分、シューティングゲームらしくなってきました。

  さて、次回は敵キャラクターに反撃する手段、
 「弾を発射させる」です。


  第01回 スクリプトって何?
  第02回 画面にキャラクターを描画する
  第03回 キャラクターをキー入力で操作する
  第04回 敵キャラクターを登場させる
  第05回 弾を発射させる
  第06回 より面白くするために

この記事についてご質問等がありましたら
こちらのブログ記事のコメントへご投稿、
よろしくお願いいたします。

コメントする

コメントするには、ログインする必要があります。

コメント一覧

コメントはありません。

メニュー
目次