211 lines
6.3 KiB
GDScript
211 lines
6.3 KiB
GDScript
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)<cos(deg_to_rad(maxsmoothangle)):
|
|
pointarray.append(panchor)
|
|
return
|
|
|
|
var rlast=min(r,lenlast/3.0)
|
|
var rnext=min(r,lennext/3.0)
|
|
|
|
if r<=minr:
|
|
pointarray.append(panchor)
|
|
return
|
|
|
|
var cornerpointlast=panchor+dirlast*rlast
|
|
var cornerpointnext=panchor+dirnext*rnext
|
|
|
|
smoothSegment(pointarray,plast,cornerpointlast,cornerpointnext,rlast/3.0,minr,maxsmoothangle)
|
|
|
|
smoothSegment(pointarray,cornerpointlast,cornerpointnext,pnext,rnext/3.0,minr,maxsmoothangle)
|
|
|
|
func addTrim(trim:Line2D,rightborder:bool) -> 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()
|