CoRでゲームをつくってみよう / 第05回 弾を発射する

投稿者:Cdv30200 aoi icon mini aoihikawa 投稿日:2022/08/14 03:23

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

 第05回 弾を発射する


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


 第04回 では、敵キャラクターを登場させ
 当たり判定をつけるところまでスクリプトを実装しました。
 第05回は弾を発射するところまでやっていきますね。



05-01 弾を表示しよう


  弾、とはキャラクターの位置から移動が開始される点と
 移動する方向が異なりますが、
 基本的な動きは敵キャラクターと同じです。

  これまでのスクリプトを元に応用しながら、
 まずは弾を表示させるところまでつくってみましょう。


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


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



  それでは、弾を発射するときに使用するZキーの入力処理から。

  方向キーの場合を参考にしながら
 ローカル変数の定義を行います。

  #_/_/_/ ローカル変数の定義 _/_/_/
  
  #キー入力用のフラグ
  key_flg_up_st    = nil;  key_flg_up_do    = nil;  key_flg_up_en    = nil
  key_flg_down_st  = nil;  key_flg_down_do  = nil;  key_flg_down_en  = nil
  key_flg_left_st  = nil;  key_flg_left_do  = nil;  key_flg_left_en  = nil
  key_flg_right_st = nil;  key_flg_right_do = nil;  key_flg_right_en = nil
  #---------- ここから ----------
  key_flg_z_st = nil;      key_flg_z_do = nil;      key_flg_z_en = nil
  #---------- ここまで ----------



  create内でローカル変数を初期化します。

    #_/_/_/ 変数の初期化 _/_/_/
    
    #キー入力用のフラグ
    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
    #---------- ここから ----------
    key_flg_z_st = false;      key_flg_z_do = false;      key_flg_z_en = false
    #---------- ここまで ----------



  メインループ内でキーの入力を受け取ります。

    #_/_/_/ 入力の判定 _/_/_/
    
    #キー入力判定
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    
    if keyboard.down?('RIGHT')
      key_flg_right_st = true
    else
      key_flg_right_st = false
      key_flg_right_do = false
    end
    #---------- ここから ----------
    if keyboard.down?('Z')
      key_flg_z_st = true
    else
      key_flg_z_st = false
      key_flg_z_do = false
    end
    #---------- ここまで ----------



  次は、弾の画像素材を読み込んでいきましょう。

  スクリプトの最後で素材の定義をします。

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

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

#~~~~~~~~~~ 中略 ~~~~~~~~~~
#---------- ここから ----------
#プレイヤー弾
sprite 'spr_char_tama' do
  image 'img_char_tama'
  origin :left_top
end
#---------- ここまで ----------

  今回のプレイヤー弾画像ではアニメーションがないため、
 背景画像のときと同じ形になります。



  preload内で素材をロードします。

  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]



  プレイヤー弾で使用するローカル変数を定義します。

  後々、使用することになる
 当たり判定用のローカル変数も一緒に定義しておきましょう。

scene 'start' do
  #_/_/_/ ローカル変数の定義 _/_/_/
#~~~~~~~~~~ 中略 ~~~~~~~~~~
  #---------- ここから ----------
  #プレイヤー弾オブジェクト
  obj_char_tama_spr = []
  
  obj_char_tama_pos_x = [];      obj_char_tama_pos_y = []
  obj_char_tama_size_w = nil;    obj_char_tama_size_h = nil
  
  obj_char_tama_scale_x = [];    obj_char_tama_scale_y = []
  obj_char_tama_scale_count = []
  
  obj_char_tama_speed = nil
  obj_char_tama_pos_x_old = [];  obj_char_tama_pos_y_old = []
  
  obj_char_tama_hit_x = nil;     obj_char_tama_hit_y = nil
  obj_char_tama_hit_w = nil;     obj_char_tama_hit_h = nil
  
  obj_char_tama_flg = []
  
  obj_char_tama_max = nil
  
  obj_char_tama_next      = nil
  obj_char_tama_next_time = nil
  
  obj_char_tama_flg_z = nil
  #---------- ここまで ----------

  今回、新しく定義した
 obj_char_tama_scale_x、obj_char_tama_scale_y、obj_char_tama_scale_countは
 弾を発射したときの、画像サイズを徐々に変更するときに使用します。

  また、弾が待機中か移動中か判断するため
 アニメーションの変わりに、obj_char_tama_flgを定義しています。

  他、obj_char_tama_next、obj_char_tama_next_timeは
 弾の連射速度。

  obj_char_tama_flg_zは
 Zキーから弾の発射の入力受け付けに使用します。



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

  create do
    #----- シーンロード時に実行される処理 -----
    #_/_/_/ 変数の初期化 _/_/_/
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    #---------- ここから ----------
    #プレイヤー弾オブジェクト
    obj_char_tama_size_w = 16;   obj_char_tama_size_h = 64
    
    obj_char_tama_speed = 12
    
    obj_char_tama_hit_x = 1;     obj_char_tama_hit_y = 0
    obj_char_tama_hit_w = 15;    obj_char_tama_hit_h = 64
    
    obj_char_tama_max = 5
    
    obj_char_tama_next      = (60 * 0.5)
    obj_char_tama_next_time = (-1)
    
    obj_char_tama_flg_z = false
    
    i = 0; ilen = obj_char_tama_max
    while i < ilen do
      obj_char_tama_pos_x[i] = 800;  obj_char_tama_pos_y[i] = 600
      
      obj_char_tama_pos_x_old[i] = obj_char_tama_pos_x[i]
      obj_char_tama_pos_y_old[i] = obj_char_tama_pos_y[i]
      
      obj_char_tama_scale_x[i] = 1;  obj_char_tama_scale_y[i] = 0
      obj_char_tama_scale_count[i] = 0
      
      obj_char_tama_flg[i] = false
      
      i += 1
    end
    #---------- ここまで ----------

  画像サイズを指定するときに使用するローカル変数の
 obj_char_tama_scale_x、obj_char_tama_scale_yの値は
 透明度を設定したときと同じように
 1が100%、0が0%となります。

  発射時に縦幅のみ0%から徐々にサイズを大きくすることにより
 発射の雰囲気を演出します。

  他、どのローカル変数がどんな役割を持っているのか
 考えながらつくることで、
 必要となるローカル変数のパターンを覚えていきましょう。



  メインループ内、キー入力処理で
 Zキーの入力受け付けを、弾の発射入力受け付けに
 渡す処理を追加します。

    #_/_/_/ メイン処理 _/_/_/
    
    #--- キー入力処理 ---
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    #---------- ここから ----------
    #Zキー
    if (key_flg_z_st && !key_flg_z_do)
      key_flg_z_do = true
      #--- 押された時に実行する処理 ---
      obj_char_tama_flg_z = true
    elsif key_flg_z_do
      key_flg_z_en = true
      #--- 押されつづけている時に実行する処理 ---
      obj_char_tama_flg_z = true
    elsif key_flg_z_en
      key_flg_z_en = false
      #--- 離された時に実行する処理 ---
      obj_char_tama_flg_z = false
    end
    #---------- ここまで ----------



  Zキーが押されているとき、連射用のカウントダウンが-1であれば
 プレイヤー弾を1つずつ
 プレイヤーキャラクターの位置に移動する処理を追加します。

  次のプレイヤー弾も続けて発射できるように
 連射用のカウントダウン処理も追加しましょう。

    #--- プレイヤーキャラクター ---
    #プレイヤーキャラクター移動方向のフラグによって処理を分岐
    if (obj_char_flg_up && obj_char_flg_left)
      #プレイヤーキャラクターのアニメーションを変更
      obj_char_anime = setChangeAnime(obj_char_spr, obj_char_anime, 'left')
    
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    #---------- ここから ----------
    #--- プレイヤー弾 ---
    #プレイヤー弾の発射カウントダウン
    if obj_char_tama_next_time > (-1)
      obj_char_tama_next_time -= 1
    end
    
    #プレイヤー弾の発射
    if obj_char_tama_flg_z && (obj_char_tama_next_time < 0)
      obj_char_tama_next_time = obj_char_tama_next
      
      i = 0; ilen = obj_char_tama_max
      while i < ilen do
        #待機状態のプレイヤー弾を探す
        if !obj_char_tama_flg[i]
          #プレイヤー弾を移動状態にする
          obj_char_tama_pos_x[i] = obj_char_pos_x + ((obj_char_size_w - obj_char_tama_size_w) / 2)
          obj_char_tama_pos_y[i] = obj_char_pos_y
          
          obj_char_tama_scale_x[i] = 1;  obj_char_tama_scale_y[i] = 0
          obj_char_tama_scale_count[i] = 0
          
          obj_char_tama_flg[i] = true
          
          #ループを終了させる
          i = ilen
        end
        i += 1
      end
    end
    #---------- ここまで ----------

  敵キャラクターのときと同様に
 1つずつ、待機状態のプレイヤー弾を探し
 移動状態に変更しています。

  弾の発射時に、プレイヤーキャラクターの中心と位置を合わせるため
 obj_char_tama_pos_xの設定でちょっとした計算を行っているところと
 プレイヤー弾発射時の弾の大きさを変更する
 obj_char_tama_scale_x、obj_char_tama_scale_y、obj_char_tama_scale_countが
 追加されているところがポイントです。



  プレイヤー弾を移動させる処理を追加します。

  こちらも、大まかな部分は
 敵キャラクターの場合と同様の形になってきます。

    #--- プレイヤー弾 ---
    
#~~~~~~~~~~ 中略 ~~~~~~~~~~
          #ループを終了させる
          i = ilen
        end
        i += 1
      end
    end
    #---------- ここから ----------
    #プレイヤー弾の移動
    i = 0; ilen = obj_char_tama_max
    while i < ilen do
      if obj_char_tama_flg[i]
        #プレイヤー弾の座標値を移動させる
        obj_char_tama_pos_y[i] -= obj_char_tama_speed
        
        #プレイヤー弾のサイズ値を変更する
        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
        
        #プレイヤー弾の移動範囲制限
        if obj_char_tama_pos_y[i] < (obj_char_tama_size_h * (-2))
          obj_char_tama_flg[i] = false
          
          obj_char_tama_pos_x[i] = 800;  obj_char_tama_pos_y[i] = 600
          
          obj_char_tama_scale_x[i] = 1;  obj_char_tama_scale_y[i] = 0
          obj_char_tama_scale_count[i] = 0
        end
        
        #プレイヤー弾のオブジェクトを移動する
        if (obj_char_tama_pos_x_old[i] != obj_char_tama_pos_x[i]) || 
           (obj_char_tama_pos_y_old[i] != obj_char_tama_pos_y[i])
          
          obj_char_tama_pos_x_old[i] = obj_char_tama_pos_x[i]
          obj_char_tama_pos_y_old[i] = obj_char_tama_pos_y[i]
          
          obj_char_tama_spr[i].position obj_char_tama_pos_x[i], obj_char_tama_pos_y[i]
          
          obj_char_tama_spr[i].scale obj_char_tama_scale_x[i], obj_char_tama_scale_y[i]
        end
      end
      i += 1
    end
    #---------- ここまで ----------

  まずは、移動中となっているプレイヤー弾を
 ループ処理で探しています。

  プレイヤー弾の座標値を移動させる処理の後
 プレイヤー弾の画像サイズを
 発射後からobj_char_tama_scale_countを増やしていくことで
 徐々に大きくしていく処理が追加されています。

  プレイヤー弾の移動範囲制限では
 画面上部に達したとき、待機状態に戻すようにしています。

  最後に、プレイヤー弾の画像オブジェクトを
 実際に移動したり、サイズ変更を行っています。

  なお、画像オブジェクトの設定を変更している部分は、
 positionで座標の変更、scaleでサイズの変更を行っています。


  1回あたりの追加行数が長くなってきましたが
 このように、ある程度の行の処理をグループとして把握することで
 長文の処理も理解しやすく書くことが出来るようになってきます。



  ここまでで、プレイヤー弾画像を
 画面上で操作するスクリプトが出来ました。

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





05-02 弾に当たり判定を付けよう


  発射したプレイヤー弾が敵キャラクターに当たり、
 敵キャラクターが倒せるようにしてみましょう。

  基本的には敵キャラクターの当たり判定を追加したときと同じですが、
 敵キャラクターとプレイヤー弾は、それぞれ複数ありますので、
 ループを2つ使用します。




  敵キャラクターにプレイヤー弾が当たったときに必要となる
 敵キャラクター用のローカル変数を追加します。

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

  プレイヤーキャラクターのときに使用した
 無敵時間と同じものですが、
 敵キャラクターは複数のため、一部ローカル変数は配列になっています。



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

  create do
    #----- シーンロード時に実行される処理 -----
    #_/_/_/ 変数の初期化 _/_/_/
#~~~~~~~~~~ 中略 ~~~~~~~~~~
    #敵キャラクターオブジェクト
    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)
    
    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)
      #---------- ここまで ----------
      i += 1
    end



  メインループ内、敵キャラクターが移動状態のときの処理で
 プレイヤーキャラクターとの当たり判定の後に
 プレイヤー弾との当たり判定を追加します。

  敵キャラクターでループ処理を使用している中で
 プレイヤー弾のループ処理が必要となるため
 配列の番号変数(今回は「i」と「j」)によく注意しましょう。

        #プレイヤーキャラクターとの当たり判定
        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
        #---------- ここから ----------
        #プレイヤー弾との当たり判定
        j = 0; jlen = obj_char_tama_max
        while j < jlen do
          #移動状態のプレイヤー弾を探す
          if obj_char_tama_flg[j] && 
             ((obj_char_tama_pos_x[j] + obj_char_tama_hit_x) < (obj_enemy_pos_x_old[i] + obj_enemy_hit_w)) && 
             ((obj_char_tama_pos_x[j] + obj_char_tama_hit_w) > (obj_enemy_pos_x_old[i] + obj_enemy_hit_x)) && 
             ((obj_char_tama_pos_y[j] + obj_char_tama_hit_y) < (obj_enemy_pos_y_old[i] + obj_enemy_hit_h)) && 
             ((obj_char_tama_pos_y[j] + obj_char_tama_hit_h) > (obj_enemy_pos_y_old[i] + obj_enemy_hit_y))
            
            #敵キャラクターに無敵時間を設定
            obj_enemy_hit_time[i] = obj_enemy_invincible_time
            
            #アニメーションの開始
            obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'damage')
            
            #プレイヤー弾を待機状態に戻す
            obj_char_tama_flg[j] = false
            
            obj_char_tama_pos_x[j] = 800;  obj_char_tama_pos_y[j] = 600
            
            obj_char_tama_scale_x[j] = 1;  obj_char_tama_scale_y[j] = 0
            obj_char_tama_scale_count[j] = 0
            
            #プレイヤー弾のオブジェクトを移動する
            obj_char_tama_spr[j].position obj_char_tama_pos_x[j], obj_char_tama_pos_y[j]
            
            obj_char_tama_spr[j].scale obj_char_tama_scale_x[j], obj_char_tama_scale_y[j]
          end
          j += 1
        end
      end
      #---------- ここまで ----------

  まずは、プレイヤー弾のループ処理内で
 移動中のプレイヤー弾かつ、当たり判定用の座標比較を行っています。

  プレイヤー弾が敵キャラクターに当たっていた場合、
 プレイヤーキャラクターのときと同じように
 敵キャラクターに無敵時間を設定し
 敵キャラクターをダメージ状態に変更しています。

  敵キャラクターに当たったプレイヤー弾の方は
 ここで効果を失うよう、待機状態に戻しています。



  ダメージ状態となっている敵キャラクターの
 無敵時間をカウントダウンします。

            #プレイヤー弾のオブジェクトを移動する
            obj_char_tama_spr[j].position obj_char_tama_pos_x[j], obj_char_tama_pos_y[j]
            
            obj_char_tama_spr[j].scale obj_char_tama_scale_x[j], obj_char_tama_scale_y[j]
          end
          j += 1
        end
      end
      #---------- ここから ----------
      #ダメージ状態の敵キャラクターを探す
      if obj_enemy_anime[i] == 'damage'
        #敵キャラクターの無敵時間をカウント
        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_spr[i].position obj_enemy_pos_x[i], obj_enemy_pos_y[i]
          elsif ((obj_enemy_hit_time[i] % 10) == 0)
            setAlpha(obj_enemy_spr[i], 1)
          elsif ((obj_enemy_hit_time[i] % 5) == 0)
            setAlpha(obj_enemy_spr[i], 0)
          elsif ((obj_enemy_hit_time[i] % 3) == 0)
            setAlpha(obj_enemy_spr[i], 0.5)
          end
        end
      end
      #---------- ここまで ----------
      i += 1
    end

  無敵時間をカウントダウン処理の流れは
 プレイヤーキャラクターのときと同じ形になっています。

  無敵時間が終了した敵キャラクターは
 待機状態に戻るように、アニメーションの変更や座標の移動などの処理が
 追加されています。



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

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





05-03 音楽や効果音を鳴らそう


  これまでのスクリプトで、シューティングゲームとしての動きは
 一通り揃いましたが、音が出ないと少し寂しいですね。

  そこで、ゲーム中の音楽の再生と、敵を倒したときに効果音を再生するよう、
 スクリプトを追加してみましょう。



  まずは、使用する音楽と効果音の素材の準備です。
 今回は、事前に使用許可をいただきました、
 助教授さまの音楽素材と、rerofumiさまの効果音素材を利用します。


効果音


zako_hit03


  第01回を参考に、クリップをしたら、COREシーンエディタを開いてください。

  今回は、音楽と効果音をリソースに追加しますので、
 COREシーンエディタのメニューを音楽管理、効果音管理に変更してから
 クリップから追加を押します。


  後の流れは、画像のときと同じです。



  それでは、スクリプトに書いてみましょう。
 まずはユーザ定義関数の設定から。

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

#オブジェクトのアニメーションを変更
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
#---------- ここから ----------
#音量を変更する
def volBGM(obj, vol)
  js_obj = obj.instance_variable_get("@js_audio")
  js_obj.volume = vol 
end
#---------- ここまで ----------

  volBGM関数では、
 引数で音楽オブジェクトとVOL値(1~0)を渡すことにより
 音量を変更しています。

  なお、音量の値は1が100%で最大音量
 0が0%でミュートとなります。
  値は小数点以下も指定可能です。



  音楽素材、効果音素材には素材の定義が必要ありません。

  preload内で、音楽素材、効果音素材をロードします。
 ここで画像素材のロードと同じように
 各素材のidが必要となります。

  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]
    
    #---------- ここから ----------
    #----- 音楽 -----
    #メイン音楽
    music 'bgm_main',  id: 77253
    
    
    #----- 効果音 -----
    #弾ヒット
    sound 'se_hit00',  id: 63622
    #---------- ここまで ----------

  読み込む素材によって、
 音楽はmusic、効果音はsoundと命令が変わります。

  音楽名、効果音名は自由に付けて構いません。
 素材の初期化時に使用するため、分かりやすい名前を付けておきましょう。



  音楽と効果音のオブジェクトを管理するための
 ローカル変数を定義します。

scene 'start' do
  #_/_/_/ ローカル変数の定義 _/_/_/
        
#~~~~~~~~~~ 中略 ~~~~~~~~~~
  obj_enemy_next      = nil
  obj_enemy_next_rnd  = nil
  obj_enemy_next_time = nil
  
  #---------- ここから ----------
  #音楽オブジェクト
  obj_bgm_main = nil
  
  
  #効果音オブジェクト
  obj_se_hit00 = nil
  #---------- ここまで ----------



  音楽と効果音のオブジェクトを生成します。

  生成したオブジェクトはゲーム全体のバランスに合わせて、
 volBGM関数で音量を設定しておきましょう。

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

    #_/_/_/ 素材の初期化 _/_/_/
    
    #メイン背景
    obj_bg_00_spr = put_sprite 'spr_bg_00' do
      position obj_bg_pos_x, obj_bg_pos_y
      src_rect 0, 0, 800, 600
    end

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

    #敵キャラクター
    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
    
    #---------- ここから ----------
    #音楽
    obj_bgm_main = add_music('bgm_main')
    volBGM(obj_bgm_main, 0.5)
    
    
    #効果音
    obj_se_hit00 = add_sound('se_hit00')
    volBGM(obj_se_hit00, 0.7)
    #---------- ここまで ----------

  音楽オブジェクトはadd_music、
 効果音オブジェクトはadd_soundでオブジェクトを生成します。

  引数の名前は、素材のロードで使用したときと
 同じ名前となります。



  ゲームの開始時に音楽が再生されるよう、
 create内の最後で、音楽オブジェクトを再生します。

    #音楽
    obj_bgm_main = add_music('bgm_main')
    volBGM(obj_bgm_main, 0.5)
    
    
    #効果音
    obj_se_hit00 = add_sound('se_hit00')
    volBGM(obj_se_hit00, 0.7)
    
    #---------- ここから ----------
    #音楽の再生を開始する
    obj_bgm_main.play()
    #---------- ここまで ----------
  end

  obj_bgm_mainオブジェクトに対して、playを指示することにより
 音楽の再生を開始しています。

  なお、音楽を停止する場合はstopを指示します。



  プレイヤー弾が敵キャラクターに当たった時に効果音が再生されるよう、
 当たり判定の処理内で効果音を再生します。

        #プレイヤー弾との当たり判定
        j = 0; jlen = obj_char_tama_max
        while j < jlen do
          #移動状態のプレイヤー弾を探す
          if obj_char_tama_flg[j] && 
             ((obj_char_tama_pos_x[j] + obj_char_tama_hit_x) < (obj_enemy_pos_x_old[i] + obj_enemy_hit_w)) && 
             ((obj_char_tama_pos_x[j] + obj_char_tama_hit_w) > (obj_enemy_pos_x_old[i] + obj_enemy_hit_x)) && 
             ((obj_char_tama_pos_y[j] + obj_char_tama_hit_y) < (obj_enemy_pos_y_old[i] + obj_enemy_hit_h)) && 
             ((obj_char_tama_pos_y[j] + obj_char_tama_hit_h) > (obj_enemy_pos_y_old[i] + obj_enemy_hit_y))
            #---------- ここから ----------
            #効果音を再生する
            obj_se_hit00.play()
            #---------- ここまで ----------
            #敵キャラクターに無敵時間を設定
            obj_enemy_hit_time[i] = obj_enemy_invincible_time
            
            #アニメーションの開始
            obj_enemy_anime[i] = setChangeAnime(obj_enemy_spr[i], obj_enemy_anime[i], 'damage')
            

  音楽は自動で再生がループしますが、
 効果音は最後まで再生されると自動で再生が停止します。



  ここまでで、音楽素材と効果音素材が
 ゲーム内で再生されるスクリプトが出来ました。

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




05-04 おわりに


  いかがでしたでしょうか。
 これで、シューティングとして必要な要素は
 一通り揃いました。

  さて、次回はスコアや残機など文字を表示する方法、
 タイトル画面やゲームクリアの作り方など
 ゲームとして必要な機能を実装する方法について実践してみましょう。


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



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

コメントする

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

コメント一覧

Material 71926 1 mini なとおとき(投稿日:2022/08/21 19:46, 履歴)
あと、スクリプトの最後で定義するスプライトが
弾1発ずつ、敵キャラクター1体ずつじゃなくて良いというのは
自分では気付けなかったです。

同じスプライトを複数の変数に代入すれば
別々の弾、別々の敵キャラクターとして扱えるんですね。
Material 71926 1 mini なとおとき(投稿日:2022/08/21 18:24, 履歴)
敵キャラクターもそうでしたが、出番が終わったら待機中にして、
待機中のものを探して再び登場させる部分のロジックに感動させられますね