Change formation followers

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses
Hello, I've been looking but I have not found any script to do this which I will explain.

I need a script to change the formation of followers. Instead they follow you in a straight line as here:
 



They will follow a different formation:



Being able to change the position in which they are located:







And if you have more than 4 followers:





Is there this script? If not, can occur to you how I could do?

Thank you. :)
 

Andar

Veteran
Veteran
Joined
Mar 5, 2013
Messages
31,365
Reaction score
7,674
First Language
German
Primarily Uses
RMMV
More than 4 followers are possible if you increase the number of battlers for the player, because that is also the number of displayed followers (only reserve members are not displayed).

Other formations are a bigger problem than you think however - what should happen if the path on the map is too small for three lines of actors wandering?

That is the real reason behind the caterpillar line - the only place guaranteed to be passable is the place that the player just left - to check the tiles above and below the player path for passability, and change the line if those parts of the map are blocked by walls, is a lot more complex and might create a lot of lag for that processing.
 

dbchest

Beast Master
Veteran
Joined
Oct 1, 2013
Messages
434
Reaction score
306
First Language
English
Primarily Uses
RMMV
Andar read my mind.

it is not likely this script will see development because it's use is limited. to incorporate the feature into the game would force the developer to follow a set of rules when developing maps, events, etc.

i suppose you could include some handlers for itinerary processing and passability, but that would be an in-depth process.
 

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses
The main problem that I assumed was a small space.

In that case, the followers would be located in a straight line and back into their position when they can.

But if this will be a heavy workload for the processor, I guess it can not be done.
 

dbchest

Beast Master
Veteran
Joined
Oct 1, 2013
Messages
434
Reaction score
306
First Language
English
Primarily Uses
RMMV
it's not to say it can't be done, but you may want to consider commissioning someone for this. else, you might get lucky, who knows!?
 

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
40,098
Reaction score
13,704
First Language
English
Primarily Uses
RMMV
$game_player.direction


$game_player.followers[n].direction


From within Game_Character (if you're doing a move route, for example), it's just @direction
 
Last edited by a moderator:

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses
It's useful for cut-scenes.
The idea is that they will always follow with a custom formation, and if they encounter an obstacle, that character is placed behind you and return to his position when he can.

Perhaps get this to start with: http://www.rpgmakervxace.net/topic/1919-ve-followers-control/

I could help write this script if anyone can tell me how on earth you get the player's direction from within Game_Character, I seem to be struggling with that little detail.
Hey, thank you very much, if you get something or need help let me know. :)
 

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A
The idea is that they will always follow with a custom formation, and if they encounter an obstacle, that character is placed behind you and return to his position when he can.
I can do better than that. It's just a small modification to a pathfinder I'm using, the only issue is I don't seem to be able to get the player's direction which seems odd. I must be missing something...

I'll figure it out in the next couple of days, I'm sure.
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
40,098
Reaction score
13,704
First Language
English
Primarily Uses
RMMV
I did just give you that information, right after you asked for it ;)
 

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A
I did just give you that information, right after you asked for it ;)
Oh, I didn't spot that :) I found out for myself anyway.

Ok, so Vigun, after several hours of work (mostly bug fixing) I have completed your script for you. I hope it's satisfactory and doesn't lag for you. Let me know how well it works, if it behaves strangely at all, I might be able to fix that.

Get this script first: http://Victor Engine – Basic Module.

Then add this below it: 

#===============================================================================# Pathfinding & Event formations# By Jet10985(Jet) & Venima#===============================================================================# This script will allow you to use a pathfinder to move players or events.# Modification: This script will also allow you to use a pathfinder which # incorporates formation handling.# This script has: 2 customization options.## Modifications:# Pathfinder:# Goal location may now be inpassable, pathfinder will still reach it.# Pathfinder still works "as intended" when the move route is set to repeat.# Added parameter: distance (explained below).# Added parameter: jump (set to true if the moves should be jumps instead of# walking).# Added parameter: commonEvent (provide the common event id for the pathfinder# to run the event before each move (useful for adding sound or effects to # movements)# Added parameters: # catchup (provide a value to indicate how far from the target the event # should be before it speeds up its movement)# catchupSpeed (provide a value for the speed when catching up)# normalSpeed (provide a value for the speed after its caught up)# Note: Pathfinder is a bit more processor heavy when used with a repeating # move route (it was useless before, so this is only a benefit)# Formations:# Added find_formation_path function# Added turn_with_player function##===============================================================================# Overwritten Methods:# None#-------------------------------------------------------------------------------# Aliased methods:# None#================================================================================begin=============================================================================== Instructions:=============================================================================== Standard pathfinder:-------------------------------------------------------------------------------To move a player or event, use this in a move route's "Script..." command:find_path(x, y, distance = 0, jump = false, commonEvent = 0, catchup = 0, catchupSpeed = 5, normalSpeed = 4)x is the target xy is the targey ydistance is set to 0 by default and can be omitted to keep the default value.While x and y represent the target location, the event will only be moved up to the specified distance from the target. This makes it easier to have an event follow the player, without getting in the player's way. This could be used as an alternative to following, except it works on any events, not just party members.jump is set to false by default and can be omitted. Jump specifies that instead of the event "moving" to the target, the event will make small "jumps" to the target. If you specify jump, you cannot omit any previous parameters.commonEvent is set to 0 by default and can be omitted. This specifies the id of a common event that you want executed before each move step. Currentlythis only applies to repeating paths. When set to 0, no common event is called.If you specify commonEvent you cannot omit any previous parameters.catchup is set to 0 by default and can be omitted. Catchup specifies that ifthe event is equal to or past the catchup distance, they will move faster to "catch up". Their speed becomes the catchUp speed. Once caught up, they will return to the normalSpeed. If you specify catchup you cannot omit any previous parameters.catchupSpeed is set to 5 by default and can be omitted. It is used when catchup is specified to a value above 0. (see catchup for details). If you specify catchupSpeed you cannot omit any previous parameters.normalSpeed is set to 5 by default and can be omitted. It is used when catchup is specified to a value above 0. (see catchup for details). If you specify normalSpeed you cannot omit any previous parameters.Running the script outside of a move route (as a standalone script call)has two extra parameters after x and y called "ev" and "wait" but has no commonEvent or catcup parameters.find_path(x, y, ev = 0, wait = false, distance = 0, jump = false)ev is set to 0 by default and can be omitted like so: find_path(9, 4).Ev represents which character is to be moved. -1 is the player, 0 is thecalling event, and anything above is an event on the map whose ID is the ev.wait is set to false by default and can be omitted like so: find_path(9, 4) or find_path(9, 4, -1)find_path(x, y) or find_path(x, y, ev)wait specifies if the player will have to wait for the move route to finishto start moving again.------------------------------------------------------------------------------- Examples:Example of following the player at a distance:In event's custom move route or specified move route (on repeat): find_path($game_player.x, $game_player.y, 3) Example of an event following an event with id 2 and catching up: find_path($game_events[2].x, $game_events[2].y, 0, false, 0, 3)=============================================================================== Formation handling:-------------------------------------------------------------------------------To move an event using a formation use this in a move route:find_formation_path(followId, shiftX, shiftY, catchup = FORM_CATCHUP_DIST, catchupSpeed = 5, normalSpeed = 4) followId is the character that this event is in formation with. -1 = player,0 = current event (although this is pointless) and above 0 is the event id.shiftX is the relational x position from the followId character WHEN that character faces "down". If you enter -1, this event will move to the left if its facing down, or right if its facing up.shiftY is the relational y position from the followId character WHEN thatcharacter faces "down". If you enter -1, this event will move above if its facing down, or below if it's facing up.catchup's default value is specified by the parameter FORM_CATCHUP_DIST andcan be omitted. This specifies how far behind this event can get before it speeds up to catch up.catchupSpeed's default value is 5 and can be omitted. This specifies how fast this event will move when it's "catching up". If you specify catchupSpeed, you cannot omit any previous parameters.normalSpeed's default value is 4 and can be omitted. This specifies how fast this event will move when it isn't "catching up". If you specify normalSpeed, you cannot omit any previous parameters.You also have another command for formations:Entering "turn_with_leader" as a separate script after find_formation_pathwill cause the event to turn the same way the player is turned after arriving at their formation position.Entering "turn_with_leader(1)" will turn the same way as event with id 1.Turn_with_leader also has a second optional parameter. Entering "left" or -1will turn this event left of the leader's direction, entering "right" or 1will turn this event right of the leader's direction, and entering "back" or 2 will turn this event opposite of the leader's direction. If you specify this parameter, you cannot omit the previous one. ------------------------------------------------------------------------------- Examples:Example of 2 events acting similar to followers behind the player:In a repeating move-route for Event 01:find_formation_path(-1,0,-1)In a repeating move_route for Event 02:find_formation_path(1,0,-1)Example of an event covering the player's back 2 spaces away:In a repeating move-route:find_formation_path(-1,0,-2)turn_with_leader(-1,"back")Example of an event with a formation determined by in-game variables:In a repeating move-route:find_formation_path(-1, $game_variables[1], $game_variables[2])=end#===============================================================================# Customisation options below:#===============================================================================module Venima module Formations # FORM_CATCHUP_DIST = 3 endendmodule Jet module Pathfinder # While mainly for coders, you may change this value to allow the # pathfinder more time to find a path. # Note from Venima, you probably don't want to change this value too much MAXIMUM_ITERATIONS = 500 endend#===============================================================================# Customisation end#===============================================================================class Node include Comparable attr_accessor :point, :parent, :cost, :cost_estimated def initialize(point) @point = point @cost = 0 @cost_estimated = 0 @on_path = false @parent = nil end def mark_path @on_path = true @parent.mark_path if @parent end def total_cost cost + cost_estimated end def <=>(other) total_cost <=> other.total_cost end def ==(other) point == other.point endendclass Point attr_accessor :x, :y def initialize(x, y) @x, @y = x, y end def ==(other) return false unless Point === other @x == other.x && @y == other.y end def distance(other) (@x - other.x).abs + (@y - other.y).abs end def relative(xr, yr) Point.new(x + xr, y + yr) endendclass Game_Map def each_neighbor(node, char = $game_player) x = node.point.x y = node.point.y nodes = [] 4.times {|i| i += 1 new_x = round_x_with_direction(x, i * 2) new_y = round_y_with_direction(y, i * 2) next unless char.passable?(x, y, i * 2) #removed line below (technically, if your goal is an inpassable block, # e.g. an event, you can still reach it) #next unless char.passable?(new_x, new_y, 10 - i * 2) nodes.push(Node.new(Point.new(new_x, new_y))) } nodes end def find_path(tx, ty, sx, sy, dist, jump, char = $game_player) start = Node.new(Point.new(sx, sy)) goal = Node.new(Point.new(tx, ty)) return [] if start == goal or (dist > 0 and start.point.distance(goal.point) <= dist) return [] if ![2, 4, 6, 8].any? {|i| char.passable?(tx, ty, i) } open_set = [start] closed_set = [] path = [] iterations = 0 loop do return [] if iterations == Jet::pathfinder::MAXIMUM_ITERATIONS iterations += 1 current = open_set.min return [] unless current each_neighbor(current, char).each {|node| if node == goal or (dist > 0 and node.point.distance(goal.point) <= dist) node.parent = current node.mark_path return recreate_path(node, jump) end next if closed_set.include?(node) cost = current.cost + 1 if open_set.include?(node) if cost < node.cost node.parent = current node.cost = cost end else open_set << node node.parent = current node.cost = cost node.cost_estimated = node.point.distance(goal.point) end } closed_set << open_set.delete(current) end end def recreate_path(node, jump) path = [] hash = {[1, 0] => 6, [-1, 0] => 4, [0, 1] => 2, [0, -1] => 8} until node.nil? pos = node.point node = node.parent next if node.nil? ar = [pos.x <=> node.point.x, pos.y <=> node.point.y] if jump path.push(RPG::MoveCommand.new(14,ar)) else path.push(RPG::MoveCommand.new(hash[ar] / 2)) end end return path endendclass Game_Character #modified function (added handling for repeated move route (recalculates path # each step so it doesn't just loop it's old path route and will revalidate # if x or y changes, will follow variable value if x and y are set to it) def find_path(x, y, dist = 0, jump = false, commonEvent = 0, catchup = 0, catchupSpeed = 5, normalSpeed = 4) path = $game_map.find_path(x, y, self.x, self.y, dist, jump).reverse if !@move_route.repeat @move_route.list.delete_at(@move_route_index) @move_route.list.insert(@move_route_index, *path) @move_route_index -= 1 elsif path.length > 0 if commonEvent > 0 $game_temp.reserve_common_event(commonEvent) end if catchup > 0 if @move_speed < catchupSpeed && path.length >= catchup process_move_command(RPG::MoveCommand.new(29,[catchupSpeed])) elsif @move_speed >= catchupSpeed && path.length < 2 process_move_command(RPG::MoveCommand.new(29,[normalSpeed])) end end process_move_command(path[0]) @move_route_index -= 1 end return path.length end def get_character(i) if i == -1 return $game_player end if i == 0 return $game_map.events[@event_id] end if i > 0 return $game_map.events end end def find_formation_path(followId, shiftX, shiftY, catchup = Venima::Formations::FORM_CATCHUP_DIST, catchupSpeed = 5, normalSpeed = 4) x = shift_follow_x(followId, shiftX, shiftY) y = shift_follow_y(followId, shiftX, shiftY) if find_path(x,y,0,false,0,catchup,catchupSpeed,normalSpeed) == 0 char = get_character(followId) find_path(char.x,char.y,3,false,0,catchup,catchupSpeed,normalSpeed) end end def shift_follow_x(followId, shiftX, shiftY) char = get_character(followId) case char.direction when 2 return char.x + shiftX when 4 return char.x - shiftY when 6 return char.x + shiftY when 8 return char.x - shiftX end return char.x end def shift_follow_y(followId, shiftX, shiftY) char = get_character(followId) case char.direction when 2 return char.y + shiftY when 4 return char.y - shiftX when 6 return char.y + shiftX when 8 return char.y - shiftY end return char.y end def turn_with_leader(eventId = -1, dirmod = "") dir = get_character(eventId).direction mod = 0 if dirmod == "left" || dirmod == -1 case dir when 2 set_direction(4) when 4 set_direction(2) when 6 set_direction(8) when 8 set_direction(6) end elsif dirmod == "right" || dirmod == 1 case dir when 2 set_direction(6) when 4 set_direction(8) when 6 set_direction(2) when 8 set_direction(4) end elsif dirmod == "back" || dirmod == 2 case dir when 2 set_direction(8) when 4 set_direction(6) when 6 set_direction(4) when 8 set_direction(2) end else set_direction(dir) end endendclass Game_Interpreter #modified line below (added distance parameter) def find_path(x, y, ev = 0, wait = false, dist = 0, jump = false) char = get_character(ev) #modified line below (added distance parameter) path = $game_map.find_path(x, y, char.x, char.y, dist, jump) path.reverse! path.push(RPG::MoveCommand.new(0)) route = RPG::MoveRoute.new route.list = path route.wait = wait route.skippable = true route.repeat = false char.force_move_route(route) endend 

Follow the instructions of VE's script, get the comment and move route set up.

Then check out the instructions and examples of this one (under Formation handling). I'm gonna leave this here for feedback, if it works well I may post it as a completed script. If you're confused about what to do, let me know.
 
Last edited by a moderator:

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses
I feel stupid, but I can not make it work. Can you make a demo or just put screenshots of how to use it?

Thank you very much for do the script. :)

On the other hand, I think you should open a post with this script, so you'll get more feedback for fixing bugs.
 

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A
Upon testing myself it has a few bugs which I'm now fixing, but apart from that it's working great :) I'll post a demo with the modified scripts once the bugs are fixed.

Edit: I have attached a demo with the fixed code.

You must copy all 3 script files under Materials in the same order as in the demo.

FormationDemo.zip
 

Attachments

Last edited by a moderator:

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses
It is an amazing script. Well, I encountered an error and a detail that will be easy to modify.

I start with this detail. When you're looking right and then change to the left, the followers you have on the right and left are exchanged.





This makes it more difficult for them to get into position, so if you walk very fast, are left behind. The same happens when you look up and down:
 





Now the bug, this happened to me, the character with pathfinding and companions have been trapped there, trying to find a route and down the fps to 0 and the game freezes indefinitely. One solution to this could be change the priorty of followers to above or below characters, if it detects such collision can not find route.
 



Finally , that you mention :
"Note I read that reinstalling May fix a bug With This command , though I have not tested it , I think it 's a bug with the Follower Script. "

It seems that happens to a person in the comments of Victor blog.

http://victorscripts.wordpress.com/rpg-maker-vx-ace/utility-scripts/followers-control/

And Victor tells it to use the Gather Follower of the RPG Maker and not the script. But as a solution, would not it be better to use the script to put them in a straight line directly?

Excellent script, seriously, you did a great job. :) Thank you very much.
 
Last edited by a moderator:

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A
There's a reason why they swap places. It's relational formations, so someone who starts off to the right of the player, remains at the right of the player. But I see what you're saying, it might be better not to do that.

Originally I had coded that they would catch up with the player if they fell too far behind (that code is still active), but it seems I can't control follower speed. This is down to the follower script or RGSS3, not me. I may look into this at some point though.

I thought I fixed the low fps bug. It's a dilemma really, I can decrease the max iterations for formations which would cause the pathfinder to give up early to improve fps, but then the pathfinder gives up early, perhaps too early.

Here's an updated demo with your suggested fixes, it should perform better:

FormationDemo.zip

Or just the updated script:

Code:
#===============================================================================# Pathfinding & Event formations# By Jet10985(Jet) & Venima#===============================================================================# This script will allow you to use a pathfinder to move players or events.# Modification: This script will also allow you to use a pathfinder which # incorporates formation handling.# This script has: 2 customization options.## Modifications:# Pathfinder:# Goal location may now be inpassable, pathfinder will still reach it.# Pathfinder still works "as intended" when the move route is set to repeat.# Added parameter: distance (explained below).# Added parameter: jump (set to true if the moves should be jumps instead of# walking).# Added parameter: commonEvent (provide the common event id for the pathfinder# to run the event before each move (useful for adding sound or effects to # movements)# Added parameters: # catchup (provide a value to indicate how far from the target the event #   should be before it speeds up its movement)# catchupSpeed (provide a value for the speed when catching up)# normalSpeed (provide a value for the speed after its caught up)# Note: Pathfinder is a bit more processor heavy when used with a repeating # move route (it was useless before, so this is only a benefit)# Formations:# Added find_formation_path function# Added turn_with_player function##===============================================================================# Overwritten Methods:# None#-------------------------------------------------------------------------------# Aliased methods:# None#================================================================================begin=============================================================================== Instructions:=============================================================================== Standard pathfinder:-------------------------------------------------------------------------------To move a player or event, use this in a move route's "Script..." command:find_path(x, y, distance = 0, jump = false, commonEvent = 0, catchup = 0,       catchupSpeed = 5, normalSpeed = 4)x is the target xy is the targey ydistance is set to 0 by default and can be omitted to keep the default value.While x and y represent the target location, the event will only be moved up to the specified distance from the target. This makes it easier to have an event follow the player, without getting in the player's way. This could be used as an alternative to following, except it works on any events, not just party members.jump is set to false by default and can be omitted. Jump specifies that instead of the event "moving" to the target, the event will make small "jumps" to the target. If you specify jump, you cannot omit any previous parameters.commonEvent is set to 0 by default and can be omitted. This specifies the id of a common event that you want executed before each move step. Currentlythis only applies to repeating paths. When set to 0, no common event is called.If you specify commonEvent you cannot omit any previous parameters.catchup is set to 0 by default and can be omitted. Catchup specifies that ifthe event is equal to or past the catchup distance, they will move faster to "catch up". Their speed becomes the catchUp speed. Once caught up, they will return to the normalSpeed. If you specify catchup you cannot omit any previous parameters.catchupSpeed is set to 5 by default and can be omitted. It is used when catchup is specified to a value above 0. (see catchup for details). If you specify catchupSpeed you cannot omit any previous parameters.normalSpeed is set to 5 by default and can be omitted. It is used when catchup is specified to a value above 0. (see catchup for details). If you specify normalSpeed you cannot omit any previous parameters.Running the script outside of a move route (as a standalone script call)has two extra parameters after x and y called "ev" and "wait" but has no commonEvent or catcup parameters.find_path(x, y, ev = 0, wait = false, distance = 0, jump = false)ev is set to 0 by default and can be omitted like so: find_path(9, 4).Ev represents which character is to be moved. -1 is the player, 0 is thecalling event, and anything above is an event on the map whose ID is the ev.wait is set to false by default and can be omitted like so: find_path(9, 4) or find_path(9, 4, -1)find_path(x, y) or find_path(x, y, ev)wait specifies if the player will have to wait for the move route to finishto start moving again.------------------------------------------------------------------------------- Examples:Example of following the player at a distance:In event's custom move route or specified move route (on repeat):   find_path($game_player.x, $game_player.y, 3)  Example of an event following an event with id 2 and catching up:  find_path($game_events[2].x, $game_events[2].y, 0, false, 0, 3)=============================================================================== Formation handling:-------------------------------------------------------------------------------To move an event using a formation use this in a move route:find_formation_path(followId, shiftX, shiftY, catchup = FORM_CATCHUP_DIST,       catchupSpeed = 5, normalSpeed = 4)      followId is the character that this event is in formation with. -1 = player,0 = current event (although this is pointless) and above 0 is the event id.shiftX is the relational x position from the followId character WHEN that character faces "down". If you enter -1, this event will move to the left if its facing down, or right if its facing up.shiftY is the relational y position from the followId character WHEN thatcharacter faces "down". If you enter -1, this event will move above if its facing down, or below if it's facing up.catchup's default value is specified by the parameter FORM_CATCHUP_DIST andcan be omitted. This specifies how far behind this event can get before it speeds up to catch up.catchupSpeed's default value is 5 and can be omitted. This specifies how fast this event will move when it's "catching up". If you specify catchupSpeed, you cannot omit any previous parameters.normalSpeed's default value is 4 and can be omitted. This specifies how fast this event will move when it isn't "catching up". If you specify normalSpeed, you cannot omit any previous parameters.You also have another command for formations:Entering "turn_with_leader" as a separate script after find_formation_pathwill cause the event to turn the same way the player is turned after arriving at their formation position.Entering "turn_with_leader(1)" will turn the same way as event with id 1.Turn_with_leader also has a second optional parameter. Entering "left" or -1will turn this event left of the leader's direction, entering "right" or 1will turn this event right of the leader's direction, and entering "back" or 2 will turn this event opposite of the leader's direction. Again, if you specify this parameter, you cannot omit the previous one. ------------------------------------------------------------------------------- Examples:Example of 2 events acting similar to followers behind the player:In a repeating move-route for Event 01:find_formation_path(-1,0,-1)In a repeating move_route for Event 02:find_formation_path(1,0,-1)Example of an event covering the player's back 2 spaces away:In a repeating move-route:find_formation_path(-1,0,-2)turn_with_leader(-1,"back")Example of an event with a formation determined by in-game variables:In a repeating move-route:find_formation_path(-1, $game_variables[1], $game_variables[2])=end#===============================================================================# Customisation options below:#===============================================================================module Venima  module Formations    #    FORM_CATCHUP_DIST = 3  endendmodule Jet  module Pathfinder        # While mainly for coders, you may change this value to allow the    # pathfinder more time to find a path. 1000 is default, as it is enough for    # a 100x100 MAZE so, yeah.    # Note from Venima, you probably don't want to change this value too much    MAXIMUM_ITERATIONS = 500      endend#===============================================================================# Customisation end#===============================================================================class Node    include Comparable  attr_accessor :point, :parent, :cost, :cost_estimated  def initialize(point)    @point = point    @cost = 0    @cost_estimated = 0    @on_path = false    @parent = nil  end  def mark_path    @on_path = true    @parent.mark_path if @parent  end     def total_cost    cost + cost_estimated  end  def <=>(other)    total_cost <=> other.total_cost  end     def ==(other)    point == other.point  endendclass Point    attr_accessor :x, :y    def initialize(x, y)    @x, @y = x, y  end  def ==(other)    return false unless Point === other    @x == other.x && @y == other.y  end  def distance(other)    (@x - other.x).abs + (@y - other.y).abs  end  def relative(xr, yr)    Point.new(x + xr, y + yr)  endendclass Game_Map    def each_neighbor(node, char = $game_player)    x = node.point.x    y = node.point.y    nodes = []    4.times {|i|      i += 1      new_x = round_x_with_direction(x, i * 2)      new_y = round_y_with_direction(y, i * 2)      next unless char.passable?(x, y, i * 2)      #removed line below (technically, if your goal is an inpassable block,      # e.g. an event, you can still reach it)      #next unless char.passable?(new_x, new_y, 10 - i * 2)      nodes.push(Node.new(Point.new(new_x, new_y)))    }    nodes  end    def find_path(tx, ty, sx, sy, dist, jump, maxIter = Jet::Pathfinder::MAXIMUM_ITERATIONS, char = $game_player)    start = Node.new(Point.new(sx, sy))    goal = Node.new(Point.new(tx, ty))    return [] if start == goal or (dist > 0 and start.point.distance(goal.point) <= dist)    return [] if ![2, 4, 6, 8].any? {|i| char.passable?(tx, ty, i) }    return [] if char.collide_with_characters?(tx,ty)    open_set = [start]    closed_set = []    path = []    iterations = 0    loop do      return [] if iterations == maxIter      iterations += 1      current = open_set.min      return [] unless current      each_neighbor(current, char).each {|node|        if node == goal or (dist > 0 and node.point.distance(goal.point) <= dist)          node.parent = current          node.mark_path          return recreate_path(node, jump)        end        next if closed_set.include?(node)        cost = current.cost + 1        if open_set.include?(node)          if cost < node.cost            node.parent = current            node.cost = cost          end        else          open_set << node          node.parent = current          node.cost = cost          node.cost_estimated = node.point.distance(goal.point)        end      }      closed_set << open_set.delete(current)    end  end    def recreate_path(node, jump)    path = []    hash = {[1, 0] => 6, [-1, 0] => 4, [0, 1] => 2, [0, -1] => 8}    until node.nil?      pos = node.point      node = node.parent      next if node.nil?      ar = [pos.x <=> node.point.x, pos.y <=> node.point.y]      if jump        path.push(RPG::MoveCommand.new(14,ar))      else        path.push(RPG::MoveCommand.new(hash[ar] / 2))      end    end    return path  endendclass Game_Character    #modified function (added handling for repeated move route (recalculates path   # each step so it doesn't just loop it's old path route and will revalidate    # if x or y changes, will follow variable value if x and y are set to it)  def find_path(x, y, dist = 0, jump = false, commonEvent = 0, catchup = 0, catchupSpeed = 5, normalSpeed = 4, maxIter = Jet::Pathfinder::MAXIMUM_ITERATIONS)    path = $game_map.find_path(x, y, self.x, self.y, dist, jump, maxIter).reverse    if !@move_route.repeat      @move_route.list.delete_at(@move_route_index)      @move_route.list.insert(@move_route_index, *path)      @move_route_index -= 1    elsif path.length > 0      if commonEvent > 0        $game_temp.reserve_common_event(commonEvent)      end      if catchup > 0        if @move_speed < catchupSpeed && path.length >= catchup          process_move_command(RPG::MoveCommand.new(29,[catchupSpeed]))        elsif @move_speed >= catchupSpeed && path.length < 2          process_move_command(RPG::MoveCommand.new(29,[normalSpeed]))        end      end      process_move_command(path[0])      @move_route_index -= 1    end    #return path[path.length-1].cost if path.length > 0    return path.length  end  def get_character(i)    if i == -1      return $game_player    end    if i == 0      return $game_map.events[@event_id]    end    if i > 0      return $game_map.events[i]    end  end    def find_formation_path(followId, shiftX, shiftY, catchup = Venima::Formations::FORM_CATCHUP_DIST, catchupSpeed = 5, normalSpeed = 4)    x = shift_follow_x(followId, shiftX, shiftY)    y = shift_follow_y(followId, shiftX, shiftY)    if find_path(x,y,0,false,0,catchup,catchupSpeed,normalSpeed, 100) == 0      char = get_character(followId)      find_path(char.x,char.y,5,false,0,catchup,catchupSpeed,normalSpeed, 200)    end  end    def shift_follow_x(followId, shiftX, shiftY)    char = get_character(followId)    case char.direction    when 2      return char.x + shiftX    when 4      return char.x - shiftY    when 6      return char.x + shiftY    when 8      return char.x + shiftX    end    return char.x  end    def shift_follow_y(followId, shiftX, shiftY)    char = get_character(followId)    case char.direction    when 2      return char.y + shiftY    when 4      return char.y + shiftX    when 6      return char.y + shiftX    when 8      return char.y - shiftY    end    return char.y  end    def turn_with_leader(eventId = -1, dirmod = "")    dir = get_character(eventId).direction    mod = 0    if dirmod == "left" || dirmod == -1      case dir      when 2        set_direction(4)      when 4        set_direction(8)      when 6        set_direction(8)      when 8        set_direction(4)      end    elsif dirmod == "right" || dirmod == 1      case dir      when 2        set_direction(6)      when 4        set_direction(2)      when 6        set_direction(2)      when 8        set_direction(6)      end    elsif dirmod == "back" || dirmod == 2      case dir      when 2        set_direction(8)      when 4        set_direction(6)      when 6        set_direction(4)      when 8        set_direction(2)      end    else      set_direction(dir)     end  endendclass Game_Interpreter    #modified line below (added distance parameter)  def find_path(x, y, ev = 0, wait = false, dist = 0, jump = false)    char = get_character(ev)    #modified line below (added distance parameter)    path = $game_map.find_path(x, y, char.x, char.y, dist, jump)    path.reverse!    path.push(RPG::MoveCommand.new(0))    route = RPG::MoveRoute.new    route.list = path    route.wait = wait    route.skippable = true    route.repeat = false    char.force_move_route(route)  endend 
 

Attachments

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A
In terms of pixel movement, the best way to do it is to use the standard pathfinding but at the end, move them to the same grid "offset" as the player. Anything else would be too computationally demanding.

In terms of 8-direction movement, this is a little bit of extra work (You would need to take a close look at how Victor's script works).

To be honest, the fact that you're using these scripts, it would be more efficient to have used a completely different approach, one that is more animation-oriented than computational. For example, you simply take the player's coordinates, offset them for formation target, and simply move the follower to that position along a line (ignoring any obstacles along the way), or use the standard following-the-player if the target position is impassable.

You could try working on these yourself, but it may take some know-how. I can't promise I will continue working on this, I get more busy as the weeks go by, but it would be nice if you could provide a template project to work on, since I haven't used diagonal or pixel movement before and don't have any projects or resources set up for it.
 
Last edited by a moderator:

Vigun

Villager
Member
Joined
Jul 2, 2013
Messages
15
Reaction score
0
First Language
Spanish
Primarily Uses
Thanks for the suggestion, I will study your work to help me try to make a script compatible with pixel movement.

For now I have compatibility problems between Followers Control and Pixel Movement, I am trying to get in contact with Victor to see what happens. The problem is that the followers don't move if Followers Control and Pixel Movement are running at once.

I put a project template that I just created with the scripts.

ProjectNew.zip
 

Attachments

Venima

Treasure experiences and sensations, not progress.
Veteran
Joined
Oct 8, 2013
Messages
128
Reaction score
48
First Language
English
Primarily Uses
N/A
For anyone wanting a demo with this script in (looks like rpgmaker forums broke links at some point).


View attachment 36384
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,860
Messages
1,017,038
Members
137,567
Latest member
sashalag
Top