Dissentrix

Veteran
Veteran
Joined
Oct 21, 2014
Messages
44
Reaction score
1
First Language
English
Primarily Uses
Hello everyone ! I'm making a game in VX where there are several chase scenes. Now, the thing is, when I set the movement route to "approach", the enemies will chase me. But the problem is that if I'm too far away, they start to act really stupid, either not moving at all or getting stuck in walls.
Now, I'm aware of modern algebra's "Path Finding" script (http://rmrk.net/index.php?topic=25952.0) and Yanfly's "Chase event". But the first doesn't allow you to make enemies chase the player, only go to a specific point, and the second is not available for VX. So what I'd like is for someone to get the AI to do a good pathfinding, like in modern algebra's script, AND chase the player.
Thank you very much !
 

RaZzi

My Peculiar Brother
Veteran
Joined
Jul 19, 2013
Messages
423
Reaction score
206
First Language
Finnish
Primarily Uses

Dissentrix

Veteran
Veteran
Joined
Oct 21, 2014
Messages
44
Reaction score
1
First Language
English
Primarily Uses
That looks awesome RaZzi ! Unfortunately, I need it for VX. Can you adapt it, or is it too much work ?

Oh, and do you know if your event will chase the player even at a long distance ? Because that's the problem I'm having. If I make an event appear and the player is, say, 100 tiles away, then the event won't chase the player.
 

RaZzi

My Peculiar Brother
Veteran
Joined
Jul 19, 2013
Messages
423
Reaction score
206
First Language
Finnish
Primarily Uses
That looks awesome RaZzi ! Unfortunately, I need it for VX. Can you adapt it, or is it too much work ?

Oh, and do you know if your event will chase the player even at a long distance ? Because that's the problem I'm having. If I make an event appear and the player is, say, 100 tiles away, then the event won't chase the player.
Oh, sorry. I totally misread that you need it for VX and not for VX Ace. Also, Its not my script and I can't script. 
 

Dissentrix

Veteran
Veteran
Joined
Oct 21, 2014
Messages
44
Reaction score
1
First Language
English
Primarily Uses
Oh, sorry. I totally misread that you need it for VX and not for VX Ace. Also, Its not my script and I can't script. 
No problem :D thanks for trying anyway.
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
Hello. Use this edited version of Modern Algebra's script:

#==============================================================================# Path Finding (EDITED, NON OFFICIAL VERSION)# Version: 2.0 (EDITED, NON OFFICIAL VERSION)# Author: modern algebra (rmrk.net)# Date: April 10, 2008#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Thanks:# Patrick Lester! For his tutorial on A* Pathfinding algorithm (found at: # http://www.gamedev.net/reference/articles/article2003.asp) as well as # another amazingly helpful tutorial on using binary heaps (found at: # http://www.policyalmanac.org/games/binaryHeaps.htm). Without his excellent# tutorials, this script would not exist. So major thanks to him.# Zeriab, for tricking me into believing that this was an actual exercise.# Also, his table printout actually makes Tables useable #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Instructions:# To use, merely use this code in a script call INSIDE a Move Event:## find_path (target_x, target_y, diagonal, max_iterations)## where target_x and target_y are the target coordinates and diagonal is an# optional boolean value (true or false) stating whether or not to allow # diagonal movement. max_iterations is also optional, and you can set this if# you want the algorithm to quit if it is taking too long. The number you set# here refers to how many nodes you let it search through before cancelling# the process. If this is set to 0, it will take as many iterations as # necessary to find the shortest path.## You can also set a default value for diagonal and max_iterations# by call script with the codes:# # $game_system.pathfinding_diagonal = true/false # Allow diagonal movement# $game_system.pathfinding_iterations = integer # When <= 0, no limit## For scripters, you can force-move a character down a path via:## character.force_path (x, y, diagonal, max_iterations)## character is any Game_Character object, such as $game_player or an event.## Then, when you do not specifically set diagonal or limit, it will default# to the values you set in there#==============================================================================#==============================================================================# ** Game_System#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Summary of Changes:# new instance variables - pathfinding_diagonal, pathfinding_iterations# aliased method - initialize#==============================================================================class Game_System #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_accessor :pathfinding_diagonal attr_accessor :pathfinding_iterations #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias modalg_pathfinding_options_init_j5yt initialize def initialize modalg_pathfinding_options_init_j5yt @pathfinding_diagonal = false @pathfinding_iterations = 0 endend#==============================================================================# ** Game_Character#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Summary of Changes:# new methods - find_path#==============================================================================class Game_Character #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Find Path # trgt_x, trgt_y : the target coordinates # diagonal : Is diagonal movement allowed? # max_iterations : maximum number of iterations #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def find_path (trgt_x, trgt_y, diagonal = $game_system.pathfinding_diagonal, max_iterations = $game_system.pathfinding_iterations) path = $game_map.find_path (self.x, self.y, trgt_x, trgt_y, diagonal, max_iterations, self) # Add the path to the move route being executed. @move_route.list.delete_at (@move_route_index) path.each { |i| @move_route.list.insert (@move_route_index, i) } @move_route_index -= 1 end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Force Path # trgt_x, trgt_y : target coordinates # diagonal : Is diagonal movement allowed? # max_iterations : maximum number of iterations #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def force_path (trgt_x, trgt_y, diagonal = $game_system.pathfinding_diagonal, max_iterations = $game_system.pathfinding_iterations) path = $game_map.find_path (self.x, self.y, trgt_x, trgt_y, diagonal, max_iterations, self) # The path retrieved is actually backwards, so it must be reversed path.reverse! # Add an end ccommand path.push (RPG::MoveCommand.new (0)) move_route = RPG::MoveRoute.new move_route.list = path move_route.repeat = false force_move_route (move_route) endend#==============================================================================# ** Game_Map#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Summary of Changes:# new method - removefrom_binaryheap, find_path #==============================================================================class Game_Map #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Remove from Heap #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def removefrom_binaryheap @open_nodes[1] = @open_nodes[@listsize] @listsize -= 1 v = 1 loop do u = v w = 2*u # Check if it's cost is greater than that of it's children if w + 1 <= @listsize # If both children exist v = w if @total_cost[@open_nodes] >= @total_cost[@open_nodes[w]] v = w + 1 if @total_cost[@open_nodes[v]] >= @total_cost[@open_nodes[w + 1]] elsif w <= @listsize # If only one child exists v = w if @total_cost[@open_nodes] >= @total_cost[@open_nodes[w]] end # Break if parent has less cost than it's children if u == v break else temp = @open_nodes @open_nodes = @open_nodes[v] @open_nodes[v] = temp end end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Find Path # src_x, src_y : the source coordinates # trgt_x, trgt_y : the target coordinates # diagonal : Is diagonal movement allowed? # max_iterations : maximum number of iterations # char : character to follow the path #-------------------------------------------------------------------------- # Uses the A* method of pathfinding to find a path #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def find_path (src_x, src_y, trgt_x, trgt_y, diagonal, max_iterations, char) # No possible path if the target itself is impassable path = [] # Finished if Target Location is closed #return path if !char.passable? (trgt_x, trgt_y) # Initialize max_elements = width*height + 2 openx = Table.new (max_elements) openy = Table.new (max_elements) @open_nodes = Table.new (max_elements) @total_cost = Table.new (max_elements) heuristic = Table.new (max_elements) step_cost = Table.new (width, height) parent_x = Table.new (width, height) parent_y = Table.new (width, height) actual_list = Table.new (width, height) # Add the source node to the open list new_openid = 1 @open_nodes[1] = 1 openx[1] = src_x openy[1] = src_y dist = [(trgt_x - src_x).abs, (trgt_y - src_y).abs] heuristic[1] = diagonal ? (dist.max*14) + (dist.min*10) : (dist[0] + dist[1])*10 @total_cost[1] = heuristic[1] actual_list[src_x, src_y] = 1 @listsize = 1 count = 0 loop do break if actual_list[trgt_x, trgt_y] != 0 count += 1 # Update Graphics every 500 iterations Graphics.update if count % 500 == 0 return path if count == max_iterations return path if @listsize == 0 node = @open_nodes[1] # Set the x and y value as parent to all possible children parent_xval, parent_yval = openx[node], openy[node] actual_list[parent_xval, parent_yval] = 2 removefrom_binaryheap # Check all adjacent squares for i in 0...8 break if i > 3 && !diagonal # Get the node x, y = case i when 0 then [parent_xval, parent_yval - 1] # UP when 1 then [parent_xval, parent_yval + 1] # DOWN when 2 then [parent_xval - 1, parent_yval] # LEFT when 3 then [parent_xval + 1, parent_yval] # RIGHT when 4 then [parent_xval - 1, parent_yval - 1] # UP LEFT when 5 then [parent_xval + 1, parent_yval - 1] # UP RIGHT when 6 then [parent_xval - 1, parent_yval + 1] # DOWN LEFT when 7 then [parent_xval + 1, parent_yval + 1] # DOWN RIGHT end # Next if this node is already in the closed list next if actual_list[x,y] == 2 # Next if this tile in impassable next unless char.passable? (x, y) || (x == trgt_x && y == trgt_y) # Take into account diagonal passability concerns if i > 3 next unless case i when 4 then char.passable? (x + 1, y) || char.passable? (x, y + 1) when 5 then char.passable? (x - 1, y) || char.passable? (x, y + 1) when 6 then char.passable? (x + 1, y) || char.passable? (x, y - 1) when 7 then char.passable? (x - 1, y) || char.passable? (x, y - 1) end end # Check if this node already open plus_step_cost = ((x - parent_xval).abs + (y - parent_yval).abs) > 1 ? 14 : 10 temp_step_cost = step_cost[parent_xval, parent_yval] + plus_step_cost if actual_list[x,y] == 1 # If this is a better path to that node if temp_step_cost < step_cost[x, y] # Change Parent, step, and total cost parent_x[x, y] = parent_xval parent_y[x, y] = parent_yval step_cost[x, y] = temp_step_cost # Find index of this position index = 1 while index < @listsize index += 1 break if openx[@open_nodes[index]] == x && openy[@open_nodes[index]] == y end @total_cost[@open_nodes[index]] = temp_step_cost + heuristic[@open_nodes[index]] else next end else # If not on open nodes # Add to open nodes new_openid += 1 # New Id for new item @listsize += 1 # Increase List Size @open_nodes[@listsize] = new_openid step_cost[x, y] = temp_step_cost # Calculate Heuristic d = [(trgt_x - x).abs, (trgt_y - y).abs] heuristic[new_openid] = diagonal ? (d.max*14) + (d.min*10) : (d[0] + d[1])*10 @total_cost[new_openid] = temp_step_cost + heuristic[new_openid] parent_x[x, y] = parent_xval parent_y[x, y] = parent_yval openx[new_openid] = x openy[new_openid] = y index = @listsize actual_list[x, y] = 1 end # Sort Binary Heap while index != 1 temp_node = @open_nodes[index] if @total_cost[temp_node] <= @total_cost[@open_nodes[index / 2]] @open_nodes[index] = @open_nodes[index / 2] index /= 2 @open_nodes[index] = temp_node else break end end end end # Get actual target node path_x, path_y = trgt_x, trgt_y # Make an array of MoveRoute Commands while path_x != src_x || path_y != src_y # Get Parent x, Parent Y prnt_x, prnt_y = parent_x[path_x, path_y], parent_y[path_x, path_y] # DOWN = 1, LEFT = 2, RIGHT = 3, UP = 4, DL = 5, DR = 6, UL = 7, UR = 8 if path_x < prnt_x # LEFT # Determine if upper, lower or direct left code = path_y < prnt_y ? 7 : path_y > prnt_y ? 5 : 2 elsif path_x > prnt_x # RIGHT # Determine if upper, lower or direct right code = path_y < prnt_y ? 8 : path_y > prnt_y ? 6 : 3 else # UP or DOWN code = path_y < prnt_y ? 4 : 1 end path.push (RPG::MoveCommand.new (code)) path_x, path_y = prnt_x, prnt_y end return path endend 

Then you could do something like the following in a Parallel Process event:

use a Call Script command and write:

if @chase_player_x != $game_player.x || @chase_player_y != $game_player.y @chase_player_x = $game_player.x @chase_player_y = $game_player.y $game_map.events[event_id].force_path( @chase_player_x, @chase_player_y ) endChange "event_id" for the actual id of the event you want to move, like 4 (not 004). You might also want to add a Wait command after that to perform the check once per second.

Try it out and let me know how it works performance wise for you. It might work fine for just one event even if the player is 100 tiles away, but it depends on your level design and other factors aside from the actual pathfinding code.
 

Dissentrix

Veteran
Veteran
Joined
Oct 21, 2014
Messages
44
Reaction score
1
First Language
English
Primarily Uses
Hello. Use this edited version of Modern Algebra's script:

#==============================================================================# Path Finding (EDITED, NON OFFICIAL VERSION)# Version: 2.0 (EDITED, NON OFFICIAL VERSION)# Author: modern algebra (rmrk.net)# Date: April 10, 2008#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Thanks:# Patrick Lester! For his tutorial on A* Pathfinding algorithm (found at: # http://www.gamedev.net/reference/articles/article2003.asp) as well as # another amazingly helpful tutorial on using binary heaps (found at: # http://www.policyalmanac.org/games/binaryHeaps.htm). Without his excellent# tutorials, this script would not exist. So major thanks to him.# Zeriab, for tricking me into believing that this was an actual exercise.# Also, his table printout actually makes Tables useable #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Instructions:# To use, merely use this code in a script call INSIDE a Move Event:## find_path (target_x, target_y, diagonal, max_iterations)## where target_x and target_y are the target coordinates and diagonal is an# optional boolean value (true or false) stating whether or not to allow # diagonal movement. max_iterations is also optional, and you can set this if# you want the algorithm to quit if it is taking too long. The number you set# here refers to how many nodes you let it search through before cancelling# the process. If this is set to 0, it will take as many iterations as # necessary to find the shortest path.## You can also set a default value for diagonal and max_iterations# by call script with the codes:# # $game_system.pathfinding_diagonal = true/false # Allow diagonal movement# $game_system.pathfinding_iterations = integer # When <= 0, no limit## For scripters, you can force-move a character down a path via:## character.force_path (x, y, diagonal, max_iterations)## character is any Game_Character object, such as $game_player or an event.## Then, when you do not specifically set diagonal or limit, it will default# to the values you set in there#==============================================================================#==============================================================================# ** Game_System#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Summary of Changes:# new instance variables - pathfinding_diagonal, pathfinding_iterations# aliased method - initialize#==============================================================================class Game_System #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_accessor :pathfinding_diagonal attr_accessor :pathfinding_iterations #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias modalg_pathfinding_options_init_j5yt initialize def initialize modalg_pathfinding_options_init_j5yt @pathfinding_diagonal = false @pathfinding_iterations = 0 endend#==============================================================================# ** Game_Character#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Summary of Changes:# new methods - find_path#==============================================================================class Game_Character #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Find Path # trgt_x, trgt_y : the target coordinates # diagonal : Is diagonal movement allowed? # max_iterations : maximum number of iterations #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def find_path (trgt_x, trgt_y, diagonal = $game_system.pathfinding_diagonal, max_iterations = $game_system.pathfinding_iterations) path = $game_map.find_path (self.x, self.y, trgt_x, trgt_y, diagonal, max_iterations, self) # Add the path to the move route being executed. @move_route.list.delete_at (@move_route_index) path.each { |i| @move_route.list.insert (@move_route_index, i) } @move_route_index -= 1 end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Force Path # trgt_x, trgt_y : target coordinates # diagonal : Is diagonal movement allowed? # max_iterations : maximum number of iterations #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def force_path (trgt_x, trgt_y, diagonal = $game_system.pathfinding_diagonal, max_iterations = $game_system.pathfinding_iterations) path = $game_map.find_path (self.x, self.y, trgt_x, trgt_y, diagonal, max_iterations, self) # The path retrieved is actually backwards, so it must be reversed path.reverse! # Add an end ccommand path.push (RPG::MoveCommand.new (0)) move_route = RPG::MoveRoute.new move_route.list = path move_route.repeat = false force_move_route (move_route) endend#==============================================================================# ** Game_Map#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# Summary of Changes:# new method - removefrom_binaryheap, find_path #==============================================================================class Game_Map #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Remove from Heap #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def removefrom_binaryheap @open_nodes[1] = @open_nodes[@listsize] @listsize -= 1 v = 1 loop do u = v w = 2*u # Check if it's cost is greater than that of it's children if w + 1 <= @listsize # If both children exist v = w if @total_cost[@open_nodes] >= @total_cost[@open_nodes[w]] v = w + 1 if @total_cost[@open_nodes[v]] >= @total_cost[@open_nodes[w + 1]] elsif w <= @listsize # If only one child exists v = w if @total_cost[@open_nodes] >= @total_cost[@open_nodes[w]] end # Break if parent has less cost than it's children if u == v break else temp = @open_nodes @open_nodes = @open_nodes[v] @open_nodes[v] = temp end end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Find Path # src_x, src_y : the source coordinates # trgt_x, trgt_y : the target coordinates # diagonal : Is diagonal movement allowed? # max_iterations : maximum number of iterations # char : character to follow the path #-------------------------------------------------------------------------- # Uses the A* method of pathfinding to find a path #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def find_path (src_x, src_y, trgt_x, trgt_y, diagonal, max_iterations, char) # No possible path if the target itself is impassable path = [] # Finished if Target Location is closed #return path if !char.passable? (trgt_x, trgt_y) # Initialize max_elements = width*height + 2 openx = Table.new (max_elements) openy = Table.new (max_elements) @open_nodes = Table.new (max_elements) @total_cost = Table.new (max_elements) heuristic = Table.new (max_elements) step_cost = Table.new (width, height) parent_x = Table.new (width, height) parent_y = Table.new (width, height) actual_list = Table.new (width, height) # Add the source node to the open list new_openid = 1 @open_nodes[1] = 1 openx[1] = src_x openy[1] = src_y dist = [(trgt_x - src_x).abs, (trgt_y - src_y).abs] heuristic[1] = diagonal ? (dist.max*14) + (dist.min*10) : (dist[0] + dist[1])*10 @total_cost[1] = heuristic[1] actual_list[src_x, src_y] = 1 @listsize = 1 count = 0 loop do break if actual_list[trgt_x, trgt_y] != 0 count += 1 # Update Graphics every 500 iterations Graphics.update if count % 500 == 0 return path if count == max_iterations return path if @listsize == 0 node = @open_nodes[1] # Set the x and y value as parent to all possible children parent_xval, parent_yval = openx[node], openy[node] actual_list[parent_xval, parent_yval] = 2 removefrom_binaryheap # Check all adjacent squares for i in 0...8 break if i > 3 && !diagonal # Get the node x, y = case i when 0 then [parent_xval, parent_yval - 1] # UP when 1 then [parent_xval, parent_yval + 1] # DOWN when 2 then [parent_xval - 1, parent_yval] # LEFT when 3 then [parent_xval + 1, parent_yval] # RIGHT when 4 then [parent_xval - 1, parent_yval - 1] # UP LEFT when 5 then [parent_xval + 1, parent_yval - 1] # UP RIGHT when 6 then [parent_xval - 1, parent_yval + 1] # DOWN LEFT when 7 then [parent_xval + 1, parent_yval + 1] # DOWN RIGHT end # Next if this node is already in the closed list next if actual_list[x,y] == 2 # Next if this tile in impassable next unless char.passable? (x, y) || (x == trgt_x && y == trgt_y) # Take into account diagonal passability concerns if i > 3 next unless case i when 4 then char.passable? (x + 1, y) || char.passable? (x, y + 1) when 5 then char.passable? (x - 1, y) || char.passable? (x, y + 1) when 6 then char.passable? (x + 1, y) || char.passable? (x, y - 1) when 7 then char.passable? (x - 1, y) || char.passable? (x, y - 1) end end # Check if this node already open plus_step_cost = ((x - parent_xval).abs + (y - parent_yval).abs) > 1 ? 14 : 10 temp_step_cost = step_cost[parent_xval, parent_yval] + plus_step_cost if actual_list[x,y] == 1 # If this is a better path to that node if temp_step_cost < step_cost[x, y] # Change Parent, step, and total cost parent_x[x, y] = parent_xval parent_y[x, y] = parent_yval step_cost[x, y] = temp_step_cost # Find index of this position index = 1 while index < @listsize index += 1 break if openx[@open_nodes[index]] == x && openy[@open_nodes[index]] == y end @total_cost[@open_nodes[index]] = temp_step_cost + heuristic[@open_nodes[index]] else next end else # If not on open nodes # Add to open nodes new_openid += 1 # New Id for new item @listsize += 1 # Increase List Size @open_nodes[@listsize] = new_openid step_cost[x, y] = temp_step_cost # Calculate Heuristic d = [(trgt_x - x).abs, (trgt_y - y).abs] heuristic[new_openid] = diagonal ? (d.max*14) + (d.min*10) : (d[0] + d[1])*10 @total_cost[new_openid] = temp_step_cost + heuristic[new_openid] parent_x[x, y] = parent_xval parent_y[x, y] = parent_yval openx[new_openid] = x openy[new_openid] = y index = @listsize actual_list[x, y] = 1 end # Sort Binary Heap while index != 1 temp_node = @open_nodes[index] if @total_cost[temp_node] <= @total_cost[@open_nodes[index / 2]] @open_nodes[index] = @open_nodes[index / 2] index /= 2 @open_nodes[index] = temp_node else break end end end end # Get actual target node path_x, path_y = trgt_x, trgt_y # Make an array of MoveRoute Commands while path_x != src_x || path_y != src_y # Get Parent x, Parent Y prnt_x, prnt_y = parent_x[path_x, path_y], parent_y[path_x, path_y] # DOWN = 1, LEFT = 2, RIGHT = 3, UP = 4, DL = 5, DR = 6, UL = 7, UR = 8 if path_x < prnt_x # LEFT # Determine if upper, lower or direct left code = path_y < prnt_y ? 7 : path_y > prnt_y ? 5 : 2 elsif path_x > prnt_x # RIGHT # Determine if upper, lower or direct right code = path_y < prnt_y ? 8 : path_y > prnt_y ? 6 : 3 else # UP or DOWN code = path_y < prnt_y ? 4 : 1 end path.push (RPG::MoveCommand.new (code)) path_x, path_y = prnt_x, prnt_y end return path endend 


Then you could do something like the following in a Parallel Process event:

use a Call Script command and write:

if @chase_player_x != $game_player.x || @chase_player_y != $game_player.y @chase_player_x = $game_player.x @chase_player_y = $game_player.y $game_map.events[event_id].force_path( @chase_player_x, @chase_player_y ) endChange "event_id" for the actual id of the event you want to move, like 4 (not 004). You might also want to add a Wait command after that to perform the check once per second.

Try it out and let me know how it works performance wise for you. It might work fine for just one event even if the player is 100 tiles away, but it depends on your level design and other factors aside from the actual pathfinding code.

Wow ! Thanks, Source ! It works perfectly ! And with no lag. Now the only problem is, I want to have the event trigger a game over when it touches the player, so I can't put it as a parallel process. Or else I have to make a new page when the two coordinates collide. Any ideas ?

On a side-note, do you know who edited the script ? Was it you ? It's for the credits, you see.
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
Wow ! Thanks, Source ! It works perfectly ! And with no lag. Now the only problem is, I want to have the event trigger a game over when it touches the player, so I can't put it as a parallel process. Or else I have to make a new page when the two coordinates collide. Any ideas ?

On a side-note, do you know who edited the script ? Was it you ? It's for the credits, you see.
Yes, I was the one who edited it. :)

To have the event do something when it touches the player, add a new Call Script after the previous one with the following:

ex = $game_map.events[1].real_xey = $game_map.events[1].real_ypx = $game_player.real_xpy = $game_player.real_ydistance = (ex - px).abs + (ey - py).absif distance < 300 $game_switches[switch_id] = true $game_map.need_refresh = trueendChange "switch_id" for the actual id of the switch. Then just have a new page or event that activates when that switch is on (Autorun or Parallel Process) and use it to perform the commands that you need (like the Game Over command).

Does that work as you want?
 

Dissentrix

Veteran
Veteran
Joined
Oct 21, 2014
Messages
44
Reaction score
1
First Language
English
Primarily Uses
It works ! I can't thank you enough for your help, ♥SOURCE♥. This solves a bunch of my problems. I'll be sure to include you in the credits.

Thanks again !
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
You're welcome. I'm glad to know it helped you :)
 

Latest Threads

Latest Profile Posts

I just don't know why, but it's funny.
5.gif
Ugh. The one time I forget to save every hour or so is also the day my computer crashes. That's life!
Even though I spent 100's of dollars on my game already. I think I might just have to give it away for free. Since I haven't heard back from people if I could use some of their graphics. Even from a global mod here. Maybe I can make a donation thing.
you know, some days you get resentful that game dev is even considered a "fun job" and other days it's like, welp, time to roll up my sleeves and code these molotov cocktails
If you suck at playing trumpets, that is probably why.

Forum statistics

Threads
115,967
Messages
1,094,496
Members
151,239
Latest member
luka1712
Top