Advertisement
Nozomu57

Robot Detour's wire logic (works 99% of the time)

Jun 3rd, 2023 (edited)
970
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
GDScript 4.79 KB | Gaming | 0 0
  1. # THIS SCRIPT IS JUST FOR EDUCATIONAL PURPOSES
  2. # It does not work in several corner cases,
  3. # but should just give an estimation of how things work.
  4. # Also no data caching, optimizing, etc.
  5. #######################################
  6.  
  7. # Don't forget to set first point in points[] as a charger position, and update last point on Player's movement
  8.  
  9. extends Line2D
  10.  
  11. var PIVOTS = [] # link to real pivot objects, populate on scene load
  12. var PIVOT_POSITIONS = []
  13. var RELATIONS = []
  14.  
  15. enum SIDE {
  16.     LEFT,
  17.     RIGHT,
  18. }
  19.  
  20. func _physics_process(_delta): #or _process for no visual latency
  21.     recalc_relations()
  22.     recalc_snapping()
  23.    
  24.     update_pivot_positions()
  25.     recalc_relations()
  26.    
  27. func update_pivot_positions():
  28.     var NEW_PIVOT_POSITIONS = []
  29.     for i in PIVOTS.size():
  30.         NEW_PIVOT_POSITIONS.push_back(PIVOTS[i].get_global_position())
  31.         if PIVOT_POSITIONS.size() <= i: continue
  32.         for pointIndex in points.size():
  33.             if points[pointIndex] == PIVOT_POSITIONS[i]:
  34.                 set_point_position(pointIndex, NEW_PIVOT_POSITIONS[i])
  35.     PIVOT_POSITIONS = NEW_PIVOT_POSITIONS
  36.  
  37. func recalc_relations():
  38.     var newPoints = []
  39.     for pivotIndex in PIVOT_POSITIONS.size():
  40.         for pointIndex in range(0, get_point_count()-1):
  41.             var newRelation = calculate_relations(
  42.                 PIVOT_POSITIONS[pivotIndex],
  43.                 points[pointIndex],
  44.                 points[pointIndex+1]
  45.                 )
  46.            
  47.             # initial fill array
  48.             if (RELATIONS[pivotIndex].size() < (pointIndex + 1)):
  49.                 RELATIONS[pivotIndex].push_back(newRelation)
  50.             else:      
  51.                 # if snapped to pivot, do nothing
  52.                 if (newRelation.snapStart == true):
  53.                     RELATIONS[pivotIndex][pointIndex].snapStart = true
  54.                     if (newRelation.snapEnd == true):
  55.                         RELATIONS[pivotIndex][pointIndex].snapEnd = true
  56.                     else:
  57.                         RELATIONS[pivotIndex][pointIndex].snapEnd = false
  58.                
  59.                 # if collision, add point.
  60.                 elif (newRelation.side != RELATIONS[pivotIndex][pointIndex].side) and newRelation.inside == true:
  61.                     newPoints.push_back(
  62.                         { "position": PIVOT_POSITIONS[pivotIndex],
  63.                         "segmentIndex": pointIndex,
  64.                         "pivotIndex": pivotIndex}
  65.                     )
  66.                 # else just update state
  67.                 else:
  68.                     RELATIONS[pivotIndex][pointIndex] = newRelation
  69.     add_points(newPoints)
  70.  
  71.  
  72. func calculate_relations(point: Vector2, start: Vector2, end: Vector2):
  73.     var relations = {"side": SIDE.LEFT, "inside": false, "snapStart": false, "snapEnd": false}
  74.     if point == start or point == end:
  75.         relations.snapStart = true
  76.         if point == end:
  77.             relations.snapEnd = true
  78.         return relations
  79.        
  80.     var segment = end-start
  81.     var fromStart = point-start
  82.     var fromEnd = point-end
  83.    
  84.     var newSide = sign(segment.cross(fromStart))
  85.     if newSide == 1:
  86.         relations.side = SIDE.RIGHT
  87.    
  88.     #check if both angles are acute
  89.     if (segment.dot(fromStart) > 0 and segment.dot(fromEnd) < 0):
  90.         relations.inside = true
  91.        
  92.     return relations
  93.  
  94. func recalc_snapping():
  95.     var deletePoints = []
  96.     for pivotRelations in RELATIONS:
  97.         for segmentIndex in pivotRelations.size() - 1:
  98.             if pivotRelations[segmentIndex].snapEnd == true:
  99.                 if should_unsnap(pivotRelations[segmentIndex + 1], segmentIndex):
  100.                     deletePoints.push_back(segmentIndex)
  101.  
  102.     if (deletePoints.size()>0): remove_points(deletePoints)
  103.  
  104.                
  105. func should_unsnap(point, segmentIndex):
  106.     if (segmentIndex + 2 >= points.size()): return false
  107.     var first = points[segmentIndex+1] - points[segmentIndex]
  108.     var second = points[segmentIndex+2] - points[segmentIndex+1]
  109.     var turn = sign(first.cross(second))
  110.     if ((point.side == SIDE.LEFT and turn > 0) or (point.side == SIDE.RIGHT and turn < 0)):
  111.         return true
  112.     return false
  113.    
  114.  
  115. func add_points(pointsArray):
  116.     pointsArray = sort_points_by_distance(pointsArray)
  117.     for newPointIndex in pointsArray.size():
  118.         add_point(pointsArray[newPointIndex].position, pointsArray[newPointIndex].segmentIndex + 1)
  119.         for i in RELATIONS.size():
  120.             var newRelation = RELATIONS[i][pointsArray[newPointIndex].segmentIndex].duplicate()
  121.             RELATIONS[i].insert(pointsArray[newPointIndex].segmentIndex + 1, newRelation)
  122.            
  123. func remove_points(pointsIndexArray):
  124.     pointsIndexArray.sort()
  125.     pointsIndexArray.reverse()
  126.     for p in pointsIndexArray:
  127.         remove_point(p + 1)
  128.         for i in RELATIONS.size():
  129.             var deletedRelation = RELATIONS[i][p + 1].duplicate()
  130.             RELATIONS[i].remove_at(p + 1)
  131.            
  132.             if (RELATIONS[i][p].snapStart == false):
  133.                 var newRelation = calculate_relations(
  134.                     PIVOT_POSITIONS[i],
  135.                     points[p],
  136.                     points[p+1])
  137.                 RELATIONS[i][p] = newRelation
  138.            
  139.             elif RELATIONS[i][p].snapEnd:
  140.                 RELATIONS[i][p].side = deletedRelation.side
  141.  
  142. func sort_points_by_distance(newPoints: Array):
  143.     newPoints.sort_custom(func(a, b):
  144.         if a.segmentIndex == b.segmentIndex:
  145.             var start = points[a.segmentIndex]
  146.             return (a.position-start).length() > (b.position-start).length()
  147.         else:
  148.             return a.segmentIndex > b.segmentIndex         
  149.     )
  150.     return newPoints
  151.    
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement