CoRでゲームをつくってみよう / 第07回 より面白くするために

投稿者:Cdv30200 aoi icon mini aoihikawa 投稿日:2022/08/18 19:03

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

 第07回 より面白くするために


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


 第06回 ではタイトル画面やゲームクリア画面など、
 シューティングゲームとして完成するまでのお話でした。
 第07回は、いよいよ最終回。
 より面白くするために、様々な工夫の方法を紹介していきます。



07-01 敵に弾を発射させる


  キャラクターが攻撃できるのに、
 敵キャラクターが攻撃できないのは不公平ですね。
 敵キャラクターにも弾を発射させてみましょう。

  基本的な仕組みは、キャラクターの弾を発射させたときと同じです。
 今回は、弾にアニメーションも付けてみましょう。



  今回もまた、恒例のサンプルの素材を準備いたしました。


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



  敵弾の画像を読み込むために
 画像の定義、素材のロードを行います。

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

#----- 画像の定義 -----

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

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

#---------- ここから ----------
#敵弾
sprite 'spr_enemy_tama' do
  image 'img_enemy_tama'
  origin :left_top
  
  animation 'wait',    [0],       60, true
  animation 'move',    [0, 1, 2], 5,  true
end
#---------- ここまで ----------


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



  ローカル変数の定義、初期化を行います。

scene 'start' do
  #_/_/_/ ローカル変数の定義 _/_/_/
  
#~~~~~~~~~~ 中略 ~~~~~~~~~~
  
  #敵キャラクターオブジェクト
  obj_enemy_spr = []
  
  obj_enemy_pos_x = [];        obj_enemy_pos_y = []
  obj_enemy_size_w = nil;      obj_enemy_size_h = nil
  
  obj_enemy_speed = nil;       obj_enemy_speed_rnd = nil
  obj_enemy_pos_x_old = [];    obj_enemy_pos_y_old = []
  
  obj_enemy_speed_r_x = [];    obj_enemy_speed_r_y = []
  
  obj_enemy_w_max = nil;       obj_enemy_h_max = nil
  
  obj_enemy_hit_time = []
  obj_enemy_invincible_time = nil
  
  obj_enemy_hit_x = nil;       obj_enemy_hit_y = nil
  obj_enemy_hit_w = nil;       obj_enemy_hit_h = nil
  
  obj_enemy_anime = []
  
  obj_enemy_max = nil
  
  obj_enemy_next      = nil
  obj_enemy_next_rnd  = nil
  obj_enemy_next_time = nil
  #---------- ここから ----------
  obj_enemy_tama_next      = nil
  obj_enemy_tama_next_time = []
  
  
  #敵弾オブジェクト
  obj_enemy_tama_spr = []
  
  obj_enemy_tama_pos_x = [];      obj_enemy_tama_pos_y = []
  obj_enemy_tama_size_w = nil;    obj_enemy_tama_size_h = nil
  
  obj_enemy_tama_speed = nil
  obj_enemy_tama_speed_r_x = [];  obj_enemy_tama_speed_r_y = []
  obj_enemy_tama_pos_x_old = [];  obj_enemy_tama_pos_y_old = []
  
  obj_enemy_tama_w_max = nil;     obj_enemy_tama_h_max = nil
  
  obj_enemy_tama_hit_x = nil;     obj_enemy_tama_hit_y = nil
  obj_enemy_tama_hit_w = nil;     obj_enemy_tama_hit_h = nil
  
  obj_enemy_tama_anime = []
  
  obj_enemy_tama_max = nil
  #---------- ここまで ----------

  敵弾のローカル変数のみではなく、
 敵にも次に敵弾を発射するまでの時間を設定する
 新規に作成しています。



  定義したローカル変数を初期化します。

    #敵キャラクターオブジェクト
    obj_enemy_size_w = 64;  obj_enemy_size_h = 64
    
    obj_enemy_w_max = (800 - obj_enemy_size_w)
    obj_enemy_h_max = (600 + obj_enemy_size_h)
    
    obj_enemy_speed = 3;    obj_enemy_speed_rnd = 2
    
    obj_enemy_invincible_time = (60 * 1)
    
    obj_enemy_hit_x = 20;   obj_enemy_hit_y = 20
    obj_enemy_hit_w = 44;   obj_enemy_hit_h = 55
    
    obj_enemy_max = 5
    
    obj_enemy_next      = (60 * 4)
    obj_enemy_next_rnd  = 60
    obj_enemy_next_time = (60 * 3)
    #---------- ここから ----------
    obj_enemy_tama_next = (60 * 2)
    #---------- ここまで ----------
    i = 0; ilen = obj_enemy_max
    while i < ilen do
      obj_enemy_pos_x[i] = 0;  obj_enemy_pos_y[i] = ((-64) * 2)
      
      obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i]
      obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i]
      
      obj_enemy_speed_r_x[i] = 0;  obj_enemy_speed_r_y[i] = 0
      #---------- ここから ----------
      obj_enemy_anime[i] = 'wait'
      #---------- ここまで ----------
      obj_enemy_hit_time[i] = (-1)
      
      obj_enemy_tama_next_time[i] = obj_enemy_tama_next
      
      i += 1
    end
    #---------- ここから ----------
    #敵弾オブジェクト
    obj_enemy_tama_size_w = 16;     obj_enemy_tama_size_h = 16
    
    obj_enemy_tama_speed = 5
    
    obj_enemy_tama_w_max = (800 + (obj_enemy_tama_size_w * 2))
    obj_enemy_tama_h_max = (600 + (obj_enemy_tama_size_h * 2))
    
    obj_enemy_tama_hit_x = 3;       obj_enemy_tama_hit_y = 3
    obj_enemy_tama_hit_w = 13;      obj_enemy_tama_hit_h = 13
    
    obj_enemy_tama_max = 10
    
    i = 0; ilen = obj_enemy_tama_max
    while i < ilen do
      obj_enemy_tama_pos_x[i] = 0
      obj_enemy_tama_pos_y[i] = ((-64) * 2)
      
      obj_enemy_tama_speed_r_x[i] = 0
      obj_enemy_tama_speed_r_y[i] = 0
      
      obj_enemy_tama_pos_x_old[i] = obj_enemy_tama_pos_x[i]
      obj_enemy_tama_pos_y_old[i] = obj_enemy_tama_pos_y[i]
      
      obj_enemy_tama_anime[i] = 'wait'
      
      i += 1
    end
    #---------- ここまで ----------



  敵弾画像オブジェクトを生成します。

    #_/_/_/ 素材の初期化 _/_/_/
  #---------- ここから ----------
    #敵弾
    i = 0; ilen = obj_enemy_tama_max
    while i < ilen do
      obj_enemy_tama_spr[i] = put_sprite 'spr_enemy_tama' do
        position obj_enemy_tama_pos_x[i], obj_enemy_tama_pos_y[i]
        frame_index 0
      end
      
      i += 1
    end
  #---------- ここまで ----------



  自機狙い弾を発射するために
 ユーザ定義関数を用意しておきます。

scene 'start' do
#_/_/_/_/_/_/ ユーザ関数の定義 _/_/_/_/_/_/
#~~~~~~~~~~ 中略 ~~~~~~~~~~

#---------- ここから ----------
#自機狙い弾
def jikinerai_tama(char_x, char_y, ememy_x, ememy_y, speed)
  r = 0; x = 0; y = 0
  if char_x == ememy_x
    if char_y > ememy_y
      y = (speed * (-1))
    elsif char_y < ememy_y
      y = speed
    end
  else
    r = (Math.atan2((ememy_y - char_y), (ememy_x - char_x)))
    x = (Math.cos(r) * speed).to_f
    y = (Math.sin(r) * speed).to_f
  end
  ret_data = createArray()
  ret_data[0] = x
  ret_data[1] = y
  return ret_data
end
#---------- ここまで ----------

  内容はarrp版の自機狙い弾と同じものですが
 新CoR向けに、三角関数関連の命令が一部変更されています。



  敵キャラクターが敵弾を発射するようにします。

    #敵キャラクターの行動ループ
    wrk_enemy_count = 0
#~~~~~~~~~~ 中略 ~~~~~~~~~~
        #敵キャラクターのオブジェクトを移動する
        if (obj_enemy_pos_x_old[i] != obj_enemy_pos_x[i]) || 
           (obj_enemy_pos_y_old[i] != obj_enemy_pos_y[i])
          
          obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i]
          obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i]
          
          obj_enemy_spr[i].position obj_enemy_pos_x[i], obj_enemy_pos_y[i]
        end
        
        #---------- ここから ----------
        #敵弾の発射は画面内に入ってから
        if obj_enemy_pos_x[i] > 0
          #敵弾の発射カウントダウン
          if obj_enemy_tama_next_time[i] > (-1)
            obj_enemy_tama_next_time[i] -= 1
          end
          
          #敵弾の発射
          if obj_enemy_tama_next_time[i] < 0
            obj_enemy_tama_next_time[i] = obj_enemy_tama_next
            
            j = 0; jlen = obj_enemy_tama_max
            while j < jlen do
              #待機状態の敵弾を探す
              if obj_enemy_tama_anime[j] == 'wait'
                #敵弾を移動状態にする
                obj_enemy_tama_pos_x[j] = obj_enemy_pos_x[i] + ((obj_enemy_size_w - obj_enemy_tama_size_w) / 2) - 10
                obj_enemy_tama_pos_y[j] = obj_enemy_pos_y[i] + obj_enemy_size_h - 10
                
                #敵弾の移動方向を決める
                wrk_p = []
                wrk_p = jikinerai_tama((obj_char_pos_x + (obj_char_size_w / 2)),
                                       (obj_char_pos_y + (obj_char_size_h / 2)), 
                                       (obj_enemy_tama_pos_x[j] + (obj_enemy_tama_size_w / 2)), 
                                       (obj_enemy_tama_pos_y[j] + (obj_enemy_tama_size_h / 2)), 
                                       obj_enemy_tama_speed)
                
                obj_enemy_tama_speed_r_x[j] = wrk_p[0]
                obj_enemy_tama_speed_r_y[j] = wrk_p[1]
                wrk_p.clear
                
                obj_enemy_tama_anime[j] = setChangeAnime(obj_enemy_tama_spr[j], obj_enemy_tama_anime[j], 'move')
                
                #ループを終了させる
                j = jlen
              end
              j += 1
            end
          end
        end
        #---------- ここまで ----------
        
        #プレイヤーキャラクターとの当たり判定

  敵弾の発射位置が、敵キャラクターの銃口付近になるよう
 若干の座標調整をしています。

  敵弾の移動方向を決める処理で
 先程のユーザ関数、jikinerai_tamaを使用しており、
 戻り値の受け取りにwrk_pという配列変数を用意して、
 obj_enemy_tama_speed_r_x、obj_enemy_tama_speed_r_yに値渡した後
 配列変数を開放しています。



  敵弾を動かす処理を追加します。

    #ゲームクリア
    if (enemy_zan == 0) && (wrk_enemy_count == 0)
      gameclear_flg = true
    end
    
    #---------- ここから ----------
    #--- 敵弾 ---
    
    #敵弾の移動
    i = 0; ilen = obj_enemy_tama_max
    while i < ilen do
      if obj_enemy_tama_anime[i] == 'move'
        #敵弾の座標値を移動させる
        obj_enemy_tama_pos_x[i] -= obj_enemy_tama_speed_r_x[i]
        obj_enemy_tama_pos_y[i] -= obj_enemy_tama_speed_r_y[i]
        
        #プレイヤーキャラクターとの当たり判定
        wrk_char_hit_flg = false
        
        if (obj_char_hit_time < 0) && 
           ((obj_char_pos_x + obj_char_hit_x) < (obj_enemy_tama_pos_x_old[i] + obj_enemy_tama_hit_w)) && 
           ((obj_char_pos_x + obj_char_hit_w) > (obj_enemy_tama_pos_x_old[i] + obj_enemy_tama_hit_x)) && 
           ((obj_char_pos_y + obj_char_hit_y) < (obj_enemy_tama_pos_y_old[i] + obj_enemy_tama_hit_h)) && 
           ((obj_char_pos_y + obj_char_hit_h) > (obj_enemy_tama_pos_y_old[i] + obj_enemy_tama_hit_y))
          
          #プレイヤーキャラクターの残機を変更
          char_zan -= 1
          
          #プレイヤーキャラクターに無敵時間を設定
          obj_char_hit_time = obj_char_invincible_time
          
          wrk_char_hit_flg = true
        end
        
        #敵弾の移動範囲制限
        if wrk_char_hit_flg ||
           (obj_enemy_tama_pos_x[i] < (obj_enemy_tama_size_w * (-2))) ||
           (obj_enemy_tama_pos_x[i] > (obj_enemy_tama_w_max)) ||
           (obj_enemy_tama_pos_y[i] < (obj_enemy_tama_size_h * (-2))) ||
           (obj_enemy_tama_pos_y[i] > (obj_enemy_tama_h_max))
           
          obj_enemy_tama_pos_x[i] = 800;  obj_enemy_tama_pos_y[i] = 600
          obj_enemy_tama_anime[i] = setChangeAnime(obj_enemy_tama_spr[i], obj_enemy_tama_anime[i], 'wait')
        end
        
        #敵弾のオブジェクトを移動する
        if (obj_enemy_tama_pos_x_old[i] != obj_enemy_tama_pos_x[i]) || 
           (obj_enemy_tama_pos_y_old[i] != obj_enemy_tama_pos_y[i])
          
          obj_enemy_tama_pos_x_old[i] = obj_enemy_tama_pos_x[i]
          obj_enemy_tama_pos_y_old[i] = obj_enemy_tama_pos_y[i]
          
          obj_enemy_tama_spr[i].position obj_enemy_tama_pos_x[i], obj_enemy_tama_pos_y[i]
        end
      end
      i += 1
    end
    #---------- ここまで ----------
    
    #--- 背景 ---
    #背景のスクロール

  プレイヤーと敵弾の当たり判定に
 wrk_char_hit_flgを用意しておき
 当たっていた場合、wrk_char_hit_flgをtrueにすることで
 敵弾の移動範囲制限と同様に
 敵弾を待機状態に戻しています。



  敵キャラクターが倒されたとき
 敵弾の発射時間をリセットするようにします。

      #ダメージ状態の敵キャラクターを探す
      if obj_enemy_anime[i] == 'damage'
        wrk_enemy_count += 1
        
        #敵キャラクターの無敵時間をカウント
        if obj_enemy_hit_time[i] > (-1)
          obj_enemy_hit_time[i] -= 1
          
          #無敵時間の場合プレイヤーキャラクターを点滅表示する
          if obj_enemy_hit_time[i] == 0
            setAlpha(obj_enemy_spr[i], 1)
            
            #無敵時間が終了したら待機状態に戻す
            obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'wait')
            obj_enemy_speed_r_x[i] = 0;  obj_enemy_speed_r_y[i] = 0
            
            obj_enemy_pos_x[i] = 0;  obj_enemy_pos_y[i] = ((-64) * 2)
            #---------- ここから ----------
            obj_enemy_tama_next_time[i] = obj_enemy_tama_next
            #---------- ここまで ----------
            #敵キャラクターのオブジェクトを移動する



  シーン移動時の配列の開放を追加します

      #配列を開放する
      obj_char_tama_spr.clear
      
      obj_char_tama_pos_x.clear;       obj_char_tama_pos_y.clear
      
      obj_char_tama_scale_x.clear;     obj_char_tama_scale_y.clear
      obj_char_tama_scale_count.clear
      
      obj_char_tama_pos_x_old.clear;   obj_char_tama_pos_y_old.clear
      
      obj_char_tama_flg.clear
      
      obj_enemy_spr.clear
      
      obj_enemy_pos_x.clear;           obj_enemy_pos_y.clear
      obj_enemy_pos_x_old.clear;       obj_enemy_pos_y_old.clear
      
      obj_enemy_speed_r_x.clear;       obj_enemy_speed_r_y.clear
      
      obj_enemy_hit_time.clear
      
      obj_enemy_anime.clear
      #---------- ここから ----------
      obj_enemy_tama_pos_x.clear
      obj_enemy_tama_pos_y.clear
      
      obj_enemy_tama_speed_r_x.clear
      obj_enemy_tama_speed_r_y.clear
      
      obj_enemy_tama_pos_x_old.clear
      obj_enemy_tama_pos_y_old.clear
      
      obj_enemy_tama_anime.clear
      
      obj_enemy_tama_next_time.clear
      #---------- ここまで ----------




  ここまでで、
 敵キャラクターが敵弾を発射するスクリプトが出来ました。

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





07-02 敵にAIを搭載する


  敵キャラクターの動きがワンパターンでは、
 やっぱり物足りない感じがしてしまいます。
 今度は、簡単なAIを搭載して、
 動きを変化させてみることにしましょう。



  今回は敵キャラクターが一定時間ごとに
 直線移動、斜め移動の右方向、左方向の3種類へ
 ランダムで切り替わるAIを実装します。



  ローカル変数の定義、初期化を行います。

  obj_enemy_tama_next      = nil
  obj_enemy_tama_next_time = []
  #---------- ここから ----------
  obj_enemy_ai = []
  
  obj_enemy_ai_next = nil
  obj_enemy_ai_next_time = []
  #---------- ここまで ----------
  
  #敵弾オブジェクト
  obj_enemy_tama_spr = []

  obj_enemy_aiは現在のAIの種類。

  obj_enemy_ai_next、obj_enemy_ai_next_timeは
 次のAIに切り替わるまでの時間を管理します。



 定義したローカル変数を初期化します。

    #敵キャラクターオブジェクト
    obj_enemy_size_w = 64;  obj_enemy_size_h = 64
    
    obj_enemy_w_max = (800 - obj_enemy_size_w)
    obj_enemy_h_max = (600 + obj_enemy_size_h)
    
    obj_enemy_speed = 3;    obj_enemy_speed_rnd = 2
    
    obj_enemy_invincible_time = (60 * 1)
    
    obj_enemy_hit_x = 20;   obj_enemy_hit_y = 20
    obj_enemy_hit_w = 44;   obj_enemy_hit_h = 55
    
    obj_enemy_max = 5
    
    obj_enemy_next      = (60 * 4)
    obj_enemy_next_rnd  = 60
    obj_enemy_next_time = (60 * 3)
    
    obj_enemy_tama_next = (60 * 2)
    #---------- ここから ----------
    obj_enemy_ai_next   = (60 * 1.5)
    #---------- ここまで ----------
    i = 0; ilen = obj_enemy_max
    while i < ilen do
      obj_enemy_pos_x[i] = 0;  obj_enemy_pos_y[i] = ((-64) * 2)
      
      obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i]
      obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i]
      
      obj_enemy_speed_r_x[i] = 0;  obj_enemy_speed_r_y[i] = 0
      
      obj_enemy_anime[i] = 'wait'
      
      obj_enemy_hit_time[i] = (-1)
      
      obj_enemy_tama_next_time[i] = obj_enemy_tama_next
      #---------- ここから ----------
      obj_enemy_ai[i] = 'wait'
      obj_enemy_ai_next_time[i] = obj_enemy_ai_next
      #---------- ここまで ----------
      i += 1
    end




  敵の出現時にランダムにAIを切り替えるようにします。

    #--- 敵キャラクター ---
    #敵キャラクターの出現カウントダウン
    obj_enemy_next_time -= 1
    
    #カウントダウンが0以下になったら敵を出現させる
    if obj_enemy_next_time < 0 && enemy_zan > 0
      obj_enemy_next_time = obj_enemy_next + rand(obj_enemy_next_rnd)
      
      i = 0; ilen = obj_enemy_max
      while i < ilen do
        #待機状態の敵キャラクターを探す
        if obj_enemy_anime[i] == 'wait'
          #敵キャラクターの残数を変更
          enemy_zan -= 1
          
          #敵キャラクターを行動状態にする
          obj_enemy_pos_x[i] = rand(obj_enemy_w_max)
          obj_enemy_pos_y[i] = (obj_enemy_size_h * (-2))
          
          obj_enemy_speed_r_x[i] = obj_enemy_speed # * (1 + ((-2) * rand(1)))  #----- 変更
          obj_enemy_speed_r_y[i] = obj_enemy_speed - obj_enemy_speed_rnd + rand(obj_enemy_speed_rnd)
          #---------- ここから ----------
          wrk_rnd = rand(3)
          case wrk_rnd
            when 0 then
              obj_enemy_ai[i] = 'left'
            when 1 then
              obj_enemy_ai[i] = 'right'
            else
              obj_enemy_ai[i] = 'straight'
          end
          #---------- ここまで ----------
          #アニメーションの開始
          obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'move')
          
          #ループを終了させる
          i = ilen
        end
        i += 1
      end
    end

  AIパターンの分岐処理にcase文を使用しています。



  敵キャラクターが一定時間ごとに
 ランダムでAIを変更するようにします。

    #敵キャラクターの行動ループ
    wrk_enemy_count = 0
    
    i = 0; ilen = obj_enemy_max
    while i < ilen do
      #移動状態の敵キャラクターを探す
      if obj_enemy_anime[i] == 'move'
        wrk_enemy_count += 1
        #---------- ここから ----------
        #敵キャラクターのAI切り替えカウントダウン
        obj_enemy_ai_next_time[i] -= 1
        
        #カウントダウンが0以下になったらAIをランダムに切り替える
        if obj_enemy_ai_next_time[i] < 0
          obj_enemy_ai_next_time[i] = obj_enemy_ai_next
          
          wrk_rnd = rand(3)
          case wrk_rnd
            when 0 then
              obj_enemy_ai[i] = 'left'
            when 1 then
              obj_enemy_ai[i] = 'right'
            else
              obj_enemy_ai[i] = 'straight'
          end
        end
        #---------- ここまで ----------
        #敵キャラクターの座標値を移動させる



  AIパターンによって、敵キャラクターの移動方向を切り替えます。

        #敵キャラクターの座標値を移動させる
        #---------- ここから変更 ----------
        case obj_enemy_ai[i]
          when 'left' then
            obj_enemy_pos_x[i] -= obj_enemy_speed_r_x[i]
          when 'right' then
            obj_enemy_pos_x[i] += obj_enemy_speed_r_x[i]
          else
            
        end
        #---------- ここまで変更 ----------
        obj_enemy_pos_y[i] += obj_enemy_speed_r_y[i]
        
        #敵キャラクターの移動範囲制限
        if obj_enemy_pos_x[i] < 0
          obj_enemy_pos_x[i] = 0
          
          #移動方向を反転させる
          #---------- ここから変更 ----------
          #obj_enemy_speed_r_x[i] = obj_enemy_speed_r_x[i] * (-1)
          obj_enemy_ai[i] = 'right'
          #---------- ここまで変更 ----------
        end
        if obj_enemy_pos_x[i] > obj_enemy_w_max
          obj_enemy_pos_x[i] = obj_enemy_w_max
          
          #移動方向を反転させる
          #---------- ここから変更 ----------
          #obj_enemy_speed_r_x[i] = obj_enemy_speed_r_x[i] * (-1)
          obj_enemy_ai[i] = 'left'
          #---------- ここまで変更 ----------
        end
        if obj_enemy_pos_y[i] > obj_enemy_h_max
          #画面外まで移動したら待機状態に戻す
          obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'wait')
          obj_enemy_speed_r_x[i] = 0;  obj_enemy_speed_r_y[i] = 0
          #---------- ここから ----------
          obj_enemy_ai[i] = 'wait'
          #---------- ここまで ----------
        end
        
        #敵キャラクターのオブジェクトを移動する
        if (obj_enemy_pos_x_old[i] != obj_enemy_pos_x[i]) || 
           (obj_enemy_pos_y_old[i] != obj_enemy_pos_y[i])
          
          obj_enemy_pos_x_old[i] = obj_enemy_pos_x[i]
          obj_enemy_pos_y_old[i] = obj_enemy_pos_y[i]
          
          obj_enemy_spr[i].position obj_enemy_pos_x[i], obj_enemy_pos_y[i]
        end

  obj_enemy_pos_xの座標移動値が
 obj_enemy_speed_r_x直接の値から
 obj_enemy_aiによる切り替えに変更されています。

  敵キャラクターの移動範囲制限も、
 obj_enemy_speed_r_x直接の変更から
 obj_enemy_aiの切り替えに変更されています。



  敵キャラクターがプレイヤー弾に当たったあと
 待機状態に戻すときに少し処理を追加します。

      #ダメージ状態の敵キャラクターを探す
      if obj_enemy_anime[i] == 'damage'
        wrk_enemy_count += 1
        
        #敵キャラクターの無敵時間をカウント
        if obj_enemy_hit_time[i] > (-1)
          obj_enemy_hit_time[i] -= 1
          
          #無敵時間の場合プレイヤーキャラクターを点滅表示する
          if obj_enemy_hit_time[i] == 0
            setAlpha(obj_enemy_spr[i], 1)
            
            #無敵時間が終了したら待機状態に戻す
            obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'wait')
            obj_enemy_speed_r_x[i] = 0;  obj_enemy_speed_r_y[i] = 0
            
            obj_enemy_pos_x[i] = 0;  obj_enemy_pos_y[i] = ((-64) * 2)
            
            obj_enemy_tama_next_time[i] = obj_enemy_tama_next
            #---------- ここから ----------
            obj_enemy_ai[i] = 'wait'
            #---------- ここまで ----------
            #敵キャラクターのオブジェクトを移動する



  シーン移動時の配列の開放を追加します

      #配列を開放する
#~~~~~~~~~~ 中略 ~~~~~~~~~~
      
      obj_enemy_anime.clear
      #---------- ここから ----------
      obj_enemy_ai.clear
      obj_enemy_ai_next_time.clear
      #---------- ここまで ----------
      obj_enemy_tama_pos_x.clear
      obj_enemy_tama_pos_y.clear



  ここまでで敵キャラクターのAIを
 ランダムで切り替えるスクリプトが出来ました。

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





07-03 ボスを登場させる


  同じ敵だけではなく、他の種類の敵も登場させてみましょう。

  最後の1体がいなくなったとき、ボスが出現するようにします。



  今回もまた、恒例のサンプルの素材を準備いたしました。








効果音


ショット


効果音


効果音16


効果音


武器5 




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


  画像素材の定義、素材のロードを行います。

  preload do
    #----- ゲームロード時に実行される処理 -----
    #_/_/_/ 素材のロード _/_/_/
    
    #----- 画像 -----
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    
    #敵弾
    image 'img_enemy_tama', id: 77349, frame_size: [16, 16]
    #---------- ここから ----------
    #ボスキャラクター
    image 'img_boss', id: 78549
    
    #ボス弾
    image 'img_boss_tama', id: 77649
    #---------- ここまで ----------
    
#~~~~~~~~~~ 中略 ~~~~~~~~~~

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

#----- 画像の定義 -----

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

#---------- ここから ----------
#ボスキャラクター
sprite 'spr_boss' do
  image 'img_boss'
  origin :left_top
end

#ボス弾
sprite 'spr_boss_tama' do
  image 'img_boss_tama'
  origin :left_top
end
#---------- ここまで ----------

#----- 文字の定義 -----



  ローカル変数の定義、初期化を行います。

#********** startシーン ここから **********
scene 'start' do
  #_/_/_/ ローカル変数の定義 _/_/_/
  
#~~~~~~~~~~ 中略 ~~~~~~~~~~
  
  
  #システム関連
  gameclear_flg = nil
  gameover_flg  = nil
  
  score = nil;      score_view = nil
  enemy_score = nil
  #---------- ここから ----------
  boss_score = nil
  #---------- ここまで ----------
  
  char_zan = nil;   char_zan_view = nil
  enemy_zan = nil;  enemy_zan_view = nil
  #---------- ここから ----------
  boss_zan = nil
  #---------- ここまで ----------
#~~~~~~~~~~ 中略 ~~~~~~~~~~
  #---------- ここから ----------
  #ボスキャラクターオブジェクト
  obj_boss_spr = nil
  
  obj_boss_pos_x = nil;      obj_boss_pos_y = nil
  obj_boss_size_w = nil;     obj_boss_size_h = nil
  
  obj_boss_pos_x_old = nil;  obj_boss_pos_y_old = nil
  
  obj_boss_speed = nil
  obj_boss_speed_r_x = nil;  obj_boss_speed_r_y = nil
  
  obj_boss_w_max = nil
  
  obj_boss_hit_time = nil
  obj_boss_invincible_time = nil
  
  obj_boss_hit_x = nil;      obj_boss_hit_y = nil
  obj_boss_hit_w = nil;      obj_boss_hit_h = nil
  
  obj_boss_ai = nil
  
  obj_boss_ai_next_y = nil
  obj_boss_ai_count = nil
  
  
  #ボス弾オブジェクト
  obj_boss_tama_spr = []
  
  obj_boss_tama_pos_x = [];      obj_boss_tama_pos_y = []
  obj_boss_tama_size_w = nil;    obj_boss_tama_size_h = nil
  
  obj_boss_tama_scale_x = [];    obj_boss_tama_scale_y = []
  obj_boss_tama_scale_count = []
  
  obj_boss_tama_speed = nil
  obj_boss_tama_pos_x_old = [];  obj_boss_tama_pos_y_old = []
  
  obj_boss_tama_h_max = nil
  
  obj_boss_tama_hit_x = nil;     obj_boss_tama_hit_y = nil
  obj_boss_tama_hit_w = nil;     obj_boss_tama_hit_h = nil
  
  obj_boss_tama_flg = []
  
  obj_boss_tama_max = nil
  
  obj_boss_tama_next      = nil
  obj_boss_tama_next_time = nil
  #---------- ここまで ----------
  
#~~~~~~~~~~ 中略 ~~~~~~~~~~

  create do
    #----- シーンロード時に実行される処理 -----
    #_/_/_/ 変数の初期化 _/_/_/

#~~~~~~~~~~ 中略 ~~~~~~~~~~
    
    #---------- ここから ----------
    #ボスキャラクターオブジェクト
    obj_boss_pos_x = 800;      obj_boss_pos_y = 600
    obj_boss_size_w = 256;     obj_boss_size_h = 160
    
    obj_boss_pos_x_old = obj_boss_pos_x
    obj_boss_pos_y_old = obj_boss_pos_y
    
    obj_boss_speed = 3
    obj_boss_speed_r_x = 0;    obj_boss_speed_r_y = 0
    
    obj_boss_w_max = (800 - obj_boss_size_w)
    
    obj_boss_hit_time = (-1)
    obj_boss_invincible_time = (60 * 1)
    
    obj_boss_hit_x = 60;       obj_boss_hit_y = 50
    obj_boss_hit_w = 196;      obj_boss_hit_h = 140
    
    obj_boss_ai = 'wait'
    
    obj_boss_ai_next_y = 60
    obj_boss_ai_count = 0
    
    
    #ボス弾オブジェクト
    obj_boss_tama_size_w = 16;    obj_boss_tama_size_h = 64
    
    obj_boss_tama_speed = 6
    
    obj_boss_tama_hit_x = 1;      obj_boss_tama_hit_y = 0
    obj_boss_tama_hit_w = 15;     obj_boss_tama_hit_h = 64
    
    obj_boss_tama_h_max = (600 + obj_boss_tama_size_h)
    
    obj_boss_tama_max = 10
    
    obj_boss_tama_next      = (60 * 0.75)
    obj_boss_tama_next_time = 0
    obj_boss_tama_next_type = 'wait'
    
    
    i = 0; ilen = obj_boss_tama_max
    while i < ilen do
      obj_boss_tama_pos_x[i] = 0
      obj_boss_tama_pos_y[i] = ((-64) * 2)
      
      obj_boss_tama_scale_x[i] = 1;      obj_boss_tama_scale_y[i] = 0
      obj_boss_tama_scale_count[i] = 0
      
      obj_boss_tama_pos_x_old[i] = obj_boss_tama_pos_x[i]
      obj_boss_tama_pos_y_old[i] = obj_boss_tama_pos_y[i]
      
      obj_boss_tama_flg[i] = false
      
      i += 1
    end
    #---------- ここまで ----------



  画像オブジェクトを生成します。

    #_/_/_/ 素材の初期化 _/_/_/
    
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    
    #アニメーションの開始
    obj_char_spr.start_animation('neutral')
    
    #---------- ここから ----------
    #ボスキャラクター
    obj_boss_spr = put_sprite 'spr_boss' do
      position obj_boss_pos_x, obj_boss_pos_y
      src_rect 0, 0, obj_boss_size_w, obj_boss_size_h
    end
    #---------- ここまで ----------
    
    #プレイヤー弾
    i = 0; ilen = obj_char_tama_max
    while i < ilen do
    
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    
    #---------- ここから ----------
    #ボス弾
    i = 0; ilen = obj_boss_tama_max
    while i < ilen do
      obj_boss_tama_spr[i] = put_sprite 'spr_boss_tama' do
        position obj_boss_tama_pos_x[i], obj_boss_tama_pos_y[i]
        src_rect 0, 0, 16, 64
      end
      obj_boss_tama_spr[i].scale obj_boss_tama_scale_x[i], obj_boss_tama_scale_y[i]
      
      i += 1
    end
    #---------- ここまで ----------

  ボスキャラクターの上を弾の表示が通過するように
 スクリプトの順序を組み立てているところがポイントです。



  ゲームクリア処理としていた部分を
 ボスの登場に変更します。

    #---------- ここから変更 ----------
    #ボスの出現
    if (enemy_zan == 0) && (wrk_enemy_count == 0) && (obj_boss_ai == 'wait')
      obj_boss_ai = 'start'
      
      obj_boss_pos_x = (800 - obj_boss_size_w) / 2
      obj_boss_pos_y = (0 - obj_boss_size_h)
    end
    #---------- ここまで変更 ----------



  ボスキャラクターの行動処理を追加します。

    #---------- ここから ----------
    #--- ボスキャラクター ---
    if obj_boss_ai != 'wait'
      #AIによってボスの移動パターンを変更
      case obj_boss_ai
        when 'left' then
          #左移動中
          obj_boss_pos_x -= obj_boss_speed
        when 'right' then
          #右移動中
          obj_boss_pos_x += obj_boss_speed
        when 'bomb'
          obj_boss_pos_y -= (obj_boss_speed / 3)
        else
          #登場シーン
          obj_boss_pos_y += (obj_boss_speed / 2)
      end
      
      #ボスキャラクターの移動範囲制限
      if obj_boss_pos_x < 0
        obj_boss_pos_x = 0
        obj_boss_ai = 'right'
      end
      if obj_boss_pos_x > obj_boss_w_max
        obj_boss_pos_x = obj_boss_w_max
        obj_boss_ai = 'left'
      end
      if obj_boss_pos_y > obj_boss_ai_next_y
        obj_boss_pos_y = obj_boss_ai_next_y
        obj_boss_ai = 'right'
      end
      
      #プレイヤーキャラクターとの当たり判定
      if (obj_char_hit_time < 0) && 
         ((obj_char_pos_x + obj_char_hit_x) < (obj_boss_pos_x_old + obj_boss_hit_w)) && 
         ((obj_char_pos_x + obj_char_hit_w) > (obj_boss_pos_x_old + obj_boss_hit_x)) && 
         ((obj_char_pos_y + obj_char_hit_y) < (obj_boss_pos_y_old + obj_boss_hit_h)) && 
         ((obj_char_pos_y + obj_char_hit_h) > (obj_boss_pos_y_old + obj_boss_hit_y))
        
        #プレイヤーキャラクターの残機を変更
        char_zan -= 1
        
        #プレイヤーキャラクターに無敵時間を設定
        obj_char_hit_time = obj_char_invincible_time
      end
      
      #ボスキャラクターのオブジェクトを移動する
      if (obj_boss_pos_x_old != obj_boss_pos_x) || 
         (obj_boss_pos_y_old != obj_boss_pos_y)
        
        obj_boss_pos_x_old = obj_boss_pos_x
        obj_boss_pos_y_old = obj_boss_pos_y
        
        obj_boss_spr.position obj_boss_pos_x, obj_boss_pos_y
      end
      
      #ボスキャラクターの無敵時間をカウント
      if (obj_boss_hit_time > (-1)) || (obj_boss_ai == 'bomb')
        obj_boss_hit_time -= 1
        if obj_boss_hit_time < (-1)
          obj_boss_hit_time = obj_boss_invincible_time
        end
        
        #無敵時間の場合プレイヤーキャラクターを点滅表示する
        if obj_boss_hit_time == 0
          setAlpha(obj_boss_spr, 1)
        elsif ((obj_boss_hit_time % 10) == 0)
          setAlpha(obj_boss_spr, 1)
        elsif ((obj_boss_hit_time % 5) == 0)
          setAlpha(obj_boss_spr, 0)
        elsif ((obj_boss_hit_time % 3) == 0)
          setAlpha(obj_boss_spr, 0.5)
        end
      end
    end
    #---------- ここまで ----------



  ボス弾の行動処理を追加します。

    #---------- ここから ----------
    #--- ボス弾 ---
    
    #ボス弾の発射カウントダウン
    if obj_boss_tama_next_time > (-1) && ((obj_boss_ai == 'left') || (obj_boss_ai == 'right'))
      obj_boss_tama_next_time -= 1
    end
    
    #ボス弾の発射
    if obj_boss_tama_next_time < 0
      obj_boss_tama_next_time = obj_boss_tama_next
      
      #2発同時に発射するカウンター
      wrk_start_count = 0
      
      i = 0; ilen = obj_boss_tama_max
      while i < ilen do
        #待機状態のボス弾を探す
        if !obj_boss_tama_flg[i]
          #ボス弾を移動状態にする
          if wrk_start_count < 1
            obj_boss_tama_pos_x[i] = obj_boss_pos_x + ((obj_boss_size_w - obj_boss_tama_size_w) / 2) - 27
            obj_boss_tama_pos_y[i] = obj_boss_pos_y + obj_boss_size_h - 20
          else
            obj_boss_tama_pos_x[i] = obj_boss_pos_x + ((obj_boss_size_w - obj_boss_tama_size_w) / 2) + 27
            obj_boss_tama_pos_y[i] = obj_boss_pos_y + obj_boss_size_h - 20
          end
          obj_boss_tama_scale_x[i] = 1;  obj_boss_tama_scale_y[i] = 0
          obj_boss_tama_scale_count[i] = 0
          
          obj_boss_tama_flg[i] = true
          
          #ループを終了させる
          wrk_start_count += 1
          if wrk_start_count > 1
            i = ilen
          end
        end
        i += 1
      end
    end
    
    #ボス弾の移動
    i = 0; ilen = obj_boss_tama_max
    while i < ilen do
      if obj_boss_tama_flg[i]
        #ボス弾の座標値を移動させる
        if obj_boss_tama_scale_y[i] < 1
          case obj_boss_ai
            when 'left' then
              #左移動中
              obj_boss_tama_pos_x[i] -= obj_boss_speed
            when 'right' then
              #右移動中
              obj_boss_tama_pos_x[i] += obj_boss_speed
            else
          end
          
          obj_boss_tama_scale_count[i] += 1
          obj_boss_tama_scale_y[i] = 
            (obj_boss_tama_speed * obj_boss_tama_scale_count[i]) / obj_boss_tama_size_h
          
          if obj_boss_tama_scale_y[i] > 1
            obj_boss_tama_scale_y[i] = 1
          end
        else
          obj_boss_tama_pos_y[i] += obj_boss_tama_speed
        end
        
        #プレイヤーキャラクターとの当たり判定
        wrk_char_hit_flg = false
        
        if (obj_char_hit_time < 0) && 
           ((obj_char_pos_x + obj_char_hit_x) < (obj_boss_tama_pos_x_old[i] + obj_boss_tama_hit_w)) && 
           ((obj_char_pos_x + obj_char_hit_w) > (obj_boss_tama_pos_x_old[i] + obj_boss_tama_hit_x)) && 
           ((obj_char_pos_y + obj_char_hit_y) < (obj_boss_tama_pos_y_old[i] + obj_boss_tama_hit_h)) && 
           ((obj_char_pos_y + obj_char_hit_h) > (obj_boss_tama_pos_y_old[i] + obj_boss_tama_hit_y))
          
          #プレイヤーキャラクターの残機を変更
          char_zan -= 1
          
          #プレイヤーキャラクターに無敵時間を設定
          obj_char_hit_time = obj_char_invincible_time
          
          wrk_char_hit_flg = true
        end
        
        #ボス弾の移動範囲制限
        if wrk_char_hit_flg ||
           (obj_boss_tama_pos_y[i] > obj_boss_tama_h_max)
           
          obj_boss_tama_pos_x[i] = 800;  obj_boss_tama_pos_y[i] = 600
          obj_boss_tama_flg[i] = false
          
          obj_boss_tama_scale_x[i] = 1;      obj_boss_tama_scale_y[i] = 0
          obj_boss_tama_scale_count[i] = 0
        end
        
        #ボス弾のオブジェクトを移動する
        if (obj_boss_tama_pos_x_old[i] != obj_boss_tama_pos_x[i]) || 
           (obj_boss_tama_pos_y_old[i] != obj_boss_tama_pos_y[i])
          
          obj_boss_tama_pos_x_old[i] = obj_boss_tama_pos_x[i]
          obj_boss_tama_pos_y_old[i] = obj_boss_tama_pos_y[i]
          
          obj_boss_tama_spr[i].position obj_boss_tama_pos_x[i], obj_boss_tama_pos_y[i]
          
          obj_boss_tama_spr[i].scale obj_boss_tama_scale_x[i], obj_boss_tama_scale_y[i]
        end
      end
      i += 1
    end
    #---------- ここまで ----------



  ボスキャラクターとプレイヤー弾の
 当たり判定を追加します。

    #プレイヤー弾の移動
#~~~~~~~~~~ 中略 ~~~~~~~~~~
        
        #プレイヤー弾のサイズ値を変更する
        if obj_char_tama_scale_y[i] < 1
          obj_char_tama_scale_count[i] += 1
          obj_char_tama_scale_y[i] = 
            (obj_char_tama_speed * obj_char_tama_scale_count[i]) / obj_char_tama_size_h
          
          if obj_char_tama_scale_y[i] > 1
            obj_char_tama_scale_y[i] = 1
          end
        end
        #---------- ここから ----------
        #ボスキャラクターとの当たり判定
        wrk_boss_hit_flg = false
        
        if ((obj_boss_ai == 'left') || (obj_boss_ai == 'right')) && 
           (obj_boss_hit_time < 0) && 
           ((obj_boss_pos_x + obj_boss_hit_x) < (obj_char_tama_pos_x_old[i] + obj_char_tama_hit_w)) && 
           ((obj_boss_pos_x + obj_boss_hit_w) > (obj_char_tama_pos_x_old[i] + obj_char_tama_hit_x)) && 
           ((obj_boss_pos_y + obj_boss_hit_y) < (obj_char_tama_pos_y_old[i] + obj_char_tama_hit_h)) && 
           ((obj_boss_pos_y + obj_boss_hit_h) > (obj_char_tama_pos_y_old[i] + obj_char_tama_hit_y))
          
          wrk_boss_hit_flg = true
          
          #ボスキャラクターの残ライフを変更
          boss_zan -= 1
          if boss_zan < 1
            #スコアの加算
            score += boss_score
            
            obj_boss_ai = 'bomb'
          end
          
          #ボスキャラクターに無敵時間を設定
          obj_boss_hit_time = obj_boss_invincible_time
        end
        #---------- ここまで ----------
        #プレイヤー弾の移動範囲制限



  ゲームクリアの条件を追加します。

    #---------- ここから ----------
    #ゲームクリア
    if (obj_boss_ai == 'bomb') && (obj_boss_pos_y < (0 - obj_boss_size_h))
      gameclear_flg = true
    end
    #---------- ここまで ----------



  ボス討伐など大きなスコアを獲得した場合の
 表示処理を変更します。

    #スコア表示の変更
    if score_view < score
      #---------- ここから変更 ----------
      if (score - score_view) > 1000
        score_view += 39
      else
        score_view += 17
      end
      #---------- ここまで変更 ----------
      if score_view > score
        score_view = score
      end



  シーン移動前に画像素材、配列を開放する処理を追加します。

      #画像素材を開放する
      
#~~~~~~~~~~ 中略 ~~~~~~~~~~
      
      i = 0; ilen = obj_enemy_tama_max
      while i < ilen do
        obj_enemy_tama_spr[i].destroy
        i += 1
      end
      #---------- ここから ----------
      obj_boss_spr.destroy
      
      i = 0; ilen = obj_boss_tama_max
      while i < ilen do
        obj_boss_tama_spr[i].destroy
        i += 1
      end
      #---------- ここまで ----------
      
#~~~~~~~~~~ 中略 ~~~~~~~~~~
      
      obj_enemy_tama_anime.clear
      
      obj_enemy_tama_next_time.clear
      #---------- ここから ----------
      obj_boss_tama_pos_x.clear
      obj_boss_tama_pos_y.clear
      
      obj_boss_tama_scale_x.clear;     obj_boss_tama_scale_y.clear
      obj_boss_tama_scale_count.clear
      
      obj_boss_tama_pos_x_old.clear
      obj_boss_tama_pos_y_old.clear
      
      obj_boss_tama_flg.clear
      #---------- ここまで ----------



  ゲームの終了時に
 アクティビティフィードを出力できるようにします。

      
      obj_boss_tama_flg.clear
      #---------- ここから ----------
      #アクティビティフィードの送信
      wrk_str = 'SCORE ' + (score).to_s
      wrk_result = send_activity_feed(wrk_str)
      #---------- ここまで ----------
      if gameclear_flg
        #ゲームクリア画面に移動
        game_clear



  他、仕上げに
 音楽や効果音を追加して
 ゲーム全体の雰囲気を盛り上げます。
 (今回までのスクリプト全体参照)



  ここまででボスの登場と
 ゲーム全体を仕上げるスクリプトが出来ました。

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





07-04 おわりに


  いかがでしたでしょうか。
 今回のシリーズではシューティングゲームの
 基本的なところをつくりましたが、
 敵の種類を増やしてみたり、
 キャラクターを強化するアイテムを登場させてみたり
 まだまだアレンジをしてみることができます。

  また、他のジャンルのゲームも、基本的なポイントは同じであり、
 キャラクターなどの動きや当たり判定の方法を変更していけば、
 つくってみることもできるでしょう。

  是非いろいろなゲーム制作に挑戦してみてください。


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



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

コメントする

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

コメント一覧

Material 71926 1 mini なとおとき(投稿日:2022/09/03 18:25, 履歴)
このAIにはゲーム内で苦しめられました。

ボス戦への移り変わりなど、
ゲーム内で場面が切り替わるようなものは多分作ったことないですが
単純に変数を駆使してゲームに動きをつけるというイメージができました。
Cdv30200 aoi icon mini aoihikawa(投稿日:2022/09/04 02:57, 履歴)
時間、距離、カウントなど
様々な基準を取る方法がありますが

いずれも、変数の応用で
組み上げることが可能です。