Ergebnis 1 bis 20 von 30

Thema: Brauche Hilfe: Pathfinding

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1

    Brauche Hilfe: Pathfinding

    Guten Tag.
    Für mein derzeitiges Projekt arbeite ich an einem geeigneten Pathfinding-System welches möglichst effektiv den schnellsten (nicht kürzesten) Weg durch ein Gebiet sucht.
    Der schnellste Weg soll bedeuten, dass manche Tiles die Geschwindigkeit der Einheit beeinflussen können; Wälder verlangsamen, Gebirge und Wüsten ebenfalls.

    Ich habe mir bereits soviel Arbeit gemacht einen funktionierenden A*-Pathfinding-Algorithmus zu schreiben.
    Wie gesagt, er funktioniert, er findet den schnellsten Weg in 100% der Fälle.

    Allerdings kommt nun ein ganz anderes Problem zu tragen, er verbraucht zu viel Performance.

    Mit diesem Script würden schwächere Computer kaum mitkommen, besonders falls mehrere Einheiten Pathfinding benötigen und es sich dazu um eine große Karte handelt.
    Ich könnte es in Kauf nehmen wenn die Wegsuche weniger genau ist und nicht immer den richtigen Weg findet falls die Performance dadurch sehr viel verbessert werden könnte.

    Hier ist mein derzeitiges Script:
    Code:
    module Pathfinding
      module_function
      
      def set_map(map)
        @map = map
        
        #create array of all nodes on the map
        @node_list = []
        width = @map.width-1
        height = @map.height-1
        for x in 0..width
          for y in 0..height
            #get the speed modification for every node
            speed_factor = @map.get_movement_speed_factor(x,y)
            #nodes with a speed factor of 0 are impassable
            if speed_factor > 0
              #id in the array, x/y coordinate, and movement speed factor > 0
              node = Node.new(x,y,speed_factor)
              @node_list.push(node)
            end
          end
        end
        #get all adjacent nodes for every node
        for current_node in @node_list
          cx = current_node.x
          cy = current_node.y
          adjacent_nodes = []
          for possible_adjacent_node in @node_list
            ax = possible_adjacent_node.x
            ay = possible_adjacent_node.y
            distance_x = ax-cx
            distance_y = ay-cy
            #a node is adjacent if the horizontal or vertical distance is -1, 0 or 1
            if distance_x.abs < 2 && distance_y.abs < 2
              adjacent_nodes.push(possible_adjacent_node)
            end
          end
          current_node.adjacent_nodes = adjacent_nodes
        end
      end
      
      def find_path(from_tile_x, from_tile_y, to_tile_x, to_tile_y)
        start_node = nil
        for node in @node_list
          #the start_node is the node at from_tile_x / from_tile_y
          if node.x == from_tile_x && node.y == from_tile_y
            start_node = node
          end
        end
        #array of all nodes which have not been expanded yet
        open_nodes = [start_node]
        
        current_node = start_node
        #flag the start node as "opened" == the node is in the open_nodes array
        current_node.opened = true
        #ensure result if the target is the start
        final_node = start_node
        loop do
          #end if no nodes can be expanded anymore == no path found
          if open_nodes.size == 0
            self.cleanup
            return nil
            break
          end
          if current_node.x == to_tile_x && current_node.y == to_tile_y
            final_node = current_node
            #break if the final node has been reached
            break
          else
            final_node = current_node
            #expand the current node
            self.expand_node(current_node,open_nodes,to_tile_x,to_tile_y)
            #the next node to be expanded is the node with the best value
            size = open_nodes.size
            current_node = open_nodes[0]
            for i in 1...size
              check_node = open_nodes[i]
              if check_node.value < current_node.value
                current_node = check_node
              end
            end
          end
        end
        #get the move route, an array containing the nodes to move along in order
        move_route = self.generate_move_route(start_node,final_node)
        #reset all data for the next task
        self.cleanup
        return move_route
      end
      
      def expand_node(current_node,open_nodes,to_tile_x,to_tile_y)
        #iterate through every adjacent node of the current node and add it to the open_nodes array
        for node in current_node.adjacent_nodes
          #if the node is already closed it cannot be opened again
          next if node.closed
          distance_x = node.x - to_tile_x
          distance_y = node.y - to_tile_y
          distance = distance_x.abs + distance_y.abs
          value = current_node.value + node.speed_factor + 350 * distance
          #the value is determined by both, the speed factor and the distance
          if node.opened
            #if the node is already opened
            if value >= node.value
              #do nothing if there is already a better value for this node
              next
            else
              #if the new value is better then the previous save the new value and the predecessor
              node.predecessor = current_node
              node.value = value
            end
          else
            open_nodes.push(node)
            #save the predecessor for this node, the value and that its opened
            node.predecessor = current_node
            node.value = value
            node.opened = true
          end
        end
        open_nodes.delete(current_node)
        current_node.closed = true
      end
      
      def cleanup
        #iterate through every node in reset its values
        for node in @node_list
          node.closed = false
          node.opened = false
          node.value = 999999
          node.predecessor = nil
        end
      end
      
      def generate_move_route(start_node,end_node)
        #the move_route is an array containing the locations of all nodes
        move_route = [[end_node.x,end_node.y]]
        predecessor = end_node.predecessor
        loop do
          break if predecessor.nil?
          move_route.insert(0,[predecessor.x,predecessor.y])
          predecessor = predecessor.predecessor
          if predecessor == start_node
            break
          end
        end
        return move_route
      end
      
      class Node
        #the coordinates of this node
        attr_reader :x
        attr_reader :y
        #how the movement speed of units at this location is modified
        attr_reader :speed_factor
        #whether the node has been expanded or not
        attr_accessor :closed
        #if the node is in the open_list or not
        attr_accessor :opened
        #an array with all adjacent nodes
        attr_accessor :adjacent_nodes
        #the value of this node. the lower the value the more likely will this node be expanded next
        attr_accessor :value
        #the predecessor of this node in the move_route
        attr_accessor :predecessor
        def initialize(x,y,speed_factor)
          @x = x
          @y = y
          #original speed_factor = 0.0 <= float <= 1.0
          @speed_factor = 1000 - (speed_factor * 1000).to_i
          #new speed_factor = 0 <= int <= 1000
          
          @adjacent_nodes = []
          
          @closed = false
          @opened = false
          @value = 999999
          @predecessor = nil
        end
      end
      
    end
    Ich bedanke mich vielmals für jede Hilfe.

    Geändert von Cornix (28.05.2011 um 18:28 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •