DerVVulfman
Sponsor
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
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
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
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
Instructions
Fairly simple.
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
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
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
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:
If this event get's activated (probably by touch/action), then the player will move to tile 3/1 on the map.
Code:
$path_finding.setup_player
$path_finding.add_paths_player(3,1)
$path_finding.start_player
"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.
- You use $game_player.find_path(x,y) to move the player to a spot on the map.
- Or you can use self.event.find_path(x,y) to move an event to a spot on the map.
- Finally, you can use self.find_path(x,y) for a movement script call to do the same.