CoRでゲームをつくってみよう / 第04回 敵キャラクターを登場させる

投稿者:Cdv30200 aoi icon mini aoihikawa 投稿日:2022/08/13 02:34

CoRでゲームをつくってみよう

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


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


 第03回 では、画面に描画した背景やキャラクターを
 動かしてみるところまでスクリプトを実装しました。
 第04回は敵キャラクターを登場させるところまでやっていきますね。



04-01 スクリプトを整理しよう


  新CoRでも、arrpスクリプトと同様に
 スクリプトを分かりやすく纏める機能が実装されています。

  まずは、前回まででかなり長くなったスクリプトを見やすくするため
 すっきりと整理する方法を説明していきますね。



  1つめテクニックは「;」です。

  文の途中に「;」があったとき、
 スクリプトではそこで次の行として判断されます。

 変更前
scene 'start' do
    #----- シーンロード時に実行される処理 -----
    #_/_/_/ 変数の初期化 _/_/_/
    
    #キー入力用のフラグ
    key_flg_up_st    = false
    key_flg_up_do    = false
    key_flg_up_en    = false
    
    key_flg_down_st  = false
    key_flg_down_do  = false
    key_flg_down_en  = false
    
    key_flg_left_st  = false
    key_flg_left_do  = false
    key_flg_left_en  = false
    
    key_flg_right_st = false
    key_flg_right_do = false
    key_flg_right_en = false

 変更後
  create do
    #----- シーンロード時に実行される処理 -----
    #_/_/_/ 変数の初期化 _/_/_/
    
    #キー入力用のフラグ
    key_flg_up_st    = false;  key_flg_up_do    = false;  key_flg_up_en    = false
    key_flg_down_st  = false;  key_flg_down_do  = false;  key_flg_down_en  = false
    key_flg_left_st  = false;  key_flg_left_do  = false;  key_flg_left_en  = false
    key_flg_right_st = false;  key_flg_right_do = false;  key_flg_right_en = false

  似たような値の代入だけというような短い変数の定義や初期化は、
 行を纏めることで、分かりやすく見た目もすっきりとします。



  2つめのテクニックは行の分割です。

  文の最後が関数の途中の「,」だったとき、
 また、文の最後がif文の途中の条件式だったとき、
 スクリプトでは改行された次の行も同じ行として判断されます。

 変更前
    #プレイヤーキャラクターのオブジェクトを移動する
    if (obj_char_pos_x_old != obj_char_pos_x) || (obj_char_pos_y_old != obj_char_pos_y)
      obj_char_pos_x_old = obj_char_pos_x
      obj_char_pos_y_old = obj_char_pos_y
      
      obj_char_spr.position obj_char_pos_x, obj_char_pos_y
    end

 変更後
    #プレイヤーキャラクターのオブジェクトを移動する
    if (obj_char_pos_x_old != obj_char_pos_x) || 
       (obj_char_pos_y_old != obj_char_pos_y)
      
      obj_char_pos_x_old = obj_char_pos_x
      obj_char_pos_y_old = obj_char_pos_y
      
      obj_char_spr.position obj_char_pos_x, obj_char_pos_y
    end

  先ほどは、行を纏めることで見やすくしましたが
 逆に長すぎる行も分かり難くなってしまいます。

  関数やif文は行が長くなりやすく
 このように行を分けることで見やすく書くことが出来ます。



  3つめテクニックはユーザ定義関数です。

  新CoRでもarrpと同様に
 オリジナルのユーザ定義関数を作成することができます。

  なお、ユーザ定義関数は
 スクリプトの上部、シーンより先に書いていきます。

 変更前
    #プレイヤーキャラクター移動方向のフラグによって処理を分岐
    if (obj_char_flg_up && obj_char_flg_left)
      #プレイヤーキャラクターのアニメーションを変更
      if obj_char_anime != 'left'
        obj_char_anime = 'left'
        obj_char_spr.start_animation(obj_char_anime)
      end
      
      #プレイヤーキャラクターの座標を変更
      obj_char_pos_x -= obj_char_speed_r_x
      obj_char_pos_y -= obj_char_speed_r_y
      
    elsif (obj_char_flg_down && obj_char_flg_left)
      #プレイヤーキャラクターのアニメーションを変更
      if obj_char_anime != 'left'
        obj_char_anime = 'left'
        obj_char_spr.start_animation(obj_char_anime)
      end
      
      #プレイヤーキャラクターの座標を変更
      obj_char_pos_x -= obj_char_speed_r_x
      obj_char_pos_y += obj_char_speed_r_y

変更後
#_/_/_/_/_/_/ ユーザ関数の定義 _/_/_/_/_/_/

#オブジェクトのアニメーションを変更
def setChangeAnime(obj, old_anime, new_anime)
  if old_anime != new_anime
     obj.start_animation(new_anime)
  end
  return new_anime
end

#~~~~~~~~~~ 中略 ~~~~~~~~~~

    #プレイヤーキャラクター移動方向のフラグによって処理を分岐
    if (obj_char_flg_up && obj_char_flg_left)
      #プレイヤーキャラクターのアニメーションを変更
      obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'left')
      
      #プレイヤーキャラクターの座標を変更
      obj_char_pos_x -= obj_char_speed_r_x;  obj_char_pos_y -= obj_char_speed_r_y
      
    elsif (obj_char_flg_down && obj_char_flg_left)
      #プレイヤーキャラクターのアニメーションを変更
      obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'left')
      
      #プレイヤーキャラクターの座標を変更
      obj_char_pos_x -= obj_char_speed_r_x;  obj_char_pos_y += obj_char_speed_r_y

  今回の自作した、setChangeAnime関数では
 画像オブジェクト、現在のアニメーション、変更先アニメーションを引数にして
 アニメーションの変更を関数内で行っています。

  このように、似ているところを1つの関数として纏めてしまうことで
 見た目が分かりやすくなるだけでなく、
 作業量もぐっと軽減することができます。




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




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


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



  新規に敵キャラクターの画像を読み込むために
 素材の定義から行います。

  プレイヤーキャラクターのときと同様に
 アニメーションを自動で行うように指定します。

#_/_/_/_/_/_/ 素材の定義 _/_/_/_/_/_/

#メイン背景
sprite 'spr_bg_00' do
  image 'img_bg_00'
  origin :left_top
end

#プレイヤーキャラクター
sprite 'spr_char' do
  image 'img_char'
  origin :left_top
  
  animation 'neutral', [0, 3], 10, true
  animation 'left',    [1, 4], 10, true
  animation 'right',   [2, 5], 10, true
end
#---------- ここから ----------
#敵キャラクター
sprite 'spr_enemy' do
  image 'img_enemy'
  origin :left_top
  
  animation 'wait',    [0],          60, true
  animation 'move',    [0, 1, 2, 1], 10, true
  animation 'damage',  [3],          60, true
end
#---------- ここまで ----------

  waitが待機中、moveが移動中、damageがダメージ中と
 3種類のアニメーション状態を準備しています。



  preload内で素材のロードを行います。

  preload do
    #----- ゲームロード時に実行される処理 -----
    #_/_/_/ 素材のロード _/_/_/
    
    #メイン背景
    image 'img_bg_00', id: 76800
    
    #プレイヤーキャラクター
    image 'img_char',  id: 76793, frame_size: [64, 64]
    #---------- ここから ----------
    #敵キャラクター
    image 'img_enemy', id: 77127, frame_size: [64, 64]
    #---------- ここまで ----------

  プレイヤーキャラクターのときと同様に
 アニメーション用の画像サイズ指定が含まれています。



  画像のオブジェクトを管理するための
 ローカル変数を定義します。

  #プレイヤーキャラクターオブジェクト
  obj_char_spr = nil
  
  obj_char_pos_x = nil;      obj_char_pos_y = nil
  obj_char_size_w = nil;     obj_char_size_h = nil
  
  obj_char_pos_x_old = nil;  obj_char_pos_y_old = nil
  
  obj_char_speed = nil
  obj_char_speed_r_x = nil;  obj_char_speed_r_y = nil
  
  obj_char_w_max = nil;      obj_char_h_max = nil
  
  obj_char_anime = nil
  
  obj_char_flg_up    = nil;  obj_char_flg_down  = nil
  obj_char_flg_left  = nil;  obj_char_flg_right = nil
  
  #---------- ここから ----------
  #敵キャラクターオブジェクト
  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_anime = []
  
  obj_enemy_max = nil
  
  obj_enemy_next      = nil
  obj_enemy_next_rnd  = nil
  obj_enemy_next_time = nil
  #---------- ここまで ----------

  敵を複数出現させるため、一部のローカル変数が配列で定義されています。
  arrpのときはcreateArray関数を使用して配列の初期化を行っていましたが
 新CoRでは「[]」が同じ役割として使用可能になっています。

  新たに追加されたローカル変数の
 obj_enemy_maxは画面上に同時出現させる敵キャラクターの最大値、
 obj_enemy_next、obj_enemy_next_rnd、obj_enemy_next_timeは
 次の敵キャラクターを出現させるまでの時間を
 カウントするときに使用します。



  定義したローカル変数を
 シーン毎のcreate内で初期化します。

    #プレイヤーキャラクターオブジェクト
    obj_char_size_w = 64;  obj_char_size_h = 64
    
    obj_char_pos_x = (800 - obj_char_size_w) / 2;  obj_char_pos_y = 500
    obj_char_pos_x_old = obj_char_pos_x;           obj_char_pos_y_old = obj_char_pos_y
    
    obj_char_speed = 5
    
    wrk_r = 45 * Math::PI / 180
    obj_char_speed_r_x = Math.cos(wrk_r) * obj_char_speed
    obj_char_speed_r_y = Math.sin(wrk_r) * obj_char_speed
    
    obj_char_w_max = (800 - obj_char_size_w)
    obj_char_h_max = (600 - obj_char_size_h)
    
    obj_char_anime = 'neutral'
    
    obj_char_flg_up    = false;  obj_char_flg_down  = false
    obj_char_flg_left  = false;  obj_char_flg_right = false
    
    #---------- ここから ----------
    #敵キャラクターオブジェクト
    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_max = 5
    
    obj_enemy_next      = (60 * 4)
    obj_enemy_next_rnd  = 60
    obj_enemy_next_time = (60 * 3)
    
    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'
      
      i += 1
    end
    #---------- ここまで ----------

  一部のローカル変数で配列内の値を操作するため、
 while文によるループ処理が使われています。

  ここでは、敵キャラクターを画面外に纏めて配置しておき
 メインループで少しずつ画面内に登場させるように
 ローカル変数の値を設定しています。

  ちなみに、次の敵キャラクターを出現させるまでの時間を管理している
 obj_enemy_next、obj_enemy_next_rnd、obj_enemy_next_timeのローカル変数が
 それぞれ、60という値を基準としているのは
 新CoRのメインループはおおよそ60フレームで動くように作られているので
 カウントが60毎に約1秒となるためです。



  敵キャラクター画像のオブジェクトを生成します。

    #プレイヤーキャラクター
    obj_char_spr = put_sprite 'spr_char' do
      position obj_char_pos_x, obj_char_pos_y
      frame_index 0
    end
    
    #アニメーションの開始
    obj_char_spr.start_animation('neutral')
    
    #---------- ここから ----------
    #敵キャラクター
    i = 0; ilen = obj_enemy_max
    while i < ilen do
      obj_enemy_spr[i] = put_sprite 'spr_enemy' do
        position obj_enemy_pos_x[i], obj_enemy_pos_y[i]
        frame_index 0
      end
      
      #アニメーションの開始
      obj_enemy_spr[i].start_animation('wait')
      
      i += 1
    end
    #---------- ここまで ----------

  このように、画像オブジェクトも変数の1種なので
 配列を使って管理することができます。

  ここでアニメーションの初期化も
 同時に行っておきましょう。



  次の敵キャラクターを出現させるまでの時間をカウントダウンして
 0を超えたら敵キャラクターを待機状態から移動状態に変更します。

  シーンのメインループであるupdate内
 プレイヤーキャラクターの処理と
 背景の処理の間に書いていきましょう

    #プレイヤーキャラクターのオブジェクトを移動する
    if (obj_char_pos_x_old != obj_char_pos_x) || 
       (obj_char_pos_y_old != obj_char_pos_y)
      
      obj_char_pos_x_old = obj_char_pos_x
      obj_char_pos_y_old = obj_char_pos_y
      
      obj_char_spr.position obj_char_pos_x, obj_char_pos_y
    end
    
    #---------- ここから ----------
    #--- 敵キャラクター ---
    #敵キャラクターの出現カウントダウン
    obj_enemy_next_time -= 1
    
    #カウントダウンが0以下になったら敵を出現させる
    if obj_enemy_next_time < 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'
          #敵キャラクターを行動状態にする
          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)
          
          #アニメーションの開始
          obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'move')
          
          #ループを終了させる
          i = ilen
        end
        i += 1
      end
    end
    #---------- ここまで ----------
    
    #--- 背景 ---
    #背景のスクロール
    obj_bg_pos_y += obj_bg_speed
    
    #背景のスクロールをループさせる
    if obj_bg_pos_y > 600
      obj_bg_pos_y -= 600
    end
    
    #背景のオブジェクトを移動する
    obj_bg_00_spr.position obj_bg_pos_x, obj_bg_pos_y
    obj_bg_01_spr.position obj_bg_pos_x, (obj_bg_pos_y - 600)

  ポイントは、敵キャラクターのループ処理の中で
 待機状態の敵キャラクターが見つかった場合
 敵キャラクターを移動状態にしたあと
 カウンターのiを最大値のilenにすることで
 ループ処理を強制的に終了しています。

  こうすることで、1回の処理で1体ずつ
 敵キャラクターを移動状態に変更することができます。

  また、敵キャラクターのX座標やY座標速度の設定で
 rand関数を使用することによりランダム性を持たせています。



  敵キャラクターの出現の下に、
 敵キャラクターが移動状態になっている場合
 移動させる処理を追加します。

          #ループを終了させる
          i = ilen
        end
        i += 1
      end
    end
    
    #---------- ここから ----------
    #敵キャラクターの行動ループ
    i = 0; ilen = obj_enemy_max
    while i < ilen do
      #移動状態の敵キャラクターを探す
      if obj_enemy_anime[i] == 'move'
        #敵キャラクターの座標値を移動させる
        obj_enemy_pos_x[i] += obj_enemy_speed_r_x[i]
        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)
        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)
        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
        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
      end
      i += 1
    end
    #---------- ここまで ----------
    
    #--- 背景 ---
    #背景のスクロール
    obj_bg_pos_y += obj_bg_speed
    
    #背景のスクロールをループさせる
    if obj_bg_pos_y > 600
      obj_bg_pos_y -= 600
    end

  まずは、ループ処理を使用して、
 移動状態となっている敵キャラクターを判断します。

  移動状態となっている敵キャラクターを見つけた場合
 プレイヤーキャラクターの場合と同様に
 座標値の移動、移動範囲制限、オブジェクトの移動の順で
 処理を実行するスクリプトを書きます。

  プレイヤーキャラクターの場合と異なるのは
 移動範囲制限で左右の限界値に達したとき
 限界値の手前に座標を戻すだけでなく
 移動速度に-1をかけることで、左右の移動方向を反転させています。

  また、下方向の限界値に達したときは
 敵キャラクターを待機状態に戻し
 再び登場できる状態に変更しています。



  ここまでで、敵キャラクター画像を
 画面上で動かすスクリプトが出来ました。

  画面上部メニューにある、「保存をして実行」を押して
 実際のゲーム画面を確認してみましょう。





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


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



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


  プレイヤーキャラクターの座標から当たり判定までの
 差分の値を設定するローカル変数を準備します。

  #プレイヤーキャラクターオブジェクト
  obj_char_spr = nil
  
  obj_char_pos_x = nil;      obj_char_pos_y = nil
  obj_char_size_w = nil;     obj_char_size_h = nil
  
  obj_char_pos_x_old = nil;  obj_char_pos_y_old = nil
  
  obj_char_speed = nil
  obj_char_speed_r_x = nil;  obj_char_speed_r_y = nil
  
  obj_char_w_max = nil;      obj_char_h_max = nil
  #---------- ここから ----------
  obj_char_hit_time = nil
  obj_char_invincible_time = nil
  
  obj_char_hit_x = nil;      obj_char_hit_y = nil
  obj_char_hit_w = nil;      obj_char_hit_h = nil
  #---------- ここまで ----------
  obj_char_anime = nil
  
  obj_char_flg_up    = nil;  obj_char_flg_down  = nil
  obj_char_flg_left  = nil;  obj_char_flg_right = nil
  
  #敵キャラクターオブジェクト
  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_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_char_hit_timeはプレイヤーがダメージを受けた場合の
 無敵時間カウンター。

  obj_char_invincible_timeはその無敵時間の定数。

  各hit_x、hit_y、hit_w、hit_hは
 現在座標から当たり判定までの差分座標を保管しておく定数です。



  定義したローカル変数を
 シーンの実行時に初期化します。

    #プレイヤーキャラクターオブジェクト
    obj_char_size_w = 64;  obj_char_size_h = 64
    
    obj_char_pos_x = (800 - obj_char_size_w) / 2;  obj_char_pos_y = 500
    obj_char_pos_x_old = obj_char_pos_x;           obj_char_pos_y_old = obj_char_pos_y
    
    obj_char_speed = 5
    
    wrk_r = 45 * Math::PI / 180
    obj_char_speed_r_x = Math.cos(wrk_r) * obj_char_speed
    obj_char_speed_r_y = Math.sin(wrk_r) * obj_char_speed
    
    obj_char_w_max = (800 - obj_char_size_w)
    obj_char_h_max = (600 - obj_char_size_h)
    #---------- ここから ----------
    obj_char_hit_time = (-1)
    obj_char_invincible_time = (60 * 2)
    
    obj_char_hit_x = 25;   obj_char_hit_y = 20
    obj_char_hit_w = 39;   obj_char_hit_h = 50
    #---------- ここまで ----------
    obj_char_anime = 'neutral'
    
    obj_char_flg_up    = false;  obj_char_flg_down  = false
    obj_char_flg_left  = false;  obj_char_flg_right = false
    
    
    #敵キャラクターオブジェクト
    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_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)
    
    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'
      
      i += 1
    end




  敵キャラクターの行動ループに
 プレイヤーキャラクターとの当たり判定処理を追加します。

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


    #敵キャラクターの行動ループ
    i = 0; ilen = obj_enemy_max
    while i < ilen do
      #移動状態の敵キャラクターを探す
      if obj_enemy_anime[i] == 'move'
        
#~~~~~~~~~~ 中略 ~~~~~~~~~~
        
        #敵キャラクターのオブジェクトを移動する
        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_char_hit_time < 0) && 
           ((obj_char_pos_x + obj_char_hit_x) < (obj_enemy_pos_x_old[i] + obj_enemy_hit_w)) && 
           ((obj_char_pos_x + obj_char_hit_w) > (obj_enemy_pos_x_old[i] + obj_enemy_hit_x)) && 
           ((obj_char_pos_y + obj_char_hit_y) < (obj_enemy_pos_y_old[i] + obj_enemy_hit_h)) && 
           ((obj_char_pos_y + obj_char_hit_h) > (obj_enemy_pos_y_old[i] + obj_enemy_hit_y))
          
          #プレイヤーキャラクターに無敵時間を設定
          obj_char_hit_time = obj_char_invincible_time
        end
        #---------- ここまで ----------
      end
      i += 1
    end

  プレイヤーキャラクターと敵キャラクターの座標の比較と
 プレイヤーキャラクターが無敵時間かどうかの判定で
 プレイヤーキャラクターに当たったかどうか判断しています。



  プレイヤーキャラクターの無敵時間を管理します。

  まずは、画像オブジェクトを点滅させるために
 オブジェクトの透明度を変更するユーザ関数を追加します。

#_/_/_/_/_/_/ ユーザ関数の定義 _/_/_/_/_/_/

#オブジェクトのアニメーションを変更
def setChangeAnime(obj, old_anime, new_anime)
  if old_anime != new_anime
     obj.start_animation(new_anime)
  end
  return new_anime
end
#---------- ここから ----------
#画像オブジェクトの透明度を設定
def setAlpha(obj, a)
  wrk_obj = obj.instance_variable_get('@js_sprite')
  wrk_obj.alpha = a
end
#---------- ここまで ----------

  setAlpha関数では、
 引数で画像オブジェクトとアルファ値(1~0)を渡すことにより
 透明度を変更しています。

  なお、透明度の値は1が100%で全て表示
 0が0%で完全に透明となります。
  値は小数点以下も指定可能です。



  プレイヤーキャラクターの無敵時間をカウントダウンさせ
 0になるまでの間、点滅させるようにします。

    #プレイヤーキャラクターのオブジェクトを移動する
    if (obj_char_pos_x_old != obj_char_pos_x) || 
       (obj_char_pos_y_old != obj_char_pos_y)
      
      obj_char_pos_x_old = obj_char_pos_x
      obj_char_pos_y_old = obj_char_pos_y
      
      obj_char_spr.position obj_char_pos_x, obj_char_pos_y
    end
    
    #---------- ここから ----------
    #プレイヤーキャラクターの無敵時間をカウント
    if obj_char_hit_time > (-1)
      obj_char_hit_time -= 1
      
      #無敵時間の場合プレイヤーキャラクターを点滅表示する
      if obj_char_hit_time == 0
        setAlpha(obj_char_spr, 1)
      elsif ((obj_char_hit_time % 10) == 0)
        setAlpha(obj_char_spr, 1)
      elsif ((obj_char_hit_time % 5) == 0)
        setAlpha(obj_char_spr, 0)
      elsif ((obj_char_hit_time % 3) == 0)
        setAlpha(obj_char_spr, 0.5)
      end
    end
    #---------- ここまで ----------
    
    #--- 敵キャラクター ---
    #敵キャラクターの出現カウントダウン
    obj_enemy_next_time -= 1

  無敵時間の値を割り、
 10のタイミング、5のタイミング、3のタイミングで
 プレイヤーキャラクターの透明度を変化させています。

  無敵時間が0でプレイヤーキャラクターの透明度を戻し
 無敵時間が終了します。



  ここまでで、プレイヤーキャラクターと敵キャラクターの
 当たり判定を行うスクリプトが出来ました。

  画面上部メニューにある、「保存をして実行」を押して
 実際のゲーム画面を確認してみましょう。





04-04 おわりに


  いかがでしたでしょうか。
 敵キャラクターが登場し
 画面が賑やかになってきました。

  さて、次回は敵キャラクターに反撃する手段
 玉を発射させる方法について実践してみましょう。


  今回までのスクリプト全体
CoRでゲームをつくってみよう / 第04回



  第01回 CoRの開発準備をしよう
  第02回 画面に背景やキャラクターを描画する
  第03回 背景やキャラクターを動かす
  第04回 敵キャラクターを登場させる
  第05回 弾を発射する
  第06回 ゲームとして必要な機能を追加する
  第07回 より面白くするために

コメントする

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

コメント一覧

Material 71926 1 mini なとおとき(投稿日:2022/08/18 17:08, 履歴)
当たり判定のロジックを自分では一度も組んだことが無かったので
長時間悩んでしまいましたが最終的になるほどと思いました!
Cdv30200 aoi icon mini aoihikawa(投稿日:2022/08/18 19:20, 履歴)
実は、新CoRには
collisionという便利な当たり判定機能もあるのですが
現状、深刻なバグが存在しているため
今回の紹介では除外させて頂きました