スクリプト/RmakeでACTゲームをつくろう / 第02回 マップを表示してみよう(履歴ID:131)

最終投稿者:Cdv30200 aoi icon mini aoihikawa 更新:2012/03/22 18:42:47
RmakeでACTゲームをつくろう

 第02回 マップを表示してみよう


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


  第01回 では「関数を再利用してみよう」ということで、移植の手順についてお話しました。

  今回はACTゲームの重要な基盤である、マップの表示を実践してみましょう。



02-01 マップを画面に表示する




  基本的な表示の仕組みは、前回の第2回で解説したとおりです。
  マップの画像から、1チップあたりのサイズに合わせて、
 切り取り・貼り付けを行うスクリプトを繰り返し、マップを表示していきます。


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


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


  今回はにぃみゃん の おさんぽびよりで使用した
 マップ設定関数を移植して利用します。
  一部、この素材向けに作っている箇所がありますので、
 ほかの素材に差し替えて利用する場合は注意してください。

  まずはチャプター0にて、一番上に汎用関数を移植します。
#メニュー項目等の表示OFF
setMenuItemVisible(getMenuBackLog(), false)
setMenuItemVisible(getMenuSave(), false)
setMenuItemVisible(getMenuLoad(), false)
setHelpVisible(false)

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

#----- 関数の設定 -----
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#べき乗
def POWER(n, b)
  r = 1; i = 0
  while i < b
    r = r * n; i = i + 1
  end
  return r
end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#ここから↓は省略


  次に、一番下にマップを設定を設定する関数を移植します。
#ここから↑は省略
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#マップを設定
def setCreateMap(img_name, img_no, pos, set_z, map_w, map_dat)
    x = 0; y = 1; w = 2; h = 3
    set_map = createArray(); get = createArray(); set = createArray()
    get[x] = 0; get[y] = 0; get[w] = 32; get[h] = 32
    set[x] = 0; set[y] = 0; set[w] = 32; set[h] = 32
    #レイヤーが4なら当たり判定の配列を作成
    if set_z == 4
        hit_map = createArray()
    end
    i = 0; ilen = getArrayLength(map_dat)
    while i < ilen
        if set_z == 4
            hit_map[i] = createArray()
        end
        j = 0; jlen = getArrayLength(map_dat[i])
        while j < jlen
            map_d = map_dat[i][j]
            k = 0; klen = map_w
            while k < klen
                if map_d == 0
                    if set_z == 4
                        hit_map[i][(k + (j * map_w))] = 19
                    end
                else
                    #画像の切り出しポイントを算出
                    if k < (klen - 1)
                        chk = (map_d / POWER(1000, (map_w - (k + 1))))
                    else
                        chk = map_d
                    end
                    chk3 = false
                    #画像の貼り付けポイントを算出
                    if chk == 0
                        set_map[x] = 0; set_map[y] = 0
                    else
                        chk = chk % 1000
                        set_map[x] = floor(chk % 20); set_map[y] = floor(chk / 20)
                        if set_map[y] > 24
                            set_map[y] = set_map[y] - 25
                            chk3 = true
                        end
                    end
                    #画像を切り出して貼り付けする
                    chk = floor(chk)
                    if (chk != 19) #019番目の画像の場合、画像とあたり判定をセットしない
                        get[x] = set_map[x] * 32; get[y] = set_map[y] * 32
                        set[x] = (32 * k) + (32 * j * map_w); set[y] = 32 * i
                        if (chk != 278) #278番目の画像の場合、画像をセットしない
                          setCreateSprite(img_name, img_no, get, set, set_z, getVariable(pos))
                          if set_z == 2
                              setSpriteIndependentCamera(getVariable(img_name), true)
                          end
                        end
                        if set_z == 4
                             hit_map[i][(k + (j * map_w))] = chk
                        end
                    else
                        if set_z == 4
                            hit_map[i][(k + (j * map_w))] = 19
                        end
                    end
                end
                k = k + 1
            end
            j = j + 1
        end
        i = i + 1
    end
    if set_z == 4
      setVariable("hit_map", hit_map)
    end
end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

  マップデータの配列を受け取り、
 画像の切り出しと、貼り付けをする関数です。

  レイヤーを指定している「set_z」変数
 2の場合、カメラにスクロールをあわせる、多重スクロール背景用のレイヤーを、
 4の場合、当たり判定の「hit_map」変数を同時に設定する、実際のマップ用のレイヤー
 設定するようになっています。

  なお、この素材向けに、
 019番目のチップ画像は、当たり判定なしの空白チップ
 278番目のチップ画像は、当たり判定ありの空白チップ
 設定するようになっていますので注意してください。


  マップ画像のチップ位置番号につきましては、
 こちらにわかりやすい一覧を纏めましたのでご活用ください。




  チャプター1に移動して、マップデータの準備を実行後、
 マップを設定する関数を呼び出すスクリプトを追加します。
#ここから↑は省略

#背景画像の設定
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)
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#マップ画像の設定
img_no = 79094
map_size = 5
img_map_name = "img_map"; pos_map = "pos_map"
setVariable(pos_map, createArray())
getVariable(pos_map)[x] = 0; getVariable(pos_map)[y] = -8

#マップデータの配列を準備
map_data = createArray()
map_data[00] = createArray()
map_data[01] = createArray()
map_data[02] = createArray()
map_data[03] = createArray()
map_data[04] = createArray()
map_data[05] = createArray()
map_data[06] = createArray()
map_data[07] = createArray()
map_data[08] = createArray()
map_data[09] = createArray()
map_data[10] = createArray()
map_data[11] = createArray()
map_data[12] = createArray()
map_data[13] = createArray()
map_data[14] = createArray()
map_data[15] = createArray()
map_data[16] = createArray()
map_data[17] = createArray()
map_data[18] = createArray()

set_z = 4

#マップデータを作成
map_data[00][0] = 019019019019019; map_data[00][1] = 019019019019019; map_data[00][2] = 019019019019019
map_data[01][0] = 019019019019019; map_data[01][1] = 019019019019019; map_data[01][2] = 019019019019019
map_data[02][0] = 019019019019019; map_data[02][1] = 019019019019019; map_data[02][2] = 019019019019019
map_data[03][0] = 019019019019019; map_data[03][1] = 019019019019019; map_data[03][2] = 019019019019019
map_data[04][0] = 019019019019019; map_data[04][1] = 019019019019019; map_data[04][2] = 019019019019019
map_data[05][0] = 019019019019019; map_data[05][1] = 019019019019019; map_data[05][2] = 019019019019019
map_data[06][0] = 019019019019019; map_data[06][1] = 019019019019019; map_data[06][2] = 019019019019019
map_data[07][0] = 019019019019019; map_data[07][1] = 019019019019019; map_data[07][2] = 019019019019019
map_data[08][0] = 019019019019019; map_data[08][1] = 019019019019019; map_data[08][2] = 019019019019019
map_data[09][0] = 019019019019019; map_data[09][1] = 019019019019019; map_data[09][2] = 019019019019019
map_data[10][0] = 019019019019019; map_data[10][1] = 019019019019019; map_data[10][2] = 019019019019019
map_data[11][0] = 019019019019019; map_data[11][1] = 019019019019019; map_data[11][2] = 019019019019019
map_data[12][0] = 019019019019019; map_data[12][1] = 019019019019019; map_data[12][2] = 019019019019019
map_data[13][0] = 019019019019019; map_data[13][1] = 019019019019019; map_data[13][2] = 019019019019019
map_data[14][0] = 019019019019019; map_data[14][1] = 019019019019019; map_data[14][2] = 019005007019019
map_data[15][0] = 019019019019019; map_data[15][1] = 019019019019019; map_data[15][2] = 019037039019019
map_data[16][0] = 019019019019019; map_data[16][1] = 019019019019019; map_data[16][2] = 019037039019019
map_data[17][0] = 019019019019019; map_data[17][1] = 019019019019019; map_data[17][2] = 019037039019019
map_data[18][0] = 006006006006006; map_data[18][1] = 006006006006006; map_data[18][2] = 006038038006006

map_data[00][3] = 019019019019019; map_data[00][4] = 019019019019019; map_data[00][5] = 019019019019019
map_data[01][3] = 019019019019019; map_data[01][4] = 019019019019019; map_data[01][5] = 019019019019019
map_data[02][3] = 019019019019019; map_data[02][4] = 019019019019019; map_data[02][5] = 019019019019019
map_data[03][3] = 019019019019019; map_data[03][4] = 019019019019019; map_data[03][5] = 019019019019019
map_data[04][3] = 019019019019019; map_data[04][4] = 019019019019019; map_data[04][5] = 019019019019019
map_data[05][3] = 019019019019019; map_data[05][4] = 019019019019019; map_data[05][5] = 019019019019019
map_data[06][3] = 019019019019019; map_data[06][4] = 019019019019019; map_data[06][5] = 019019019019019
map_data[07][3] = 019019019019019; map_data[07][4] = 019019019019019; map_data[07][5] = 019019019019019
map_data[08][3] = 019019019019019; map_data[08][4] = 019019019019019; map_data[08][5] = 019019019019019
map_data[09][3] = 019019019019019; map_data[09][4] = 019019019019019; map_data[09][5] = 019019019019019
map_data[10][3] = 019019019019019; map_data[10][4] = 019019019019019; map_data[10][5] = 019019019019019
map_data[11][3] = 019019019019019; map_data[11][4] = 019019019019019; map_data[11][5] = 019019019019019
map_data[12][3] = 019019019019019; map_data[12][4] = 019019019019019; map_data[12][5] = 019019019019019
map_data[13][3] = 019019019019019; map_data[13][4] = 019019019019019; map_data[13][5] = 019019019019019
map_data[14][3] = 019019019019019; map_data[14][4] = 019019019019019; map_data[14][5] = 019019019019019
map_data[15][3] = 019019019019019; map_data[15][4] = 019019019019019; map_data[15][5] = 019019019019019
map_data[16][3] = 019019019019019; map_data[16][4] = 019019019019019; map_data[16][5] = 005006006006006
map_data[17][3] = 019019019019019; map_data[17][4] = 019019019019019; map_data[17][5] = 037038038038038
map_data[18][3] = 006006006006006; map_data[18][4] = 006006006006006; map_data[18][5] = 038038038038038

map_data[00][6] = 019019019019019; map_data[00][7] = 019019019019019; map_data[00][8] = 019019019019019
map_data[01][6] = 019019019019019; map_data[01][7] = 019019019019019; map_data[01][8] = 019019019019019
map_data[02][6] = 019019019019019; map_data[02][7] = 019019019019019; map_data[02][8] = 019019019019019
map_data[03][6] = 019019019019019; map_data[03][7] = 019019019019019; map_data[03][8] = 019019019019019
map_data[04][6] = 019019019019019; map_data[04][7] = 019019019019019; map_data[04][8] = 019019019019019
map_data[05][6] = 019019019019019; map_data[05][7] = 019019019019019; map_data[05][8] = 019019019019019
map_data[06][6] = 019019019019019; map_data[06][7] = 019019019019019; map_data[06][8] = 019019019019019
map_data[07][6] = 019019019019019; map_data[07][7] = 019019019019019; map_data[07][8] = 019019019019019
map_data[08][6] = 019019019019019; map_data[08][7] = 019019019019019; map_data[08][8] = 019019019019019
map_data[09][6] = 019019019019019; map_data[09][7] = 019019019019019; map_data[09][8] = 019019019019019
map_data[10][6] = 019019019019019; map_data[10][7] = 019019019019019; map_data[10][8] = 019019019019019
map_data[11][6] = 019019019019019; map_data[11][7] = 019019019019019; map_data[11][8] = 019019019019019
map_data[12][6] = 019019019019019; map_data[12][7] = 019019019019019; map_data[12][8] = 019019019019019
map_data[13][6] = 019019019019019; map_data[13][7] = 019019019019019; map_data[13][8] = 019019019001002
map_data[14][6] = 005006006007019; map_data[14][7] = 019019019019019; map_data[14][8] = 019019019019019
map_data[15][6] = 037038038039019; map_data[15][7] = 019019019019019; map_data[15][8] = 019019019019019
map_data[16][6] = 038038038039019; map_data[16][7] = 019019019019019; map_data[16][8] = 019019019019019
map_data[17][6] = 038038038039019; map_data[17][7] = 019019019019019; map_data[17][8] = 019019019019019
map_data[18][6] = 038038038039019; map_data[18][7] = 019019019019005; map_data[18][8] = 006006006006006

map_data[00][9] = 019019019019019; map_data[00][10] = 019019019019019; map_data[00][11] = 019019019019019
map_data[01][9] = 019019019019019; map_data[01][10] = 019019019019019; map_data[01][11] = 019019019019019
map_data[02][9] = 019019019019019; map_data[02][10] = 019019019019019; map_data[02][11] = 019019019019019
map_data[03][9] = 019019019019019; map_data[03][10] = 019019019019019; map_data[03][11] = 019019019019019
map_data[04][9] = 019019019019019; map_data[04][10] = 019019019019019; map_data[04][11] = 019019019019019
map_data[05][9] = 019019019019019; map_data[05][10] = 019019019019019; map_data[05][11] = 019019019019019
map_data[06][9] = 019019019019019; map_data[06][10] = 019019019019019; map_data[06][11] = 019019019019019
map_data[07][9] = 019019019019019; map_data[07][10] = 019019019019019; map_data[07][11] = 019019019019019
map_data[08][9] = 001003019019019; map_data[08][10] = 019019019019019; map_data[08][11] = 019019019019019
map_data[09][9] = 019019019019019; map_data[09][10] = 019019019019019; map_data[09][11] = 019019019019019
map_data[10][9] = 019019019019019; map_data[10][10] = 019019019019019; map_data[10][11] = 019019019019019
map_data[11][9] = 019019019019019; map_data[11][10] = 019019019019019; map_data[11][11] = 019019019019019
map_data[12][9] = 019019019019019; map_data[12][10] = 019019019019019; map_data[12][11] = 019019019019019
map_data[13][9] = 002002002003019; map_data[13][10] = 019019019019019; map_data[13][11] = 019019019019019
map_data[14][9] = 019019019019019; map_data[14][10] = 019019019019019; map_data[14][11] = 019019019019019
map_data[15][9] = 019019019019019; map_data[15][10] = 019019019019019; map_data[15][11] = 019019019019019
map_data[16][9] = 019019019019019; map_data[16][10] = 019019019019019; map_data[16][11] = 019019019019019
map_data[17][9] = 019019019019019; map_data[17][10] = 019019019019019; map_data[17][11] = 019019019019019
map_data[18][9] = 006006006006006; map_data[18][10] = 006006006006006; map_data[18][11] = 006006006006006

#マップデータの設定
setCreateMap(img_map_name, img_no, pos_map, set_z, map_size, map_data)
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

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

#ここから↓は省略

  画像表示に関連した基本的な部分の設定項目は、
 他の画像表示設定と同じ要領で行います。

 「map_size」変数は、1つの配列データあたりのチップ数を設定しています。
 「map_data」変数の配列は、先ほどの画像チップ番号情報を設定しています。
 1チップあたり3桁の数字、実際の画面表示と同じ方向へデータ列が並んでいます。
 最後に、マップを設定するsetCreateMap関数を利用して、画像の設定を行います。


  ここまでで、マップの表示ができました。
 保存、終了をして、テストプレーを行い、
 マップが設定したデータ通りに表示されているか確認してみましょう。




02-02 マップをスクロールさせる


  第01回で少しお話に出てきました、カメラの移動を利用して
 マップのスクロールをつくってみましょう。

  なお、マップのスクロールは次のような仕組みでつくります。


  まずは、必要な定数の設定から。
#ここから↑は省略

#キャラクターの設定
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

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#背景の設定
bg_center = 352
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#音楽・効果音の設定
#ここから↓は省略

  「bg_center」変数は、画面横幅の半分となるサイズから、
 キャラクター画像横幅の半分となるサイズを引いた値を設定しています。

  マップをスクロールさせるとは、
 マップが画面端の場合はキャラクターの座標を、
 そうでない場合はマップの座標を
 進行方向とは逆方向に移動させて行います。

  このとき、キャラクターとマップのどちらを移動させるか
 切り替えるポイントとなる中心点の座標です。


  次は、必要な変数の設定。
 チャプター1にて、先ほど追加したマップの設定のすぐ後ろに追加します。
#ここから↑は省略
map_data[18][9] = 006006006006006; map_data[18][10] = 006006006006006; map_data[18][11] = 006006006006006

#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
setCreateMap(img_map_name, img_no, pos_map, set_z, map_size, map_data)
map_count = getArrayLength(map_data[0]) * map_size
map_max_w = map_count * 32
map_w  = map_max_w - 800
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

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

#ここから↓は省略

 「map_count」変数は、全体のマップ横サイズ(チップ数)
 「map_max_w」変数は、全体のマップ横サイズ(座標値)
 「map_w」変数は、全体のマップ横サイズ(座標値)から画面横幅の800を引いた数を
 設定しています。

  マップが画面端に到達しているか、判定するために使用します。


  キャラクターの移動スクリプトを差し替えて、
 マップのスクロールをつくります。
#ここから↑は省略
#_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
        #----- キャラクターの移動 -----
        if char_act != act_dmg
            if key_flg_left
                #左へ移動
                if (pos_char[x] < bg_center) || ((pos_char[x] > bg_center) && 
                   (getVariable(pos_map)[x] == map_w))
                    #中心線より外側
                    pos_char[x] = pos_char[x] - char_speed
                    if (pos_char[x] < bg_center) && (getVariable(pos_map)[x] == map_w)
                        getVariable(pos_map)[x] = getVariable(pos_map)[x] - (bg_center - pos_char[x])
                        pos_char[x] = bg_center
                    end
                else
                    #中心線
                    getVariable(pos_map)[x] = getVariable(pos_map)[x] - char_speed
                    if getVariable(pos_map)[x] < 0
                        pos_char[x] = pos_char[x] + getVariable(pos_map)[x]
                        getVariable(pos_map)[x] = 0
                    end
                end
                char_muki = 0
            elsif key_flg_right
                #右へ移動
                if (pos_char[x] > bg_center) || ((pos_char[x] < bg_center) && 
                   (getVariable(pos_map)[x] == 0))
                    #中心線より外側
                    pos_char[x] = pos_char[x] + char_speed
                    if (pos_char[x] > bg_center) && (getVariable(pos_map)[x] == 0)
                        getVariable(pos_map)[x] = getVariable(pos_map)[x] + (pos_char[x] - bg_center)
                        pos_char[x] = bg_center
                    end
                else
                    #中心線
                    getVariable(pos_map)[x] = getVariable(pos_map)[x] + char_speed
                    if getVariable(pos_map)[x] > map_w
                        pos_char[x] = pos_char[x] + (getVariable(pos_map)[x] - map_w)
                        getVariable(pos_map)[x] = map_w
                    end
                end
                char_muki = 1
            else
            end
        end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#ここから↓は省略

  先ほど追加した定数・変数を元に、
 キャラクターとマップのスクロールを切り替えています。
  また、切り替わる瞬間のとき、
 キャラクターの移動速度とキャラクターの移動量・マップの移動量を比較して
 端数が出た場合、それぞれマップの移動量・キャラクターの移動量に
 その端数を加算するように調整しています。



  最後に、実際にマップをスクロールさせます。
 マップのスクロールはカメラの移動を利用します。
#ここから↑は省略
            setSpritePos(img_char_name, pos_char)
        end
        
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
        #----- 背景のスクロール -----
        setSpriteCameraOffset(-(getVariable(pos_map)[x]), 0)
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        
        #----- 画面の更新 -----
#ここから↓は省略

  カメラが右に移動するとマップは左に、
 カメラが右に移動するとマップは右に移動するため、
 X座標の値をマイナスでセットしています。


  ここまでで、マップのスクロールができました。
 保存、終了をして、テストプレーを行い、
 マップがスクロールできているか確認してみましょう。





02-03 マップの当たり判定を追加する


  基本的な当たり判定の仕組みは、前回の第4回で解説したとおりです。

  しかし、マップ内にあるすべてのチップひとつひとつに、
 当たり判定のスクリプトを動かしていると、膨大な処理量になってしまいます。
  そこで、マップ側の当たり判定を座標情報を元に簡易的に判定することで、
 この処理量を軽減します。



  「hit_map」変数については、setCreateMap関数を行うとき、
 レイヤーが4なら同時に作っておくスクリプトになっていました。

  この「hit_map」変数を元に、当たり判定を行う仕組みをつくっていきます。


  まずは、チャプター0にて、一番下に座標情報を取得する関数を追加します。
#ここから↑は省略
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
#当たり判定の座標を算出
def setHitMap(char_atari, map_count)
    x1 = 0;   y1 = 1;   x2 = 2;   y2 = 3;   x3 = 4;   y3 = 5
    
    #当たり判定を行う座標を算出
    charHit_X1 = floor((char_atari[x1] + (getVariable("pos_map")[0])) / 32)
    charHit_X2 = floor((char_atari[x2] + (getVariable("pos_map")[0])) / 32)
    charHit_X3 = floor((char_atari[x3] + (getVariable("pos_map")[0])) / 32)
    charHit_Y1 = floor((char_atari[y1] + (getVariable("pos_map")[1] + 16)) / 32)
    charHit_Y2 = floor((char_atari[y2] + (getVariable("pos_map")[1] + 16)) / 32)
    charHit_Y3 = floor((char_atari[y3] + (getVariable("pos_map")[1] + 16)) / 32)
    charHit_Y4 = floor((char_atari[y3] + (getVariable("pos_map")[1] + 17)) / 32)
    
    #画面外の場合、画面端の座標とする
    if charHit_X1 < 0
        charHit_X1 = 0
    end
    if charHit_X3 > map_count
        charHit_X3 = map_count
    end
    
    if charHit_Y1 < 0
        charHit_Y1 = 0
        if charHit_Y2 < 0
            charHit_Y2 = 0
            if charHit_Y3 < 0
                charHit_Y3 = 0
                if charHit_Y4 < 0
                    charHit_Y4 = 0
                end
            end
        end
    end
    if charHit_Y4 > 18
        charHit_Y4 = 18
        if charHit_Y3 > 18
            charHit_Y3 = 18
            if charHit_Y2 > 18
                charHit_Y2 = 18
                if charHit_Y1 > 18
                    charHit_Y1 = 18
                end
            end
        end
    end
    
    #座標のマップ情報を取得
    charHitpos = createArray()
    charHitpos[0]  = getVariable("hit_map")[charHit_Y1][charHit_X1]
    charHitpos[1]  = getVariable("hit_map")[charHit_Y1][charHit_X2]
    charHitpos[2]  = getVariable("hit_map")[charHit_Y1][charHit_X3]
    charHitpos[3]  = getVariable("hit_map")[charHit_Y2][charHit_X1]
    charHitpos[4]  = getVariable("hit_map")[charHit_Y2][charHit_X2]
    charHitpos[5]  = getVariable("hit_map")[charHit_Y2][charHit_X3]
    charHitpos[6]  = getVariable("hit_map")[charHit_Y3][charHit_X1]
    charHitpos[7]  = getVariable("hit_map")[charHit_Y3][charHit_X2]
    charHitpos[8]  = getVariable("hit_map")[charHit_Y3][charHit_X3]
    charHitpos[9]  = getVariable("hit_map")[charHit_Y4][charHit_X1]
    charHitpos[10] = getVariable("hit_map")[charHit_Y4][charHit_X2]
    charHitpos[11] = getVariable("hit_map")[charHit_Y4][charHit_X3]
    
    charHitpos[12] = charHit_X1
    charHitpos[13] = charHit_X2
    charHitpos[14] = charHit_X3
    charHitpos[15] = charHit_Y1
    charHitpos[16] = charHit_Y2
    charHitpos[17] = charHit_Y3
    charHitpos[18] = charHit_Y4
    
    return charHitpos
end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

  キャラクターとマップの座標を元に、
 先ほどのイラストの黄色ポイントを算出する関数です。
  各座標のhit_map情報と、座標番号を戻り値にセットしています。
 なお、Y座標の3番目と4番目は、キャラクターの足元の判定より
 1ドット下の当たり判定を比較することで、
 着地しているかどうか判断するために使用します。


  次は、定数の設定です。
#ここから↑は省略
#----- 定数の設定 -----

x = 0;    y = 1;    w = 2;    h = 3
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
x1 = 0;   y1 = 1;   x2 = 2;   y2 = 3;   x3 = 4;   y3 = 5
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
act_std = 0; act_wrk = 1; act_jmp = 2; act_dmg = 3
#ここから↓は省略



  当たり判定のポイントによって、
 キャラクターの座標を当たり判定外に移動させるスクリプトをつくります。
  少しスクリプトの流れが複雑ですので、フローを纏めました。
・開始
 ↓
<地面に埋まっている    >
 ↓ はい         |いいえ
・着地状態に変更     |
 |           ↓
 |          <着地している       >
 ↓            ↓ はい         ↓ いいえ
<壁にめり込んでいる    >         <ジャンプ中        >
 ↓ はい         |いいえ        |はい         ↓ いいえ
・壁の外側へ移動     |           |          ・ジャンプ状態に変更
 |           |           ↓            ↓
 |           |          <天井にめり込んでいる   >
 |           |           ↓ はい         |いいえ
 |           |          ・天井の位置に変更    |
 |           |           ↓            ↓
 |           |          <壁にめり込んでいる    >
 |           |           ↓ はい         |いいえ
 |           |          ・壁の外側へ移動     |
 ↓            ↓            ↓            ↓
・終了

  このフローにそって、スクリプトを書いていきます。


#ここから↑は省略
#_/_/_/_/_/_/_/_/_/_/_/_/ 変更分 _/_/_/_/_/_/_/_/_/_/_/_/
        #マップとの当たり判定
        if char_act != act_dmg
            HitFlgD = false; HitFlgM = false; HitFlgLD = false; HitFlgRD = false
            HitFlgU = false; HitFlgLU = false; HitFlgRU = false
            HitFlgLS = false; HitFlgRS = false
            xSa = 0; ySa = 0
            
            #キャラクターの当たり判定範囲
            char_atari[x1] = pos_char[x] + char_hit[x]
            char_atari[y1] = pos_char[y] + char_hit[y]
            char_atari[x2] = char_atari[x1] + (char_hit[w] * 0.5)
            char_atari[y2] = char_atari[y1] + (char_hit[h] * 0.5)
            char_atari[x3] = char_atari[x1] + char_hit[w]
            char_atari[y3] = char_atari[y1] + char_hit[h]
            
            #当たり判定の座標を算出
            charHitpos = setHitMap(char_atari, map_count)
            charHit_X1 = charHitpos[12]
            charHit_X2 = charHitpos[13]
            charHit_X3 = charHitpos[14]
            charHit_Y1 = charHitpos[15]
            charHit_Y2 = charHitpos[16]
            charHit_Y3 = charHitpos[17]
            charHit_Y4 = charHitpos[18]
            
            #床の当たり判定
            #右端または左端だけの場合フラグ除外するためのフラグ
            if (charHitpos[9] != 19) && (charHitpos[10] == 19) && (charHitpos[11] == 19)
                HitFlgLD = true
            end
            if (charHitpos[9] == 19) && (charHitpos[10] == 19) && (charHitpos[11] != 19)
                HitFlgRD = true
            end
            
            if ((charHitpos[6] == 19) && (charHitpos[9]  != 19)) ||
               ((charHitpos[7] == 19) && (charHitpos[10] != 19)) ||
               ((charHitpos[8] == 19) && (charHitpos[11] != 19))
                #着地中
                HitFlgD = true
            elsif ((charHitpos[6] != 19) && (charHitpos[9]  != 19)) ||
                  ((charHitpos[7] != 19) && (charHitpos[10] != 19)) ||
                  ((charHitpos[8] != 19) && (charHitpos[11] != 19))
                #埋まり中
                HitFlgM = true
                #当たり判定からの差分座標を算出
                ySa = char_atari[y3] - (((charHit_Y3 - 1) * 32) - getVariable("pos_map")[y] + 15)
            end
            
            #天井の当たり判定
            #右端または左端だけの場合フラグ除外するためのフラグ
            if (charHitpos[0] != 19) && (charHitpos[1] == 19) && (charHitpos[2] == 19)
                HitFlgLU = true
            end
            if (charHitpos[0] == 19) && (charHitpos[1] == 19) && (charHitpos[2] != 19)
                HitFlgRU = true
            end
            
            if (!(HitFlgD) || !(HitFlgM)) && !(HitFlgLU) && !(HitFlgRU) && (
               (charHitpos[0] != 19) ||
               (charHitpos[1] != 19) ||
               (charHitpos[2] != 19))
                #埋まり中
                HitFlgU = true
                #当たり判定からの差分座標を算出
                ySa = ((charHit_Y1 * 32) - getVariable("pos_map")[y] + 16) - char_atari[y1]
            end
            
            if pos_char[y] > 600
                ySa = 0
            end
            
            #キャラクターの状態変化と差分の移動
            if (HitFlgD || HitFlgM) && !(HitFlgLD) && !(HitFlgRD)
                #着地中
                if HitFlgM
                    #床 / 差分の移動
                    pos_char[y] = pos_char[y] - ySa
                end
            else
                #落下中
            end
            
            if HitFlgU
                #天井 / 差分の移動
                pos_char[y] = pos_char[y] + ySa
            end
            
            #キャラクターの当たり判定範囲(座標変化後の再設定)
            char_atari[x1] = pos_char[x] + char_hit[x]
            char_atari[y1] = pos_char[y] + char_hit[y]
            char_atari[x2] = char_atari[x1] + (char_hit[w] * 0.5)
            char_atari[y2] = char_atari[y1] + (char_hit[h] * 0.5)
            char_atari[x3] = char_atari[x1] + char_hit[w]
            char_atari[y3] = char_atari[y1] + char_hit[h]
            
            #当たり判定の座標を算出(座標変化後の再設定)
            charHitpos = setHitMap(char_atari, map_count)
            charHit_X1 = charHitpos[12]
            charHit_X2 = charHitpos[13]
            charHit_X3 = charHitpos[14]
            charHit_Y1 = charHitpos[15]
            charHit_Y2 = charHitpos[16]
            charHit_Y3 = charHitpos[17]
            charHit_Y4 = charHitpos[18]
            
            if !(HitFlgU)
                
                #壁の当たり判定
                if ((charHitpos[0] != 19) ||
                    (charHitpos[3] != 19) ||
                    (charHitpos[6] != 19))
                    #左の壁
                    HitFlgLS = true
                    #当たり判定からの差分座標を算出
                    xSa = char_atari[x1] + (getVariable("pos_map")[x] - ((charHit_X1 + 1) * 32))
                elsif ((charHitpos[2] != 19) ||
                       (charHitpos[5] != 19) ||
                       (charHitpos[8] != 19))
                    #右の壁
                    HitFlgRS = true
                    #当たり判定からの差分座標を算出
                    xSa = char_atari[x3] + (getVariable("pos_map")[x] - (charHit_X3 * 32) + 1)
                end
                
                #キャラクターの状態変化と差分の移動
                
                #壁 / 差分の移動
                if HitFlgRS
                    #左へ移動
                    if (pos_char[x] < bg_center) || ((pos_char[x] > bg_center) && 
                       (getVariable(pos_map)[x] == map_w))
                        #中心線より外側
                        pos_char[x] = pos_char[x] - xSa
                        if (pos_char[x] < bg_center) && (getVariable(pos_map)[x] == map_w)
                            getVariable(pos_map)[x] = getVariable(pos_map)[x] - (bg_center - pos_char[x])
                            pos_char[x] = bg_center
                        end
                    else
                        #中心線
                        getVariable(pos_map)[x] = getVariable(pos_map)[x] - xSa
                        if getVariable(pos_map)[x] < 0
                            pos_char[x] = pos_char[x] + getVariable(pos_map)[x]
                            getVariable(pos_map)[x] = 0
                        end
                    end
                elsif HitFlgLS
                    #右へ移動
                    if (pos_char[x] > bg_center) || ((pos_char[x] < bg_center) && 
                       (getVariable(pos_map)[x] == 0))
                        #中心線より外側
                        pos_char[x] = pos_char[x] - xSa
                        if (pos_char[x] > bg_center) && (getVariable(pos_map)[x] == 0)
                            getVariable(pos_map)[x] = getVariable(pos_map)[x] + (pos_char[x] - bg_center)
                            pos_char[x] = bg_center
                        end
                    else
                        #中心線
                        getVariable(pos_map)[x] = getVariable(pos_map)[x] - xSa
                        if getVariable(pos_map)[x] > map_w
                            pos_char[x] = pos_char[x] + (getVariable(pos_map)[x] - map_w)
                            getVariable(pos_map)[x] = map_w
                        end
                    end
                end
            end
        end
        
        #画面端との当たり判定
        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)
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
#ここから↓は省略

  フローの状態を判定するために、沢山のフラグや変数が登場しました。
 ひとつずつ、詳しく解説します。

 「HitFlgD」  キャラクターの足元の当たり判定フラグ。
        着地状態であればオンになります。
 「HitFlgM」  キャラクターの足元の当たり判定フラグ。
        地面に埋まっている状態であればオンになります。
 「HitFlgLD」 キャラクターの足元の当たり判定フラグ。
        左下のみ設置しているときオンになります。
 「HitFlgRD」 キャラクターの足元の当たり判定フラグ。
        右下のみ設置しているときオンになります。
 「HitFlgU」  キャラクターの頭上の当たり判定フラグ。
 「HitFlgLU」 キャラクターの頭上の当たり判定フラグ。
        左上のみ設置しているときオンになります。
 「HitFlgRU」 キャラクターの頭上の当たり判定フラグ。
        右上のみ設置しているときオンになります。
 「HitFlgLS」 キャラクターの左側の当たり判定フラグ。
 「HitFlgRS」 キャラクターの右側の当たり判定フラグ。
 「xSa」    キャラクターとチップの横方向重なり差分座標。
 「ySa」    キャラクターとチップの縦方向重なり差分座標。


  まずはフラグ関連で当たり状態を判断し、
 当たっていた場合、差分座標を計算する仕組みになっています。

  最後に、差分座標をキャラクター・マップに追加しています。


  ここまでで、マップの当たり判定ができました。
 保存、終了をして、テストプレーを行い、
 マップに接触すると立ち止まるか確認してみましょう。




02-04 ジャンプができるようにする




  床の当たり判定ができましたので、
 キャラクターもジャンプができるようにしてみましょう。

  まずは定数・変数の準備から。
#ここから↑は省略
#キャラクターの設定
char_speed = 7
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
char_jmp_h = 40
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
char_w_max = 800 - 63;      char_h_max = 600 - 80
char_anime_change = 6

#中略

char_muki = 1
char_act = act_std
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
char_jmp_count = 0
char_jmp_flg = false
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/

#キャラクターの当たり判定範囲
char_atari = createArray()
#ここから↓は省略

 「char_jmp_h」変数はキャラクターのジャンプ力
 「char_jmp_count」変数はジャンプしてからの経過時間
 「char_jmp_flg」変数はジャンプ中かどうかの判定に使用します


  Zキーを押したときにジャンプを開始するようにします。
#ここから↑は省略
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
        #----- キャラクターのジャンプ -----
        if key_flg_z
            if (char_act != act_jmp) && !(char_jmp_flg)
                char_act = act_jmp; char_jmp_count = 0; char_jmp_flg = true
            end
        else
            char_jmp_flg = false
        end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        #----- キャラクターのアニメーション -----
#ここから↓は省略



  ジャンプ中の動作をつくります。
 まずはジャンプ中の座標移動。
#ここから↑は省略
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
        if char_act == act_jmp
            if char_jmp_count < 10
                pos_char[y] = pos_char[y] - (char_jmp_h * (0.4 + ((6 - char_jmp_count) * 0.1)))
                
            else
                pos_char[y] = pos_char[y] + (char_jmp_h * (0.4 + ((char_jmp_count - 14) * 0.1)))
                
            end
            
            if char_jmp_count < 20
                char_jmp_count = char_jmp_count + 1
            end
        end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
        #----- キャラクターのアニメーション -----
#ここから↓は省略

  ジャンプ時間が10を頂点に、上昇中・下降中を切り替えています。
  ジャンプ時間が20以上になったとき、落下速度は固定となります。

 次に、表示の切り替え。
#ここから↑は省略
        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
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
        elsif char_act == act_jmp
            if char_jmp_count < 10
                setCharSpritePattern(7 + (char_muki * 10))
            else
                setCharSpritePattern(8 + (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 char_act != act_dmg
            if key_flg_left
                #左へ移動
                if (pos_char[x] < bg_center) || ((pos_char[x] > bg_center) && 
                   (getVariable(pos_map)[x] == map_w))
                    #中心線より外側
                    pos_char[x] = pos_char[x] - char_speed
                    if (pos_char[x] < bg_center) && (getVariable(pos_map)[x] == map_w)
                        getVariable(pos_map)[x] = getVariable(pos_map)[x] - (bg_center - pos_char[x])
                        pos_char[x] = bg_center
                    end
                else
                    #中心線
                    getVariable(pos_map)[x] = getVariable(pos_map)[x] - char_speed
                    if getVariable(pos_map)[x] < 0
                        pos_char[x] = pos_char[x] + getVariable(pos_map)[x]
                        getVariable(pos_map)[x] = 0
                    end
                end
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
                char_muki = 0
                if char_act != act_jmp
                    char_act = act_wrk
                end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
            elsif key_flg_right
                #右へ移動
                if (pos_char[x] > bg_center) || ((pos_char[x] < bg_center) && 
                   (getVariable(pos_map)[x] == 0))
                    #中心線より外側
                    pos_char[x] = pos_char[x] + char_speed
                    if (pos_char[x] > bg_center) && (getVariable(pos_map)[x] == 0)
                        getVariable(pos_map)[x] = getVariable(pos_map)[x] + (pos_char[x] - bg_center)
                        pos_char[x] = bg_center
                    end
                else
                    #中心線
                    getVariable(pos_map)[x] = getVariable(pos_map)[x] + char_speed
                    if getVariable(pos_map)[x] > map_w
                        pos_char[x] = pos_char[x] + (getVariable(pos_map)[x] - map_w)
                        getVariable(pos_map)[x] = map_w
                    end
                end
                char_muki = 1
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
                if char_act != act_jmp
                    char_act = act_wrk
                end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
            else
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
                if char_act != act_jmp
                    char_act = act_std
                end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
            end
        end
#ここから↓は省略


 次に、当たり判定スクリプト
#ここから↑は省略
            #キャラクターの状態変化と差分の移動
            if (HitFlgD || HitFlgM) && !(HitFlgLD) && !(HitFlgRD)
                #着地中
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
                #ジャンプ中の場合立ち状態に変更
                if char_act == act_jmp
                   char_act = act_std; char_jmp_count = 0
                end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
                if HitFlgM
                    #床 / 差分の移動
                    pos_char[y] = pos_char[y] - ySa
                end
            else
                #落下中
#_/_/_/_/_/_/_/_/_/_/_/_/ 追加分 _/_/_/_/_/_/_/_/_/_/_/_/
                #立ち状態の場合ジャンプ中に変更
                if char_act != act_jmp
                    char_act = act_jmp; char_jmp_count = 10
                end
#_/_/_/_/_/_/_/_/_/_/_/_/ここまで_/_/_/_/_/_/_/_/_/_/_/_/
            end
#ここから↓は省略




  スクリプト全体

  これで、一通り完成です。
 保存、終了をして、テストプレーを行い、
 マップの当たり判定、キャラクターのジャンプが行えるか
 確認してみましょう。




02-05 おわりに


  いかがでしたでしょうか。
 スクリプトの量も増えてきて、一度に全体を見渡すのは難しくなってきましたが、
 各処理ごとに分割して見てみると、これまでの応用であることがわかると思います。

  さて、次回はキャラクター以外の要素、
 「敵・アイテムを追加してみよう」を実践してみましょう。


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

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