extends Line2D const END_FITTING_DISTANCE=1 #fitting distance from end of pipe const CORNER_FITTING_DISTANCE=4 #fitting of last pipe before a corner piece const CORNER_NEXT_FITTING_DISTANCE=8 #fitting after corner const PIPE_MAX_LENGTH=2*55 #1m=55,172px const WEIGHT_DISTANCE_FROM_PIPE=9 const WEIGHT_RANDOM_OFFSET=0 const WEIGHT_DISTANCE_MIN=0.5*55 const WEIGHT_DISTANCE_MAX=4*55 const MIN_WEIGHT_DISTANCE_FROM_CORNER=20 #Smoothing Parameters @export var smoothingradius=32 @export var minsmoothingsradius=8 @export var maxsmoothangle=175 #degrees # Called when the node enters the scene tree for the first time. func _ready() -> void: #var staticbody=get_child(0) #get road collision object (StaticBody2D) var rightborder=true var staticbody:StaticBody2D=$road_r if staticbody==null: staticbody=$road_l rightborder=false #is left border if points.size()<2: print("Not enough points") return if smoothingradius>0: points=smoothLine(points) # Add Visual extras addCaps($fitting) addWeights($weight,rightborder) addTrim($trim,rightborder) # Create Collision Polygon var line_poly=Geometry2D.offset_polyline(points,width/2) for poly in line_poly: var col = CollisionPolygon2D.new() col.polygon=poly staticbody.add_child(col) ''' var vcol = Polygon2D.new() vcol.polygon=poly staticbody.add_child(vcol) ''' func smoothLine(points:PackedVector2Array) -> PackedVector2Array: print("Running Smooth Line") var newpoints:PackedVector2Array var lastlastpoint=null var lastpoint=null var pointscopy=points.duplicate() if closed: pointscopy.append(points[0]) #when closes, add first point to array to smooth the last before last corner for p in pointscopy: if lastlastpoint==null and lastpoint!=null: #p is 2nd point, lastpoint is first point newpoints.append(lastpoint) #add first point if lastlastpoint!=null: # around lastpoint two points exist smoothSegment(newpoints,lastlastpoint,lastpoint,p,smoothingradius,minsmoothingsradius,maxsmoothangle) lastlastpoint=lastpoint lastpoint=p if not closed: newpoints.append(points[-1]) #add last point print( "From numpoints="+str(points.size())+" to "+str(newpoints.size())+" (+"+str(newpoints.size()-points.size())+")"+" ="+str(newpoints.size()/points.size()*100.0)+"%") return newpoints func smoothSegment(pointarray:PackedVector2Array,plast,panchor,pnext,r,minr,maxsmoothangle): var dirlast=(plast-panchor).normalized() var lenlast=(plast-panchor).length() var dirnext=(pnext-panchor).normalized() var lennext=(pnext-panchor).length() if dirlast.dot(dirnext) void: if trim==null: return trim.points=points trim.closed=closed if rightborder: #mirror texture to be inside of road var textureimg:Image=trim.texture.get_image() textureimg.flip_y() trim.texture=ImageTexture.create_from_image(textureimg) func addCaps(fitting:Sprite2D) -> void: if fitting==null: return var lastp:Vector2 var skipfirst=true for p:Vector2 in points: if skipfirst: lastp=p skipfirst=false continue #skip first var line_angle=(p-lastp).angle() #print("Point="+str(p)+" lastp="+str(lastp)) #Add end fitting var fitting_distance_from_end=CORNER_FITTING_DISTANCE if points.find(p)==points.size()-1: fitting_distance_from_end=END_FITTING_DISTANCE var line_end_fitting_point=p + (lastp-p).normalized()*fitting_distance_from_end var newfitting:Sprite2D=fitting.duplicate() newfitting.transform=Transform2D(line_angle,line_end_fitting_point) add_child(newfitting) #Add corner fitting (beginning of pipe) if points.find(lastp)!=0: #if this pipe segment is not the first var line_corner_fitting_point=lastp + (p-lastp).normalized()*CORNER_NEXT_FITTING_DISTANCE var newcornerfitting:Sprite2D=fitting.duplicate() newcornerfitting.transform=Transform2D(line_angle,line_corner_fitting_point) add_child(newcornerfitting) #add intermediate fittings while (p-lastp).length()>PIPE_MAX_LENGTH: var line_end_intfitting_point=lastp + (p-lastp).normalized()*PIPE_MAX_LENGTH lastp=line_end_intfitting_point #update var newintfitting:Sprite2D=fitting.duplicate() newintfitting.transform=Transform2D(line_angle,line_end_intfitting_point) add_child(newintfitting) lastp=p fitting.queue_free() #remote original fitting func addWeights(weight:Sprite2D,rightborder:bool) -> void: if weight==null: return print("Add weights, rightboarder="+str(rightborder)) var lengthWithoutSupport=0 var lastp:Vector2 var skipfirst=true for p:Vector2 in points: if skipfirst: lastp=p skipfirst=false continue #skip first var line_angle=(p-lastp).angle() lengthWithoutSupport+=(p-lastp).length() while lengthWithoutSupport>WEIGHT_DISTANCE_MAX: var line_weight_point=lastp + (p-lastp).normalized()*min(randf_range(WEIGHT_DISTANCE_MIN,WEIGHT_DISTANCE_MAX),(p-lastp).length()-MIN_WEIGHT_DISTANCE_FROM_CORNER) var newweight:Sprite2D=weight.duplicate() if newweight.region_enabled: var countTextures=newweight.texture.get_size().x/newweight.region_rect.size.x print("countTextures="+str(countTextures)) newweight.region_rect.position.x=newweight.region_rect.size.x*randi_range(0,countTextures-1) print(" using pos="+str(newweight.region_rect.position)) newweight.transform=Transform2D(0,line_weight_point+(Vector2.ONE*WEIGHT_DISTANCE_FROM_PIPE).rotated(line_angle+(90 if rightborder else -90))+Vector2(randf_range(-WEIGHT_RANDOM_OFFSET,WEIGHT_RANDOM_OFFSET),randf_range(-WEIGHT_RANDOM_OFFSET,WEIGHT_RANDOM_OFFSET))) if rad_to_deg(line_angle)<-90 or rad_to_deg(line_angle)>90: newweight.z_index=-1 #put behind else: newweight.z_index=1 #put in front if not rightborder: newweight.z_index*=-1 #flip for other side add_child(newweight) lastp=line_weight_point #update lengthWithoutSupport=(p-lastp).length() lastp=p weight.queue_free()