RmakeでACTゲームをつくろう / 第01回 関数を再利用してみよう

投稿者:Cdv30200 aoi icon mini aoihikawa 投稿日:2011/09/28 23:14

RmakeでACTゲームをつくろう

 第01回 関数を再利用してみよう


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


  前回、Rmakeで自由なゲームをつくろう の連載では
 スクリプトについての基本を学びながら、
 シューティングゲーム(STG)をつくってみました。
  今回はこのSTGを応用して
 アクション(ACT)ゲームを作ってみましょう。

  第01回は「関数を再利用してみよう」
 というところから始めていきますね。



01-01 前回までのおさらい


  Rmakeのゲームは絵や音楽などの素材と、
 それをどのように動かすか指示することができる「スクリプト」
 の組み合わせで出来ています。

  このスクリプトを作り込むことで、
 様々なゲームを作り出すことが出来ますが、
 規模が大きくなってくるほど、沢山のスクリプトを
 書く必要がでてくるため、大変になってきます。


  しかし、前回の第1回にて解説いたしました、
 自作の「関数」を利用することで、スクリプトを書く量を
 ぐっと減らすことができます。


  関数とは、処理を代行してくれる便利な纏まりのことです。

  例えば、画像を表示したり、アニメーションさせたり、
 当たり判定を行ったり、という内容はSTGでもACTでも変わりません。

  こういった処理を自作の「関数」で行っている場合、
 この関数をコピーしてくる(移植と呼びます)だけで、
 同じ処理が行えるようになるわけです。


 さて、それでは実際にスクリプトや関数の移植から始めてみましょう。



01-02 必要なスクリプトを移植しよう




  第06回 より面白くするために のスクリプトから
 まずは、そのまま利用できる関数を移植します。
#メニュー項目等の表示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


  続いて、メイン処理の基盤部分を移植します。
 場所は先ほどのスクリプトのすぐ後ろです。
#----- 定数の設定 -----

#FPS管理の設定
draw_setting = 30 #ゲームのメイン処理実行タイミングを設定(ミリ秒)

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

#FPS管理の設定
fps = 0
fpscount = 0
oldfpstime = 0

draw_count = 0
olddrawtime = 0
draw_flg = false

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

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

setBaseTime()    #時間計測の開始
startInput()     #入力受付の開始

#メインループの開始
mainloop = true
while mainloop
    
    #----- FPSの計測と判定 -----
    timer = getTime() #差分の時間を取得
     
    fps = fps + 1 #FPSのカウント
    fpscount = timer - oldfpstime
     
    if fpscount < (draw_setting * fps)
        draw_flg = true #最低限のFPSを満たしている場合描画OK
    else 
        #最低限のFPSを満たしていない場合、前回描画したかどうか
        if draw_flg
            draw_flg = false
        else
            draw_flg = true
        end
    end
    
    if fpscount > 999
        #1秒を超えたらFPSのカウントをリセットする
        fps = 0
        oldfpstime = timer
        fpscount = fpscount % 1000
    end
    
    #----- ゲームのメイン処理実行判定 ----- 
    draw_count = timer - olddrawtime #メイン処理実行タイミングのカウント
    
    if draw_setting < draw_count 
        #ゲームのメイン処理実行タイミングになっていたら、カウントをリセットする
        olddrawtime = timer
        draw_count = draw_count % draw_setting
        
        
        #キー入力の判定
        while hasInput()
            takeInput()
            #----- キー入力の判定処理を入れる場所 -----
            if isKeyDown("LEFT")
                key_flg_left = true
            elsif isKeyUp("LEFT")
                key_flg_left = false
            elsif isKeyDown("RIGHT")
                key_flg_right = true
            elsif isKeyUp("RIGHT")
                key_flg_right = false
            elsif isKeyDown("UP")
                key_flg_up = true
            elsif isKeyUp("UP")
                key_flg_up = false
            elsif isKeyDown("DOWN")
                key_flg_down = true
            elsif isKeyUp("DOWN")
                key_flg_down = false
            elsif isKeyDown("Z")
                key_flg_z = true
            elsif isKeyUp("Z")
                key_flg_z = false
            end
        end
        
        #----- ゲームのメイン処理を入れる場所 -----
        #(ゲームの終了時はmainloopをfalseに)
        
        
        
        
        
        #----- 画面の更新 -----
        if draw_flg
            drawCanvas() #描画OKならキャンバスを更新 
        end
    else
        waitTime(1) #ゲームのメイン処理実行タイミングになるまで保留 
    end
end

endInput()     #入力受付の終了


  これで、一通り基盤部分が完成しました。



01-03 チャプターで分割してみよう




  スクリプトの量が増えてくると、修正したい箇所やエラーの発生した箇所が
 探しにくくなってきます。

  これまでは、1つのチャプターに全てのスクリプトを書いてきましたが、
 複数のチャプターにスクリプトを分割することで、これを解消することができます。
  チャプターについてもスクリプトと同様、上から順に流れるため、
 関数などを1つめのチャプター、メイン処理などを2つめのチャプターというように、
 スクリプトの流れ順に分割します。


  チャプターを追加します。



  追加したチャプターに初期スクリプトを書きます。
#メニュー項目等の表示OFF
setMenuItemVisible(getMenuBackLog(), false)
setMenuItemVisible(getMenuSave(), false)
setMenuItemVisible(getMenuLoad(), false)
setHelpVisible(false)


  01-02の後半部分のスクリプトを切り取り、
 追加したチャプターに貼り付けます。


  今回は関数とメイン処理で分けたため、すんなりと分割できましたが、
 チャプターを分割した場合、ローカル変数は引継ぎされないという点に
 注意する必要があります。
  ローカル変数を受け渡しする場合、通常変数に変更するか、
 関数の引数や戻り値の仕組みを利用するように変更しましょう。



01-04 カスタマイズしながら移植してみよう


  キャラクターと背景を描画する仕組みをつくります。

  今回もまた、お手軽にスクリプトの作成までできるよう、
 サンプルの素材を準備いたしました。
  なお、BGMにつきましては助教授さまの音楽素材を利用いたします。






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

  まずはチャプター0にて、関数の追加から。
#ここから↑は省略
#キャラクターの表示内容を変更する関数
def setCharSpritePattern(no)
    img_char_name = "img_char"
    get_x = 0;    get_y = 0;    get_w = 96;   get_h = 96
    set_x = 0;    set_y = 0;    set_w = 96;   set_h = 96
    
    if no == 1
        get_x = 0;    get_y = 0
    elsif no == 2
        get_x = 96;   get_y = 0
    elsif no == 3
        get_x = 192;  get_y = 0
    elsif no == 4
        get_x = 288;  get_y = 0
    elsif no == 5
        get_x = 384;  get_y = 0
    elsif no == 6
        get_x = 480;  get_y = 0
    elsif no == 7
        get_x = 576;  get_y = 0
    elsif no == 8
        get_x = 672;  get_y = 0
    elsif no == 9
        get_x = 768;  get_y = 0
    elsif no == 10
        get_x = 864;  get_y = 0
    elsif no == 11
        get_x = 0;    get_y = 96
    elsif no == 12
        get_x = 96;   get_y = 96
    elsif no == 13
        get_x = 192;  get_y = 96
    elsif no == 14
        get_x = 288;  get_y = 96
    elsif no == 15
        get_x = 384;  get_y = 96
    elsif no == 16
        get_x = 480;  get_y = 96
    elsif no == 17
        get_x = 576;  get_y = 96
    elsif no == 18
        get_x = 672;  get_y = 96
    elsif no == 19
        get_x = 768;  get_y = 96
    elsif no == 20
        get_x = 864;  get_y = 96
    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

  内容は、STGにもありました、
 キャラクターの表示内容を変更する関数と同様です。
 画像サイズと、アニメーションの画像数分、
 if文による分岐が追加されています。


  次はチャプター1にて、実際の描画処理を追加します。

  まずは、初期設定から。
#ここから↑は省略
#----- 定数の設定 -----
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
x = 0;    y = 1;    w = 2;    h = 3
act_std = 0; act_wrk = 1; act_jmp = 2; act_dmg = 3
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#FPS管理の設定
draw_setting = 30 #ゲームのメイン処理実行タイミングを設定(ミリ秒)

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

#キャラクターの設定
char_speed = 7
char_w_max = 800 - 63;      char_h_max = 600 - 80
char_anime_change = 6

char_hit = createArray()
char_hit[x] = 30;           char_hit[y] = 10
char_hit[w] = 33;           char_hit[h] = 80

#音楽・効果音の設定
bgm_main = 66498

bgm_vol = 0.7


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

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

get[x] = 0;    get[y] = 96;   get[w] = 96;   get[h] = 96
set[x] = 0;    set[y] = 0;    set[w] = 96;   set[h] = 96
set_z = 7
pos_char = createArray()
pos_char[x] = 96;            pos_char[y] = 478

setCreateSprite(img_char_name, img_no, get, set, set_z, pos_char)
setSpriteIndependentCamera(getVariable(img_char_name), true)

#背景画像の設定
img_no = 79101
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[x] = 0; pos_bg[y] = 0

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

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

#FPS管理の設定
fps = 0
fpscount = 0
oldfpstime = 0

draw_count = 0
olddrawtime = 0
draw_flg = false

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

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

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

char_muki = 1
char_act = act_std

#キャラクターの当たり判定範囲
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]


#音楽の再生開始
playBGM(bgm_main);  setMusicVolume(bgm_vol)

#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#ここから↓は省略

  基本な構造はSTGのから変更はありませんが、
 画像ID、音楽IDの変更と、
 新たにsetSpriteIndependentCamera関数が追加されています。

  setSpriteIndependentCamera関数は、
 カメラ移動に連動させて画像を動かすかどうかを設定します。
  今回は「true」つまり、カメラが移動しても画像も連動して移動するため、
 カメラの位置にとらわれず、常に同じ位置に表示されるようになります。


  キー入力による座標の移動をメインループ内に追加します。
#ここから↑は省略
        #----- ゲームのメイン処理を入れる場所 -----
        #(ゲームの終了時はmainloopをfalseに)
        
        #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
        
        #----- キャラクターの移動 -----
        if key_flg_left
            #左
            pos_char[x] = pos_char[x] - char_speed
            char_muki = 0
            char_act = act_wrk
        elsif key_flg_right
            #右
            pos_char[x] = pos_char[x] + char_speed
            char_muki = 1
            char_act = act_wrk
        else
            char_act = act_std
        end
        
        #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        
#ここから↓は省略

  変数「char_muki」はキャラクターの方向、
 「char_act」はキャラクターの状態を格納しています。
  これらの変数の状態によって、
 アニメーション種類の切り替えを行います。


  最後に、アニメーション処理をメインループ内に追加します。
 先ほどのスクリプトのすぐ下です。
#ここから↑は省略
        #_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
        #----- キャラクターのアニメーション -----
        
        #アニメーション用カウンター
        char_anime_count = char_anime_count + 1
        if char_anime_count == (char_anime_change * 4)
            char_anime_count = 0
        end
        
        #キャラクターの表示を切替
        if char_act == act_wrk
            if char_anime_count < (char_anime_change)
                setCharSpritePattern(3 + (char_muki * 10))
            elsif char_anime_count < (char_anime_change * 2)
                setCharSpritePattern(4 + (char_muki * 10))
            elsif char_anime_count < (char_anime_change * 3)
                setCharSpritePattern(5 + (char_muki * 10))
            else
                setCharSpritePattern(6 + (char_muki * 10))
            end
        else
            if char_anime_count < (char_anime_change * 2)
                setCharSpritePattern(1 + (char_muki * 10))
            else
                setCharSpritePattern(2 + (char_muki * 10))
            end
        end
        
        #キャラクターの当たり判定範囲
        if key_flg_left || key_flg_right
            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]
            
            if pos_char[x] < -(char_hit[x])
                pos_char[x] = -(char_hit[x])
            elsif pos_char[x] > char_w_max
                pos_char[x] = char_w_max
            end
            setSpritePos(img_char_name, pos_char)
        end
        
        #_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        
        #----- 画面の更新 -----
        if draw_flg
            drawCanvas() #描画OKならキャンバスを更新 
        end
#ここから↓は省略

  アニメーションのカウンターと種類を元に
 キャラクターを描画する関数の変数を変更し、画像を切り替えています。
  また、キャラクターの当たり判定を元に、
 キャラクターを画面内で移動させています。


  スクリプト全体

  これで、一通り完成です。
 保存、終了をして、テストプレーを行い、
 背景とキャラクターの描画、キャラクターの移動が行えるか
 確認してみましょう。




01-05 おわりに


  いかがでしたでしょうか。
 このように、移植の仕方やコツを理解できれば、
 以前の作品を元にして、簡単に新しいゲームを作成することができます。

  また、他の方が作成された関数やスクリプトも、
 効率的に利用できるようになります。
  さらに、その仕組みを理解することができれば、
 アレンジも自由自在です。

  さて、次回は新しい関数を利用して、
 「マップを表示してみよう」を実践してみましょう。


  第01回 関数を再利用してみよう
  第02回 マップを表示してみよう
  第03回 敵・アイテムを追加してみよう
  第04回 敵の動きや背景の演出を入れてみよう
  番外 外部ツールと連携してみよう

コメントする

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

コメント一覧

Material 7186 1 mini ikosami(投稿日:2011/10/01 23:47, 履歴)
aoihikawaさん
>>まずは、「仕組みを理解する」という意味もあり
>>行いたい処理そのままの形のスクリプトで掲載しております。

たしかに、短縮したものを説明に使うと、
仕組みがわかる人にしか何がしたいのか、よく分からないですね(^^;)
Cdv30200 aoi icon mini aoihikawa(投稿日:2011/09/30 20:35, 履歴)
>ikosamiさま

短縮されたスクリプト、問題ありません
正解です。

まずは、「仕組みを理解する」という意味もあり
行いたい処理そのままの形のスクリプトで掲載しております。

仕組みが理解できましたら、
是非こういった短縮化やアレンジなど
行ってみてください。
User icon mini 退会したユーザー(投稿日:2011/09/30 19:07, 履歴)
この段階はクリアしたどっ!
Material 7186 1 mini ikosami(投稿日:2011/09/30 18:41, 履歴)
僕はいつも、処理を早くするために、できる限り短くしようとして、
逆にエラーが起こったり不都合が発生したりするのですが、
これだと何か問題はありますか?

#キャラクターの表示内容を変更する関数
def setCharSpritePattern(no)
    img_char_name = "img_char"
    get_x = 0;    get_y = 0;    get_w = 96;   get_h = 96
    set_x = 0;    set_y = 0;    set_w = 96;   set_h = 96
    
    if no > 0 && no < 11
      get_y = 0
      get_x = (no-1)*96
    elsif no < 21
      get_y = 96
      get_x = (no-11)*96
    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
002 1  mini ugonight(投稿日:2011/09/29 23:24, 履歴)
横スクですかっ!!!!!!!!!
ルメ子もなんかかわいくなっとる!!!!

…あとでこのページコピーして読みふけろ~☆
User icon mini 退会したユーザー(投稿日:2011/09/29 19:04, 履歴)
キターーーーーッ