RGSS2備忘録その1 壁の上を歩行可能にするスクリプト

今日からRGSS2シリーズをやっていきます。ヤッタネ(^▽^)
ちなみにRGSS2というのはRPGツクールVXでの話しとなります。
XPではないのでお間違えのなく。

で、第1回目は壁グラフィック上を通行可能にする方法であります。
壁グラフィックはダンジョン生成コマンドで使われる壁グラフィックのタイル群です。
071230_01.jpg

通行可能にするのはもちろん、視覚的に水平に見える方です。
垂直に見える壁は、そのまま通行不可のまんまとします。
これ以降、通行可能にする壁グラフィックのことを水平壁と呼ぶことにします。( ・`ω・´)

通常、通行可能、不可能を設定する場合は、ツクール上で通行設定というアイコンを
クリックするか、メニューから選択し、タイル別に○か×を選んでやります。
しかし、そうやると地面と水平壁の間を自由に行き来できるようになってしまいます。
それを回避するために、通行不可のイベントを境目に配置するという方法でも
できなくはないですが入り組んだ一マス分の通路とかは、作れません。(´;ω;`)ウッ
そこで、タイルごとの通行属性を改ざんすることで、そこの問題をうまく回避
しようと思います。

今回は、かなり長くなりそうなのでSupponはここいらで、
お茶を一杯いただこうかとおもいます。

ズズズズズズ←お茶をすする音

(*^▽^)ノアイッ ごちそうさまでした。

では説明にもどります。( ・`ω・´)
まず、タイルグラフィックそれぞれには、個々にIDと通行属性のデータ
が割り当てられています。
それぞれのタイルのIDはトリアコンタンさんという方のホームページに
エクセルのデータとして公開されています。
こちらです→Delusional Field
そちらを拝見すると一目瞭然です。(^▽^)ヤッタネ
一番左上の水平壁のIDは5888はになります。
次に通行属性のデータについてですが、通行可能、不可能はビットでの比較で
行われます。ヘルプやスクリプトにはなぜか、わかりにくい16進数で表記されていますが、
2進数表記であらわすと、わかりやすいです。
↓画像にまとめました。
071230_02.jpg

1の位が0なら歩行可能、1なら歩行不可
2の位が0なら小型船通行可能、1なら通行不可という感じです。
普通の何もない歩行可能な地面なら00000110(0x06)になります。
このような通行属性データがそれぞれのタイルに割り当てられています。

一番左上の水平壁のIDは5888で、その隣は5936になっているのがわかると思います。
なぜこうなっているかというと、オートタイルの組み合わせで、一種類の水平壁は
46通りの組み合わせがあるからなのです。
5936 - 5888 = 48 なので、48通りあるのかと思うかもしれませんが、おそらく残り2つは
使われてないと思います。おそらく48っていうのが 16 * 3 なので、ちょうどキリがいい
数字だから、48ずつIDを割り当ててるんだと思います。
で、どのような組み合わせがあるのかというと、このようになります。多分これで全部です。
わかりやすいように境界を見やすくしました。
071230_03.jpg

この画像に表示されてる番号は、その種のタイルIDの開始番号を差し引いた、それぞれのタイルのIDです。したがって、番号0のタイルのIDは5888です。

続いて、これら46通りの通行属性をつくってみます。
とはいっても、46通りすべて違うデータにする必要はありません。
肝心なのは、4方向で通行可能なのはどの方向かということです。
なので、0番目から15番目までは4方向とも通行可能なので、同じデータでいいっていう
ことがわかるとおもいます。

ここでどのように通行属性を割り当てるかというと、
先ほどの2進数の表記で6の位が空いているのがわかります。なので、水平壁は
とりあえず、この6の位を1とします。そして下4桁で、上下左右の通行可能・不可能を
表したいとおもいます。
とするとこうなります。
071230_04.jpg


だいぶ疲れてきましたが、こんなことでへこたれるSupponではありません( ・`ω・´)
でも、ここで一息いれようと思います。( ^ω^)

ズズズズズ ←ココアをすする音

(*^▽^)ノアイッ ご馳走様でした。

ではつづけます( ・`ω・´)
スクリプト上でこれら46通りのタイルに通行属性を割り当てます。
class Game_Map
  #--------------------------------------------------------------------------
  # ● セットアップ
  #     map_id : マップ ID
  #--------------------------------------------------------------------------
  def setup(map_id)
    @map_id = map_id
    @map = load_data(sprintf("Data/Map%03d.rvdata", @map_id))
    @display_x = 0
    @display_y = 0
    @passages = $data_system.passages
    for m in 0..2
      for k in 0..7
        j = 5888 + 48 * k + 768 * m
        for i in 0..47
          if i < 16
            @passages[i + j] = 0x06
          elsif 16 <= i and  i <= 19
            @passages[i + j] = 0x21
          elsif 20 <= i and  i <= 23
            @passages[i + j] = 0x22
          elsif 24 <= i and  i <= 27
            @passages[i + j] = 0x24
          elsif 28 <= i and  i <= 31
            @passages[i + j] = 0x28
          elsif i == 32
            @passages[i + j] = 0x25
          elsif i == 33
            @passages[i + j] = 0x2a
          elsif i == 34 or i == 35
            @passages[i + j] = 0x23
          elsif i == 36 or i == 37
            @passages[i + j] = 0x26
          elsif i == 38 or i == 39
            @passages[i + j] = 0x2c
          elsif i == 40 or i == 41
            @passages[i + j] = 0x29
          elsif i == 42
            @passages[i + j] = 0x27
          elsif i == 43
            @passages[i + j] = 0x2b
          elsif i == 44
            @passages[i + j] = 0x2d
          elsif i == 45
            @passages[i + j] = 0x2e
          elsif i >= 46
            @passages[i + j] = 0x2f
          end
        end
      end
    end
    referesh_vehicles
    setup_events
    setup_scroll
    setup_parallax
    @need_refresh = false
  end
end
こんな感じになります。(´・ω・`)


新しい通行属性データは、@passagesというインスタンス変数に格納します。

つぎに、Game_CharactorクラスとGame_Playerクラスで
新しい通行判定メソッドを設定してやります。
今回はpassable2?(x, y, self_x, self_y, flag = 0x01)というメソッド
をつくります。
x, yは移動先のタイル、self_x, self_yは今自分が立っている場所のタイルの座標です。

class Game_Charactor
  def map_passable?(x, y)
    return $game_map.passable2?(x, y, @x, @y)
  end
end

class Game_Player
  def map_passable?(x, y)
    case @vehicle_type
    when 0  # 小型船
      return $game_map.boat_passable?(x, y)
    when 1  # 大型船
      return $game_map.ship_passable?(x, y)
    when 2  # 飛行船
      return true
    else    # 徒歩
      return $game_map.passable2?(x, y, @x, @y)
    end
  end
end

最後に、実際の判定処理の改造です。

class Game_Map
  def passable2?(x, y, self_x, self_y, flag = 0x01)
    for event in events_xy(x, y)            # 座標が一致するイベントを調べる
      next if event.tile_id == 0            # グラフィックがタイルではない
      next if event.priority_type > 0       # [通常キャラの下] ではない
      next if event.through                 # すり抜け状態
      pass = @passages[event.tile_id]       # 通行属性を取得
      next if pass & 0x10 == 0x10           # [☆] : 通行に影響しない
      return true if pass & flag == 0x00    # [○] : 通行可
      return false if pass & flag == flag   # [×] : 通行不可
    end
    for i in [2, 1, 0]                      # レイヤーの上から順に調べる
      tile_id = @map.data[x, y, i]          # タイル ID を取得
      return false if tile_id == nil        # タイル ID 取得失敗 : 通行不可
      pass = @passages[tile_id]             # 通行属性を取得
      self_pass = @passages[@map.data[self_x, self_y, 0]]
      if i == 0 and flag == 0x01
        if self_pass & 0x20 == 0x20 #★ 今たっている場所の水平壁判定
          if x > self_x #右を向いている
            return false if self_pass & 0x04 == 0x04
          elsif x < self_x #左を向いている
            return false if self_pass & 0x01 == 0x01
          elsif y > self_y #下を向いている
            return false if self_pass & 0x08 == 0x08
          elsif y < self_y #上を向いている
            return false if self_pass & 0x02 == 0x02
          end
        end
        if pass & 0x20 == 0x20 #★ 移動先の水平壁判定
          if x > self_x #右を向いている
            return false if pass & 0x01 == 0x01
          elsif x < self_x #左を向いている
            return false if pass & 0x04 == 0x04
          elsif y > self_y #下を向いている
            return false if pass & 0x02 == 0x02
          elsif y < self_y #上を向いている
            return false if pass & 0x08 == 0x08
          end
          return true
        end
      end
      next if pass & 0x10 == 0x10           # [☆] : 通行に影響しない
      return true if pass & flag == 0x00    # [○] : 通行可
      return false if pass & flag == flag   # [×] : 通行不可
    end
    return false                            # 通行不可
  end
end



となります。
かなり長いですが、これはSupponの構文の作り方がへたくそだからです。
うまい人だったら、もっと短い文でまとめられるのではないかと思います。

これで、このような立体的なマップもつくれるようになったのではないでしょうか。
071230_05.jpg

では、今日はこのへんで(^▽^)ノシ
スポンサーサイト

テーマ : RPGツクール
ジャンル : ゲーム

トラックバック


この記事にトラックバックする(FC2ブログユーザー)

[FreeRGSS]Tilemapクラスの実装

TilemapのマップデータはTableオブジェクトで格納されるが、その値はタイルIDと8方向の境界パターンの組み合わせで決まる。 自分で調べると面倒なこういうのも、ネットで検索すると調査した先人がちゃんと存在する。 http://supponweblog.blog88.fc2.com/blog-entry-9.html

コメントの投稿

管理者にだけ表示を許可する

壁の上を歩行可能にするスクリプト

はじめまして。

革新的なスクリプトばかりですね!
拝見していてわくわくします。

勝手ながら、このスクリプトの挙動を試させていただいたのですが、

○ ←通行可能上層チップ(はしごの足など)
■ ←水平壁上端

のような並びの場合、
水平壁上端側から通行可能上層チップへ降りられてしまうようです。
(わかりにくい記述でごめんなさい。)

まだ解析させていただいている途中でして、
どこを改造すればうまくいくと申し上げられないのですが、
ご報告までと思いました。

壁の上を歩行可能にするスクリプト

おわ、本当ですね。
ご指摘ありがとうございます。

今回紹介したスクリプトでは
水平壁の端に通行可能な上層チップがあると水平壁側から
通行可能になってるのは、このスクリプトでは下層チップのレイヤー
しか考慮してないからです。

なので、Game_Mapクラスの passable2?メソッド
の中ほどにある if i == 0 and flag == 0x01 という文の
i == 0 and を取り除いてやれば、とりあえず、問題は回避できると思います。

ですが、まだこのままだと、通行可能なイベントとかをおくと水平壁の端から外に
出られるという問題があるので、あとで、修正したスクリプトができたら
紹介したいと思います。

壁の上を歩行可能にするスクリプト

タイルやイベントのレイヤー情報がほとんど内部データであるだけに、
それを使った処理というのもなかなかシビアになるのですね。


話は変わりまして、以下は何の確証もない発言です。

『レクトール』のダメージ床設定において、
床タイルを直接ダメージ床に指定するのではなく、
上層に専用のタイル(透明など)を置いて、
それでダメージ床と認識させるというテクニックがあります。
(MATERIAL QUEST ONLINE 07/12/15の記事)

これをまねて、例えば、
TileEの空いたスペースに、各方向の通行可不可を担当する
上層タイル(2^4枚)を用意して、それを、被せて配置することで、
下層タイルの通行可能方向を制御するというようなことはできないでしょうか。
(もちろん、他の上層タイルは置けなくなりますが…。)

壁の上を歩行可能にするスクリプト

そうですね。
セットEを使うのも一つの手として使えそうですね。
ですが、そうしなくてもいい、スクリプトを考えました。
今日の記事に掲載しておきましたので、
もしよろしかったら、お試しください( ^ω^)
プロフィール

Suppon

Author:Suppon
すっぽんでーす。(^▽^)
カルドラ鋭意制作中( ・`ω・´)
Twitter => suppon01
メールはこちらへ
suppon2008@gmail.com

Twitter...

Twitter Reload

最近のコメント
最近のトラックバック
月別アーカイブ
カテゴリー
ブログ内検索
RSSフィード
リンク
ブロとも申請フォーム

この人とブロともになる