Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Path Finding

Path Finding
Version: 2
by Jaime 'Near Fantastica' Webster
Not DerVVulfman

and Version: 2 beta
Event Start & Option_Close option Correction
Minor Edit By DerVVulfman

BONUS
Version: 1
The original version at the bottom of the post!



Introduction
"NO MORE CUSTOM MOVEMENTS! This script uses path finding to return the shortest path from the START XY to the END XY then uses the custom movement to move the character(s). You can chain this path finds together to path link between 2 points or more...

As well an Error message will be displayed if you try to send an event to a place it can not get to. 'Target Is Unreachable for Event ID' " - Near Fantastica

By the poster
I didn't create the script, and as of now the links that Near Fantastica put up are down (and he can't get to them) and his RMXP system is down. Given that he posted the original (though broken) demo links here, there should be no problem to post the script.

However as I didn't create the script, I cannot offer support.


Demo
Both v1 and the new v2 beta in one set
It's about time...

Script
Code:
#======================================
# â–  Path Finding
#------------------------------------------------------------------------------
#  By: Near Fantastica
#   Date: 21.06.05
#   Verion 2
#
#   Path Fiding Element By Fuso
#======================================

class Path_Finding
  #--------------------------------------------------------------------------
  def initialize
    @player_path = nil
    @player_points = []
  end
  #--------------------------------------------------------------------------
  def setup_event(index, repeat = false, skippable = false)
    event = $game_map.events[index]
    event.points = []
    event.path = RPG::MoveRoute.new
    event.path.repeat = repeat
    event.path.skippable = skippable
    event.path.list.clear
    key = [event.x,event.y]
    event.points.push(key)
  end
  #--------------------------------------------------------------------------
  def add_command_event(index, code, parameters = [])
    event = $game_map.events[index]
    event.path.list.push RPG::MoveCommand.new(code, parameters)
  end
  #--------------------------------------------------------------------------
  def add_paths_event(index, trg_x, trg_y)
    event = $game_map.events[index]
    key = event.points.last
    paths = $game_map.find_short_paths(key[0], key[1], trg_x, trg_y, event)
    if paths == nil
      print "Target " + trg_x.to_s + ","+ trg_y.to_s + " Is Unreachable for Event " + index.to_s 
      return
    end
    key = [trg_x, trg_y]
    event.points.push(key)
    for path in paths
      event.path.list.push RPG::MoveCommand.new(4) if path == 2
      event.path.list.push RPG::MoveCommand.new(2) if path == 4
      event.path.list.push RPG::MoveCommand.new(3) if path == 6
      event.path.list.push RPG::MoveCommand.new(1) if path == 8
    end
  end
  #--------------------------------------------------------------------------
  def start_event(index)
    event = $game_map.events[index]
    event.path.list.push RPG::MoveCommand.new(0)
    event.move_route = event.path
    event.move_route_index = 0
  end
  #--------------------------------------------------------------------------
  def setup_player(repeat = false, skippable = false)
    @player_points = []
    @player_path = RPG::MoveRoute.new
    @player_path.repeat = repeat
    @player_path.skippable = skippable
    @player_path.list.clear
    key = [$game_player.x, $game_player.y]
    @player_points.push(key)
  end
  #--------------------------------------------------------------------------
  def add_command_player(code, parameters = [])
    @player_path.list.push RPG::MoveCommand.new(code, parameters)
  end
  #--------------------------------------------------------------------------
  def add_paths_player(trg_x, trg_y)
    key = @player_points.last
    paths = $game_map.find_short_paths(key[0], key[1], trg_x, trg_y, $game_player, [$game_player])
    if paths == nil
      print "Target " + trg_x.to_s + "," + trg_y.to_s + " Is Unreachable for Player"
      return
    end
    key = [trg_x, trg_y]
    @player_points.push(key)
    for path in paths
      @player_path.list.push RPG::MoveCommand.new(4) if path == 2
      @player_path.list.push RPG::MoveCommand.new(2) if path == 4
      @player_path.list.push RPG::MoveCommand.new(3) if path == 6
      @player_path.list.push RPG::MoveCommand.new(1) if path == 8
    end
  end
  #--------------------------------------------------------------------------
  def start_player
    @player_path.list.push RPG::MoveCommand.new(0)
    $game_player.force_move_route(@player_path)
  end
end
#======================================
# â–  Path Finding
#------------------------------------------------------------------------------
#  By: Fuso
#======================================
class Game_Character
  attr_accessor :move_route
  attr_accessor :move_route_index
  #--------------------------------------------------------------------------
  def pf_passable?(x, y, d, ignore_events = [self], check_player = (self != $game_player))
    ignore_event = [ignore_event] if not ignore_event.is_a?(Array)
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
   unless $game_map.valid?(new_x, new_y)
     return false
   end
   if @through
     return true
   end
   unless $game_map.pf_passable?(x, y, d, ignore_events, check_player)
     return false
   end
   unless $game_map.pf_passable?(new_x, new_y, 10 - d, ignore_events, check_player)
     return false
   end
   for event in $game_map.events.values
     if event.x == new_x and event.y == new_y
       if not ignore_events.include?(event) and not event.through and not event == self
         if self != $game_player
           return false
         end
         if event.character_name != ""
           return false
         end
       end
     end
   end
   if $game_player.x == new_x and $game_player.y == new_y
     unless $game_player.through or ignore_events.include?($game_player) or not check_player
       if @character_name != ""
         return false
       end
     end
   end
   return true
 end
end
#======================================
class Game_Player < Game_Character
  def pf_passable?(x, y, d, ignore_events = [self], check_player = false)
    passable?(x,y,d)
  end
end
#======================================
class Game_Map
 #--------------------------------------------------------------------------
  attr_accessor :events
  #--------------------------------------------------------------------------
  UP = 2
  LEFT = 4
  RIGHT = 6
  DOWN = 8
  #--------------------------------------------------------------------------
  def find_short_paths(src_x,src_y,trg_x,trg_y, passable_owner = self, ignore_events = [], option_close = false, depth = 200)
   return [] if not (passable_owner.pf_passable?(trg_x, trg_y, UP, ignore_events) or
                   passable_owner.pf_passable?(trg_x, trg_y, LEFT, ignore_events) or
                   passable_owner.pf_passable?(trg_x, trg_y, RIGHT, ignore_events) or
                   passable_owner.pf_passable?(trg_x, trg_y, DOWN, ignore_events))
   # Paths will hold the succeeding paths.
   paths = []
   #  path_map will hold what paths has already been visited, to prevent that we attempt to
   #  walk on the same tile twice.
   path_map = [src_x + src_y / 10000.0]
   trackers = []
   new_trackers = [[src_x, src_y, []]]
   if not option_close
     depth.times {
       break if new_trackers.empty?
       trackers = new_trackers
       new_trackers = []
       for tracker in trackers
         if tracker[0] == trg_x and tracker[1] == trg_y
           paths.push tracker[2].compact
           next
         end
         path_map.push tracker[0] + tracker[1] / 10000.0
         if passable_owner.pf_passable?(tracker[0], tracker[1], DOWN, ignore_events, true) and
             not path_map.include? tracker[0] + (tracker[1] - 1) / 10000.0
           path_map.push tracker[0] + (tracker[1] - 1) / 10000.0
           new_trackers.push [tracker[0], tracker[1] - 1, [tracker[2], UP].flatten]
         end
         if passable_owner.pf_passable?(tracker[0], tracker[1], LEFT, ignore_events, true) and
             not path_map.include? tracker[0] - 1 + tracker[1] / 10000.0
           path_map.push tracker[0] - 1 + tracker[1] / 10000.0
           new_trackers.push [tracker[0] - 1, tracker[1], [tracker[2], LEFT].flatten]
         end
         if passable_owner.pf_passable?(tracker[0], tracker[1], RIGHT, ignore_events, true) and
             not path_map.include? tracker[0] + 1 + tracker[1] / 10000.0
           path_map.push tracker[0] + 1 + tracker[1] / 10000.0
           new_trackers.push [tracker[0] + 1, tracker[1], [tracker[2], RIGHT].flatten]
         end
         if passable_owner.pf_passable?(tracker[0], tracker[1], UP, ignore_events, true) and
             not path_map.include? tracker[0] + (tracker[1] + 1) / 10000.0
           path_map.push tracker[0] + (tracker[1] + 1) / 10000.0
           new_trackers.push [tracker[0], tracker[1] + 1, [tracker[2], DOWN].flatten]
         end
       end
       break if paths.size > 0
     }
   else
     paths_distance = 10000 ** 2 * 2
     depth.times {
       trackers = new_trackers
       new_trackers = []
       for tracker in trackers

         if tracker[0] == trg_x and tracker[1] == trg_y
           if paths_distance > 0
             paths_distance = 0
             paths.clear
           end
           paths.push tracker[2].compact
           next
         end
         distance = (tracker[0] - trg_x) ** 2 + (tracker[1] - trg_y) ** 2
         if distance <= paths_distance
           if distance < paths_distance
             paths.clear
             paths_distance = distance
           end
           paths.push tracker[2].compact
         end
         path_map.push tracker[0] + tracker[1] / 10000.0
         if passable_owner.pf_passable?(tracker[0], tracker[1], DOWN, ignore_events, true) and
             not path_map.include? tracker[0] + (tracker[1] - 1) / 10000.0
           path_map.push tracker[0] + (tracker[1] - 1) / 10000.0
           new_trackers.push [tracker[0], tracker[1] - 1, [tracker[2], UP].flatten]
         end
         if passable_owner.pf_passable?(tracker[0], tracker[1], LEFT, ignore_events, true) and
             not path_map.include? tracker[0] - 1 + tracker[1] / 10000.0
           path_map.push tracker[0] - 1 + tracker[1] / 10000.0
           new_trackers.push [tracker[0] - 1, tracker[1], [tracker[2], LEFT].flatten]
         end
         if passable_owner.pf_passable?(tracker[0], tracker[1], RIGHT, ignore_events, true) and
             not path_map.include? tracker[0] + 1 + tracker[1] / 10000.0
           path_map.push tracker[0] + 1 + tracker[1] / 10000.0
           new_trackers.push [tracker[0] + 1, tracker[1], [tracker[2], RIGHT].flatten]
         end
         if passable_owner.pf_passable?(tracker[0], tracker[1], UP, ignore_events, true) and
             not path_map.include? tracker[0] + (tracker[1] + 1) / 10000.0
           path_map.push tracker[0] + (tracker[1] + 1) / 10000.0
           new_trackers.push [tracker[0], tracker[1] + 1, [tracker[2], DOWN].flatten]
         end
       end
       break if distance == 0 and paths.size > 0
     }
   end
   route = paths[0]
   return route
 end
 #--------------------------------------------------------------------------
 def pf_passable?(x, y, d, ignore_events = [], check_player = false)
   ignore_events = [ignore_events].compact if not ignore_events.is_a?(Array)
   unless valid?(x, y)
     return false
   end
   bit = (1 << (d / 2 - 1)) & 0x0f
   checks = events.values
   checks.push $game_player if check_player
   for event in checks
     if event.tile_id >= 0 and not ignore_events.include?(event) and
         event.x == x and event.y == y and not event.through
       return false if event == $game_player and check_player
       if @passages[event.tile_id] & bit != 0
         return false
       elsif @passages[event.tile_id] & 0x0f == 0x0f
         return false
       elsif @priorities[event.tile_id] == 0
         return true
       end
     end
   end
   for i in [2, 1, 0]
     tile_id = data[x, y, i]
     if tile_id == nil
       return false
     elsif @passages[tile_id] & bit != 0
       return false
     elsif @passages[tile_id] & 0x0f == 0x0f
       return false
     elsif @priorities[tile_id] == 0
       return true
     end
   end
   return true
 end
end
#======================================
class Scene_Title
 #--------------------------------------------------------------------------
 alias pf_scene_title_update update
 #--------------------------------------------------------------------------
 def update
   $path_finding = Path_Finding.new
   pf_scene_title_update
 end
end
#======================================
class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  alias pf_game_event_initialize initialize
  #--------------------------------------------------------------------------
  attr_accessor :path
  attr_accessor :points
  #--------------------------------------------------------------------------
  def initialize(map_id, event)
    @path = []
    @points = nil
    pf_game_event_initialize(map_id, event)
  end
end

Good as it is, it had an error with the system that started to move 'events' on the map. Also, a feature added by Fuso (the option_close feature) was 'accidentally' removed in version 2. These have been remedied in the version below, and I added a new feature to change the estimated pathfinding range (explained in script & demo):
Instructions revised and included in the script.
Code:
#==============================================================================
# ** Path Finding v2 beta
#------------------------------------------------------------------------------
#  Original version by:     Near Fantastica
#  Original date:           June 21, 2005
#  Pathfinding Element by:  Fuso
#
#  Modifications/edit by:   DerVVulfman
#  Modification date:       October 28, 2007
#
#==============================================================================
#
#  INTRODUCTION:
#  The original v2 pathfinding system allowed for more control over player and
#  event motions than version 1.  A more comprehensive 'event passable' system
#  and a new interface system by Fuso added to the system's flexibility.
#
#  Unfortunately, when version 2 was released (at least where I found it), the
#  instructions for the system's use were only partially correct and a feature
#  to enable movement 'to' a blocked destination was disabled.
#
#  Though it was not my intention to tangle with any pathfinding system,  luck
#  (and a few friends) nudged me into experimenting with this system.   And it
#  is thanks to Fuso for informing me of the 'option_close' switch that origi-
#  nally allows the scripter (you) to choose  if a warning message pops up, or
#  if the player/event can move to a blocked location.
#
#  A newly added feature is the 'turn and face' feature.   It adds the ability
#  for the player/event to face a blocked location.  Previous incarnations had
#  not counted on the direction faced  and merely ended the movement system if
#  a location was not reachable.
#
#  Another feature added is an editable 'depth' or 'limit' value. By increasing
#  the depth of the pathfinding system, you can permit the pathfinding system 
#  to search through larger maps rather than not moving to the target location.
#  Also, by reducing the depth,  you can speed up the pathfinding system.   The
#  larger the value,  the more time it takes to generate the path... but larger
#  maps may need it.
#
#------------------------------------------------------------------------------
#
#  FEATURES:
#  * Use a 'pre-designed' movement systems similar to the Force Move Route call
#  * Use a 'system generated' movement system (pathfinding) for final locations
#  * Allows for 'pre-designed' or 'system generated' movement for players
#  * Allows for 'pre-designed' or 'system generated' movement for events
#  * Can generate a warning pop if 'pathfinding' target is blocked -OPTIONAL-
#  * Can move to 'blocked' locations with 'pathfinding' systems -OPTIONAL-
#  * Can 'turn and face' a desired location if blocked
#  * Editable 'depth' system
#
#------------------------------------------------------------------------------
#
#  INSTRUCTIONS:
#  Performing a pathfinding routine with this system uses three steps.  These
#  steps are to:
#  1) Setup for the move
#  2) Set your pathfinding destination or custom move
#  3) Start the move.
#
#  So the instructions given below will be fairly brief and in two sections...
#  one section for the movement of the player and the other to move events.
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
#  --PLAYER CALLS--
#
#  $path_finding.setup_player(repeat, skippable = false)
#    This routine call readies the player graphic for the input of pathfinding
#    data or of a simple command movement call.  It has to be called before
#    any other call is made. 
#  
#    repeat       = If you set the repeat flag to true and the define movement
#                   will repeat.  If set to false it will not repeat.
#    skippable    = If you set skippable flag to true, the event will continue
#                   through it's list of movement commands even when blocked.
#
#                   NOTE : These are not wanted in most cases that is why they
#                   are defaulted to false
#
#
#  $path_finding.add_paths_player(trg_x, trg_y, option_close = false)
#     This routine call attempts to chart a path for the player graphic so the
#     player can be moved to said location.  If a path is unobtainable, the
#     system may either bring up a warning message or move to the closest 
#     possible location.
#
#     trg_x         = This is the X-coordinate on the map where the pathfinding
#                     system will chart for the player.
#     trg_y         = This is the y-coordinate on the map where the pathfinding
#                     system will chart for the player.
#     option_close  = This is a true/false switch.  If you set this switch to
#                     true then the player  will move to the closest possible 
#                     location if the destination is blocked.   If set to false,
#                     then the system will bring up a pop-up warning that the
#                     destination is unobtainable.
#
#
#  $path_finding.add_command_player(code, parameters = [])
#    This routine call attempts to move the player one step or movement command
#    at a time.  Passing (for example) a movement code of 'down' will move the
#    character down.  Very simple.
#
#    code         = The RGSS movement code (see below for a small list)
#    parameters   = Needed parameters for that movement code (such as for Jump)
#                   NOTE : Movement codes can be found in the Game_Character
#                   page 2 move_type_custom as well as there needed parameters
#
#
#  $path_finding.start_player
#    Once the paths or commands have been set, call this routine to move the
#    player to the set location.
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
#  --EVENT CALLS--
#
#  $path_finding.setup_event(index, repeat, skippable = false)
#    This routine call readies an event for the input of pathfinding data or of
#    a simple command movement call.  It has to be called before any other call
#    is made.  It can also be used to 'stop' an event's movement.
#
#    index        = the index or ID number of the map event to be moved
#    repeat       = If you set the repeat flag to true and the define movement
#                   will repeat.  If set to false it will not repeat.
#    skippable    = If you set skippable flag to true, the event will continue
#                   through it's list of movement commands even when blocked.
#
#                   NOTE : These are not wanted in most cases that is why they
#                   are defaulted to false
#
#
#  $path_finding.add_paths_event(index, trg_x, trg_y, option_close = false)
#     This routine call attempts to chart a path for the map event so the
#     event can be moved to said location.  If a path is unobtainable, the
#     system may either bring up a warning message or move to the closest 
#     possible location.
#
#     index         = the index or ID number of the map event to be moved
#     trg_x         = This is the X-coordinate on the map where the pathfinding
#                     system will chart for the event.
#     trg_y         = This is the y-coordinate on the map where the pathfinding
#                     system will chart for the event.
#     option_close  = This is a true/false switch.  If you set this switch to
#                     true then the event will move to the closest possible lo-
#                     cation if the destination is blocked.   If set to false,
#                     then the system will bring up a pop-up warning  that the
#                     destination is unobtainable.
#
#
#  $path_finding.add_command_event(index, code, parameters = [])
#    This routine call attempts to move the event one step or movement command
#    at a time.  Passing (for example) a movement code of 'down' will move the
#    event down.  Very simple.
#
#    index        = the index or ID number of the map event to be moved
#    code         = The RGSS movement code (see below for a small list)
#    parameters   = Needed parameters for that movement code (such as for Jump)
#                   NOTE : Movement codes can be found in the Game_Character
#                   page 2 move_type_custom as well as there needed parameters
#
#
#  $path_finding.start_event(index)
#    Once the paths or commands have been set, call this routine to move the
#    event to the set location.
#
#    index        = the index or ID number of the map event to be moved
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
#  --DEPTH--
#
#  $path_finding.set_depth(depth)
#    This routine is the only call that can apply to both player and event
#    movement, and directly affects the pathfinding system.  It sets the max-
#    imum number of steps taken to reach the destination or just how far the
#    player or event will travel while trying to reach that goal.
#
#    depth        = the estimated number of tiles the character/event will move
#                   to the desired/targetted location.
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
#  --MOVEMENT CODES--
#
#  This is a selection of movement codes you can use in the add_command and 
#  the add_command_player routines.  This is only a selection of the available
#  commands... not all of them.
#
# 1) Move down          10) Move toward player      19) Turn up
# 2) Move left          11) Move away from player   20) Turn 90? right
# 3) Move right         12) 1 step forward          21) Turn 90? left
# 4) Move up            13) 1 step backward         22) Turn 180? 
# 5) Move lower left    14) Jump*                   23) Turn 90? right or left  
# 6) Move lower right   15) Set wait count*         24) Turn at Random    
# 7) Move upper left    16) Turn down               25) Turn toward player
# 8) Move upper right   17) Turn left               26) Turn away from player       
# 9) Move at random     18) Turn right
# 
#  * These require additional parameters for use (x/y coordinates, time delay
#    or other values).
#  
#==============================================================================



#==============================================================================
# ** Path_Finding
#------------------------------------------------------------------------------
#  This class sets and controls pathfinding movement routines.  It is used
#  within the Game_Character, Game_Event, Game_Player, and Game_Map classes.
#==============================================================================

class Path_Finding
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------  
  attr_accessor :pf_depth                 # pathfinding depth (limit)
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    @player_path = nil
    @player_points = []
    @pf_depth = 100
  end
  #--------------------------------------------------------------------------
  # * Setup Depth
  #     depth          : Depth / Max number of pathfinding steps
  #--------------------------------------------------------------------------  
  def setup_depth(depth)
    @pf_depth = depth
  end
  #--------------------------------------------------------------------------
  # * Setup Event
  #     index          : event index / event ID number
  #     repeat         : if path/movement is repeated
  #     skippable      : if any blocked step can be skipped
  #--------------------------------------------------------------------------
  def setup_event(index, repeat = false, skippable = false)
    event = $game_map.events[index]
    event.points = []
    event.path = RPG::MoveRoute.new
    event.path.repeat = repeat
    event.path.skippable = skippable
    event.path.list.clear
    key = [event.x,event.y]
    event.points.push(key)
  end
  #--------------------------------------------------------------------------
  # * Add Command Event
  #     index          : event index / event ID number
  #     code           : movement code 
  #     parameters     : movement parameters  
  #--------------------------------------------------------------------------
  def add_command_event(index, code, parameters = [])
    event = $game_map.events[index]
    event.path.list.push RPG::MoveCommand.new(code, parameters)
  end
  #--------------------------------------------------------------------------
  # * Add Paths Event
  #     index          : event index / event ID number
  #     trg_x          : target x-coordinate
  #     trg_y          : target y-coordinate
  #     option_close   : if blocked location is approachable
  #--------------------------------------------------------------------------
  def add_paths_event(index, trg_x, trg_y, option_close = false)
    event = $game_map.events[index]
    key = event.points.last
    paths = $game_map.find_short_paths(key[0], key[1], trg_x, trg_y, option_close, event)
    if paths == nil
      print "Target " + trg_x.to_s + ","+ trg_y.to_s + " Is Unreachable for Event " + index.to_s 
      return
    end
    key = [trg_x, trg_y]
    event.points.push(key)
    for path in paths
      event.path.list.push RPG::MoveCommand.new(4) if path == 2
      event.path.list.push RPG::MoveCommand.new(2) if path == 4
      event.path.list.push RPG::MoveCommand.new(3) if path == 6
      event.path.list.push RPG::MoveCommand.new(1) if path == 8
      # Facing direction
      event.path.list.push RPG::MoveCommand.new(16) if path == 16
      event.path.list.push RPG::MoveCommand.new(17) if path == 17
      event.path.list.push RPG::MoveCommand.new(18) if path == 18
      event.path.list.push RPG::MoveCommand.new(19) if path == 19
    end
  end
  #--------------------------------------------------------------------------
  # * Start Event
  #     index         : event index / event ID number
  #--------------------------------------------------------------------------
  def start_event(index)
    event = $game_map.events[index]
    event.path.list.push RPG::MoveCommand.new(0)
    event.force_move_route(event.path)
  end
  #--------------------------------------------------------------------------
  # * Setup Player
  #     repeat         : if path/movement is repeated
  #     skippable      : if any blocked step can be skipped
  #--------------------------------------------------------------------------
  def setup_player(repeat = false, skippable = false)
    @player_points = []
    @player_path = RPG::MoveRoute.new
    @player_path.repeat = repeat
    @player_path.skippable = skippable
    @player_path.list.clear
    key = [$game_player.x, $game_player.y]
    @player_points.push(key)
  end
  #--------------------------------------------------------------------------
  # * Add Command Player
  #     code           : movement code 
  #     parameters     : movement parameters  
  #--------------------------------------------------------------------------
  def add_command_player(code, parameters = [])
    @player_path.list.push RPG::MoveCommand.new(code, parameters)
  end
  #--------------------------------------------------------------------------
  # * Add Paths Player
  #     trg_x          : target x-coordinate
  #     trg_y          : target y-coordinate
  #     option_close   : if blocked location is approachable
  #--------------------------------------------------------------------------
  def add_paths_player(trg_x, trg_y, option_close = false)
    key = @player_points.last
    paths = $game_map.find_short_paths(key[0], key[1], trg_x, trg_y, option_close, $game_player, [$game_player])
    if paths == nil
      print "Target " + trg_x.to_s + "," + trg_y.to_s + " Is Unreachable for Player"
      return
    end
    key = [trg_x, trg_y]
    @player_points.push(key)
    for path in paths
      @player_path.list.push RPG::MoveCommand.new(4) if path == 2
      @player_path.list.push RPG::MoveCommand.new(2) if path == 4
      @player_path.list.push RPG::MoveCommand.new(3) if path == 6
      @player_path.list.push RPG::MoveCommand.new(1) if path == 8
      # Facing direction
      @player_path.list.push RPG::MoveCommand.new(16) if path == 16
      @player_path.list.push RPG::MoveCommand.new(17) if path == 17
      @player_path.list.push RPG::MoveCommand.new(18) if path == 18
      @player_path.list.push RPG::MoveCommand.new(19) if path == 19      
    end
  end
  #--------------------------------------------------------------------------
  # * Start Player
  #--------------------------------------------------------------------------
  def start_player
    @player_path.list.push RPG::MoveCommand.new(0)
    $game_player.force_move_route(@player_path)
  end
end



#==============================================================================
# ** Game_Character
#------------------------------------------------------------------------------
#  This class deals with characters. It's used as a superclass for the
#  Game_Player and Game_Event classes.
#==============================================================================

class Game_Character
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------  
  attr_accessor :move_route
  attr_accessor :move_route_index
  #--------------------------------------------------------------------------
  # * Pathfinding Passable?
  #     x              : x-coordinate
  #     y              : y-coordinat
  #     d              : direction
  #     ignore_events  : events to ignore
  #     check_player   : player event to check (if event is being moved)
  #--------------------------------------------------------------------------
  def pf_passable?(x, y, d, ignore_events = [self], check_player = (self != $game_player))
    ignore_event = [ignore_event] if not ignore_event.is_a?(Array)
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    unless $game_map.valid?(new_x, new_y)
      return false
    end
    if @through
      return true
    end
    unless $game_map.pf_passable?(x, y, d, ignore_events, check_player)
      return false
    end
    unless $game_map.pf_passable?(new_x, new_y, 10 - d, ignore_events, check_player)
      return false
    end
    for event in $game_map.events.values
      if event.x == new_x and event.y == new_y
        if not ignore_events.include?(event) and not event.through and not event == self
          if self != $game_player
            return false
          end
          if event.character_name != ""
            return false
          end
        end
      end
    end
    if $game_player.x == new_x and $game_player.y == new_y
      unless $game_player.through or ignore_events.include?($game_player) or not check_player
        if @character_name != ""
          return false
        end
      end
    end
    return true
  end
end



#==============================================================================
# ** Game_Event
#------------------------------------------------------------------------------
#  This class deals with events. It handles functions including event page 
#  switching via condition determinants, and running parallel process events.
#  It's used within the Game_Map class.
#==============================================================================

class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :path
  attr_accessor :points
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  alias pf_game_event_initialize initialize
  def initialize(map_id, event)
    @path = []
    @points = nil
    pf_game_event_initialize(map_id, event)
  end
end



#==============================================================================
# ** Game_Player
#------------------------------------------------------------------------------
#  This class handles the player. Its functions include event starting
#  determinants and map scrolling. Refer to "$game_player" for the one
#  instance of this class.
#==============================================================================

class Game_Player < Game_Character
  #--------------------------------------------------------------------------
  # * Pathfinding Passable?
  #     x              : x-coordinate
  #     y              : y-coordinat
  #     d              : direction
  #     ignore_events  : events to ignore
  #     check_player   : player event to check (if event is being moved)
  #--------------------------------------------------------------------------
  def pf_passable?(x, y, d, ignore_events = [self], check_player = false)
    passable?(x,y,d)
  end
end



#==============================================================================
# ** Game_Map
#------------------------------------------------------------------------------
#  This class handles the map. It includes scrolling and passable determining
#  functions. Refer to "$game_map" for the instance of this class.
#==============================================================================

class Game_Map
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :events
  #--------------------------------------------------------------------------
  # * Directional Constants
  #--------------------------------------------------------------------------
  UP    = 2
  LEFT  = 4
  RIGHT = 6
  DOWN  = 8
  #--------------------------------------------------------------------------
  # * Find Short Paths
  #     src_x          : starting / source x-coordinate
  #     srx_y          : starting / source y-coordinate
  #     trg_x          : target x-coordinate
  #     trg_y          : target y-coordinate
  #     option_close   : if blocked location is approachable
  #     passable_owner : event being moved
  #     ignore_events  : events to ignore
  #--------------------------------------------------------------------------
  def find_short_paths(src_x, src_y, trg_x, trg_y, option_close = false, passable_owner = self, ignore_events = [])
    # Obtain currently selected depth/limit
    depth = $path_finding.pf_depth
    # Initialize final targetted coordinates (F Target x & F Target y)
    ftrg_x, ftrg_y = trg_x, trg_y
    # Initialize last steppable coordinates (L Target x & L Target y)
    ltrg_x, ltrg_y = src_x, src_y
    # Only return for impassable if 'get closest to' isn't enabled
    unless option_close
      return [] if not (passable_owner.pf_passable?(trg_x, trg_y, UP,    ignore_events) or
                        passable_owner.pf_passable?(trg_x, trg_y, LEFT,  ignore_events) or
                        passable_owner.pf_passable?(trg_x, trg_y, RIGHT, ignore_events) or
                        passable_owner.pf_passable?(trg_x, trg_y, DOWN,  ignore_events))
    end
    # Paths will hold the succeeding paths.
    paths = []
    #  Path_map will hold what paths has already been visited, to prevent that
    #  we attempt to walk on the same tile twice.
    path_map = [src_x + src_y / 10000.0]
    trackers = []
    new_trackers = [[src_x, src_y, []]]
    # Unless option to 'get closest to' target option enabled    
    unless option_close
      depth.times {
        break if new_trackers.empty?
        trackers = new_trackers
        new_trackers = []
        for tracker in trackers
          if tracker[0] == trg_x and tracker[1] == trg_y
            paths.push tracker[2].compact
            next
          end
          path_map.push tracker[0] + tracker[1] / 10000.0
          if passable_owner.pf_passable?(tracker[0], tracker[1], DOWN, ignore_events, true) and
              not path_map.include? tracker[0] + (tracker[1] - 1) / 10000.0
            path_map.push tracker[0] + (tracker[1] - 1) / 10000.0
            new_trackers.push [tracker[0], tracker[1] - 1, [tracker[2], UP].flatten]
          end
          if passable_owner.pf_passable?(tracker[0], tracker[1], LEFT, ignore_events, true) and
              not path_map.include? tracker[0] - 1 + tracker[1] / 10000.0
            path_map.push tracker[0] - 1 + tracker[1] / 10000.0
            new_trackers.push [tracker[0] - 1, tracker[1], [tracker[2], LEFT].flatten]
          end
          if passable_owner.pf_passable?(tracker[0], tracker[1], RIGHT, ignore_events, true) and
              not path_map.include? tracker[0] + 1 + tracker[1] / 10000.0
            path_map.push tracker[0] + 1 + tracker[1] / 10000.0
            new_trackers.push [tracker[0] + 1, tracker[1], [tracker[2], RIGHT].flatten]
          end
          if passable_owner.pf_passable?(tracker[0], tracker[1], UP, ignore_events, true) and
              not path_map.include? tracker[0] + (tracker[1] + 1) / 10000.0
            path_map.push tracker[0] + (tracker[1] + 1) / 10000.0
            new_trackers.push [tracker[0], tracker[1] + 1, [tracker[2], DOWN].flatten]
          end
        end
        break if paths.size > 0
      }
    # Allow to 'get close to' if blocked
    else
      paths_distance = 10000 ** 2 * 2
      depth.times {
        trackers = new_trackers
        new_trackers = []
        for tracker in trackers   
          if tracker[0] == trg_x and tracker[1] == trg_y
            if paths_distance > 0
              paths_distance = 0
              paths.clear
              ftrg_x = tracker[0] 
              ftrg_y = tracker[1] 
            end
            paths.push tracker[2].compact
            next
          end
          distance = (tracker[0] - trg_x) ** 2 + (tracker[1] - trg_y) ** 2
          if distance <= paths_distance
            if distance < paths_distance
              paths.clear
              paths_distance = distance
              ltrg_x = tracker[0] 
              ltrg_y = tracker[1] 
            end
            paths.push tracker[2].compact
          end
          path_map.push tracker[0] + tracker[1] / 10000.0
          if passable_owner.pf_passable?(tracker[0], tracker[1], DOWN, ignore_events, true) and
              not path_map.include? tracker[0] + (tracker[1] - 1) / 10000.0
            path_map.push tracker[0] + (tracker[1] - 1) / 10000.0
            new_trackers.push [tracker[0], tracker[1] - 1, [tracker[2], UP].flatten]
          end
          if passable_owner.pf_passable?(tracker[0], tracker[1], LEFT, ignore_events, true) and
              not path_map.include? tracker[0] - 1 + tracker[1] / 10000.0
            path_map.push tracker[0] - 1 + tracker[1] / 10000.0
            new_trackers.push [tracker[0] - 1, tracker[1], [tracker[2], LEFT].flatten]
          end
          if passable_owner.pf_passable?(tracker[0], tracker[1], RIGHT, ignore_events, true) and
              not path_map.include? tracker[0] + 1 + tracker[1] / 10000.0
            path_map.push tracker[0] + 1 + tracker[1] / 10000.0
            new_trackers.push [tracker[0] + 1, tracker[1], [tracker[2], RIGHT].flatten]
          end
          if passable_owner.pf_passable?(tracker[0], tracker[1], UP, ignore_events, true) and
              not path_map.include? tracker[0] + (tracker[1] + 1) / 10000.0
            path_map.push tracker[0] + (tracker[1] + 1) / 10000.0
            new_trackers.push [tracker[0], tracker[1] + 1, [tracker[2], DOWN].flatten]
          end
        end
        break if distance == 0 and paths.size > 0
      }
    end
    # turn to event (if applicable)
    if option_close
      # Calculate facing
      facing = 0
      facing = 17 if (ftrg_x - ltrg_x) <= -1
      facing = 18 if (ftrg_x - ltrg_x) >=  1
      facing = 19 if (ftrg_y - ltrg_y) <= -1
      facing = 16 if (ftrg_y - ltrg_y) >=  1
      paths[0].push facing if facing != 0
    end
    route = paths[0]
    return route
  end
  #--------------------------------------------------------------------------
  # * Pathfinding Passable?
  #     x              : x-coordinate
  #     y              : y-coordinat
  #     d              : direction
  #     ignore_events  : events to ignore
  #     check_player   : player event to check (if event is being moved)
  #--------------------------------------------------------------------------
  def pf_passable?(x, y, d, ignore_events = [], check_player = false)
    ignore_events = [ignore_events].compact if not ignore_events.is_a?(Array)
    unless valid?(x, y)
      return false
    end
    bit = (1 << (d / 2 - 1)) & 0x0f
    checks = events.values
    checks.push $game_player if check_player
    for event in checks
      if event.tile_id >= 0 and not ignore_events.include?(event) and
          event.x == x and event.y == y and not event.through
        return false if event == $game_player and check_player
        if @passages[event.tile_id] & bit != 0
          return false
        elsif @passages[event.tile_id] & 0x0f == 0x0f
          return false
        elsif @priorities[event.tile_id] == 0
          return true
        end
      end
    end
    for i in [2, 1, 0]
      tile_id = data[x, y, i]
      if tile_id == nil
        return false
      elsif @passages[tile_id] & bit != 0
        return false
      elsif @passages[tile_id] & 0x0f == 0x0f
        return false
      elsif @priorities[tile_id] == 0
        return true
      end
    end
    return true
  end
end



#==============================================================================
# ** Scene_Title
#------------------------------------------------------------------------------
#  This class performs title screen processing.
#==============================================================================

class Scene_Title
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  alias pf_scene_title_update update
  def update
    #set the pathfinding class as a callable class
    $path_finding = Path_Finding.new
    pf_scene_title_update
  end
end
This little addon (to be placed above Pathfinding v2 & v2 beta) will allow you to enter recognizable lines in either the $path_finding.add_command_player or the $path_finding.add_command_event routines.

Like
Code:
$path_finding.add_command_player(PF_DOWN, PF_DOWN, PF_LEFT)

Code:
#==============================================================================
# ** Path Finding v2 beta (Constants Add-On)
#------------------------------------------------------------------------------
#
#  This isn't even a script.  It's a simple addon that creates constants to use
#  in the pathfinding system.   You can now type THESE  in place of the numeric
#  command codes when using either the $path_finding.add_command_player  or the
#  $path_finding.add_command_event  routines.   It should  be posted  above the
#  Pathfinding v2 system to take affect.
#
#==============================================================================

PF_DOWN           =  1  # Move down
PF_LEFT           =  2  # Move Up
PF_RIGHT          =  3  # Move Right
PF_UP             =  4  # Move Up
PF_DN_LEFT        =  5  # Move Lower Left
PF_DN_RIGHT       =  6  # Move Lower Right
PF_UP_LEFT        =  7  # Move Upper Left
PF_UP_RIGHT       =  8  # Move Upper Right
PF_RAND           =  9  # Move at Random
PF_TO_PLAYER      = 10  # Move to Player
PF_FR_PLAYER      = 11  # Move from Player
PF_FOREWARD       = 12  # Move 1-Step Foreward
PF_BACKWARD       = 13  # Move 1-Step Backward
PF_JUMP           = 14  # Jump *
PF_WAIT           = 15  # Set Wait Count *
PF_TURN_DOWN      = 16  # Turn Down
PF_TURN_LEFT      = 17  # Turn Left
PF_TURN_RIGHT     = 18  # Turn Right
PF_TURN_UP        = 19  # Turn Up
PF_TURN_90_RT     = 20  # Turn 90? Right
PF_TURN_90_LF     = 21  # Turn 90? Left
PF_TURN_180       = 22  # Turn 180?
PF_TURN_90_RAND   = 23  # Turn 90? Left or Right (Random)
PF_TURN_RAND      = 24  # Turn at Random
PF_TURN_TO_PLAYER = 25  # Turn to Player
PF_TURN_FR_PLAYER = 26  # Turn from Player

#  * These require additional parameters for use (x/y coordinates, time delay
#    or other values)

Instructions
You need to setup a movement event before you can add a path or commands this is done with the $path_finding.setup_event or $path_finding.setup_player command then you can add a command or a path this is done by $path_finding.add_command or $path_finding.add_paths (or appropriate for players movement) commands. Now you can add as many commands and paths as you want to event by adding more of these. This is called path linking. Then when you are ready to start the movement use $path_finding.start_event or $path_finding.start_player.

Now this can be done in 2 places in the events command window or in the custom movement of an event. If you do it in the movement window to start use this
return $path_finding.start_event(index) or the code will not work right.

As well I found out something interesting if you have a repeating movement event using this movement with a defined wait the wait will repeat everytime, but if you add a normal move event wait it will only operate once. This can be a good things to add this delay so not all the events start at once yet do not repeat that wait later.

Syntax
$path_finding.setup_event(index, repeat, skippable = false)[/FONT]
index = the index of the event
repeat = set the repeat flag to true and the define movement will repeat false it will not repeat..
skippable = set skippable flag to true and the event will move ever when blocked
NOTE : This is not wanted in must cases that is why its defaulted to false

$path_finding.add_command_event(index, code, parameters = [])[/FONT]
index = the index of the event
code = movement code
parameters = the needed parameters for that movement code

Note : the movement codes can be found in the Game_Character page 2 move_type_custom as well as there needed parameters

$path_finding.start_event(index)[/FONT]
index = the index of the event

$path_finding.add_paths_event(index, trg_x, trg_y)[/FONT]
index = the index of the event
trg_x = target x
trg_y = target y
$path_finding.setup_player(repeat, skippable = false)[/FONT]
repeat = set the repeat flag to true and the define movement will repeat false it will not repeat..
skippable = set skippable flag to true and the event will move ever when blocked
NOTE : This is not wanted in must cases that is why its defaulted to false

$path_finding.add_command_player(code, parameters = [])[/FONT]
code = movement code
parameters = the needed parameters for that movement code

Note : the movement codes can be found in the Game_Character page 2 move_type_custom as well as there needed parameters


$path_finding.start_player[/FONT]

$path_finding.add_paths_player(src_x, src_y, trg_x, trg_y)[/FONT]
src_x = source x
src_y = source y
trg_x = target x
trg_y = target y

Create a simple map event, and add a 'script call' into the the map event:
Code:
$path_finding.setup_player
$path_finding.add_paths_player(3,1)
$path_finding.start_player
If this event get's activated (probably by touch/action), then the player will move to tile 3/1 on the map.
Credits and Thanks
"Fuso made the main part of this script all I did was make it work. Fuso needs as much credit or more then I do for this script." - Near Fantastica


BONUS!
Version 1.0

Introduction
I somehow found an old 'abandoned' site that had this version... prior to any SDK edit! This is the original!?? And as a bonus, this script doesn't conflict with version 2!

Why do you ask? This system allows you to move to a map event's space and stop right at the event. In the version 2 system, attempting to move to a space occupied by a map event results in a 'Cannot move to...' prompt/flag. This one still moves to the spot. Good if you plan to make a mouse/pathfinding combo.

Script
Code:
#==============================================================================
#  â–  Path Finding
#==============================================================================
# Near Fantastica
# Version 1
# 29.11.05
#==============================================================================
# Lets the Player or Event draw a path from an desonation to the source. This
# method is very fast and because the pathfinding is imbedded into the Game
# Character the pathfinding can be interrupted or redrawn at any time. 
#==============================================================================
# Player :: $game_player.find_path(x,y)
# Event Script Call :: self.event.find_path(x,y)
# Event Movement Script Call :: self.find_path(x,y)
#==============================================================================

class Game_Character
  #--------------------------------------------------------------------------
  alias nf_pf_game_character_initialize initialize
  alias nf_pf_game_character_update update
  #--------------------------------------------------------------------------
  attr_accessor :map
  attr_accessor :runpath
  #--------------------------------------------------------------------------
  def initialize
    nf_pf_game_character_initialize
    @map = nil
    @runpath = false
  end
  #--------------------------------------------------------------------------
  def update
    run_path if @runpath == true
    nf_pf_game_character_update
  end
  #--------------------------------------------------------------------------
  def run_path
    return if moving?
    step = @map[@x,@y]
    if step == 1
      @map = nil
      @runpath = false
      return
    end
    dir = rand(2)
    case dir
    when 0
      move_right if @map[@x+1,@y] == step - 1 and step != 0
      move_down if @map[@x,@y+1] == step - 1 and step != 0
      move_left if @map[@x-1,@y] == step -1 and step != 0
      move_up if @map[@x,@y-1] == step - 1 and step != 0
    when 1
      move_up if @map[@x,@y-1] == step - 1 and step != 0
      move_left if @map[@x-1,@y] == step -1 and step != 0
      move_down if @map[@x,@y+1] == step - 1 and step != 0
      move_right if @map[@x+1,@y] == step - 1 and step != 0
    end
  end
  #--------------------------------------------------------------------------
  def find_path(x,y)
    sx, sy = @x, @y
    result = setup_map(sx,sy,x,y)
    @runpath = result[0]
    @map = result[1]
    @map[sx,sy] = result[2] if result[2] != nil
  end
  #--------------------------------------------------------------------------
  def clear_path
    @map = nil
    @runpath = false
  end
  #--------------------------------------------------------------------------
  def setup_map(sx,sy,ex,ey)
    map = Table.new($game_map.width, $game_map.height)
    map[ex,ey] = 1
    old_positions = []
    new_positions = []
    old_positions.push([ex, ey])
    depth = 2
    depth.upto(100){|step|
      loop do
        break if old_positions[0] == nil
        x,y = old_positions.shift
        return [true, map, step] if x == sx and y+1 == sy
        if $game_player.passable?(x, y, 2) and map[x,y + 1] == 0
          map[x,y + 1] = step
          new_positions.push([x,y + 1])
        end
        return [true, map, step] if x-1 == sx and y == sy
        if $game_player.passable?(x, y, 4) and map[x - 1,y] == 0
          map[x - 1,y] = step
          new_positions.push([x - 1,y])
        end
        return [true, map, step] if x+1 == sx and y == sy
        if $game_player.passable?(x, y, 6) and map[x + 1,y] == 0
          map[x + 1,y] = step
          new_positions.push([x + 1,y])
        end
        return [true, map, step] if x == sx and y-1 == sy
        if $game_player.passable?(x, y, 8) and map[x,y - 1] == 0
          map[x,y - 1] = step
          new_positions.push([x,y - 1])
        end
      end
      old_positions = new_positions
      new_positions = []
    }
    return [false, nil, nil]
  end
end
  
class Game_Map
  #--------------------------------------------------------------------------
  alias pf_game_map_setup setup
  #--------------------------------------------------------------------------
  def setup(map_id)
    pf_game_map_setup(map_id)
    $game_player.clear_path
  end
end
  
class Game_Player
  #--------------------------------------------------------------------------
  alias pf_game_player_update update
  #--------------------------------------------------------------------------
  def update
    $game_player.clear_path if Input.dir4 != 0
    pf_game_player_update
  end
end
  
class Interpreter
  #--------------------------------------------------------------------------
  def event
    return $game_map.events[@event_id]
  end
end

Instructions
Fairly simple.
  1. You use $game_player.find_path(x,y) to move the player to a spot on the map.
  2. Or you can use self.event.find_path(x,y) to move an event to a spot on the map.
  3. Finally, you can use self.find_path(x,y) for a movement script call to do the same.
 
BUMP!

I added a small 'samplet' of code to try in a map event for the version 2 system. I also found that the instructions I garnered were HACKED!!!!! It's corrected!

A BONUS!

Found now is the original Version 1 script... prior to the SDK changes!! Yay! This system is easy to use, though it doesn't have the feature of 'planned routes' as version 2 does. But it doesn't interfere or conflict with version 2 so both can work together!
 
Eh?
DerVVulfman in the spoiler called 'Try This...'":29pp36xy said:
Create a simple map event, and add a 'script call' into the the map event:
Code:
$path_finding.setup_player
$path_finding.add_paths_player(3,1)
$path_finding.start_player
If this event get's activated (probably by touch/action), then the player will move to tile 3/1 on the map.

Simply put, make a regular map event and make it an 'Action' trigger so you can move to it and hit [Enter/Select] to use it. And then add a 'script call' to the list with those three simple lines of code'.

When you run your project, go to the event (whatever it is) and trigger it. It will do the following:
  • The system begins to 'setup the player'
  • Tells the system to find a path to coordinate 3/1 on the map.
  • Gets it going...
Pretty much it.


For version 1... it's much simpler. Just use this one line of code in a script call:
  • $game_player.find_path(3,1)
And this gets the player ready, finds a path for him to 3/1 and gets him moving... all in one shot.

However as I didn't create the script, I cannot offer support.
Did I say that??? Well, I've been messing with it for someone's... eh... *cough* Now, that's a secret. ;)
 

Kain

Member

DerVVulfman;303447 said:
Similar coding for events... Just gotta use the 'event' statements.

Funny since I ne'er used this until last week... :D

it doesent work, the Maker show me a Argument Error with following Code:

Code:
$path_finding.setup_event
$path_finding.add_paths_event(3,1)
$path_finding.start_event
 
EDIT: I found that the $path_finding.start_event statement did not work at all. Don't misunderstand... you didn't tell it 'which' event to setup, add to, or start... Just that the actual 'start_event' routine for events didn't activate the loaded move route.

So, I posted right below version 2, a version 2 alpha that actually triggers the paths loaded. :thumb:


Code:
$path_finding.setup_event(3)
$path_finding.add_paths_event(3, 3, 1)
$path_finding.start_event(3)

This will move event #3 to location 3,1 on your map

* - * - * - * - *

The one for Pathfinding version 1 works fine with triggered event script calls:

Code:
self.event.find_path(4,26)
would move the triggered event to position 4,26...

...or...
Code:
$game_map.events[11].find_path(4,26)
Would move event #11 to position 4/26, even if triggered by some other event.
 
BUMP... kinda

Thanks to fuso (...really...), I was informed that there was an option built into some of the routines that allowed pathfinding v2 to approach spaces occupied on the map.
Main topic":41lz9vjg said:
In the version 2 system, attempting to move to a space occupied by a map event results in a 'Cannot move to...' prompt/flag.
This switch (option_close) was not available in the statements that you would use to create a pathfinding system. I think it was an oversight when it was initially released.

The version 2 alpha I posted is now a version 2 beta which includes this fix, a new 'depth' setting for the pathfinding system, instructions in the script...

And finally (yes... finally...) a demo. ;)
 

fuso

Member

Excellent that someone takes on to clean it up a bit more. I like your comments.

It is important to note that when no path can be found, it will search the entire max_depth. The (my) default of 200 is rather unrealistic, and the same goes for 100. To get a better estimate, try pathfinding on a huge empty map til RMXP returns that no path can be found instead of timing out and subtracting two from that (cause some PCs can be a lot slower). A total count would be more appropriate than depth since depth does not cost that much in say narrow passages.

option_close does not take considerable extra work for this naive path finding algorithm since it would search the same area if no path can be found and it will search the same area if a path can be found, save the initial checks.

The list of setup functions listed now may seem daunting to some scripters though.

You may want to define constants for these
# 1) Move down 10) Move toward player 19) Turn up
# 2) Move left 11) Move away from player 20) Turn 90? right
# 3) Move right 12) 1 step forward 21) Turn 90? left
# 4) Move up 13) 1 step backward 22) Turn 180?
# 5) Move lower left 14) Jump* 23) Turn 90? right or left
# 6) Move lower right 15) Set wait count* 24) Turn at Random
# 7) Move upper left 16) Turn down 25) Turn toward player
# 8) Move upper right 17) Turn left 26) Turn away from player
# 9) Move at random 18) Turn right

Regarding the facing, is the goal to face the target location or to face one of the tiles adjacent to the nearest location? If it is the target location, you want to see if the dislocation is the greatest for x or y. It could for instance be an x-dislocation of 4 and an y-dislocation of negative 1. Facing up would be bit odd then.
 
AT WORK[/FONT]

Optional use of CONSTANTS for the move values... good thing to consider. I'll add em in soon, though the actual numeric values may be preferable from MapEvent script calls (space lacking in MAPEVENT's tiny window ;) ).

The FACING feature is intended to make it face the target location, something that would be useful in a mouse's point-n-click interface. Previously blocked locations didn't allow it to turn and face something as simple as a treasure chest.

But now that I think about it, I may have merely made it turn and face the next 'intended' space. I think it works better that way, eh? ^_^

List of setup commands... daunting? I guess, though it really boils down to two sets of: setup, find path, and go... one set for actors and one set for the events. The version 1 system has all three built into a single find_path command. But the setup command does have things like skipping and repeat features too. ;)
 

fuso

Member

You do not have to reply right now.

Optional use of CONSTANTS for the move values... good thing to consider. I'll add em in soon, though the actual numeric values may be preferable from MapEvent script calls (space lacking in MAPEVENT's tiny window ).
You do not need that many characters, for instance
MVUP, MVDW, MVLF, ...
albeit i'd prefer MCC_UP, MCC_DOWN, et.c.
I think it is more durable, both cause people will make less mistakes, understand theirs and others code better, it will be more flexible, et.c.

The FACING feature is intended to make it face the target location, something that would be useful in a mouse's point-n-click interface. Previously blocked locations didn't allow it to turn and face something as simple as a treasure chest.

But now that I think about it, I may have merely made it turn and face the next 'intended' space. I think it works better that way, eh?
Sure, it's an improvement. Currently, it always looks at the target, because ftrg is initialized to trg and only updated when the target is reached, in which case "tracker" is trg again.
If you wanted it to check the "next intended" location, you should update ftrg to be one of the adjacent tiles of ltrg closest to the actual target. This can be done after the path finding.

List of setup commands... daunting? I guess, though it really boils down to two sets of: setup, find path, and go... one set for actors and one set for the events. The version 1 system has all three built into a single find_path command. But the setup command does have things like skipping and repeat features too.
I was not talking about myself. I thought you may want to augment your already much helpful introduction and description with small hints that all an eventer or initiate scripter really needs to do is x or y. The complexity of the initial description, overview, commentaries and the bottom instructions seems to vary slightly.
 
Heh... I just threw together a li'l mini-addon that creates constants. It doesn't even need to be added into the script as it merely makes constants. I named 'em with a PF_ prefix to differentiate them as PathFinding constants. I put it under the v2 beta spoiler.

*For those reading this, just put it above PathFinding v2 to have 'em take effect. Should work for the original as well as v2 beta*

I know I go into a bit more detail than some... but moreso in 'technical' stuff it seems. I reaaaalllyyyy gotta include examples. Good thing I have the demo, eh?
 

Lei

Member

Could this be implimented to a sort of catepiller script?

I mean, I hate the fact that catepiller party systems walk in an exact line... Since when have you ever seen that happen in real life?

I guess that the event could move to the players XY with some variation depending on which direction the player was facing... Is this possible with the above scripts?
 
To felix1001010:
That would require additional scripting.

To Lei:
Yes... it could be but...

Near Fantastica made a non-linear follow system called 'Squad Movement' that may cater to your tastes. You can even tell 'em to 'STAY' until called. Of course, it's available here. :D
 
To move the 'player' to go to location 3,15 on the map...
Code:
$path_finding.setup_player
$path_finding.add_paths_player(3,15)
$path_finding.start_player

To move an 'event'... say event #4 (they all have ID numbers ;) )
Code:
$path_finding.setup_event(4, true)
$path_finding.add_paths_event(4, 3, 15, true)
$path_finding.start_event(4)

In either case, it is in three steps:
1 - Prep the event/player
2 - Set the course
3 - Go!

Please remember the 'option_close' value.  If it is set to 'true', then it will allow you to move to the 'closest' tile if the actual destination is blocked.  And if it is set to 'false', it will deliver a popup warning that the destination is impossible.
 
To move an 'event'... say event #4 (they all have ID numbers Wink )
Code:
$path_finding.setup_event(4, true)
$path_finding.add_paths_event(4, 3, 15, true)
$path_finding.start_event(4)

this doesnt work.
And this seems to move the event to place in the map, what i want is the event A move to the event B (who is in a random position)
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top