赞 | 1 |
VIP | 0 |
好人卡 | 0 |
积分 | 5 |
经验 | 0 |
最后登录 | 2024-8-23 |
在线时间 | 59 小时 |
Lv2.观梦者
- 梦石
- 0
- 星屑
- 549
- 在线时间
- 59 小时
- 注册时间
- 2017-11-19
- 帖子
- 71
|
20星屑
本帖最后由 寒冷的企鹅 于 2018-4-30 11:33 编辑
问题只解决了第二个
这个脚本我已经按照上面说的在移动路线里设置脚本,可每次都报错,只有初始时向玩家移动没事
#============================================================================== # ■ 経路探索VXAce (VX Ace用) #------------------------------------------------------------------------------ # 製作者 : CanariAlternate # サイト名 : カルトの鳥篭 # サイトURL : [url]http://canarialt.blog.fc2.com[/url] #------------------------------------------------------------------------------ # ■ 概要 : 指定した座標(またはキャラクター)まで経路探索をしながら移動する。 # この経路探索では一定時間動いていないイベントは障害物として認識する。 # # ■ 必須 : 「注釈取得スクリプト」 # # ■ 位置 : 「注釈取得スクリプト」より下 # 「マルチレイヤーシステム」より下 #------------------------------------------------------------------------------ # ■ 機能 : 1. 指定した座標(またはキャラクター)まで移動する。 # # 2. 経路探索の移動で進入禁止の領域をリージョンIDで指定する。 # # 3. 注釈にキーワードを記述すると経路探索において障害物と見なさない。 # # ■ スクリプト(移動ルートの設定) : # 1. route_search(引数) # 目標に到達するまで移動を繰り返す。 # 移動ルートの設定の「移動できない場合は飛ばす」は route_search には無効である。 # 引数はハッシュで設定する。省略するとあらかじめ設定されている初期値が採用される。 # a. 目標の設定(※初期値はプレイヤー) # :x => x座標 # :y => y座標 # :z => z座標(通常は使用しないので省略可能) # :char_id => イベントID # :character => オブジェクト($game_playerなど) # # 指定する方法は以下の3通りである。 # :x, :y, :z は座標で指定する。:x と :y の両方設定しないと無効になる。 # :char_id はイベントのIDで指定する。プレイヤーを指定したい場合は -1 である。 # :character はオブジェクトを直接指定する。 # 例1 route_search(:x => 5, :y => 7) 座標(5, 7)が目標 # 例2 route_search(:char_id => 5) イベントIDが5番のイベントが目標 # 例3 route_search(:character => $game_player) プレイヤーが目標 # # b. 斜め移動の使用(※初期値はfalse) # :diagonal => true / false # true は斜め移動を使用する。 # false は斜め移動を使用しない。 # # c. 探索失敗時の行動(※初期値はtrue) # :fail => true / false # true は失敗時はランダムに移動する。 # false は失敗時はウェイトする。 # # d. 経路探索を実行する目標との距離(※初期値は25) # :length => 数値 # 設定した数値より目標が遠い場合はウェイトする。 # # e. ウェイトの時間(※初期値は6) # :wait => フレーム数 # false を設定するとウェイトせずに経路探索を中止する。 # # f. 目標の何歩前まで移動するか(※初期値は0) # :near => 数値 # 例えば、1 の場合は目標の1歩手前で探索終了する。 # 0 であれば目標と重なるまで探索を終了しない。 # # g. 探索回数の上限(※初期値はfalse) # :give_up => 数値 # false を設定すると自動モードになる。 # 大きな数値(およそ100以上)を設定すると遠くまで探索するがPCへの負荷も大きくなる。 # # h. 1回移動したら次の命令を実行(※初期値はfalse) # :manual => true / false # true は1回移動すると次の命令を実行します。 # false は目標への移動が完了するまで移動を続けます。 # # i. 進入禁止のリージョンIDを設定(※初期値はこの下で設定) # :region => [5, 6, 7] # リージョンIDは配列で設定する必要がある。 # # これらの引数は全て省略可能で route_search と記述するだけでもプレイヤーを追尾する。 #------------------------------------------------------------------------------ # 更新履歴 : 2013/01/05 Ver2.05 スクリプトを大幅に変更した。スクリプト名を変更した。 # 2013/01/09 Ver3.05 内部処理を大幅に変更した。 # 2013/02/19 Ver3.06 共通処理スクリプトの廃止による変更を施した。 # 2013/06/28 Ver3.07 失敗時のランダム移動のバグを修正した。 # 2013/06/28 Ver3.08 斜め移動では[経路探索で無視]を無効にするように変更した。 # 2013/06/29 Ver3.09 ある条件を満たすと経路情報を捨てる機能を廃止した。 # 2013/06/29 Ver3.10 1回移動したら次の命令を実行するオプションを追加した。 # 2013/06/29 Ver3.11 ループしたマップで正常に移動しないバグを修正した。 # 2013/08/18 Ver3.12 進入禁止のリージョンIDを個別に設定できる機能を追加した。 #============================================================================== $imported ||= {} $imported[:CanariAlternate_RouteSearch] = true #============================================================================== # ■ Calt #------------------------------------------------------------------------------ # CanariAlternateが製作したスクリプト用のモジュールです。 #============================================================================== module Calt #----------------------------------------------------------------------------- # ◆経路探索で進入禁止にするリージョンIDの配列(引数を省略した際に適用される設定) NOT_ENTER_REGION_ID = [4] # # ◆イベントを障害物として扱わないことを設定するキーワード SCAN_THROUGH_EVENT_NOTE = /\[経路探索で無視\]/ # 記述した頁に適用 SCAN_THROUGH_WHOLE_NOTE = /\<経路探索で無視\>/ # 全ての頁に適用(1頁目に記述) #----------------------------------------------------------------------------- end #============================================================================== # ■ 探索処理 ■ #============================================================================== #============================================================================== # ■ Game_Character #------------------------------------------------------------------------------ # 主に移動ルートなどの処理を追加したキャラクターのクラスです。Game_Player、 # Game_Follower、GameVehicle、Game_Event のスーパークラスとして使用されます。 #============================================================================== class Game_Character < Game_CharacterBase #-------------------------------------------------------------------------- # ● 定数 #-------------------------------------------------------------------------- LongSearchRate = 0.1 # 探索回数の自動設定で長距離探索する確率 #-------------------------------------------------------------------------- # ● クラス変数 #-------------------------------------------------------------------------- @@route_search_frame = 0 # 経路探索を実行したフレームを記憶 @@give_up_rate = LongSearchRate # 長距離探索を実行する確率 #-------------------------------------------------------------------------- # ● 経路探索で移動 [新規] #-------------------------------------------------------------------------- def route_search(argument={}) # パラメータの取得 gx, gy, gz = get_goal_coordinate(argument) # 目的地(対象)の座標を取得 diagonal = argument[:diagonal] != nil ? argument[:diagonal] : false # 斜め移動の使用の有無 length = argument[:length] != nil ? argument[:length] : 25 # 探索を実行する対象との距離 wait = argument[:wait] != nil ? argument[:wait] : 6 # ウェイト時間(false は待機せず探索中止) near = argument[:near] != nil ? argument[:near] : 0 # 対象の何歩手前で停止するか fail = argument[:fail] != nil ? argument[:fail] : true # 探索失敗時に適当な移動を行うか give_up = argument[:give_up] != nil ? argument[:give_up] : false # 探索回数の上限(false は自動) manual = argument[:manual] != nil ? argument[:manual] : false # 1回移動したら次の命令を実行 region = argument[:region] != nil ? argument[:region] : Calt::NOT_ENTER_REGION_ID # 進入禁止のリージョンIDの配列 # 経路探索の設定 @routing_object ||= Route_Search.new(self) # 経路探索のクラスのオブジェクトを生成 @routing_object.not_enter_region_id = region # 進入禁止のリージョンIDの配列を設定 @routing_object.limit_search_count = get_give_up(give_up) # 探索回数の上限を設定 @routing_object.always_collide_through = false # 常に衝突判定無視を無効に設定 @routing_object.ending_collide_distance = near != 0 ? near - 1 : 0 # 終点付近で衝突判定無視の距離を設定 @routing_object.ending_through_distance = near - 1 # 終点付近で通行判定無視の距離を設定 @routing_object.diagonal = diagonal # 斜め移動の使用の有無を設定 @routing_object.active_collide_through = 60 # 指定フレーム以内に移動してるキャラクターは衝突判定無視を設定 # 探索実行範囲内か判定 distance = @routing_object.distance_xy(@x, @y, gx, gy) # 終点までの最短距離を取得 return wait_search(wait, manual) if distance > length # 探索範囲外の場合はウェイト # 探索成功範囲内か判定 if distance <= near && !(gx == @x && gy == @y && gz != z) # 探索成功の場合 return end_route_search # 経路探索終了の手続きを実行 end last_x, last_y, last_z = @x, @y, z # 現在の座標を記憶 last_route_list = @route_list # 現在の経路情報を記憶 # 通常の経路探索 @route_list = @routing_object.a_star_search(gx, gy, gz) # 経路情報の取得 if !@route_list || @route_list.empty? # 経路情報を取得できなかった場合 @route_list = nil # 経路情報を消去 return wait_search(wait, manual) unless fail # 失敗時にランダム移動しない場合はウェイト fail_move_random(diagonal, region) # 失敗した場合の移動 set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定 continue_route_search unless manual # 経路探索継続の手続きを実行 return end if @route_list[0] == [gx, gy, gz] # 終点までの経路情報の取得に成功した場合 route_list_to_move(@route_list) # 経路に従って移動 set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定 continue_route_search unless manual # 経路探索継続の手続きを実行 return end # 以前の経路情報を使用して経路探索 new_route_list = @route_list # 最新の推定経路情報を記憶 @routing_object.limit_search_count = get_give_up(give_up) # 探索回数の上限を設定 @route_list = @routing_object.reuse_route_list(last_route_list, 5, gx, gy, gz) # 以前の経路情報を使って探索 if !@route_list || @route_list.empty? # 経路情報を取得できなかった場合 @route_list = nil # 経路情報を消去 return wait_search(wait, manual) unless fail # 失敗時に移動しない場合はウェイト @route_list = new_route_list # 最新の推定経路情報を復帰 route_list_to_move(@route_list) # 経路に従って移動 set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定 continue_route_search unless manual # 経路探索継続の手続きを実行 return end if @route_list[0] == [gx, gy, gz] # 終点までの経路情報の取得に成功した場合 route_list_to_move(@route_list) # 経路に従って移動 set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定 continue_route_search unless manual # 経路探索継続の手続きを実行 return end unless fail # 失敗時に移動しない場合 @route_list = nil # 経路情報を消去 wait_search(wait, manual) # ウェイト return end old_x = @route_list[0][0] old_y = @route_list[0][1] old_distance = @routing_object.distance_xy(old_x, old_y, gx, gy) # 更新推定経路の終点までの最短距離を取得 new_x = new_route_list[0][0] new_y = new_route_list[0][1] new_distance = @routing_object.distance_xy(new_x, new_y, gx, gy) # 最新推定経路の終点までの最短距離を取得 @route_list = new_route_list if old_distance >= new_distance # 最新推定経路の方が優れている場合は経路情報を復帰 route_list_to_move(@route_list) # 経路に従って移動 set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定 continue_route_search unless manual # 経路探索継続の手続きを実行 return end #-------------------------------------------------------------------------- # ● 対象の座標を取得 [新規] #-------------------------------------------------------------------------- def get_goal_coordinate(argument) if argument[:x] && argument[:y] # 座標で直接指定の場合 return [argument[:x], argument[:y], argument[:z] || 0] end character = argument[:char] # キャラクターのオブジェクトを直接指定 if !character && id = argument[:char_id] # キャラクターのIDで指定の場合 character = case id when 0 ; self # id : 0 はこのキャラクター自体 when -1; $game_player # id : -1 はプレイヤー else ; $game_map.events[id] || self # それ以外はイベント end else character = $game_player # 指定が無い場合はプレイヤー end return [character.x, character.y, character.z] end #-------------------------------------------------------------------------- # ● 経路探索を待機 [新規] #-------------------------------------------------------------------------- def wait_search(wait, manual) if wait @wait_count = wait # ウェイトを設定 manual ? end_route_search : continue_route_search else @wait_count = 0 # ウェイトはなし end_route_search end end #-------------------------------------------------------------------------- # ● 経路探索による移動を終了の手続き [新規] #-------------------------------------------------------------------------- def end_route_search @move_succeed = true end #-------------------------------------------------------------------------- # ● 経路探索による移動を継続の手続き [新規] #-------------------------------------------------------------------------- def continue_route_search @move_succeed = true @move_route_index -= 1 # もう1度実行されるように実行位置を1つ戻す end #-------------------------------------------------------------------------- # ● 経路リストに従って移動 [新規] #-------------------------------------------------------------------------- def route_list_to_move(route_list) dx = distance_x_from(route_list[-1][0]) dy = distance_y_from(route_list[-1][1]) if dx == 0 dy == 0 ? nil : (dy < 0 ? move_straight(2) : move_straight(8) ) elsif dx < 0 dy == 0 ? move_straight(6) : (dy < 0 ? move_diagonal(6, 2) : move_diagonal(6, 8)) else dy == 0 ? move_straight(4) : (dy < 0 ? move_diagonal(4, 2) : move_diagonal(4, 8)) end end #-------------------------------------------------------------------------- # ● 移動成功を判定 [新規] #-------------------------------------------------------------------------- def set_move_succeed(wait, last_x, last_y, last_z) if last_x != @x || last_y != @y || last_z != z @move_succeed = true # 移動成功 else @move_succeed = false # 移動失敗 @wait_count = (wait || 6) # 過負荷を回避する為にウェイト @route_list.push [@x, @y, z] if @route_list # 経路情報を修正 end end #-------------------------------------------------------------------------- # ● 負荷を考慮した探索回数の上限値を取得 [新規] #-------------------------------------------------------------------------- def get_give_up(give_up) return give_up if give_up if @@route_search_frame != Graphics.frame_count @@give_up_rate = LongSearchRate # 確率を初期化 @@route_search_frame = Graphics.frame_count # フレームの記憶を更新 end if rand(10000) < 10000 * @@give_up_rate @@give_up_rate = 0 # 確率を更新 result = 10 + rand(140) # 高い上限を設定 else @@give_up_rate *= @@give_up_rate / (1.0 - @@give_up_rate) # 確率を更新 result = 10 # 低い上限を設定 end return result end #-------------------------------------------------------------------------- # ● 失敗した場合の移動 [新規] #-------------------------------------------------------------------------- def fail_move_random(diagonal, region) # 斜め移動の場合 if diagonal && rand(2) == 0 horz = rand(2) == 0 ? 4 : 6 vert = rand(2) == 0 ? 2 : 8 nx = $game_map.round_x_with_direction(@x, horz) ny = $game_map.round_y_with_direction(@y, vert) return if region.include?($game_map.region_id(nx, ny)) move_diagonal(horz, vert) return end # 4方向移動の場合 if rand(2) == 0 horz = rand(2) == 0 ? 4 : 6 nx = $game_map.round_x_with_direction(@x, horz) return if region.include?($game_map.region_id(nx, @y)) move_straight(horz) else vert = rand(2) == 0 ? 2 : 8 ny = $game_map.round_y_with_direction(@y, vert) return if region.include?($game_map.region_id(@x, ny)) move_straight(vert) end end end #============================================================================== # ■ 基礎定義 ■ #============================================================================== #============================================================================== # ■ Game_CharacterBase #------------------------------------------------------------------------------ # キャラクターを扱う基本のクラスです。全てのキャラクターに共通する、座標やグ # ラフィックなどの基本的な情報を保持します。 #============================================================================== class Game_CharacterBase #-------------------------------------------------------------------------- # ● クラス変数 #-------------------------------------------------------------------------- @@active_collide_through = false # 座標一致判定の無効化 @@collide_through = false # 衝突判定無視 @@search_diagonal = false # 斜めの移動判定か否か def active_collide_through=(arg) ; @@active_collide_through = arg ; end def collide_through=(arg) ; @@collide_through = arg ; end def search_diagonal=(arg) ; @@search_diagonal = arg ; end #-------------------------------------------------------------------------- # ● 公開インスタンス変数 #-------------------------------------------------------------------------- attr_reader :stopwatch # 連続停止時間 #-------------------------------------------------------------------------- # ● z 座標の取得 [新規] #-------------------------------------------------------------------------- def z return 0 # 座標が3次元の場合は再定義する end #-------------------------------------------------------------------------- # ● 公開メンバ変数の初期化 [追加] #-------------------------------------------------------------------------- alias init_public_members_RouteSearch init_public_members def init_public_members init_public_members_RouteSearch @stopwatch = 1.0/0 # 1.0/0 #=> Infinity @movement_record = [[nil, nil, nil]] # 移動履歴 end #-------------------------------------------------------------------------- # ● 非公開メンバ変数の初期化 [追加] #-------------------------------------------------------------------------- alias init_private_members_RouteSearch init_private_members def init_private_members init_private_members_RouteSearch @scan_through_event = false # 経路探索において障害物として扱わないフラグ end #-------------------------------------------------------------------------- # ● フレーム更新 [追加] #-------------------------------------------------------------------------- alias update_RouteSearch update def update update_RouteSearch update_stopwatch # 連続停止時間を更新 end #-------------------------------------------------------------------------- # ● 連続停止時間を更新 [新規] #-------------------------------------------------------------------------- def update_stopwatch if @movement_record[-1] != [x, y, z] @stopwatch = 0 if @movement_record.size > 1 @movement_record.push [x, y, z] @movement_record.shift if @movement_record.size > 10 elsif !moving? @stopwatch += 1 end end #-------------------------------------------------------------------------- # ● 座標一致判定 [追加] #-------------------------------------------------------------------------- alias pos_RouteSearch? pos? def pos?(*args) return false if @@collide_through and !tile? || @scan_through_event && !@@search_diagonal # 連続停止時間が指定値以下の場合は座標を不一致にすることで衝突判定を回避する。 return false if @@active_collide_through and @stopwatch <= @@active_collide_through && !tile? || @scan_through_event && !@@search_diagonal pos_RouteSearch?(*args) end end #============================================================================== # ■ Game_Event #------------------------------------------------------------------------------ # イベントを扱うクラスです。条件判定によるイベントページ切り替えや、並列処理 # イベント実行などの機能を持っており、Game_Map クラスの内部で使用されます。 #============================================================================== class Game_Event < Game_Character #-------------------------------------------------------------------------- # ● 衝突判定無視の設定を取得 [新規] #-------------------------------------------------------------------------- def get_scan_through_event_note event_result = event_note_include?(Calt::SCAN_THROUGH_EVENT_NOTE) whole_result = whole_note_include?(Calt::SCAN_THROUGH_WHOLE_NOTE) return event_result ^ whole_result end #-------------------------------------------------------------------------- # ● イベントページ更新時に注釈から設定を取得 [追加] #-------------------------------------------------------------------------- alias setup_note_settings_RouteSearch setup_note_settings def setup_note_settings setup_note_settings_RouteSearch @scan_through_event = get_scan_through_event_note end end #============================================================================== # ■ Route_Search #------------------------------------------------------------------------------ # 経路探索の処理を定義したクラスです。 #============================================================================== class Route_Search #-------------------------------------------------------------------------- # ● 基礎変数の初期化 #-------------------------------------------------------------------------- def init_base_instance(character) @character = character # キャラクターへの参照 @x , @y , @z = 0, 0, 0 # 今のノードの座標 @sx, @sy, @sz = 0, 0, 0 # 始点の座標 @gx, @gy, @gz = 0, 0, 0 # 終点の座標 @diagonal = false # 斜め移動の使用の有無 @collide_through = false # 衝突判定を無視するフラグ @active_collide_through = 60 # 指定フレーム以内に移動してるキャラクターは衝突判定無視 end #-------------------------------------------------------------------------- # ● 2点間の x 方向の距離 #-------------------------------------------------------------------------- def distance_x(start_x, end_x) result = end_x - start_x return result unless $game_map.loop_horizontal? && result.abs > $game_map.width / 2 return result + (result < 0 ? $game_map.width : -$game_map.width) end #-------------------------------------------------------------------------- # ● 2点間の y 方向の距離 #-------------------------------------------------------------------------- def distance_y(start_y, end_y) result = end_y - start_y return result unless $game_map.loop_vertical? && result.abs > $game_map.height / 2 return result + (result < 0 ? $game_map.height : -$game_map.height) end #-------------------------------------------------------------------------- # ● 2点間の z 方向の距離 #-------------------------------------------------------------------------- def distance_z(start_z, end_z) return end_z - start_z end #-------------------------------------------------------------------------- # ● 2点の距離を取得 #-------------------------------------------------------------------------- def distance_xy(start_x, start_y, end_x, end_y) if @diagonal return [distance_x(start_x, end_x).abs, distance_y(start_y, end_y).abs].max # 8方向の場合 else return distance_x(start_x, end_x).abs + distance_y(start_y, end_y).abs # 4方向の場合 end end #-------------------------------------------------------------------------- # ● x 座標の取得 #-------------------------------------------------------------------------- def character_x return @character.x end #-------------------------------------------------------------------------- # ● y 座標の取得 #-------------------------------------------------------------------------- def character_y return @character.y end #-------------------------------------------------------------------------- # ● z 座標の取得 #-------------------------------------------------------------------------- def character_z return @character.z end #-------------------------------------------------------------------------- # ● z 座標の変換 #-------------------------------------------------------------------------- def xyz_to_z(x, y, z) return z end #-------------------------------------------------------------------------- # ● 進入禁止のリージョンIDの座標か判定 #-------------------------------------------------------------------------- def not_enter_coordinate?(x, y, z) return not_enter_region_id.include?($game_map.region_id(x, y)) end #-------------------------------------------------------------------------- # ● 終点か判定 #-------------------------------------------------------------------------- def end_coordinate?(x, y, z) return x == @gx && y == @gy && z == @gz end #-------------------------------------------------------------------------- # ● 終点から範囲内か判定 #-------------------------------------------------------------------------- def ending_distance?(x, y, z, distance) return false if x == @gx && y == @gy && z != @gz return false if distance_xy(x, y, @gx, @gy) > distance return true end # #-------------------------------------------------------------------------- # # ● 始点から範囲内か判定 # #-------------------------------------------------------------------------- # def starting_distance?(x, y, z, distance) # return false if x == @sx && y == @sy && z != @sz # return false if distance_xy(x, y, @sx, @sy) > distance # return true # end # #-------------------------------------------------------------------------- # # ● 始点の隣接座標か判定(始点を含む) # #-------------------------------------------------------------------------- # def adjoin_coordinate?(x, y, z) # return false unless starting_distance?(x, y, z, 1) # return xyz_to_z(x, y, @sz) == z # end #-------------------------------------------------------------------------- # ● 通行可能判定 #-------------------------------------------------------------------------- def passable?(d) @character.active_collide_through = @active_collide_through @character.collide_through = @collide_through @character.search_diagonal = false result = base_passable?(:passable?, d) @character.collide_through = false @character.active_collide_through = false return result end #-------------------------------------------------------------------------- # ● 斜めの通行可能判定 #-------------------------------------------------------------------------- def diagonal_passable?(horz, vert) @character.active_collide_through = @active_collide_through @character.collide_through = @collide_through @character.search_diagonal = true result = base_passable?(:diagonal_passable?, horz, vert) @character.collide_through = false @character.active_collide_through = false return result end #-------------------------------------------------------------------------- # ● 通行可能判定の呼び出し #-------------------------------------------------------------------------- def base_passable?(name, *d) return @character.send(name, @x, @y, *d) end end #============================================================================== # ■ 内部処理 ■ #============================================================================== #============================================================================== # ■ Route_Search #------------------------------------------------------------------------------ # 経路探索の処理を定義したクラスです。 #============================================================================== class Route_Search #-------------------------------------------------------------------------- # ● 座標の配列のインデックス #-------------------------------------------------------------------------- X = 0 # x座標 Y = 1 # y座標 Z = 2 # z座標 #-------------------------------------------------------------------------- # ● ノードの配列のインデックス #-------------------------------------------------------------------------- RANK_A = 0 # 評価値A RANK_B = 1 # 評価値B RANK_C = 2 # 評価値C PARENT = 3 # 親の座標 LENGTH = 4 # 移動距離 #-------------------------------------------------------------------------- # ● 公開インスタンス変数 #-------------------------------------------------------------------------- attr_accessor :not_enter_region_id # 進入禁止のリージョンIDの配列 attr_accessor :limit_search_count # 探索回数の上限値 attr_accessor :always_collide_through # 常に衝突判定を無視のフラグ attr_accessor :ending_collide_distance # 終点付近で衝突判定を無視の距離 attr_accessor :ending_through_distance # 終点付近で通行判定を無視の距離 attr_accessor :diagonal # 斜め移動の使用の有無 attr_accessor :active_collide_through # 指定フレーム以内に移動してるキャラクターは衝突判定無視 #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize(character) init_base_instance(character) @parent = [nil, nil, nil] # 親の座標 @past_distance = 0 # 探索点までの移動距離 @open_list = {} # 探索候補のノードのリスト @close_list = {} # 探索済みのノードのリスト @limit_search_count = 100 @always_collide_through = false @ending_collide_distance = 0 @ending_through_distance = 0 end #-------------------------------------------------------------------------- # ● A*経路探索の通常実行 #-------------------------------------------------------------------------- def a_star_search(gx, gy, gz=0) init_process(gx, gy, gz) # A*経路探索の初期化 return main_process # A*経路探索の主要処理 end #-------------------------------------------------------------------------- # ● A*経路探索の初期化 #-------------------------------------------------------------------------- def init_process(gx, gy, gz) @x, @y, @z = character_x, character_y, character_z # 現在の座標 @sx, @sy, @sz = @x, @y, @z # 始点の座標 @gx, @gy, @gz = gx, gy, gz # 終点の座標 @open_list = {[@sx, @sy, @sz]=>create_node(@sx, @sy, @sz, [nil, nil, nil], 0)} @close_list = {} end #-------------------------------------------------------------------------- # ● A*経路探索の主要処理 #-------------------------------------------------------------------------- def main_process count = 0 until @open_list.empty? node, coordinate = get_best_node(@open_list) # 最も高評価のノードを探索候補のリストから取得 # 探索成功の場合 return create_route_list(node, coordinate) if end_coordinate?(*coordinate) # 探索回数の上限オーバーの場合 return create_estimate_list if (count += 1) > @limit_search_count # 隣接点を探索候補に追加する処理 @close_list[coordinate] = @open_list.delete(coordinate) # 探索候補から探索済みに移動 @x, @y, @z = *coordinate @parent = node[PARENT] @past_distance = node[LENGTH] + 1 down = $game_map.round_y(@y + 1) up = $game_map.round_y(@y - 1) right = $game_map.round_x(@x + 1) left = $game_map.round_x(@x - 1) open_list_add(@x, down , 2) # 下 open_list_add(@x, up , 8) # 上 open_list_add(right, @y, 6) # 右 open_list_add(left , @y, 4) # 左 if @diagonal open_list_add_diagonal(right, down, 6, 2) # 右下 open_list_add_diagonal(left , down, 4, 2) # 左下 open_list_add_diagonal(right, up , 6, 8) # 右上 open_list_add_diagonal(left , up , 4, 8) # 左上 end end return false # 到達する経路は存在しない。 end #-------------------------------------------------------------------------- # ● ノードのデータを生成 #-------------------------------------------------------------------------- def create_node(x, y, z, parent, length) dx = distance_x(x, @gx).abs dy = distance_y(y, @gy).abs rank_a = length + dx + dy rank_b = Math.sqrt(dx ** 2 + dy ** 2) rank_c = distance_z(z, @gz).abs return [rank_a, rank_b, rank_c, parent, length] # [評価値A, 評価値B, 評価値C, 親の座標, 移動距離] # 評価値A : 始点から終点までの推定最短経路の距離 # 評価値B : 終点との直線距離 # 評価値C : z 座標の距離 # 親の座標 : 移動元の座標 # 移動距離 : 始点からこの点までの移動距離 end #-------------------------------------------------------------------------- # ● 最も高評価のノードを取得 #-------------------------------------------------------------------------- def get_best_node(hash_list, compare=:node_a_better?) best_node = [1.0/0, 1.0/0, 1.0/0] # 1.0/0 #=> Infinity best_coordinate = nil hash_list.each do |coordinate, node| next if send(compare, best_node, node) # node よりも best_node が高評価なら next best_node = node best_coordinate = coordinate end return best_node, best_coordinate end #-------------------------------------------------------------------------- # ● ノードの優劣判定 #-------------------------------------------------------------------------- def node_a_better?(node_a, node_b) return true if node_a[RANK_A] < node_b[RANK_A] return false if node_a[RANK_A] > node_b[RANK_A] return true if node_a[RANK_B] < node_b[RANK_B] return false if node_a[RANK_B] > node_b[RANK_B] return true if node_a[RANK_C] < node_b[RANK_C] return false if node_a[RANK_C] > node_b[RANK_C] return true end #-------------------------------------------------------------------------- # ● 探索候補リストに隣接点を追加 #-------------------------------------------------------------------------- def open_list_add(nx, ny, d) return if @parent[X] == nx && @parent[Y] == ny nz = xyz_to_z(nx, ny, @z) # z 座標の変換 result = exception_decision?(nx, ny, nz) return if result == false # 通行禁止の場合 if result == nil # 通行可能判定に委ねる場合 @collide_through = collide_through?(nx, ny, nz) return if !passable?(d) # 通行可能判定 end open_list_add_node(nx, ny, nz) # 探索候補リストに追加 end #-------------------------------------------------------------------------- # ● 探索候補リストに隣接点を追加(斜めの判定版) #-------------------------------------------------------------------------- def open_list_add_diagonal(nx, ny, horz, vert) return if @parent[X] == nx && @parent[Y] == ny nz = xyz_to_z(nx, ny, @z) # z 座標の変換 result = exception_decision?(nx, ny, nz) return if result == false # 通行禁止の場合 if result == nil # 通行可能判定に委ねる場合 @collide_through = collide_through?(nx, ny, nz) return if !diagonal_passable?(horz, vert) # 斜めの通行可能判定 end open_list_add_node(nx, ny, nz) # 探索候補リストに追加 end #-------------------------------------------------------------------------- # ● 例外通行判定 #-------------------------------------------------------------------------- def exception_decision?(x, y, z) return false if not_enter_coordinate?(x, y, z) return true if ending_distance?(x, y, z, @ending_through_distance) return nil end #-------------------------------------------------------------------------- # ● 衝突判定を無視するか判定 #-------------------------------------------------------------------------- def collide_through?(x, y, z) return true if @always_collide_through return true if ending_distance?(x, y, z, @ending_collide_distance) return false end #-------------------------------------------------------------------------- # ● 探索候補リストに隣接点を追加する処理 #-------------------------------------------------------------------------- def open_list_add_node(nx, ny, nz) next_coordinate = [nx, ny, nz] if old_node = @close_list[next_coordinate] # 探索済みリストに既にある場合 if old_node[LENGTH] > @past_distance # 移動距離が優れている場合 @open_list[next_coordinate] = @close_list.delete(next_coordinate) # 探索候補リストに移動 update_node(old_node) end return end if old_node = @open_list[next_coordinate] # 探索候補リストに既にある場合 update_node(old_node) if old_node[LENGTH] > @past_distance # 移動距離が優れている場合 return end @open_list[next_coordinate] = create_node(*next_coordinate, [@x, @y, @z], @past_distance) end #-------------------------------------------------------------------------- # ● ノードのデータを更新 #-------------------------------------------------------------------------- def update_node(old_node) old_node[RANK_A] += @past_distance - old_node[LENGTH] # 移動距離の差を減算 old_node[PARENT] = [@x, @y, @z] # 親の座標を更新 old_node[LENGTH] = @past_distance # 移動距離を更新 end #-------------------------------------------------------------------------- # ● 経路の配列を生成 #-------------------------------------------------------------------------- def create_route_list(node, coordinate) parent = node[PARENT] route_list = [] while parent != [nil, nil, nil] route_list.push coordinate parent = @close_list[coordinate = parent][PARENT] end return route_list # 先頭が終点で末尾が始点の次の座標(推定経路の場合は先頭は終点ではない) end #-------------------------------------------------------------------------- # ● 推定経路の配列を生成 #-------------------------------------------------------------------------- def create_estimate_list open_node, open_coordinate = get_best_node(@open_list, :estimate_node_a_better?) close_node, close_coordinate = get_best_node(@close_list, :estimate_node_a_better?) if estimate_node_a_better?(open_node, close_node) return create_route_list(open_node, open_coordinate) else return create_route_list(close_node, close_coordinate) end end #-------------------------------------------------------------------------- # ● ノードの優劣判定(推定経路用) #-------------------------------------------------------------------------- def estimate_node_a_better?(node_a, node_b) return true if node_a[RANK_B] < node_b[RANK_B] return false if node_a[RANK_B] > node_b[RANK_B] return true if node_a[RANK_C] < node_b[RANK_C] return false if node_a[RANK_C] > node_b[RANK_C] return true end #-------------------------------------------------------------------------- # ● 探索結果を再利用 #-------------------------------------------------------------------------- def reuse_route_list(route_list, reuse_distance, gx, gy, gz=0) return false unless route_list @sx, @sy, @sz = character_x, character_y, character_z return false unless index = route_list.index([@sx, @sy, @sz]) # 始点を含んでいるか判定 (route_list.size - index).times { route_list.pop } return false if route_list.empty? @gx, @gy, @gz = gx, gy, gz if index = route_list.index([@gx, @gy, @gz]) # 終点を含んでいるか判定 index.times { route_list.shift } return false unless route_list_valid?(route_list) # 経路を使用可能か判定 return route_list else return false unless ending_distance?(*route_list[0], reuse_distance) return false unless route_list_valid?(route_list) # 経路を使用可能か判定 reuse_search(route_list) # 以前の探索結果を使用して経路探索 end end #-------------------------------------------------------------------------- # ● 経路を使用可能か判定 #-------------------------------------------------------------------------- def route_list_valid?(route_list) @x, @y, @z = @sx, @sy, @sz route_list.reverse.each do |coordinate| nx, ny, nz = *coordinate result = exception_decision?(nx, ny, nz) return false if result == false # 通行禁止の場合 if result == nil # 通行可能判定に委ねる場合 @collide_through = collide_through?(nx, ny, nz) if nx == @x return false unless ny == @y ? nil : (ny > @y ? passable?(2) : passable?(8) ) elsif nx > @x return false unless ny == @y ? passable?(6) : (ny > @y ? diagonal_passable?(6, 2) : diagonal_passable?(6, 8)) else return false unless ny == @y ? passable?(4) : (ny > @y ? diagonal_passable?(4, 2) : diagonal_passable?(4, 8)) end end @x , @y , @z = nx, ny, nz end return true end #-------------------------------------------------------------------------- # ● 以前の探索結果を使用して経路探索 #-------------------------------------------------------------------------- def reuse_search(route_list) init_process(@gx, @gy, @gz) parent = [@sx, @sy, @sz] route_list.reverse.each do |coordinate| @open_list[coordinate] = create_node(*coordinate, parent, 0) # 移動距離に細工をして追加 parent = coordinate end @close_list = @open_list.dup return main_process end end #============================================================================== # ■ マルチレイヤーシステムとの競合回避 ■ #============================================================================== if $imported[:CanariAlternate_Multilayer] #============================================================================== # ■ Game_CharacterBase #------------------------------------------------------------------------------ # キャラクターを扱う基本のクラスです。全てのキャラクターに共通する、座標やグ # ラフィックなどの基本的な情報を保持します。 #============================================================================== class Game_CharacterBase #-------------------------------------------------------------------------- # ● z 座標の取得 [◆再定義] #-------------------------------------------------------------------------- def z return current_floor end end #============================================================================== # ■ Route_Search #------------------------------------------------------------------------------ # 経路探索の処理を定義したクラスです。 #============================================================================== class Route_Search #-------------------------------------------------------------------------- # ● 定数 #-------------------------------------------------------------------------- DummyEvent = Game_CharacterBase.new # ダミーのイベント #-------------------------------------------------------------------------- # ● z 座標の変換 [◆再定義] #-------------------------------------------------------------------------- def xyz_to_z(x, y, z) return $game_map.floor_xy(x, y, z) end #-------------------------------------------------------------------------- # ● 進入禁止のリージョンIDの座標か判定 [◆再定義] #-------------------------------------------------------------------------- def not_enter_coordinate?(x, y, z) return not_enter_region_id.include?($game_map.region_id(x, y, z)) end #-------------------------------------------------------------------------- # ● 通行可能判定の呼び出し [◆再定義] #-------------------------------------------------------------------------- def base_passable?(name, *d) DummyEvent.current_floor = @z return $game_map.temp_execute(DummyEvent) { @character.send(name, @x, @y, *d) } end end end
#==============================================================================
# ■ 経路探索VXAce (VX Ace用)
#------------------------------------------------------------------------------
# 製作者 : CanariAlternate
# サイト名 : カルトの鳥篭
# サイトURL : [url]http://canarialt.blog.fc2.com[/url]
#------------------------------------------------------------------------------
# ■ 概要 : 指定した座標(またはキャラクター)まで経路探索をしながら移動する。
# この経路探索では一定時間動いていないイベントは障害物として認識する。
#
# ■ 必須 : 「注釈取得スクリプト」
#
# ■ 位置 : 「注釈取得スクリプト」より下
# 「マルチレイヤーシステム」より下
#------------------------------------------------------------------------------
# ■ 機能 : 1. 指定した座標(またはキャラクター)まで移動する。
#
# 2. 経路探索の移動で進入禁止の領域をリージョンIDで指定する。
#
# 3. 注釈にキーワードを記述すると経路探索において障害物と見なさない。
#
# ■ スクリプト(移動ルートの設定) :
# 1. route_search(引数)
# 目標に到達するまで移動を繰り返す。
# 移動ルートの設定の「移動できない場合は飛ばす」は route_search には無効である。
# 引数はハッシュで設定する。省略するとあらかじめ設定されている初期値が採用される。
# a. 目標の設定(※初期値はプレイヤー)
# :x => x座標
# :y => y座標
# :z => z座標(通常は使用しないので省略可能)
# :char_id => イベントID
# :character => オブジェクト($game_playerなど)
#
# 指定する方法は以下の3通りである。
# :x, :y, :z は座標で指定する。:x と :y の両方設定しないと無効になる。
# :char_id はイベントのIDで指定する。プレイヤーを指定したい場合は -1 である。
# :character はオブジェクトを直接指定する。
# 例1 route_search(:x => 5, :y => 7) 座標(5, 7)が目標
# 例2 route_search(:char_id => 5) イベントIDが5番のイベントが目標
# 例3 route_search(:character => $game_player) プレイヤーが目標
#
# b. 斜め移動の使用(※初期値はfalse)
# :diagonal => true / false
# true は斜め移動を使用する。
# false は斜め移動を使用しない。
#
# c. 探索失敗時の行動(※初期値はtrue)
# :fail => true / false
# true は失敗時はランダムに移動する。
# false は失敗時はウェイトする。
#
# d. 経路探索を実行する目標との距離(※初期値は25)
# :length => 数値
# 設定した数値より目標が遠い場合はウェイトする。
#
# e. ウェイトの時間(※初期値は6)
# :wait => フレーム数
# false を設定するとウェイトせずに経路探索を中止する。
#
# f. 目標の何歩前まで移動するか(※初期値は0)
# :near => 数値
# 例えば、1 の場合は目標の1歩手前で探索終了する。
# 0 であれば目標と重なるまで探索を終了しない。
#
# g. 探索回数の上限(※初期値はfalse)
# :give_up => 数値
# false を設定すると自動モードになる。
# 大きな数値(およそ100以上)を設定すると遠くまで探索するがPCへの負荷も大きくなる。
#
# h. 1回移動したら次の命令を実行(※初期値はfalse)
# :manual => true / false
# true は1回移動すると次の命令を実行します。
# false は目標への移動が完了するまで移動を続けます。
#
# i. 進入禁止のリージョンIDを設定(※初期値はこの下で設定)
# :region => [5, 6, 7]
# リージョンIDは配列で設定する必要がある。
#
# これらの引数は全て省略可能で route_search と記述するだけでもプレイヤーを追尾する。
#------------------------------------------------------------------------------
# 更新履歴 : 2013/01/05 Ver2.05 スクリプトを大幅に変更した。スクリプト名を変更した。
# 2013/01/09 Ver3.05 内部処理を大幅に変更した。
# 2013/02/19 Ver3.06 共通処理スクリプトの廃止による変更を施した。
# 2013/06/28 Ver3.07 失敗時のランダム移動のバグを修正した。
# 2013/06/28 Ver3.08 斜め移動では[経路探索で無視]を無効にするように変更した。
# 2013/06/29 Ver3.09 ある条件を満たすと経路情報を捨てる機能を廃止した。
# 2013/06/29 Ver3.10 1回移動したら次の命令を実行するオプションを追加した。
# 2013/06/29 Ver3.11 ループしたマップで正常に移動しないバグを修正した。
# 2013/08/18 Ver3.12 進入禁止のリージョンIDを個別に設定できる機能を追加した。
#==============================================================================
$imported ||= {}
$imported[:CanariAlternate_RouteSearch] = true
#==============================================================================
# ■ Calt
#------------------------------------------------------------------------------
# CanariAlternateが製作したスクリプト用のモジュールです。
#==============================================================================
module Calt
#-----------------------------------------------------------------------------
# ◆経路探索で進入禁止にするリージョンIDの配列(引数を省略した際に適用される設定)
NOT_ENTER_REGION_ID = [4]
#
# ◆イベントを障害物として扱わないことを設定するキーワード
SCAN_THROUGH_EVENT_NOTE = /\[経路探索で無視\]/ # 記述した頁に適用
SCAN_THROUGH_WHOLE_NOTE = /\<経路探索で無視\>/ # 全ての頁に適用(1頁目に記述)
#-----------------------------------------------------------------------------
end
#==============================================================================
# ■ 探索処理 ■
#==============================================================================
#==============================================================================
# ■ Game_Character
#------------------------------------------------------------------------------
# 主に移動ルートなどの処理を追加したキャラクターのクラスです。Game_Player、
# Game_Follower、GameVehicle、Game_Event のスーパークラスとして使用されます。
#==============================================================================
class Game_Character < Game_CharacterBase
#--------------------------------------------------------------------------
# ● 定数
#--------------------------------------------------------------------------
LongSearchRate = 0.1 # 探索回数の自動設定で長距離探索する確率
#--------------------------------------------------------------------------
# ● クラス変数
#--------------------------------------------------------------------------
@@route_search_frame = 0 # 経路探索を実行したフレームを記憶
@@give_up_rate = LongSearchRate # 長距離探索を実行する確率
#--------------------------------------------------------------------------
# ● 経路探索で移動 [新規]
#--------------------------------------------------------------------------
def route_search(argument={})
# パラメータの取得
gx, gy, gz = get_goal_coordinate(argument) # 目的地(対象)の座標を取得
diagonal = argument[:diagonal] != nil ? argument[:diagonal] : false # 斜め移動の使用の有無
length = argument[:length] != nil ? argument[:length] : 25 # 探索を実行する対象との距離
wait = argument[:wait] != nil ? argument[:wait] : 6 # ウェイト時間(false は待機せず探索中止)
near = argument[:near] != nil ? argument[:near] : 0 # 対象の何歩手前で停止するか
fail = argument[:fail] != nil ? argument[:fail] : true # 探索失敗時に適当な移動を行うか
give_up = argument[:give_up] != nil ? argument[:give_up] : false # 探索回数の上限(false は自動)
manual = argument[:manual] != nil ? argument[:manual] : false # 1回移動したら次の命令を実行
region = argument[:region] != nil ? argument[:region] : Calt::NOT_ENTER_REGION_ID # 進入禁止のリージョンIDの配列
# 経路探索の設定
@routing_object ||= Route_Search.new(self) # 経路探索のクラスのオブジェクトを生成
@routing_object.not_enter_region_id = region # 進入禁止のリージョンIDの配列を設定
@routing_object.limit_search_count = get_give_up(give_up) # 探索回数の上限を設定
@routing_object.always_collide_through = false # 常に衝突判定無視を無効に設定
@routing_object.ending_collide_distance = near != 0 ? near - 1 : 0 # 終点付近で衝突判定無視の距離を設定
@routing_object.ending_through_distance = near - 1 # 終点付近で通行判定無視の距離を設定
@routing_object.diagonal = diagonal # 斜め移動の使用の有無を設定
@routing_object.active_collide_through = 60 # 指定フレーム以内に移動してるキャラクターは衝突判定無視を設定
# 探索実行範囲内か判定
distance = @routing_object.distance_xy(@x, @y, gx, gy) # 終点までの最短距離を取得
return wait_search(wait, manual) if distance > length # 探索範囲外の場合はウェイト
# 探索成功範囲内か判定
if distance <= near && !(gx == @x && gy == @y && gz != z) # 探索成功の場合
return end_route_search # 経路探索終了の手続きを実行
end
last_x, last_y, last_z = @x, @y, z # 現在の座標を記憶
last_route_list = @route_list # 現在の経路情報を記憶
# 通常の経路探索
@route_list = @routing_object.a_star_search(gx, gy, gz) # 経路情報の取得
if !@route_list || @route_list.empty? # 経路情報を取得できなかった場合
@route_list = nil # 経路情報を消去
return wait_search(wait, manual) unless fail # 失敗時にランダム移動しない場合はウェイト
fail_move_random(diagonal, region) # 失敗した場合の移動
set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定
continue_route_search unless manual # 経路探索継続の手続きを実行
return
end
if @route_list[0] == [gx, gy, gz] # 終点までの経路情報の取得に成功した場合
route_list_to_move(@route_list) # 経路に従って移動
set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定
continue_route_search unless manual # 経路探索継続の手続きを実行
return
end
# 以前の経路情報を使用して経路探索
new_route_list = @route_list # 最新の推定経路情報を記憶
@routing_object.limit_search_count = get_give_up(give_up) # 探索回数の上限を設定
@route_list = @routing_object.reuse_route_list(last_route_list, 5, gx, gy, gz) # 以前の経路情報を使って探索
if !@route_list || @route_list.empty? # 経路情報を取得できなかった場合
@route_list = nil # 経路情報を消去
return wait_search(wait, manual) unless fail # 失敗時に移動しない場合はウェイト
@route_list = new_route_list # 最新の推定経路情報を復帰
route_list_to_move(@route_list) # 経路に従って移動
set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定
continue_route_search unless manual # 経路探索継続の手続きを実行
return
end
if @route_list[0] == [gx, gy, gz] # 終点までの経路情報の取得に成功した場合
route_list_to_move(@route_list) # 経路に従って移動
set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定
continue_route_search unless manual # 経路探索継続の手続きを実行
return
end
unless fail # 失敗時に移動しない場合
@route_list = nil # 経路情報を消去
wait_search(wait, manual) # ウェイト
return
end
old_x = @route_list[0][0]
old_y = @route_list[0][1]
old_distance = @routing_object.distance_xy(old_x, old_y, gx, gy) # 更新推定経路の終点までの最短距離を取得
new_x = new_route_list[0][0]
new_y = new_route_list[0][1]
new_distance = @routing_object.distance_xy(new_x, new_y, gx, gy) # 最新推定経路の終点までの最短距離を取得
@route_list = new_route_list if old_distance >= new_distance # 最新推定経路の方が優れている場合は経路情報を復帰
route_list_to_move(@route_list) # 経路に従って移動
set_move_succeed(wait, last_x, last_y, last_z) # 移動成功を判定
continue_route_search unless manual # 経路探索継続の手続きを実行
return
end
#--------------------------------------------------------------------------
# ● 対象の座標を取得 [新規]
#--------------------------------------------------------------------------
def get_goal_coordinate(argument)
if argument[:x] && argument[:y] # 座標で直接指定の場合
return [argument[:x], argument[:y], argument[:z] || 0]
end
character = argument[:char] # キャラクターのオブジェクトを直接指定
if !character && id = argument[:char_id] # キャラクターのIDで指定の場合
character = case id
when 0 ; self # id : 0 はこのキャラクター自体
when -1; $game_player # id : -1 はプレイヤー
else ; $game_map.events[id] || self # それ以外はイベント
end
else
character = $game_player # 指定が無い場合はプレイヤー
end
return [character.x, character.y, character.z]
end
#--------------------------------------------------------------------------
# ● 経路探索を待機 [新規]
#--------------------------------------------------------------------------
def wait_search(wait, manual)
if wait
@wait_count = wait # ウェイトを設定
manual ? end_route_search : continue_route_search
else
@wait_count = 0 # ウェイトはなし
end_route_search
end
end
#--------------------------------------------------------------------------
# ● 経路探索による移動を終了の手続き [新規]
#--------------------------------------------------------------------------
def end_route_search
@move_succeed = true
end
#--------------------------------------------------------------------------
# ● 経路探索による移動を継続の手続き [新規]
#--------------------------------------------------------------------------
def continue_route_search
@move_succeed = true
@move_route_index -= 1 # もう1度実行されるように実行位置を1つ戻す
end
#--------------------------------------------------------------------------
# ● 経路リストに従って移動 [新規]
#--------------------------------------------------------------------------
def route_list_to_move(route_list)
dx = distance_x_from(route_list[-1][0])
dy = distance_y_from(route_list[-1][1])
if dx == 0
dy == 0 ? nil : (dy < 0 ? move_straight(2) : move_straight(8) )
elsif dx < 0
dy == 0 ? move_straight(6) : (dy < 0 ? move_diagonal(6, 2) : move_diagonal(6, 8))
else
dy == 0 ? move_straight(4) : (dy < 0 ? move_diagonal(4, 2) : move_diagonal(4, 8))
end
end
#--------------------------------------------------------------------------
# ● 移動成功を判定 [新規]
#--------------------------------------------------------------------------
def set_move_succeed(wait, last_x, last_y, last_z)
if last_x != @x || last_y != @y || last_z != z
@move_succeed = true # 移動成功
else
@move_succeed = false # 移動失敗
@wait_count = (wait || 6) # 過負荷を回避する為にウェイト
@route_list.push [@x, @y, z] if @route_list # 経路情報を修正
end
end
#--------------------------------------------------------------------------
# ● 負荷を考慮した探索回数の上限値を取得 [新規]
#--------------------------------------------------------------------------
def get_give_up(give_up)
return give_up if give_up
if @@route_search_frame != Graphics.frame_count
@@give_up_rate = LongSearchRate # 確率を初期化
@@route_search_frame = Graphics.frame_count # フレームの記憶を更新
end
if rand(10000) < 10000 * @@give_up_rate
@@give_up_rate = 0 # 確率を更新
result = 10 + rand(140) # 高い上限を設定
else
@@give_up_rate *= @@give_up_rate / (1.0 - @@give_up_rate) # 確率を更新
result = 10 # 低い上限を設定
end
return result
end
#--------------------------------------------------------------------------
# ● 失敗した場合の移動 [新規]
#--------------------------------------------------------------------------
def fail_move_random(diagonal, region)
# 斜め移動の場合
if diagonal && rand(2) == 0
horz = rand(2) == 0 ? 4 : 6
vert = rand(2) == 0 ? 2 : 8
nx = $game_map.round_x_with_direction(@x, horz)
ny = $game_map.round_y_with_direction(@y, vert)
return if region.include?($game_map.region_id(nx, ny))
move_diagonal(horz, vert)
return
end
# 4方向移動の場合
if rand(2) == 0
horz = rand(2) == 0 ? 4 : 6
nx = $game_map.round_x_with_direction(@x, horz)
return if region.include?($game_map.region_id(nx, @y))
move_straight(horz)
else
vert = rand(2) == 0 ? 2 : 8
ny = $game_map.round_y_with_direction(@y, vert)
return if region.include?($game_map.region_id(@x, ny))
move_straight(vert)
end
end
end
#==============================================================================
# ■ 基礎定義 ■
#==============================================================================
#==============================================================================
# ■ Game_CharacterBase
#------------------------------------------------------------------------------
# キャラクターを扱う基本のクラスです。全てのキャラクターに共通する、座標やグ
# ラフィックなどの基本的な情報を保持します。
#==============================================================================
class Game_CharacterBase
#--------------------------------------------------------------------------
# ● クラス変数
#--------------------------------------------------------------------------
@@active_collide_through = false # 座標一致判定の無効化
@@collide_through = false # 衝突判定無視
@@search_diagonal = false # 斜めの移動判定か否か
def active_collide_through=(arg) ; @@active_collide_through = arg ; end
def collide_through=(arg) ; @@collide_through = arg ; end
def search_diagonal=(arg) ; @@search_diagonal = arg ; end
#--------------------------------------------------------------------------
# ● 公開インスタンス変数
#--------------------------------------------------------------------------
attr_reader :stopwatch # 連続停止時間
#--------------------------------------------------------------------------
# ● z 座標の取得 [新規]
#--------------------------------------------------------------------------
def z
return 0 # 座標が3次元の場合は再定義する
end
#--------------------------------------------------------------------------
# ● 公開メンバ変数の初期化 [追加]
#--------------------------------------------------------------------------
alias init_public_members_RouteSearch init_public_members
def init_public_members
init_public_members_RouteSearch
@stopwatch = 1.0/0 # 1.0/0 #=> Infinity
@movement_record = [[nil, nil, nil]] # 移動履歴
end
#--------------------------------------------------------------------------
# ● 非公開メンバ変数の初期化 [追加]
#--------------------------------------------------------------------------
alias init_private_members_RouteSearch init_private_members
def init_private_members
init_private_members_RouteSearch
@scan_through_event = false # 経路探索において障害物として扱わないフラグ
end
#--------------------------------------------------------------------------
# ● フレーム更新 [追加]
#--------------------------------------------------------------------------
alias update_RouteSearch update
def update
update_RouteSearch
update_stopwatch # 連続停止時間を更新
end
#--------------------------------------------------------------------------
# ● 連続停止時間を更新 [新規]
#--------------------------------------------------------------------------
def update_stopwatch
if @movement_record[-1] != [x, y, z]
@stopwatch = 0 if @movement_record.size > 1
@movement_record.push [x, y, z]
@movement_record.shift if @movement_record.size > 10
elsif !moving?
@stopwatch += 1
end
end
#--------------------------------------------------------------------------
# ● 座標一致判定 [追加]
#--------------------------------------------------------------------------
alias pos_RouteSearch? pos?
def pos?(*args)
return false if @@collide_through and !tile? || @scan_through_event && !@@search_diagonal
# 連続停止時間が指定値以下の場合は座標を不一致にすることで衝突判定を回避する。
return false if @@active_collide_through and @stopwatch <= @@active_collide_through && !tile? || @scan_through_event && !@@search_diagonal
pos_RouteSearch?(*args)
end
end
#==============================================================================
# ■ Game_Event
#------------------------------------------------------------------------------
# イベントを扱うクラスです。条件判定によるイベントページ切り替えや、並列処理
# イベント実行などの機能を持っており、Game_Map クラスの内部で使用されます。
#==============================================================================
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# ● 衝突判定無視の設定を取得 [新規]
#--------------------------------------------------------------------------
def get_scan_through_event_note
event_result = event_note_include?(Calt::SCAN_THROUGH_EVENT_NOTE)
whole_result = whole_note_include?(Calt::SCAN_THROUGH_WHOLE_NOTE)
return event_result ^ whole_result
end
#--------------------------------------------------------------------------
# ● イベントページ更新時に注釈から設定を取得 [追加]
#--------------------------------------------------------------------------
alias setup_note_settings_RouteSearch setup_note_settings
def setup_note_settings
setup_note_settings_RouteSearch
@scan_through_event = get_scan_through_event_note
end
end
#==============================================================================
# ■ Route_Search
#------------------------------------------------------------------------------
# 経路探索の処理を定義したクラスです。
#==============================================================================
class Route_Search
#--------------------------------------------------------------------------
# ● 基礎変数の初期化
#--------------------------------------------------------------------------
def init_base_instance(character)
@character = character # キャラクターへの参照
@x , @y , @z = 0, 0, 0 # 今のノードの座標
@sx, @sy, @sz = 0, 0, 0 # 始点の座標
@gx, @gy, @gz = 0, 0, 0 # 終点の座標
@diagonal = false # 斜め移動の使用の有無
@collide_through = false # 衝突判定を無視するフラグ
@active_collide_through = 60 # 指定フレーム以内に移動してるキャラクターは衝突判定無視
end
#--------------------------------------------------------------------------
# ● 2点間の x 方向の距離
#--------------------------------------------------------------------------
def distance_x(start_x, end_x)
result = end_x - start_x
return result unless $game_map.loop_horizontal? && result.abs > $game_map.width / 2
return result + (result < 0 ? $game_map.width : -$game_map.width)
end
#--------------------------------------------------------------------------
# ● 2点間の y 方向の距離
#--------------------------------------------------------------------------
def distance_y(start_y, end_y)
result = end_y - start_y
return result unless $game_map.loop_vertical? && result.abs > $game_map.height / 2
return result + (result < 0 ? $game_map.height : -$game_map.height)
end
#--------------------------------------------------------------------------
# ● 2点間の z 方向の距離
#--------------------------------------------------------------------------
def distance_z(start_z, end_z)
return end_z - start_z
end
#--------------------------------------------------------------------------
# ● 2点の距離を取得
#--------------------------------------------------------------------------
def distance_xy(start_x, start_y, end_x, end_y)
if @diagonal
return [distance_x(start_x, end_x).abs, distance_y(start_y, end_y).abs].max # 8方向の場合
else
return distance_x(start_x, end_x).abs + distance_y(start_y, end_y).abs # 4方向の場合
end
end
#--------------------------------------------------------------------------
# ● x 座標の取得
#--------------------------------------------------------------------------
def character_x
return @character.x
end
#--------------------------------------------------------------------------
# ● y 座標の取得
#--------------------------------------------------------------------------
def character_y
return @character.y
end
#--------------------------------------------------------------------------
# ● z 座標の取得
#--------------------------------------------------------------------------
def character_z
return @character.z
end
#--------------------------------------------------------------------------
# ● z 座標の変換
#--------------------------------------------------------------------------
def xyz_to_z(x, y, z)
return z
end
#--------------------------------------------------------------------------
# ● 進入禁止のリージョンIDの座標か判定
#--------------------------------------------------------------------------
def not_enter_coordinate?(x, y, z)
return not_enter_region_id.include?($game_map.region_id(x, y))
end
#--------------------------------------------------------------------------
# ● 終点か判定
#--------------------------------------------------------------------------
def end_coordinate?(x, y, z)
return x == @gx && y == @gy && z == @gz
end
#--------------------------------------------------------------------------
# ● 終点から範囲内か判定
#--------------------------------------------------------------------------
def ending_distance?(x, y, z, distance)
return false if x == @gx && y == @gy && z != @gz
return false if distance_xy(x, y, @gx, @gy) > distance
return true
end
# #--------------------------------------------------------------------------
# # ● 始点から範囲内か判定
# #--------------------------------------------------------------------------
# def starting_distance?(x, y, z, distance)
# return false if x == @sx && y == @sy && z != @sz
# return false if distance_xy(x, y, @sx, @sy) > distance
# return true
# end
# #--------------------------------------------------------------------------
# # ● 始点の隣接座標か判定(始点を含む)
# #--------------------------------------------------------------------------
# def adjoin_coordinate?(x, y, z)
# return false unless starting_distance?(x, y, z, 1)
# return xyz_to_z(x, y, @sz) == z
# end
#--------------------------------------------------------------------------
# ● 通行可能判定
#--------------------------------------------------------------------------
def passable?(d)
@character.active_collide_through = @active_collide_through
@character.collide_through = @collide_through
@character.search_diagonal = false
result = base_passable?(:passable?, d)
@character.collide_through = false
@character.active_collide_through = false
return result
end
#--------------------------------------------------------------------------
# ● 斜めの通行可能判定
#--------------------------------------------------------------------------
def diagonal_passable?(horz, vert)
@character.active_collide_through = @active_collide_through
@character.collide_through = @collide_through
@character.search_diagonal = true
result = base_passable?(:diagonal_passable?, horz, vert)
@character.collide_through = false
@character.active_collide_through = false
return result
end
#--------------------------------------------------------------------------
# ● 通行可能判定の呼び出し
#--------------------------------------------------------------------------
def base_passable?(name, *d)
return @character.send(name, @x, @y, *d)
end
end
#==============================================================================
# ■ 内部処理 ■
#==============================================================================
#==============================================================================
# ■ Route_Search
#------------------------------------------------------------------------------
# 経路探索の処理を定義したクラスです。
#==============================================================================
class Route_Search
#--------------------------------------------------------------------------
# ● 座標の配列のインデックス
#--------------------------------------------------------------------------
X = 0 # x座標
Y = 1 # y座標
Z = 2 # z座標
#--------------------------------------------------------------------------
# ● ノードの配列のインデックス
#--------------------------------------------------------------------------
RANK_A = 0 # 評価値A
RANK_B = 1 # 評価値B
RANK_C = 2 # 評価値C
PARENT = 3 # 親の座標
LENGTH = 4 # 移動距離
#--------------------------------------------------------------------------
# ● 公開インスタンス変数
#--------------------------------------------------------------------------
attr_accessor :not_enter_region_id # 進入禁止のリージョンIDの配列
attr_accessor :limit_search_count # 探索回数の上限値
attr_accessor :always_collide_through # 常に衝突判定を無視のフラグ
attr_accessor :ending_collide_distance # 終点付近で衝突判定を無視の距離
attr_accessor :ending_through_distance # 終点付近で通行判定を無視の距離
attr_accessor :diagonal # 斜め移動の使用の有無
attr_accessor :active_collide_through # 指定フレーム以内に移動してるキャラクターは衝突判定無視
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#--------------------------------------------------------------------------
def initialize(character)
init_base_instance(character)
@parent = [nil, nil, nil] # 親の座標
@past_distance = 0 # 探索点までの移動距離
@open_list = {} # 探索候補のノードのリスト
@close_list = {} # 探索済みのノードのリスト
@limit_search_count = 100
@always_collide_through = false
@ending_collide_distance = 0
@ending_through_distance = 0
end
#--------------------------------------------------------------------------
# ● A*経路探索の通常実行
#--------------------------------------------------------------------------
def a_star_search(gx, gy, gz=0)
init_process(gx, gy, gz) # A*経路探索の初期化
return main_process # A*経路探索の主要処理
end
#--------------------------------------------------------------------------
# ● A*経路探索の初期化
#--------------------------------------------------------------------------
def init_process(gx, gy, gz)
@x, @y, @z = character_x, character_y, character_z # 現在の座標
@sx, @sy, @sz = @x, @y, @z # 始点の座標
@gx, @gy, @gz = gx, gy, gz # 終点の座標
@open_list = {[@sx, @sy, @sz]=>create_node(@sx, @sy, @sz, [nil, nil, nil], 0)}
@close_list = {}
end
#--------------------------------------------------------------------------
# ● A*経路探索の主要処理
#--------------------------------------------------------------------------
def main_process
count = 0
until @open_list.empty?
node, coordinate = get_best_node(@open_list) # 最も高評価のノードを探索候補のリストから取得
# 探索成功の場合
return create_route_list(node, coordinate) if end_coordinate?(*coordinate)
# 探索回数の上限オーバーの場合
return create_estimate_list if (count += 1) > @limit_search_count
# 隣接点を探索候補に追加する処理
@close_list[coordinate] = @open_list.delete(coordinate) # 探索候補から探索済みに移動
@x, @y, @z = *coordinate
@parent = node[PARENT]
@past_distance = node[LENGTH] + 1
down = $game_map.round_y(@y + 1)
up = $game_map.round_y(@y - 1)
right = $game_map.round_x(@x + 1)
left = $game_map.round_x(@x - 1)
open_list_add(@x, down , 2) # 下
open_list_add(@x, up , 8) # 上
open_list_add(right, @y, 6) # 右
open_list_add(left , @y, 4) # 左
if @diagonal
open_list_add_diagonal(right, down, 6, 2) # 右下
open_list_add_diagonal(left , down, 4, 2) # 左下
open_list_add_diagonal(right, up , 6, 8) # 右上
open_list_add_diagonal(left , up , 4, 8) # 左上
end
end
return false # 到達する経路は存在しない。
end
#--------------------------------------------------------------------------
# ● ノードのデータを生成
#--------------------------------------------------------------------------
def create_node(x, y, z, parent, length)
dx = distance_x(x, @gx).abs
dy = distance_y(y, @gy).abs
rank_a = length + dx + dy
rank_b = Math.sqrt(dx ** 2 + dy ** 2)
rank_c = distance_z(z, @gz).abs
return [rank_a, rank_b, rank_c, parent, length]
# [評価値A, 評価値B, 評価値C, 親の座標, 移動距離]
# 評価値A : 始点から終点までの推定最短経路の距離
# 評価値B : 終点との直線距離
# 評価値C : z 座標の距離
# 親の座標 : 移動元の座標
# 移動距離 : 始点からこの点までの移動距離
end
#--------------------------------------------------------------------------
# ● 最も高評価のノードを取得
#--------------------------------------------------------------------------
def get_best_node(hash_list, compare=:node_a_better?)
best_node = [1.0/0, 1.0/0, 1.0/0] # 1.0/0 #=> Infinity
best_coordinate = nil
hash_list.each do |coordinate, node|
next if send(compare, best_node, node) # node よりも best_node が高評価なら next
best_node = node
best_coordinate = coordinate
end
return best_node, best_coordinate
end
#--------------------------------------------------------------------------
# ● ノードの優劣判定
#--------------------------------------------------------------------------
def node_a_better?(node_a, node_b)
return true if node_a[RANK_A] < node_b[RANK_A]
return false if node_a[RANK_A] > node_b[RANK_A]
return true if node_a[RANK_B] < node_b[RANK_B]
return false if node_a[RANK_B] > node_b[RANK_B]
return true if node_a[RANK_C] < node_b[RANK_C]
return false if node_a[RANK_C] > node_b[RANK_C]
return true
end
#--------------------------------------------------------------------------
# ● 探索候補リストに隣接点を追加
#--------------------------------------------------------------------------
def open_list_add(nx, ny, d)
return if @parent[X] == nx && @parent[Y] == ny
nz = xyz_to_z(nx, ny, @z) # z 座標の変換
result = exception_decision?(nx, ny, nz)
return if result == false # 通行禁止の場合
if result == nil # 通行可能判定に委ねる場合
@collide_through = collide_through?(nx, ny, nz)
return if !passable?(d) # 通行可能判定
end
open_list_add_node(nx, ny, nz) # 探索候補リストに追加
end
#--------------------------------------------------------------------------
# ● 探索候補リストに隣接点を追加(斜めの判定版)
#--------------------------------------------------------------------------
def open_list_add_diagonal(nx, ny, horz, vert)
return if @parent[X] == nx && @parent[Y] == ny
nz = xyz_to_z(nx, ny, @z) # z 座標の変換
result = exception_decision?(nx, ny, nz)
return if result == false # 通行禁止の場合
if result == nil # 通行可能判定に委ねる場合
@collide_through = collide_through?(nx, ny, nz)
return if !diagonal_passable?(horz, vert) # 斜めの通行可能判定
end
open_list_add_node(nx, ny, nz) # 探索候補リストに追加
end
#--------------------------------------------------------------------------
# ● 例外通行判定
#--------------------------------------------------------------------------
def exception_decision?(x, y, z)
return false if not_enter_coordinate?(x, y, z)
return true if ending_distance?(x, y, z, @ending_through_distance)
return nil
end
#--------------------------------------------------------------------------
# ● 衝突判定を無視するか判定
#--------------------------------------------------------------------------
def collide_through?(x, y, z)
return true if @always_collide_through
return true if ending_distance?(x, y, z, @ending_collide_distance)
return false
end
#--------------------------------------------------------------------------
# ● 探索候補リストに隣接点を追加する処理
#--------------------------------------------------------------------------
def open_list_add_node(nx, ny, nz)
next_coordinate = [nx, ny, nz]
if old_node = @close_list[next_coordinate] # 探索済みリストに既にある場合
if old_node[LENGTH] > @past_distance # 移動距離が優れている場合
@open_list[next_coordinate] = @close_list.delete(next_coordinate) # 探索候補リストに移動
update_node(old_node)
end
return
end
if old_node = @open_list[next_coordinate] # 探索候補リストに既にある場合
update_node(old_node) if old_node[LENGTH] > @past_distance # 移動距離が優れている場合
return
end
@open_list[next_coordinate] = create_node(*next_coordinate, [@x, @y, @z], @past_distance)
end
#--------------------------------------------------------------------------
# ● ノードのデータを更新
#--------------------------------------------------------------------------
def update_node(old_node)
old_node[RANK_A] += @past_distance - old_node[LENGTH] # 移動距離の差を減算
old_node[PARENT] = [@x, @y, @z] # 親の座標を更新
old_node[LENGTH] = @past_distance # 移動距離を更新
end
#--------------------------------------------------------------------------
# ● 経路の配列を生成
#--------------------------------------------------------------------------
def create_route_list(node, coordinate)
parent = node[PARENT]
route_list = []
while parent != [nil, nil, nil]
route_list.push coordinate
parent = @close_list[coordinate = parent][PARENT]
end
return route_list # 先頭が終点で末尾が始点の次の座標(推定経路の場合は先頭は終点ではない)
end
#--------------------------------------------------------------------------
# ● 推定経路の配列を生成
#--------------------------------------------------------------------------
def create_estimate_list
open_node, open_coordinate = get_best_node(@open_list, :estimate_node_a_better?)
close_node, close_coordinate = get_best_node(@close_list, :estimate_node_a_better?)
if estimate_node_a_better?(open_node, close_node)
return create_route_list(open_node, open_coordinate)
else
return create_route_list(close_node, close_coordinate)
end
end
#--------------------------------------------------------------------------
# ● ノードの優劣判定(推定経路用)
#--------------------------------------------------------------------------
def estimate_node_a_better?(node_a, node_b)
return true if node_a[RANK_B] < node_b[RANK_B]
return false if node_a[RANK_B] > node_b[RANK_B]
return true if node_a[RANK_C] < node_b[RANK_C]
return false if node_a[RANK_C] > node_b[RANK_C]
return true
end
#--------------------------------------------------------------------------
# ● 探索結果を再利用
#--------------------------------------------------------------------------
def reuse_route_list(route_list, reuse_distance, gx, gy, gz=0)
return false unless route_list
@sx, @sy, @sz = character_x, character_y, character_z
return false unless index = route_list.index([@sx, @sy, @sz]) # 始点を含んでいるか判定
(route_list.size - index).times { route_list.pop }
return false if route_list.empty?
@gx, @gy, @gz = gx, gy, gz
if index = route_list.index([@gx, @gy, @gz]) # 終点を含んでいるか判定
index.times { route_list.shift }
return false unless route_list_valid?(route_list) # 経路を使用可能か判定
return route_list
else
return false unless ending_distance?(*route_list[0], reuse_distance)
return false unless route_list_valid?(route_list) # 経路を使用可能か判定
reuse_search(route_list) # 以前の探索結果を使用して経路探索
end
end
#--------------------------------------------------------------------------
# ● 経路を使用可能か判定
#--------------------------------------------------------------------------
def route_list_valid?(route_list)
@x, @y, @z = @sx, @sy, @sz
route_list.reverse.each do |coordinate|
nx, ny, nz = *coordinate
result = exception_decision?(nx, ny, nz)
return false if result == false # 通行禁止の場合
if result == nil # 通行可能判定に委ねる場合
@collide_through = collide_through?(nx, ny, nz)
if nx == @x
return false unless ny == @y ? nil : (ny > @y ? passable?(2) : passable?(8) )
elsif nx > @x
return false unless ny == @y ? passable?(6) : (ny > @y ? diagonal_passable?(6, 2) : diagonal_passable?(6, 8))
else
return false unless ny == @y ? passable?(4) : (ny > @y ? diagonal_passable?(4, 2) : diagonal_passable?(4, 8))
end
end
@x , @y , @z = nx, ny, nz
end
return true
end
#--------------------------------------------------------------------------
# ● 以前の探索結果を使用して経路探索
#--------------------------------------------------------------------------
def reuse_search(route_list)
init_process(@gx, @gy, @gz)
parent = [@sx, @sy, @sz]
route_list.reverse.each do |coordinate|
@open_list[coordinate] = create_node(*coordinate, parent, 0) # 移動距離に細工をして追加
parent = coordinate
end
@close_list = @open_list.dup
return main_process
end
end
#==============================================================================
# ■ マルチレイヤーシステムとの競合回避 ■
#==============================================================================
if $imported[:CanariAlternate_Multilayer]
#==============================================================================
# ■ Game_CharacterBase
#------------------------------------------------------------------------------
# キャラクターを扱う基本のクラスです。全てのキャラクターに共通する、座標やグ
# ラフィックなどの基本的な情報を保持します。
#==============================================================================
class Game_CharacterBase
#--------------------------------------------------------------------------
# ● z 座標の取得 [◆再定義]
#--------------------------------------------------------------------------
def z
return current_floor
end
end
#==============================================================================
# ■ Route_Search
#------------------------------------------------------------------------------
# 経路探索の処理を定義したクラスです。
#==============================================================================
class Route_Search
#--------------------------------------------------------------------------
# ● 定数
#--------------------------------------------------------------------------
DummyEvent = Game_CharacterBase.new # ダミーのイベント
#--------------------------------------------------------------------------
# ● z 座標の変換 [◆再定義]
#--------------------------------------------------------------------------
def xyz_to_z(x, y, z)
return $game_map.floor_xy(x, y, z)
end
#--------------------------------------------------------------------------
# ● 進入禁止のリージョンIDの座標か判定 [◆再定義]
#--------------------------------------------------------------------------
def not_enter_coordinate?(x, y, z)
return not_enter_region_id.include?($game_map.region_id(x, y, z))
end
#--------------------------------------------------------------------------
# ● 通行可能判定の呼び出し [◆再定義]
#--------------------------------------------------------------------------
def base_passable?(name, *d)
DummyEvent.current_floor = @z
return $game_map.temp_execute(DummyEvent) { @character.send(name, @x, @y, *d) }
end
end
end
他还需要一个前置脚本#============================================================================== # ■ 注釈取得スクリプト (VX Ace用) #------------------------------------------------------------------------------ # 製作者 : CanariAlternate # サイト名 : カルトの鳥篭 # サイトURL : [url]http://canarialt.blog.fc2.com[/url] #------------------------------------------------------------------------------ # ■ 概要 : 注釈を取得する処理を定義する。 # # ■ 必須 : なし # # ■ 位置 : 「Game_Event」より下 #------------------------------------------------------------------------------ # ■ 注釈での設定方法 # 以下の例のように実行内容の1行目から注釈以外のコマンドまでの注釈のどこかに # キーワードを記述すると有効(結果を反転してる場合には無効)になります。 # # 例 : 実行内容 # ◆注釈:キーワードA キーワードC # : :キーワードG キーワードF # : :キーワードE # ◆注釈:キーワードD # : :キーワードH キーワードB # ◆変数の操作などの注釈以外のイベントコマンド # ◆注釈:ここ以下に書いても無視される。 # ◆ # # ※キーワードとなる文字列の設定は正規表現です。詳しいことはヘルプを「正規表現」で検索すると出てきます。 # 簡単に言うと / で囲まれた文字列があるかないかで判定します。 # \ とか ! みたいな記号を使いたい時はヘルプを参照して下さい。 # 設定例、/\[キーワード\]/ #=> [キーワード] # # ※キーワードを記述すると有効と無効が切り替わります。初期状態は無効です。 # 例 : 初期状態を反転, 記述したイベントの全ての頁を反転, 記述した頁のみを反転 # まず 「初期状態を反転」 で有効に # 次に 「記述したイベントの全ての頁を反転」で無効に # 最後に「記述した頁のみを反転」 で有効に #------------------------------------------------------------------------------ # 更新履歴 : 2012/10/05 Ver1.00 コードを共通処理スクリプトに統一 # 2012/10/06 Ver1.01 コードを共通処理スクリプトから分離 # 2012/10/08 Ver1.02 コードの整理 # 2013/02/19 Ver1.03 共通処理スクリプトの廃止による変更を施した。 #============================================================================== $imported ||= {} $imported[:CanariAlternate_EventNote] = true #============================================================================== # ■ Calt #------------------------------------------------------------------------------ # CanariAlternateが製作したスクリプトの管理用モジュール #============================================================================== module Calt #-------------------------------------------------------------------------- # ● イベントコマンドから注釈を取得 [新規] #-------------------------------------------------------------------------- def self.Read_EventNote(list) return String.new unless list && list[i = 0].code == 108 note = list[i].parameters[0] note += "\n#{list[i].parameters[0]}" while [108, 408].include?(list[i += 1].code) return note end end #============================================================================== # ■ Game_Event #------------------------------------------------------------------------------ # イベントを扱うクラスです。条件判定によるイベントページ切り替えや、並列処理 # イベント実行などの機能を持っており、Game_Map クラスの内部で使用されます。 #============================================================================== class Game_Event < Game_Character #-------------------------------------------------------------------------- # ● イベントページの設定をセットアップ [追加] #-------------------------------------------------------------------------- alias setup_page_settings_EventNote setup_page_settings def setup_page_settings setup_page_settings_EventNote setup_note_settings end #-------------------------------------------------------------------------- # ● イベントページ更新時に注釈から設定を取得 [新規] #-------------------------------------------------------------------------- def setup_note_settings # 注釈の取得処理はここに追加 end #-------------------------------------------------------------------------- # ● 1頁目の注釈にキーワードが含まれているか判定 [新規] #-------------------------------------------------------------------------- def whole_note_include?(keyword) return @event.pages[0].event_note =~ keyword ? true : false end #-------------------------------------------------------------------------- # ● この頁の注釈にキーワードが含まれているか判定 [新規] #-------------------------------------------------------------------------- def event_note_include?(keyword) return @page.event_note =~ keyword ? true : false end end #============================================================================== # ■ RPG::Event::Page #------------------------------------------------------------------------------ # イベントページのデータクラス。 #============================================================================== class RPG::Event::Page #-------------------------------------------------------------------------- # ● 取得する注釈内容を変更 [新規] #-------------------------------------------------------------------------- attr_writer :event_note #-------------------------------------------------------------------------- # ● この頁の注釈を取得 [新規] #-------------------------------------------------------------------------- def event_note return @event_note ||= Calt::Read_EventNote(@list) end end
#==============================================================================
# ■ 注釈取得スクリプト (VX Ace用)
#------------------------------------------------------------------------------
# 製作者 : CanariAlternate
# サイト名 : カルトの鳥篭
# サイトURL : [url]http://canarialt.blog.fc2.com[/url]
#------------------------------------------------------------------------------
# ■ 概要 : 注釈を取得する処理を定義する。
#
# ■ 必須 : なし
#
# ■ 位置 : 「Game_Event」より下
#------------------------------------------------------------------------------
# ■ 注釈での設定方法
# 以下の例のように実行内容の1行目から注釈以外のコマンドまでの注釈のどこかに
# キーワードを記述すると有効(結果を反転してる場合には無効)になります。
#
# 例 : 実行内容
# ◆注釈:キーワードA キーワードC
# : :キーワードG キーワードF
# : :キーワードE
# ◆注釈:キーワードD
# : :キーワードH キーワードB
# ◆変数の操作などの注釈以外のイベントコマンド
# ◆注釈:ここ以下に書いても無視される。
# ◆
#
# ※キーワードとなる文字列の設定は正規表現です。詳しいことはヘルプを「正規表現」で検索すると出てきます。
# 簡単に言うと / で囲まれた文字列があるかないかで判定します。
# \ とか ! みたいな記号を使いたい時はヘルプを参照して下さい。
# 設定例、/\[キーワード\]/ #=> [キーワード]
#
# ※キーワードを記述すると有効と無効が切り替わります。初期状態は無効です。
# 例 : 初期状態を反転, 記述したイベントの全ての頁を反転, 記述した頁のみを反転
# まず 「初期状態を反転」 で有効に
# 次に 「記述したイベントの全ての頁を反転」で無効に
# 最後に「記述した頁のみを反転」 で有効に
#------------------------------------------------------------------------------
# 更新履歴 : 2012/10/05 Ver1.00 コードを共通処理スクリプトに統一
# 2012/10/06 Ver1.01 コードを共通処理スクリプトから分離
# 2012/10/08 Ver1.02 コードの整理
# 2013/02/19 Ver1.03 共通処理スクリプトの廃止による変更を施した。
#==============================================================================
$imported ||= {}
$imported[:CanariAlternate_EventNote] = true
#==============================================================================
# ■ Calt
#------------------------------------------------------------------------------
# CanariAlternateが製作したスクリプトの管理用モジュール
#==============================================================================
module Calt
#--------------------------------------------------------------------------
# ● イベントコマンドから注釈を取得 [新規]
#--------------------------------------------------------------------------
def self.Read_EventNote(list)
return String.new unless list && list[i = 0].code == 108
note = list[i].parameters[0]
note += "\n#{list[i].parameters[0]}" while [108, 408].include?(list[i += 1].code)
return note
end
end
#==============================================================================
# ■ Game_Event
#------------------------------------------------------------------------------
# イベントを扱うクラスです。条件判定によるイベントページ切り替えや、並列処理
# イベント実行などの機能を持っており、Game_Map クラスの内部で使用されます。
#==============================================================================
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# ● イベントページの設定をセットアップ [追加]
#--------------------------------------------------------------------------
alias setup_page_settings_EventNote setup_page_settings
def setup_page_settings
setup_page_settings_EventNote
setup_note_settings
end
#--------------------------------------------------------------------------
# ● イベントページ更新時に注釈から設定を取得 [新規]
#--------------------------------------------------------------------------
def setup_note_settings
# 注釈の取得処理はここに追加
end
#--------------------------------------------------------------------------
# ● 1頁目の注釈にキーワードが含まれているか判定 [新規]
#--------------------------------------------------------------------------
def whole_note_include?(keyword)
return @event.pages[0].event_note =~ keyword ? true : false
end
#--------------------------------------------------------------------------
# ● この頁の注釈にキーワードが含まれているか判定 [新規]
#--------------------------------------------------------------------------
def event_note_include?(keyword)
return @page.event_note =~ keyword ? true : false
end
end
#==============================================================================
# ■ RPG::Event::Page
#------------------------------------------------------------------------------
# イベントページのデータクラス。
#==============================================================================
class RPG::Event::Page
#--------------------------------------------------------------------------
# ● 取得する注釈内容を変更 [新規]
#--------------------------------------------------------------------------
attr_writer :event_note
#--------------------------------------------------------------------------
# ● この頁の注釈を取得 [新規]
#--------------------------------------------------------------------------
def event_note
return @event_note ||= Calt::Read_EventNote(@list)
end
end
PS:还有一个寻路脚本,同样有BUG,就是那个等待到移动结束没法用,不知道有没有那个脚本大佬帮帮忙#------------------------------------------------------------------------------- # * [ACE] Khas 寻路 #------------------------------------------------------------------------------- # * By Khas Arcthunder - arcthunder.site40.net # * Version: 1.0 EN # * Released on: 28/02/2012 # #------------------------------------------------------------------------------- # * Terms of Use #------------------------------------------------------------------------------- # When using any Khas script, you agree with the following terms: # 1. You must give credit to Khas; # 2. All Khas scripts are licensed under a Creative Commons license; # 3. All Khas scripts are for non-commercial projects. If you need some script # for your commercial project (I accept requests for this type of project), # 4. All Khas scripts are for personal use, you can use or edit for your own # project, but you are not allowed to post any modified version; # 5. You can’t give credit to yourself for posting any Khas script; # 6. If you want to share a Khas script, don’t post the script or the direct # download link, please redirect the user to arcthunder.site40.net # 7. You are not allowed to convert any of Khas scripts to another engine, # such converting a RGSS3 script to RGSS2 or something of that nature. # # Check all terms at [url]http://arcthunder.site40.net/terms/[/url] # #------------------------------------------------------------------------------- # * Features #------------------------------------------------------------------------------- # Smart pathfinding # Fast Algorithm # Easy to use # Plug'n'Play # Game_Character objects compatible # Log tool # #------------------------------------------------------------------------------- # * 使用方法 #------------------------------------------------------------------------------- # 使用脚本 # find_path(id,x,y) # # id => -1玩家, 0本事件,x事件ID # # find_path(id,x,y,true) # 等待直到结束 # # 如果你要启用寻路日志的功能, 请将"Log"设定为true. # #------------------------------------------------------------------------------- # * Register #------------------------------------------------------------------------------- $khas_awesome = [] if $khas_awesome.nil? $khas_awesome << ["Pathfinder",1.0] #------------------------------------------------------------------------------- # * Script #------------------------------------------------------------------------------- class Game_Interpreter def find_path(char,fx,fy,wait=false) $game_map.refresh if $game_map.need_refresh character = get_character(char) return if character.nil? return unless Path_Core.runnable?(character,fx,fy) path = Path_Core.run(character,fx,fy) return if path.nil? route = RPG::MoveRoute.new route.repeat = false route.wait = wait route.skippable = true route.list = [] path << 0x00 path.each { |code| route.list << RPG::MoveCommand.new(code)} character.force_move_route(route) @moving_character = character if wait end end class Path attr_accessor :axis attr_accessor :from attr_accessor :cost attr_accessor :dir def initialize(x,y,f,c,d) @axis = [x,y] @from = f @cost = c @dir = d end end module Path_Core Log = false #是否启用寻路日志 Directions = {[1,0] => 3,[-1,0] => 2,[0,-1] => 4,[0,1] => 1} def self.runnable?(char,x,y) return false unless $game_map.valid?(x,y) return false if char.collide_with_characters?(x,y) $game_map.all_tiles(x,y).each { |id| flag = $game_map.tileset.flags[id] next if flag & 0x10 != 0 return flag & 0x0f != 0x0f} return false end def self.run(char,fx,fy) return nil if char.x == fx && char.y == fy st = Time.now @char = char @start = Path.new(@char.x,@char.y,nil,0,nil) @finish = Path.new(fx,fy,nil,0,nil) @list = [] @queue = [] @preference = ((@char.x-fx).abs > (@char.y-fy).abs ? 0x0186aa : 0x01d) class << @list def new_path?(path_class) for path in self return false if path.axis == path_class.axis end return true end end class << @queue def new_path?(path_class) for path in self return false if path.axis == path_class.axis end return true end end if @preference & 0x02 == 0x02 @queue << Path.new(@char.x,@char.y+1,@start,1,[0,1]) if @char.passable?(@char.x,@char.y,2) @queue << Path.new(@char.x,@char.y-1,@start,1,[0,-1]) if @char.passable?(@char.x,@char.y,8) @queue << Path.new(@char.x+1,@char.y,@start,1,[1,0]) if @char.passable?(@char.x,@char.y,6) @queue << Path.new(@char.x-1,@char.y,@start,1,[-1,0]) if @char.passable?(@char.x,@char.y,4) @list << @start loop do break if @queue.empty? @cpath = @queue[0] if @cpath.axis == @finish.axis @finish.cost = @cpath.cost @finish.from = @cpath break end @list << @cpath @path_array = [] p1 = Path.new(@cpath.axis[0]+1,@cpath.axis[1],@cpath,@cpath.cost+1,[1,0]) p2 = Path.new(@cpath.axis[0]-1,@cpath.axis[1],@cpath,@cpath.cost+1,[-1,0]) p3 = Path.new(@cpath.axis[0],@cpath.axis[1]+1,@cpath,@cpath.cost+1,[0,1]) p4 = Path.new(@cpath.axis[0],@cpath.axis[1]-1,@cpath,@cpath.cost+1,[0,-1]) @path_array << p3 if @char.passable?(@cpath.axis[0],@cpath.axis[1],2) && @list.new_path?(p3) && @queue.new_path?(p3) @path_array << p4 if @char.passable?(@cpath.axis[0],@cpath.axis[1],8) && @list.new_path?(p4) && @queue.new_path?(p4) @path_array << p1 if @char.passable?(@cpath.axis[0],@cpath.axis[1],6) && @list.new_path?(p1) && @queue.new_path?(p1) @path_array << p2 if @char.passable?(@cpath.axis[0],@cpath.axis[1],4) && @list.new_path?(p2) && @queue.new_path?(p2) @path_array.each { |path| @queue << path } @queue.delete(@cpath) end else @queue << Path.new(@char.x+1,@char.y,@start,1,[1,0]) if @char.passable?(@char.x,@char.y,6) @queue << Path.new(@char.x-1,@char.y,@start,1,[-1,0]) if @char.passable?(@char.x,@char.y,4) @queue << Path.new(@char.x,@char.y+1,@start,1,[0,1]) if @char.passable?(@char.x,@char.y,2) @queue << Path.new(@char.x,@char.y-1,@start,1,[0,-1]) if @char.passable?(@char.x,@char.y,8) @list << @start loop do break if @queue.empty? @cpath = @queue[0] if @cpath.axis == @finish.axis @finish.cost = @cpath.cost @finish.from = @cpath break end @list << @cpath @path_array = [] p1 = Path.new(@cpath.axis[0]+1,@cpath.axis[1],@cpath,@cpath.cost+1,[1,0]) p2 = Path.new(@cpath.axis[0]-1,@cpath.axis[1],@cpath,@cpath.cost+1,[-1,0]) p3 = Path.new(@cpath.axis[0],@cpath.axis[1]+1,@cpath,@cpath.cost+1,[0,1]) p4 = Path.new(@cpath.axis[0],@cpath.axis[1]-1,@cpath,@cpath.cost+1,[0,-1]) @path_array << p1 if @char.passable?(@cpath.axis[0],@cpath.axis[1],6) && @list.new_path?(p1) && @queue.new_path?(p1) @path_array << p2 if @char.passable?(@cpath.axis[0],@cpath.axis[1],4) && @list.new_path?(p2) && @queue.new_path?(p2) @path_array << p3 if @char.passable?(@cpath.axis[0],@cpath.axis[1],2) && @list.new_path?(p3) && @queue.new_path?(p3) @path_array << p4 if @char.passable?(@cpath.axis[0],@cpath.axis[1],8) && @list.new_path?(p4) && @queue.new_path?(p4) @path_array.each { |path| @queue << path } @queue.delete(@cpath) end end if @finish.from.nil? return nil else steps = [@finish.from] loop do cr = steps[-1] if cr.cost == 1 @result = [] steps.each { |s| @result << Directions[s.dir]} break else steps << cr.from end end self.print_log(Time.now-st) if Log return @result.reverse end end def self.print_log(time) print "\n--------------------\n" print "Khas Pathfinder\n" print "Time: #{time}\n" print "Size: #{@result.size}\n" print "--------------------\n" end end
#-------------------------------------------------------------------------------
# * [ACE] Khas 寻路
#-------------------------------------------------------------------------------
# * By Khas Arcthunder - arcthunder.site40.net
# * Version: 1.0 EN
# * Released on: 28/02/2012
#
#-------------------------------------------------------------------------------
# * Terms of Use
#-------------------------------------------------------------------------------
# When using any Khas script, you agree with the following terms:
# 1. You must give credit to Khas;
# 2. All Khas scripts are licensed under a Creative Commons license;
# 3. All Khas scripts are for non-commercial projects. If you need some script
# for your commercial project (I accept requests for this type of project),
# 4. All Khas scripts are for personal use, you can use or edit for your own
# project, but you are not allowed to post any modified version;
# 5. You can’t give credit to yourself for posting any Khas script;
# 6. If you want to share a Khas script, don’t post the script or the direct
# download link, please redirect the user to arcthunder.site40.net
# 7. You are not allowed to convert any of Khas scripts to another engine,
# such converting a RGSS3 script to RGSS2 or something of that nature.
#
# Check all terms at [url]http://arcthunder.site40.net/terms/[/url]
#
#-------------------------------------------------------------------------------
# * Features
#-------------------------------------------------------------------------------
# Smart pathfinding
# Fast Algorithm
# Easy to use
# Plug'n'Play
# Game_Character objects compatible
# Log tool
#
#-------------------------------------------------------------------------------
# * 使用方法
#-------------------------------------------------------------------------------
# 使用脚本
# find_path(id,x,y)
#
# id => -1玩家, 0本事件,x事件ID
#
# find_path(id,x,y,true)
# 等待直到结束
#
# 如果你要启用寻路日志的功能, 请将"Log"设定为true.
#
#-------------------------------------------------------------------------------
# * Register
#-------------------------------------------------------------------------------
$khas_awesome = [] if $khas_awesome.nil?
$khas_awesome << ["Pathfinder",1.0]
#-------------------------------------------------------------------------------
# * Script
#-------------------------------------------------------------------------------
class Game_Interpreter
def find_path(char,fx,fy,wait=false)
$game_map.refresh if $game_map.need_refresh
character = get_character(char)
return if character.nil?
return unless Path_Core.runnable?(character,fx,fy)
path = Path_Core.run(character,fx,fy)
return if path.nil?
route = RPG::MoveRoute.new
route.repeat = false
route.wait = wait
route.skippable = true
route.list = []
path << 0x00
path.each { |code| route.list << RPG::MoveCommand.new(code)}
character.force_move_route(route)
@moving_character = character if wait
end
end
class Path
attr_accessor :axis
attr_accessor :from
attr_accessor :cost
attr_accessor :dir
def initialize(x,y,f,c,d)
@axis = [x,y]
@from = f
@cost = c
@dir = d
end
end
module Path_Core
Log = false #是否启用寻路日志
Directions = {[1,0] => 3,[-1,0] => 2,[0,-1] => 4,[0,1] => 1}
def self.runnable?(char,x,y)
return false unless $game_map.valid?(x,y)
return false if char.collide_with_characters?(x,y)
$game_map.all_tiles(x,y).each { |id|
flag = $game_map.tileset.flags[id]
next if flag & 0x10 != 0
return flag & 0x0f != 0x0f}
return false
end
def self.run(char,fx,fy)
return nil if char.x == fx && char.y == fy
st = Time.now
@char = char
@start = Path.new(@char.x,@char.y,nil,0,nil)
@finish = Path.new(fx,fy,nil,0,nil)
@list = []
@queue = []
@preference = ((@char.x-fx).abs > (@char.y-fy).abs ? 0x0186aa : 0x01d)
class << @list
def new_path?(path_class)
for path in self
return false if path.axis == path_class.axis
end
return true
end
end
class << @queue
def new_path?(path_class)
for path in self
return false if path.axis == path_class.axis
end
return true
end
end
if @preference & 0x02 == 0x02
@queue << Path.new(@char.x,@char.y+1,@start,1,[0,1]) if @char.passable?(@char.x,@char.y,2)
@queue << Path.new(@char.x,@char.y-1,@start,1,[0,-1]) if @char.passable?(@char.x,@char.y,8)
@queue << Path.new(@char.x+1,@char.y,@start,1,[1,0]) if @char.passable?(@char.x,@char.y,6)
@queue << Path.new(@char.x-1,@char.y,@start,1,[-1,0]) if @char.passable?(@char.x,@char.y,4)
@list << @start
loop do
break if @queue.empty?
@cpath = @queue[0]
if @cpath.axis == @finish.axis
@finish.cost = @cpath.cost
@finish.from = @cpath
break
end
@list << @cpath
@path_array = []
p1 = Path.new(@cpath.axis[0]+1,@cpath.axis[1],@cpath,@cpath.cost+1,[1,0])
p2 = Path.new(@cpath.axis[0]-1,@cpath.axis[1],@cpath,@cpath.cost+1,[-1,0])
p3 = Path.new(@cpath.axis[0],@cpath.axis[1]+1,@cpath,@cpath.cost+1,[0,1])
p4 = Path.new(@cpath.axis[0],@cpath.axis[1]-1,@cpath,@cpath.cost+1,[0,-1])
@path_array << p3 if @char.passable?(@cpath.axis[0],@cpath.axis[1],2) && @list.new_path?(p3) && @queue.new_path?(p3)
@path_array << p4 if @char.passable?(@cpath.axis[0],@cpath.axis[1],8) && @list.new_path?(p4) && @queue.new_path?(p4)
@path_array << p1 if @char.passable?(@cpath.axis[0],@cpath.axis[1],6) && @list.new_path?(p1) && @queue.new_path?(p1)
@path_array << p2 if @char.passable?(@cpath.axis[0],@cpath.axis[1],4) && @list.new_path?(p2) && @queue.new_path?(p2)
@path_array.each { |path| @queue << path }
@queue.delete(@cpath)
end
else
@queue << Path.new(@char.x+1,@char.y,@start,1,[1,0]) if @char.passable?(@char.x,@char.y,6)
@queue << Path.new(@char.x-1,@char.y,@start,1,[-1,0]) if @char.passable?(@char.x,@char.y,4)
@queue << Path.new(@char.x,@char.y+1,@start,1,[0,1]) if @char.passable?(@char.x,@char.y,2)
@queue << Path.new(@char.x,@char.y-1,@start,1,[0,-1]) if @char.passable?(@char.x,@char.y,8)
@list << @start
loop do
break if @queue.empty?
@cpath = @queue[0]
if @cpath.axis == @finish.axis
@finish.cost = @cpath.cost
@finish.from = @cpath
break
end
@list << @cpath
@path_array = []
p1 = Path.new(@cpath.axis[0]+1,@cpath.axis[1],@cpath,@cpath.cost+1,[1,0])
p2 = Path.new(@cpath.axis[0]-1,@cpath.axis[1],@cpath,@cpath.cost+1,[-1,0])
p3 = Path.new(@cpath.axis[0],@cpath.axis[1]+1,@cpath,@cpath.cost+1,[0,1])
p4 = Path.new(@cpath.axis[0],@cpath.axis[1]-1,@cpath,@cpath.cost+1,[0,-1])
@path_array << p1 if @char.passable?(@cpath.axis[0],@cpath.axis[1],6) && @list.new_path?(p1) && @queue.new_path?(p1)
@path_array << p2 if @char.passable?(@cpath.axis[0],@cpath.axis[1],4) && @list.new_path?(p2) && @queue.new_path?(p2)
@path_array << p3 if @char.passable?(@cpath.axis[0],@cpath.axis[1],2) && @list.new_path?(p3) && @queue.new_path?(p3)
@path_array << p4 if @char.passable?(@cpath.axis[0],@cpath.axis[1],8) && @list.new_path?(p4) && @queue.new_path?(p4)
@path_array.each { |path| @queue << path }
@queue.delete(@cpath)
end
end
if @finish.from.nil?
return nil
else
steps = [@finish.from]
loop do
cr = steps[-1]
if cr.cost == 1
@result = []
steps.each { |s| @result << Directions[s.dir]}
break
else
steps << cr.from
end
end
self.print_log(Time.now-st) if Log
return @result.reverse
end
end
def self.print_log(time)
print "\n--------------------\n"
print "Khas Pathfinder\n"
print "Time: #{time}\n"
print "Size: #{@result.size}\n"
print "--------------------\n"
end
end
|
最佳答案
查看完整内容
大概是这样用?
khas的寻路
74行 @moving_character = character if wait 后面 end 前面加上
if wait
Fiber.yield while character.x != fx || character.y != fy
end[/pre]
评分
-
查看全部评分
|