Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # THIS SCRIPT IS JUST FOR EDUCATIONAL PURPOSES
- # It does not work in several corner cases,
- # but should just give an estimation of how things work.
- # Also no data caching, optimizing, etc.
- #######################################
- # Don't forget to set first point in points[] as a charger position, and update last point on Player's movement
- extends Line2D
- var PIVOTS = [] # link to real pivot objects, populate on scene load
- var PIVOT_POSITIONS = []
- var RELATIONS = []
- enum SIDE {
- LEFT,
- RIGHT,
- }
- func _physics_process(_delta): #or _process for no visual latency
- recalc_relations()
- recalc_snapping()
- update_pivot_positions()
- recalc_relations()
- func update_pivot_positions():
- var NEW_PIVOT_POSITIONS = []
- for i in PIVOTS.size():
- NEW_PIVOT_POSITIONS.push_back(PIVOTS[i].get_global_position())
- if PIVOT_POSITIONS.size() <= i: continue
- for pointIndex in points.size():
- if points[pointIndex] == PIVOT_POSITIONS[i]:
- set_point_position(pointIndex, NEW_PIVOT_POSITIONS[i])
- PIVOT_POSITIONS = NEW_PIVOT_POSITIONS
- func recalc_relations():
- var newPoints = []
- for pivotIndex in PIVOT_POSITIONS.size():
- for pointIndex in range(0, get_point_count()-1):
- var newRelation = calculate_relations(
- PIVOT_POSITIONS[pivotIndex],
- points[pointIndex],
- points[pointIndex+1]
- )
- # initial fill array
- if (RELATIONS[pivotIndex].size() < (pointIndex + 1)):
- RELATIONS[pivotIndex].push_back(newRelation)
- else:
- # if snapped to pivot, do nothing
- if (newRelation.snapStart == true):
- RELATIONS[pivotIndex][pointIndex].snapStart = true
- if (newRelation.snapEnd == true):
- RELATIONS[pivotIndex][pointIndex].snapEnd = true
- else:
- RELATIONS[pivotIndex][pointIndex].snapEnd = false
- # if collision, add point.
- elif (newRelation.side != RELATIONS[pivotIndex][pointIndex].side) and newRelation.inside == true:
- newPoints.push_back(
- { "position": PIVOT_POSITIONS[pivotIndex],
- "segmentIndex": pointIndex,
- "pivotIndex": pivotIndex}
- )
- # else just update state
- else:
- RELATIONS[pivotIndex][pointIndex] = newRelation
- add_points(newPoints)
- func calculate_relations(point: Vector2, start: Vector2, end: Vector2):
- var relations = {"side": SIDE.LEFT, "inside": false, "snapStart": false, "snapEnd": false}
- if point == start or point == end:
- relations.snapStart = true
- if point == end:
- relations.snapEnd = true
- return relations
- var segment = end-start
- var fromStart = point-start
- var fromEnd = point-end
- var newSide = sign(segment.cross(fromStart))
- if newSide == 1:
- relations.side = SIDE.RIGHT
- #check if both angles are acute
- if (segment.dot(fromStart) > 0 and segment.dot(fromEnd) < 0):
- relations.inside = true
- return relations
- func recalc_snapping():
- var deletePoints = []
- for pivotRelations in RELATIONS:
- for segmentIndex in pivotRelations.size() - 1:
- if pivotRelations[segmentIndex].snapEnd == true:
- if should_unsnap(pivotRelations[segmentIndex + 1], segmentIndex):
- deletePoints.push_back(segmentIndex)
- if (deletePoints.size()>0): remove_points(deletePoints)
- func should_unsnap(point, segmentIndex):
- if (segmentIndex + 2 >= points.size()): return false
- var first = points[segmentIndex+1] - points[segmentIndex]
- var second = points[segmentIndex+2] - points[segmentIndex+1]
- var turn = sign(first.cross(second))
- if ((point.side == SIDE.LEFT and turn > 0) or (point.side == SIDE.RIGHT and turn < 0)):
- return true
- return false
- func add_points(pointsArray):
- pointsArray = sort_points_by_distance(pointsArray)
- for newPointIndex in pointsArray.size():
- add_point(pointsArray[newPointIndex].position, pointsArray[newPointIndex].segmentIndex + 1)
- for i in RELATIONS.size():
- var newRelation = RELATIONS[i][pointsArray[newPointIndex].segmentIndex].duplicate()
- RELATIONS[i].insert(pointsArray[newPointIndex].segmentIndex + 1, newRelation)
- func remove_points(pointsIndexArray):
- pointsIndexArray.sort()
- pointsIndexArray.reverse()
- for p in pointsIndexArray:
- remove_point(p + 1)
- for i in RELATIONS.size():
- var deletedRelation = RELATIONS[i][p + 1].duplicate()
- RELATIONS[i].remove_at(p + 1)
- if (RELATIONS[i][p].snapStart == false):
- var newRelation = calculate_relations(
- PIVOT_POSITIONS[i],
- points[p],
- points[p+1])
- RELATIONS[i][p] = newRelation
- elif RELATIONS[i][p].snapEnd:
- RELATIONS[i][p].side = deletedRelation.side
- func sort_points_by_distance(newPoints: Array):
- newPoints.sort_custom(func(a, b):
- if a.segmentIndex == b.segmentIndex:
- var start = points[a.segmentIndex]
- return (a.position-start).length() > (b.position-start).length()
- else:
- return a.segmentIndex > b.segmentIndex
- )
- return newPoints
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement