From 7735245b0526184ec791f5cf62e0090f40debf40 Mon Sep 17 00:00:00 2001 From: Fisch Date: Sat, 30 Nov 2024 19:16:24 +0100 Subject: [PATCH] add line to racetrack --- project.godot | 4 + scenes/map_04.tscn | 294 ++++++++++++++++++++++ scenes/menu.tscn | 5 + scripts/line2d_to_collisionpolygon.gd | 131 ++++++++++ sprites/htrohr/ht_rohr.png | Bin 0 -> 604 bytes sprites/htrohr/ht_rohr.png.import | 34 +++ sprites/htrohr/ht_rohr_fitting.png | Bin 0 -> 591 bytes sprites/htrohr/ht_rohr_fitting.png.import | 34 +++ sprites/htrohr/weights.png | Bin 0 -> 1873 bytes sprites/htrohr/weights.png.import | 34 +++ sprites/htrohr/weights.xcf | Bin 0 -> 3072 bytes 11 files changed, 536 insertions(+) create mode 100644 scenes/map_04.tscn create mode 100644 scripts/line2d_to_collisionpolygon.gd create mode 100644 sprites/htrohr/ht_rohr.png create mode 100644 sprites/htrohr/ht_rohr.png.import create mode 100644 sprites/htrohr/ht_rohr_fitting.png create mode 100644 sprites/htrohr/ht_rohr_fitting.png.import create mode 100644 sprites/htrohr/weights.png create mode 100644 sprites/htrohr/weights.png.import create mode 100644 sprites/htrohr/weights.xcf diff --git a/project.godot b/project.godot index 300e742..43cce65 100644 --- a/project.godot +++ b/project.godot @@ -29,3 +29,7 @@ window/stretch/mode="canvas_items" 2d_physics/layer_2="walldetection" 2d_physics/layer_3="Marking" 2d_physics/layer_4="Layer 4" + +[rendering] + +textures/canvas_textures/default_texture_repeat=1 diff --git a/scenes/map_04.tscn b/scenes/map_04.tscn new file mode 100644 index 0000000..b02a6dd --- /dev/null +++ b/scenes/map_04.tscn @@ -0,0 +1,294 @@ +[gd_scene load_steps=17 format=4 uid="uid://dji2ku3464aus"] + +[ext_resource type="Texture2D" uid="uid://bu05e161cb61k" path="res://sprites/background/spritesheet_bg.png" id="1_m3cjb"] +[ext_resource type="TileSet" uid="uid://beswbm12qkkxk" path="res://sprites/spritesheet_road/bg_road.tres" id="2_u1rh5"] +[ext_resource type="TileSet" uid="uid://buu8w8n61kbxf" path="res://sprites/spritesheet_road/markings.tres" id="3_xmt4t"] +[ext_resource type="Texture2D" uid="uid://cvkrjllwsen6r" path="res://sprites/htrohr/ht_rohr.png" id="4_46p8j"] +[ext_resource type="Texture2D" uid="uid://dpuhee0x5ekud" path="res://sprites/background/spritesheet_scenery.png" id="5_unub2"] +[ext_resource type="Script" path="res://scripts/line2d_to_collisionpolygon.gd" id="6_50nf2"] +[ext_resource type="Texture2D" uid="uid://bal4r8rnh38dx" path="res://sprites/htrohr/ht_rohr_fitting.png" id="6_lu60n"] +[ext_resource type="Texture2D" uid="uid://b0h14qq3jgbcw" path="res://sprites/htrohr/weights.png" id="7_7xqft"] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_qbu02"] +texture = ExtResource("1_m3cjb") +texture_region_size = Vector2i(256, 256) +0:0/0 = 0 +1:0/0 = 0 +2:0/0 = 0 +3:0/0 = 0 +4:0/0 = 0 +5:0/0 = 0 +6:0/0 = 0 +7:0/0 = 0 +0:1/0 = 0 +1:1/0 = 0 +2:1/0 = 0 +3:1/0 = 0 +4:1/0 = 0 +5:1/0 = 0 +6:1/0 = 0 +7:1/0 = 0 +0:2/0 = 0 +1:2/0 = 0 +2:2/0 = 0 +3:2/0 = 0 +4:2/0 = 0 +5:2/0 = 0 +6:2/0 = 0 +7:2/0 = 0 +0:3/0 = 0 +1:3/0 = 0 +2:3/0 = 0 +3:3/0 = 0 +4:3/0 = 0 +5:3/0 = 0 +6:3/0 = 0 +7:3/0 = 0 + +[sub_resource type="TileSet" id="TileSet_5knbn"] +tile_size = Vector2i(256, 256) +sources/1 = SubResource("TileSetAtlasSource_qbu02") + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_daqun"] +size = Vector2(23, 222) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_dltky"] +size = Vector2(19, 108) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_uys5r"] +size = Vector2(20, 126) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_82iti"] +size = Vector2(20, 231) + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_hclam"] +texture = ExtResource("5_unub2") +texture_region_size = Vector2i(128, 128) +2:0/0 = 0 +3:0/0 = 0 +6:0/0 = 0 +7:0/0 = 0 +8:0/0 = 0 +9:0/0 = 0 +10:0/0 = 0 +11:0/0 = 0 +12:0/0 = 0 +13:0/0 = 0 +14:0/0 = 0 +15:0/0 = 0 +2:1/0 = 0 +3:1/0 = 0 +6:1/0 = 0 +7:1/0 = 0 +8:1/0 = 0 +9:1/0 = 0 +10:1/0 = 0 +11:1/0 = 0 +12:1/0 = 0 +13:1/0 = 0 +14:1/0 = 0 +15:1/0 = 0 +0:2/0 = 0 +1:2/0 = 0 +2:2/0 = 0 +3:2/0 = 0 +4:2/0 = 0 +5:2/0 = 0 +6:2/0 = 0 +7:2/0 = 0 +8:2/0 = 0 +9:2/0 = 0 +10:2/0 = 0 +11:2/0 = 0 +12:2/0 = 0 +13:2/0 = 0 +14:2/0 = 0 +15:2/0 = 0 +0:3/0 = 0 +1:3/0 = 0 +2:3/0 = 0 +3:3/0 = 0 +4:3/0 = 0 +5:3/0 = 0 +6:3/0 = 0 +7:3/0 = 0 +8:3/0 = 0 +9:3/0 = 0 +10:3/0 = 0 +11:3/0 = 0 +12:3/0 = 0 +13:3/0 = 0 +14:3/0 = 0 +15:3/0 = 0 +0:4/0 = 0 +1:4/0 = 0 +2:4/0 = 0 +3:4/0 = 0 +4:4/0 = 0 +5:4/0 = 0 +6:4/0 = 0 +7:4/0 = 0 +8:4/0 = 0 +9:4/0 = 0 +10:4/0 = 0 +11:4/0 = 0 +12:4/0 = 0 +13:4/0 = 0 +14:4/0 = 0 +15:4/0 = 0 +0:5/0 = 0 +1:5/0 = 0 +2:5/0 = 0 +3:5/0 = 0 +4:5/0 = 0 +5:5/0 = 0 +6:5/0 = 0 +7:5/0 = 0 +8:5/0 = 0 +9:5/0 = 0 +10:5/0 = 0 +11:5/0 = 0 +12:5/0 = 0 +13:5/0 = 0 +14:5/0 = 0 +15:5/0 = 0 +0:6/0 = 0 +1:6/0 = 0 +2:6/0 = 0 +3:6/0 = 0 +4:6/0 = 0 +5:6/0 = 0 +6:6/0 = 0 +7:6/0 = 0 +8:6/0 = 0 +9:6/0 = 0 +10:6/0 = 0 +11:6/0 = 0 +12:6/0 = 0 +13:6/0 = 0 +14:6/0 = 0 +15:6/0 = 0 +0:7/0 = 0 +1:7/0 = 0 +2:7/0 = 0 +3:7/0 = 0 +4:7/0 = 0 +5:7/0 = 0 +6:7/0 = 0 +7:7/0 = 0 +8:7/0 = 0 +9:7/0 = 0 +10:7/0 = 0 +11:7/0 = 0 +12:7/0 = 0 +13:7/0 = 0 +14:7/0 = 0 +15:7/0 = 0 +0:0/size_in_atlas = Vector2i(2, 2) +0:0/0 = 0 +4:0/size_in_atlas = Vector2i(2, 2) +4:0/0 = 0 + +[sub_resource type="TileSet" id="TileSet_s6rw7"] +tile_size = Vector2i(128, 128) +sources/0 = SubResource("TileSetAtlasSource_hclam") + +[node name="Map" type="Node"] + +[node name="Background" type="TileMapLayer" parent="."] +tile_map_data = PackedByteArray("AAD+/wEAAQAAAAAAAAD+/wAAAQAAAAAAAAD+////AQAAAAAAAAD+//7/AQABAAAAAAD///7/AQAAAAAAAAD///3/AQAAAAAAAAAAAP3/AQAAAAAAAAD+//3/AQABAAAAAAABAP3/AQAAAAAAAAACAP3/AQAAAAAAAAADAP3/AQABAAAAAAADAP7/AQAAAAAAAAAEAP7/AQAAAAAAAAACAP7/AQAAAAAAAAABAP7/AQAAAAAAAAAAAP7/AQAAAAAAAAAAAP//AQAAAAAAAAD/////AQAAAAAAAAABAP//AQAAAAAAAAACAP//AQAAAAAAAAADAP//AQAAAAAAAAAEAP//AQAAAAAAAAAEAAAAAQAAAAAAAAADAAAAAQABAAAAAAACAAAAAQAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAD//wAAAQAAAAAAAAD//wEAAQAAAAAAAAAAAAEAAQAAAAAAAAABAAEAAQAAAAAAAAACAAEAAQAAAAAAAAADAAEAAQAAAAAAAAAEAAEAAQABAAAAAAAEAP3/AQABAAAAAAA=") +tile_set = SubResource("TileSet_5knbn") +collision_enabled = false + +[node name="road_bg" type="TileMapLayer" parent="."] +tile_set = ExtResource("2_u1rh5") + +[node name="road_bg2" type="TileMapLayer" parent="."] +tile_set = ExtResource("2_u1rh5") + +[node name="road_bg_fixes" type="TileMapLayer" parent="."] +tile_set = ExtResource("2_u1rh5") + +[node name="markings" type="TileMapLayer" parent="."] +z_index = 1 +tile_map_data = PackedByteArray("AAAAAAAAAQAAAAAAAFAAAP//AQAAAAAAAHA=") +tile_set = ExtResource("3_xmt4t") + +[node name="Line2D" type="Line2D" parent="."] +z_index = 1 +texture_filter = 1 +points = PackedVector2Array(-137, 119, 353, 120, 429, 83, 498, 39, 621, 8, 744, 1, 859, -10, 935, -52, 935, -178, 888, -246, 825, -299, 471, -448, 256, -445, 121, -532, -32, -502, -250, -181, -308, -42, -260, 59, -146, 119, -147, 136) +width = 8.0 +texture = ExtResource("4_46p8j") +texture_mode = 1 +script = ExtResource("6_50nf2") + +[node name="road_r" type="StaticBody2D" parent="Line2D"] +collision_layer = 3 + +[node name="fitting" type="Sprite2D" parent="Line2D"] +texture_filter = 1 +position = Vector2(259, 120) +texture = ExtResource("6_lu60n") + +[node name="weight" type="Sprite2D" parent="Line2D"] +texture = ExtResource("7_7xqft") +region_enabled = true +region_rect = Rect2(32, 0, 32, 32) + +[node name="Line2D2" type="Line2D" parent="."] +z_index = 1 +points = PackedVector2Array(-97, -109, 236, -111, 298, -107, 370, -83, 452, -64, 517, -82, 661, -85, 745, -98, 784, -149, 784, -228, 466, -384, 295, -358, 207, -356, 143, -399, 106, -433, 58, -433, -177, -159, -203, -92, -176, -55, -80, -127) +width = 6.0 +texture = ExtResource("4_46p8j") +texture_mode = 1 +script = ExtResource("6_50nf2") + +[node name="road_l" type="StaticBody2D" parent="Line2D2"] +collision_layer = 3 + +[node name="fitting" type="Sprite2D" parent="Line2D2"] +texture_filter = 1 +position = Vector2(259, 120) +texture = ExtResource("6_lu60n") + +[node name="weight" type="Sprite2D" parent="Line2D2"] +texture = ExtResource("7_7xqft") +region_enabled = true +region_rect = Rect2(32, 0, 32, 32) + +[node name="area_finish" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 4 + +[node name="CollisionShape2D_Fin" type="CollisionShape2D" parent="area_finish"] +position = Vector2(89.5, -1) +shape = SubResource("RectangleShape2D_daqun") + +[node name="area_cp0" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 4 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="area_cp0"] +position = Vector2(536, -25) +shape = SubResource("RectangleShape2D_dltky") + +[node name="area_cp1" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 4 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="area_cp1"] +position = Vector2(364, -411) +shape = SubResource("RectangleShape2D_uys5r") + +[node name="area_cp2" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 4 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="area_cp2"] +position = Vector2(-123, -283) +shape = SubResource("RectangleShape2D_82iti") + +[node name="scenery" type="TileMapLayer" parent="."] +z_index = 20 +tile_set = SubResource("TileSet_s6rw7") diff --git a/scenes/menu.tscn b/scenes/menu.tscn index 470590e..1c264da 100644 --- a/scenes/menu.tscn +++ b/scenes/menu.tscn @@ -127,6 +127,11 @@ layout_mode = 2 toggle_mode = true icon = ExtResource("7_5f67q") +[node name="btn_map_04" type="Button" parent="MenuDisplay/map_container"] +layout_mode = 2 +toggle_mode = true +icon = ExtResource("3_p822h") + [node name="rounds_selection" type="OptionButton" parent="MenuDisplay"] offset_left = 690.0 offset_top = 556.0 diff --git a/scripts/line2d_to_collisionpolygon.gd b/scripts/line2d_to_collisionpolygon.gd new file mode 100644 index 0000000..ed9a8d2 --- /dev/null +++ b/scripts/line2d_to_collisionpolygon.gd @@ -0,0 +1,131 @@ +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 + + +# 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 + + addCaps($fitting) + addWeights($weight,rightborder) + + + + 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) + + + +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() diff --git a/sprites/htrohr/ht_rohr.png b/sprites/htrohr/ht_rohr.png new file mode 100644 index 0000000000000000000000000000000000000000..03fd743f8064aaca44b272d7523d95838f4d5815 GIT binary patch literal 604 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 literal 0 HcmV?d00001