¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.
Conectarse

Recuperar mi contraseña

Temas importantes
----------------------------------------
Páginas con recursos RPG Maker
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
Afiliados
Estadísticas
Tenemos 3393 miembros registrados.
El último usuario registrado es nino34.

Nuestros miembros han publicado un total de 79784 mensajes en 11253 argumentos.
Navega con Google Chrome
[DESCARGA]

Pathfinder

 :: RPG Maker :: Scripts

Ver el tema anterior Ver el tema siguiente Ir abajo

RPG Maker VX ACE Pathfinder

Mensaje por Metalero el 2015-01-09, 03:56

El otro dia me acorde de esto, que habia hecho (ahora lo adapte para que sea mas generico), para un proyecto que (lamentablemente) quedo en la nada.

Se trata de un sistema de Pathfinding (debe haber mas de uno por ahi, este lo hice yo desde cero), para el ACE.
Para quien no sepa lo que es, es un sistema para definir una ruta de movimiento hacia un destino, con la posibilidad de tomar en cuenta obstaculos, y encontrar el camino mas corto evitando esos obstaculos

Código:
#==============================================================================
# PathFinder System
# Author: Juan Martin Leiva [Metalero]
#
# To use, call script in an event:
# move_to_position_with_pathfinder(x, y, wait)
#==============================================================================

#==============================================================================
# ** Game_Character
#==============================================================================

class Game_Character < Game_CharacterBase
  #--------------------------------------------------------------------------
  # * Move To Posisition with Pathfinder
  #--------------------------------------------------------------------------
  def pf_move_to_position(x, y, wait)
    path = PathFinder.GetPath(Point.new(self.x, self.y), Point.new(x,y)) 
    route = RPG::MoveRoute.new
    route.repeat = false
    route.skippable = false
    route.wait = wait

    commands = []

    for node in path
      commands.push(RPG::MoveCommand.new(node.dir))
    end
    commands.push(RPG::MoveCommand.new(0))
    route.list = commands
    force_move_route(route)
    
    return commands.size
  end
end

#==============================================================================
# ** Game_Interpreter
#------------------------------------------------------------------------------
#  An interpreter for executing event commands. This class is used within the
# Game_Map, Game_Troop, and Game_Event classes.
#==============================================================================

class Game_Interpreter
  #--------------------------------------------------------------------------
  # *  Move To Posisition with Pathfinder
  #--------------------------------------------------------------------------
  def move_to_position_with_pathfinder(x, y, wait)
    p x.to_s + " " + y.to_s
    $game_map.refresh if $game_map.need_refresh
    character = get_character(0)
    if character
      character.pf_move_to_position(x, y, wait)
      
      if wait
        while character.move_route_forcing
          Fiber.yield
        end
      end
    end
  end
end

#==============================================================================
# ** Point
#==============================================================================
class Point
  attr_accessor   :x
  attr_accessor   :y
  
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    @x = 0
    @y = 0
  end
  
  def initialize(x, y)
    @x = x
    @y = y
  end
  
  def +(other)
    return Point.new(@x + other.x, @y + other.y)
  end
  
  def -(other)
    return Point.new(@x - other.x, @y - other.y)
  end
  
  def to_s
    return "(#{@x},  #{@y})"
  end
end

#==============================================================================
# ** Binary Heap Node
#==============================================================================
class BinaryHeapNode
   #--------------------------------------------------------------------------
   # * Public Instance Variables
   #--------------------------------------------------------------------------
   attr_accessor   :object
   
   #--------------------------------------------------------------------------
   # * Object Initialization
   #--------------------------------------------------------------------------
   def initialize
      @object = 0
   end
   
   #--------------------------------------------------------------------------
   # * Comparison method override
   #--------------------------------------------------------------------------
   def <=>(another_node)
      return self.object.<=>(another_node.object)
   end
  
  def to_s
    return self.object.to_s
  end
end



#==============================================================================
# ** Min Binary Heap 
#==============================================================================
class MinBinaryHeap
   
   #--------------------------------------------------------------------------
   # * Public Instance Variables
   #--------------------------------------------------------------------------
   def initialize
      @nodes = []
   end
   
   #--------------------------------------------------------------------------
   # * Peek Min Node
   #--------------------------------------------------------------------------
   def Peek
      if @nodes.size <= 0
         return nil
    end
    
      return @nodes[0]
   end
   
   #--------------------------------------------------------------------------
   # * Insert Node
   #--------------------------------------------------------------------------
   def Insert(node)
      @nodes.push(node)
      currentPos = @nodes.size - 1
      done = false
      while true
         parentId = currentPos  / 2
         
         if currentPos == 0
            break
         end

         if @nodes[parentId].<=>(node) > 0
            #Swap Nodes
            Swap(currentPos,parentId)
            currentPos = parentId
         else
            break
         end
      end
   end
   
   #--------------------------------------------------------------------------
   # * Remove Min Node, and returns it
   #--------------------------------------------------------------------------
   def Pop
      if @nodes.size <= 0
         return nil
      end
    
      #Extract root, and put last element in root
      root = @nodes[0]
      lastNode = @nodes.pop
    
    if @nodes.size == 0
      return root
    end
    
      @nodes[0] = lastNode
      
   
    
      #Re-sort
      currentPos = 0
      
      while true
         if currentPos * 2 >= @nodes.size()
            break
         end
         
         
         minNode = @nodes[currentPos * 2]
         minNode_id = currentPos * 2
         
         if currentPos * 2 + 1 < @nodes.size()
            
         
            nodeLeft = @nodes[currentPos * 2]
            nodeRight = @nodes[currentPos * 2 + 1]
         
         
         
            if nodeLeft.<=>(nodeRight) > 0
               minNode = nodeRight
               minNode_id = currentPos * 2 + 1
            end
         end
         
         currentNode = @nodes[currentPos]
         
         if minNode.<=>(currentNode) < 0
            Swap(minNode_id, currentPos)
            currentPos = minNode_id
         else
            break
         end
      end

      return root
   end
   
   #--------------------------------------------------------------------------
   # * Swap Nodes (Helper class)
   #--------------------------------------------------------------------------
   def Swap(id1, id2)
      if id1 == id2
         return
      end
      
      if id1 < 0 or id1 >= @nodes.size() or id2 < 0 or id2 >= @nodes.size()
         return
      end
      
      tempNode = @nodes[id1] 
      @nodes[id1] = @nodes[id2]
      @nodes[id2] = tempNode
   end
   
  #--------------------------------------------------------------------------
   # * Clear Heap
   #--------------------------------------------------------------------------
  def Clear
    @nodes.clear
  end
  
  #--------------------------------------------------------------------------
   # * Size
   #--------------------------------------------------------------------------
  def Size
   return @nodes.size
  end
  
  #--------------------------------------------------------------------------
   # * GetNode
   #--------------------------------------------------------------------------
  def GetNode(i)
    return @nodes[i]
  end
  
  def Nodes
    return @nodes
  end
  #--------------------------------------------------------------------------
   # * To String
   #--------------------------------------------------------------------------
   def print
      str = ""
      max = 1
      i = 0
      
      for node in @nodes
         if i >= max
            max *= 2
            i = 0
        print(str)
            print("")
        str = ""
      end
      
      str += "| " + node.to_s + " |"
         
      i += 1
    end
    print(str)
   end
  
end

#==============================================================================
# ** Path Finder Node
#==============================================================================
class PFNode
   include Comparable
   
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
   attr_accessor      :position
   attr_accessor      :path_score
   attr_accessor      :path_cost
   attr_accessor      :path_heuristic
   attr_accessor      :dir
   attr_accessor      :parent
   
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
   def initialize
      @x = 0
      @y = 0
      @path_score = 0
      @path_cost = 0
      @path_heuristic = 0
      @dir = -1
      @parent = nil
  end
  
  #--------------------------------------------------------------------------
  # * Comparison method override
  #--------------------------------------------------------------------------
   def <=>(another_node)
      if self.path_score < another_node.path_score
         return -1
      elsif self.path_score > another_node.path_score
         return 1
      else
         return 0
      end
   end
end

#==============================================================================
# ** Path Finder
#==============================================================================
module PathFinder
    
   #--------------------------------------------------------------------------
   # * Get Path
   #--------------------------------------------------------------------------
   def self.GetPath(init, dest)
      openList = MinBinaryHeap.new
      closedList = []

      nodePath = []
      
      #First Node
      firstNode = CreateNode(init, nil, -1, dest)
      
      openList.Insert(firstNode)
      
      smallestNode = nil
      parent = nil
      
      while openList.Size > 0
         smallestNode =  openList.Pop
         
         if smallestNode.position.x == dest.x and smallestNode.position.y == dest.y
            parent = smallestNode
            
            for i in 0...smallestNode.path_cost
               nodePath.push(parent)
               parent = parent.parent
            end
            
            break
         end

         closedList.push(smallestNode)
         children = GetChildrenOf(smallestNode, dest, openList, closedList)
         
         for child in children
        if child == nil
          next
        end
            openList.Insert(child)
         end
      end
      
      return nodePath.reverse
   end

   #--------------------------------------------------------------------------
   # * Create Node
   #--------------------------------------------------------------------------
   def self.CreateNode(position, parent, dir, dest)
      node = PFNode.new
      node.position = position
      node.parent = parent
      node.dir = dir
      CalculateH(node, dest)
      return node
   end
   
   #--------------------------------------------------------------------------
   # * Calculate Heuristic
   #--------------------------------------------------------------------------
   def self.CalculateH(node, dest)

      if node.parent != nil
         node.path_cost = node.parent.path_cost + 1

      else
         node.path_cost = 0
      end
    
      node.path_heuristic = (node.position.x - dest.x).abs + (node.position.y - dest.y).abs
      node.path_score= node.path_cost + node.path_heuristic
   end
   
   #--------------------------------------------------------------------------
   # * Add children of Node to @openList
   #--------------------------------------------------------------------------
  def self.GetChildrenOf(node, dest, openList, closedList)
      upNode = GetChild(node,  0, -1, 4, dest, openList, closedList) #UP
      downNode = GetChild(node,   0,  1, 1, dest, openList, closedList) #DOWN
      leftNode = GetChild(node, -1,   0, 2, dest, openList, closedList) #LEFT
      rightNode = GetChild(node,   1,   0, 3, dest, openList, closedList) #RIGHT
      
      return [upNode, downNode, leftNode, rightNode]
   end
      
   def self.GetChild(node, diffX, diffY, dir, dest, openList, closedList)
   
      targetPos = Point.new(node.position.x + diffX, node.position.y + diffY)
      
      #If Valid
    if !$game_map.passable?(targetPos.x, targetPos.y, dir * 2)
      #if !$game_map.check_passage(targetPos.x, targetPos.y, 0x0001)
         return
      end
      
    $game_map.events_xy_nt(targetPos.x, targetPos.y).any? do |event|
      if event.normal_priority? || self.is_a?(Game_Event)
      
        return
      end
    end
      
      #if not closed or open
      for closedNode in closedList
         if closedNode.position.x == targetPos.x and closedNode.position.y == targetPos.y
            return
         end
      end
      
      for i in 0...openList.Size
         openNode = openList.GetNode(i)
         if openNode.position.x == targetPos.x and openNode.position.y == targetPos.y
            return
         end
      end
      
      return CreateNode(targetPos, node, dir, dest)
   end
      

   #--------------------------------------------------------------------------
   # * Get Posible Paths with distance
   #--------------------------------------------------------------------------
   def self.GetPosiblePathsWithDistance(init, distance)
      openList = MinBinaryHeap.new
      closedList = []
      
    dest = Point.new(0,0)
    
      #First Node
      firstNode = CreateNode(init, nil, -1, dest)
      
      openList.Insert(firstNode)
      
      smallestNode = nil
      parent = nil
      
    result = []
    
      while openList.Size > 0
         smallestNode =  openList.Pop
         closedList.push(smallestNode)
      
         children = GetChildrenOf(smallestNode, dest, openList, closedList)
     
      for child in children

        if child == nil
          next
        end
            if child.path_cost <= distance
               openList.Insert(child)
          result.push(child.position)
            end
         end
      end
      
      return result
   end
end




Basta pegarlo sobre main y listo.

Para usarlo, simplemente se hace una llamada a script en el evento al cual se le quiere mover usando pathfinder:

Código:

move_to_position_with_pathfinder(x, y, wait)




Donde X, e Y son las posiciones horizontal y vertical respectivamente de destino en el mapa.
Wait es un booleano que define si se debe esperar a llegar a destino para continuar la ejecucion del evento.

Ej:

Código:
move_to_position_with_pathfinder(5, 15, true)




Notas: como obstaculos, se toman los tiles del mapa que son NO-PASABLES, y los eventos NO-PASABLES al momento de la llamada*

*si hay eventos no pasables móviles, tomara en cuenta la posicion que tenian al momento en que se llamo el script. Para remediar esto, se puede llamar cada cierto tiempo el el comando, para "updatear" el camino.


Como casi siempre, no exijo créditos, pero es agradable recibirlos si usan el script.

_________________

Metalero
Administrador
Administrador



Créditos 1715

Gracias : 98

Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


 :: RPG Maker :: Scripts

Permisos de este foro:
No puedes responder a temas en este foro.