teststrecke-game/scripts/roadborder.gd
2024-12-27 14:39:31 +01:00

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()