FC2ブログ

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

こんばんわ( ^ω^)
平日は忙しくてブログが更新できませんでした。(´;ω;`)ウッ
今後は土日のみの更新になるとおもいます。
とはいえ、もうRGSSについて書くことがなくなってきましたがね。
書くことがなくなったらQuest Maniaの進捗状況でも書こうかと思います。

実は今日、以前紹介した壁の上を歩行可能にするスクリプトでは、
水平壁の端に歩行可能な上層レイヤーを置くと歩行可能になったり、
レイヤーがきちんと機能しないというご指摘を受けました。スミマセン(´;ω;`)ウッ
そこで、今日はその不具合を改善するスクリプトを紹介します。

まず、前回のスクリプトは削除していただいて、以下のスクリプトのコピーをお願いします。
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] = 0x20
          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

class Game_Character
  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)
    wall = wall_passable?(x, y, self_x, self_y, flag)   
    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 and wall  # [○] : 通行可
      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]
      next if pass & 0x10 == 0x10       # [☆] : 通行に影響しない
      pass = 0x00 if pass & 0x20 == 0x20
      return true if pass & flag == 0x00 and wall # [○] : 通行可
      return false if pass & flag == flag   # [×] : 通行不可
    end
    return false                            # 通行不可
  end
 
  def wall_passable?(x, y, self_x, self_y, flag = 0x01)
    return false if @map.data[x, y, 0] == nil
    pass = @passages[@map.data[x, y, 0]]         # 通行属性を取得
    self_pass = @passages[@map.data[self_x, self_y, 0]]
    if 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
      end 
    end
    return true 
  end
end


これで、水平壁の上にレイヤーを敷いてもちゃんと機能するようになったと思います。
でも、このままだとプレイヤーの隣にいるイベントが、決定ボタンを押した場合や、
接したときにコマンドが起動するように設定してる場合、水平壁の端をまたいで
いたとしても、起動してしまいます。
この状況は避けたい場合は、以下のスクリプトもコピーしておいてください。
多少重くなるかも知れませんが(´・ω・`)

class Game_Player
  def check_event_trigger_there(triggers)
    return false if $game_map.interpreter.running?
    result = false
    front_x = $game_map.x_with_direction(@x, @direction)
    front_y = $game_map.y_with_direction(@y, @direction)
    if $game_map.passable2?(@x, @y, front_x, front_y) #★
      for event in $game_map.events_xy(front_x, front_y)
        if triggers.include?(event.trigger) and event.priority_type == 1
          event.start
          result = true
        end
      end
    end #★
    if result == false and $game_map.counter?(front_x, front_y)
      front_x = $game_map.x_with_direction(front_x, @direction)
      front_y = $game_map.y_with_direction(front_y, @direction)
      for event in $game_map.events_xy(front_x, front_y)
        if triggers.include?(event.trigger) and event.priority_type == 1
          event.start
          result = true
        end
      end
    end
    return result
  end
end

class Game_Character
  #--------------------------------------------------------------------------
  # ● 下に移動
  #     turn_ok : その場での向き変更を許可
  #--------------------------------------------------------------------------
  def move_down(turn_ok = true)
    if passable?(@x, @y+1)                  # 通行可能
      turn_down
      @y = $game_map.round_y(@y+1)
      @real_y = (@y-1)*256
      increase_steps
      @move_failed = false
    else                                    # 通行不可能
      turn_down if turn_ok
      if $game_map.passable2?(@x, @y+1, @x, @y) #★
        check_event_trigger_touch(@x, @y+1)   # 接触イベントの起動判定
      end #★
      @move_failed = true
    end
  end
  #--------------------------------------------------------------------------
  # ● 左に移動
  #     turn_ok : その場での向き変更を許可
  #--------------------------------------------------------------------------
  def move_left(turn_ok = true)
    if passable?(@x-1, @y)                  # 通行可能
      turn_left
      @x = $game_map.round_x(@x-1)
      @real_x = (@x+1)*256
      increase_steps
      @move_failed = false
    else                                    # 通行不可能
      turn_left if turn_ok
      if $game_map.passable2?(@x-1, @y, @x, @y) #★
        check_event_trigger_touch(@x-1, @y)   # 接触イベントの起動判定
      end #★
      @move_failed = true
    end
  end
  #--------------------------------------------------------------------------
  # ● 右に移動
  #     turn_ok : その場での向き変更を許可
  #--------------------------------------------------------------------------
  def move_right(turn_ok = true)
    if passable?(@x+1, @y)                  # 通行可能
      turn_right
      @x = $game_map.round_x(@x+1)
      @real_x = (@x-1)*256
      increase_steps
      @move_failed = false
    else                                    # 通行不可能
      turn_right if turn_ok
      if $game_map.passable2?(@x+1, @y, @x, @y) #★
        check_event_trigger_touch(@x+1, @y)   # 接触イベントの起動判定
      end #★
      @move_failed = true
    end
  end
  #--------------------------------------------------------------------------
  # ● 上に移動
  #     turn_ok : その場での向き変更を許可
  #--------------------------------------------------------------------------
  def move_up(turn_ok = true)
    if passable?(@x, @y-1)                  # 通行可能
      turn_up
      @y = $game_map.round_y(@y-1)
      @real_y = (@y+1)*256
      increase_steps
      @move_failed = false
    else                                    # 通行不可能
      turn_up if turn_ok
      if $game_map.passable2?(@x, @y-1, @x, @y) #★
        check_event_trigger_touch(@x, @y-1)   # 接触イベントの起動判定
      end #★
      @move_failed = true
    end
  end
end



これで問題はなくなったと思います。
もしまだ あったらすみません。(´・ω・`)

今日はもうひとつ、水平壁のマップの作り方を紹介します。
壁のタイルをマップ上に敷こうとすると、オートマップ機能で、
うまく設置できない場合があります。こういう場合は、Shiftキーをおしながら、
操作するとうまくいきます。
壁に階段やはしごを設置する場合、水平壁の端の部分は、
あらかじめ、ダミーを作っておき、それをShiftを押したままコピーし貼り付けます。
示した図のように矢印の方にコピーすればうまくいきます。
080112_01.jpg


まだ、あまりテストしてませんが、もしまだ不具合がありましたら
コメントのほうによろしくお願いいたします。
でわ( ^ω^)ノシ
スポンサーサイト

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

コメントの投稿

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

すごい!

すごい!
このスクリプトを使えば、すごく入り組んだダンジョンが作れますね!
オレも、スクリプト勉強しなければ(--;)

不具合?

乗り物の通行属性判定が、passable? を用いたままですね。
ここも書き換える必要があるのではないでしょうか。

例えば、飛行船着陸禁止を 2^3 の位が担当していますが、
改変フラグ (2^5 の位) のチェックをしない passable? では、
↓通行不可のタイルとの区別がつきません。
つまり、↓通行不可を設定したタイルはみな、
飛行船着陸禁止になってしまいます。

単純に passable2? に書き換えれば完全かどうかは検証中ということで…。


それにしても、このシステムはおもしろいですね。
定数ハッシュに
タイル ID => [↓禁止, →禁止, ↑禁止, ←禁止]
のように指定しておき、
Game_Map クラスでそれに基づいた通行属性改変を行えば、
オートタイル以外は、容易に 4 方向指定できそうです。

(´・ω:;.:...サラサラ

ああ、そういえば乗り物のことは考えてませんでした。スミマセン(´;ω;`)ウッ
たしかに、水平壁で下に通行できないところに着地できなかったり、
船で通行できたりと・・・・。

とりあえず、乗り物の場合は、passable?の一つ前の行に
return false if @passages[@map.data[x, y, 0]] & 0x20 == 0x20
と置いて、壁の場合は通行できないようにするっていうのでどうでしょうか。
(飛行船なら return true)

おれにはもう、ブログを更新する気力は・・・
(´・ω:;.:...サラサラ
プロフィール

Suppon

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

Twitter...

Twitter Reload

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

この人とブロともになる