├── .gitignore ├── README.md ├── assets ├── characters │ ├── enemy │ │ ├── enemy.png │ │ └── enemy.png.import │ └── player │ │ ├── player.png │ │ └── player.png.import ├── door.png ├── door.png.import ├── fonts │ ├── vonwaon_bitmap-12px.ttf │ └── vonwaon_bitmap-12px.ttf.import ├── shadow.png ├── shadow.png.import ├── tile_sets │ ├── door_scene.gd │ ├── door_scene.gd.uid │ ├── door_scene.tscn │ ├── fence.png │ ├── fence.png.import │ ├── house.png │ ├── house.png.import │ ├── stone.png │ ├── stone.png.import │ ├── stone_scene.tscn │ ├── tile_set.png │ ├── tile_set.png.import │ ├── tile_set.tres │ ├── tile_set_floor.png │ ├── tile_set_floor.png.import │ ├── tile_set_grass.png │ └── tile_set_grass.png.import └── trees │ ├── tree.png │ └── tree.png.import ├── global ├── global.gd └── global.gd.uid ├── icon.svg ├── icon.svg.import ├── modules ├── enemy.gd ├── enemy.gd.uid ├── enemy.tscn ├── player.gd ├── player.gd.uid └── player.tscn ├── project.godot ├── scenes ├── main_scene.gd ├── main_scene.gd.uid └── main_scene.tscn ├── scripts ├── astar_agent.gd ├── astar_agent.gd.uid ├── auto_tile.gd ├── auto_tile.gd.uid ├── block_data.gd ├── block_data.gd.uid ├── block_node.gd ├── block_node.gd.uid ├── main_camera.gd ├── main_camera.gd.uid ├── map_loader.gd ├── map_loader.gd.uid ├── tile_detector.gd └── tile_detector.gd.uid └── shaders ├── character.gdshader ├── character.gdshader.uid ├── door_focus.gdshader ├── door_focus.gdshader.uid ├── sway.gdshader └── sway.gdshader.uid /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | 4 | # Godot-specific ignores 5 | .import/ 6 | export.cfg 7 | export_presets.cfg 8 | 9 | # Imported translations (automatically generated from CSV files) 10 | *.translation 11 | 12 | # Mono-specific ignores 13 | .mono/ 14 | data_*/ 15 | mono_crash.*.json 16 | 17 | .DS_Store 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sandbox 2 | 适用于2d沙盒游戏的演示,拥有程序化地图生成,无限地图,导航,和保存 3 | ### 注意事项 4 | 此项目仅支持4.3及以上版本,本人使用4.4开发,你可以使用4.3打开,后续Godot的新版本也会进行更新 5 | -------------------------------------------------------------------------------- /assets/characters/enemy/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/characters/enemy/enemy.png -------------------------------------------------------------------------------- /assets/characters/enemy/enemy.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://chxs84wgtxo56" 6 | path="res://.godot/imported/enemy.png-41baf4ebb9557959d604eaec935ddc25.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/characters/enemy/enemy.png" 14 | dest_files=["res://.godot/imported/enemy.png-41baf4ebb9557959d604eaec935ddc25.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/characters/player/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/characters/player/player.png -------------------------------------------------------------------------------- /assets/characters/player/player.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://djfsbbaouh6vm" 6 | path="res://.godot/imported/player.png-928f4d30a37c774758bcb01de07ddedf.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/characters/player/player.png" 14 | dest_files=["res://.godot/imported/player.png-928f4d30a37c774758bcb01de07ddedf.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/door.png -------------------------------------------------------------------------------- /assets/door.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bv8ixoao5sas" 6 | path="res://.godot/imported/door.png-b71998044d513d047c9b0091ee4a07ff.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/door.png" 14 | dest_files=["res://.godot/imported/door.png-b71998044d513d047c9b0091ee4a07ff.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/fonts/vonwaon_bitmap-12px.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/fonts/vonwaon_bitmap-12px.ttf -------------------------------------------------------------------------------- /assets/fonts/vonwaon_bitmap-12px.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://dti01c1qmahf1" 6 | path="res://.godot/imported/vonwaon_bitmap-12px.ttf-a36088d64cd457fda9d8056e3a0e9cf6.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/vonwaon_bitmap-12px.ttf" 11 | dest_files=["res://.godot/imported/vonwaon_bitmap-12px.ttf-a36088d64cd457fda9d8056e3a0e9cf6.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=0 17 | generate_mipmaps=false 18 | disable_embedded_bitmaps=true 19 | multichannel_signed_distance_field=true 20 | msdf_pixel_range=8 21 | msdf_size=48 22 | allow_system_fallback=true 23 | force_autohinter=false 24 | hinting=1 25 | subpixel_positioning=1 26 | keep_rounding_remainders=true 27 | oversampling=0.0 28 | Fallbacks=null 29 | fallbacks=[] 30 | Compress=null 31 | compress=true 32 | preload=[{ 33 | "chars": [], 34 | "glyphs": [], 35 | "name": "新建配置", 36 | "size": Vector2i(16, 0), 37 | "variation_embolden": 0.0 38 | }] 39 | language_support={} 40 | script_support={} 41 | opentype_features={} 42 | -------------------------------------------------------------------------------- /assets/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/shadow.png -------------------------------------------------------------------------------- /assets/shadow.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://fibedao7oqot" 6 | path="res://.godot/imported/shadow.png-fa649b8bf20b5924dee4fa3287dfd1b8.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/shadow.png" 14 | dest_files=["res://.godot/imported/shadow.png-fa649b8bf20b5924dee4fa3287dfd1b8.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/tile_sets/door_scene.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - DOOR SCENE 5 | # - 6 | # - 门场景,它会被添加到TileSet中, 7 | # - 在打开门时,它会将所在的瓷砖注册为障碍物, 8 | # - 反之则取消注册 9 | # - 10 | # ================================================ 11 | 12 | class_name DoorScene 13 | extends StaticBody2D 14 | 15 | @onready var _collision :CollisionShape2D = $CollisionShape2D 16 | @onready var _door :Sprite2D = $Door 17 | @onready var _shader :ShaderMaterial = $Door.material 18 | @onready var _astar_agent :AStarAgent = $AStarAgent 19 | 20 | @export var _open_door_height := 32.0 21 | 22 | # 是否打开门,会更新障碍物注册状态 23 | var _open := false : 24 | 25 | set(new_value): 26 | _open = new_value 27 | # 打开门时禁用碰撞反之启用 28 | _collision.disabled = _open 29 | # 打开门时注销障碍物,反之注册 30 | _astar_agent.register_obstacle = not _open 31 | 32 | var _player :Player 33 | 34 | func _process(delta: float) -> void: 35 | 36 | # 按照打开或关闭设置门精灵的高度 37 | _door.position.y = move_toward(_door.position.y,-_open_door_height if _open else 0.0,100.0*delta) 38 | 39 | # 如果玩家在附近设置交互文本 40 | if is_instance_valid(_player): 41 | _player.set_interaction_text("关闭门" if _open else "打开门") 42 | 43 | # 交互 44 | func _interaction() -> void: 45 | _open = not _open 46 | 47 | # 玩家进入门的交互区域 48 | func _on_body_entered(body:Node2D) -> void: 49 | 50 | if body is Player: 51 | _shader.set_shader_parameter("focus",1.0) 52 | _player = body 53 | _player.interaction.connect(_interaction) 54 | 55 | # 玩家退出门的交互区域 56 | func _on_body_exited(body:Node2D) -> void: 57 | 58 | if body is Player: 59 | _shader.set_shader_parameter("focus",0.0) 60 | _player.set_interaction_text("") 61 | _player.interaction.disconnect(_interaction) 62 | _player = null 63 | -------------------------------------------------------------------------------- /assets/tile_sets/door_scene.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bounymcxe3lm4 2 | -------------------------------------------------------------------------------- /assets/tile_sets/door_scene.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=3 uid="uid://d2wkyy0nje3q1"] 2 | 3 | [ext_resource type="Script" uid="uid://bounymcxe3lm4" path="res://assets/tile_sets/door_scene.gd" id="1_36xr3"] 4 | [ext_resource type="Texture2D" uid="uid://bv8ixoao5sas" path="res://assets/door.png" id="1_hpnnb"] 5 | [ext_resource type="Shader" uid="uid://cdybycue1n2cj" path="res://shaders/door_focus.gdshader" id="2_073di"] 6 | [ext_resource type="Script" uid="uid://cdghfj5qq5q3o" path="res://scripts/astar_agent.gd" id="4_k51fu"] 7 | 8 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_nfmdl"] 9 | resource_local_to_scene = true 10 | shader = ExtResource("2_073di") 11 | shader_parameter/focus = 0.0 12 | 13 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_6h2yr"] 14 | size = Vector2(16, 4) 15 | 16 | [sub_resource type="CircleShape2D" id="CircleShape2D_vwo6y"] 17 | radius = 30.0 18 | 19 | [node name="DoorScene" type="StaticBody2D"] 20 | collision_layer = 4 21 | collision_mask = 3 22 | script = ExtResource("1_36xr3") 23 | 24 | [node name="Door" type="Sprite2D" parent="."] 25 | texture_filter = 1 26 | material = SubResource("ShaderMaterial_nfmdl") 27 | texture = ExtResource("1_hpnnb") 28 | offset = Vector2(0, -16) 29 | 30 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 31 | shape = SubResource("RectangleShape2D_6h2yr") 32 | 33 | [node name="Area2D" type="Area2D" parent="."] 34 | collision_layer = 0 35 | 36 | [node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] 37 | shape = SubResource("CircleShape2D_vwo6y") 38 | 39 | [node name="AStarAgent" type="Node2D" parent="."] 40 | script = ExtResource("4_k51fu") 41 | _mode = 1 42 | coordinates = Array[Vector2i]([Vector2i(0, 0)]) 43 | 44 | [connection signal="body_entered" from="Area2D" to="." method="_on_body_entered"] 45 | [connection signal="body_exited" from="Area2D" to="." method="_on_body_exited"] 46 | -------------------------------------------------------------------------------- /assets/tile_sets/fence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/tile_sets/fence.png -------------------------------------------------------------------------------- /assets/tile_sets/fence.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cp1idcnps7vet" 6 | path="res://.godot/imported/fence.png-6d42bd6b75de58db4c56d5da30b2ef7c.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/tile_sets/fence.png" 14 | dest_files=["res://.godot/imported/fence.png-6d42bd6b75de58db4c56d5da30b2ef7c.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/tile_sets/house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/tile_sets/house.png -------------------------------------------------------------------------------- /assets/tile_sets/house.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bpskp8j4yrc76" 6 | path="res://.godot/imported/house.png-6f9e3531467a1157b5a00383e0a7a2c1.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/tile_sets/house.png" 14 | dest_files=["res://.godot/imported/house.png-6f9e3531467a1157b5a00383e0a7a2c1.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/tile_sets/stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/tile_sets/stone.png -------------------------------------------------------------------------------- /assets/tile_sets/stone.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cwivpgsvtynip" 6 | path="res://.godot/imported/stone.png-e7f70404dc42f517293d420a3a947397.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/tile_sets/stone.png" 14 | dest_files=["res://.godot/imported/stone.png-e7f70404dc42f517293d420a3a947397.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/tile_sets/stone_scene.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://b3wbbi8chmxre"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://cwivpgsvtynip" path="res://assets/tile_sets/stone.png" id="1_34fnn"] 4 | [ext_resource type="Script" uid="uid://cdghfj5qq5q3o" path="res://scripts/astar_agent.gd" id="2_pnwpi"] 5 | 6 | [sub_resource type="CircleShape2D" id="CircleShape2D_k7ewq"] 7 | radius = 8.0 8 | 9 | [sub_resource type="CircleShape2D" id="CircleShape2D_ma8yo"] 10 | 11 | [node name="StoneScene" type="StaticBody2D"] 12 | texture_filter = 1 13 | collision_layer = 4 14 | collision_mask = 3 15 | 16 | [node name="Stone" type="Sprite2D" parent="."] 17 | position = Vector2(0, -1.84) 18 | texture = ExtResource("1_34fnn") 19 | 20 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 21 | position = Vector2(0, 3.26) 22 | shape = SubResource("CircleShape2D_k7ewq") 23 | 24 | [node name="AStarAgent" type="Node2D" parent="."] 25 | script = ExtResource("2_pnwpi") 26 | shape = SubResource("CircleShape2D_ma8yo") 27 | -------------------------------------------------------------------------------- /assets/tile_sets/tile_set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/tile_sets/tile_set.png -------------------------------------------------------------------------------- /assets/tile_sets/tile_set.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c2ke48iwerkrg" 6 | path="res://.godot/imported/tile_set.png-f3624ed1fd15456a00ad3dda57fac4ee.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/tile_sets/tile_set.png" 14 | dest_files=["res://.godot/imported/tile_set.png-f3624ed1fd15456a00ad3dda57fac4ee.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/tile_sets/tile_set.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="TileSet" load_steps=19 format=3 uid="uid://dy1nypwbt8mye"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://c2ke48iwerkrg" path="res://assets/tile_sets/tile_set.png" id="1_ruds0"] 4 | [ext_resource type="PackedScene" uid="uid://b3wbbi8chmxre" path="res://assets/tile_sets/stone_scene.tscn" id="2_pd1k1"] 5 | [ext_resource type="Shader" uid="uid://cm0sy5la8j5md" path="res://shaders/sway.gdshader" id="3_mqjx0"] 6 | [ext_resource type="Texture2D" uid="uid://unn5ptujnbw5" path="res://assets/trees/tree.png" id="4_a880d"] 7 | [ext_resource type="PackedScene" uid="uid://d2wkyy0nje3q1" path="res://assets/tile_sets/door_scene.tscn" id="4_gg5sm"] 8 | [ext_resource type="Texture2D" uid="uid://cp1idcnps7vet" path="res://assets/tile_sets/fence.png" id="5_rlseo"] 9 | [ext_resource type="Texture2D" uid="uid://bpskp8j4yrc76" path="res://assets/tile_sets/house.png" id="6_rgdkk"] 10 | 11 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_0flk2"] 12 | shader = ExtResource("3_mqjx0") 13 | shader_parameter/range = 1.5 14 | shader_parameter/speed = 1.0 15 | 16 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_6fm7e"] 17 | shader = ExtResource("3_mqjx0") 18 | shader_parameter/range = 1.8 19 | shader_parameter/speed = 0.9 20 | 21 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_ukhf3"] 22 | shader = ExtResource("3_mqjx0") 23 | shader_parameter/range = 1.6 24 | shader_parameter/speed = 0.9 25 | 26 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_y5xdi"] 27 | shader = ExtResource("3_mqjx0") 28 | shader_parameter/range = 2.2 29 | shader_parameter/speed = 1.2 30 | 31 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_it2i8"] 32 | texture = ExtResource("1_ruds0") 33 | 0:0/0 = 0 34 | 0:0/0/custom_data_0 = 1 35 | 1:0/0 = 0 36 | 1:0/0/terrain_set = 0 37 | 1:0/0/terrain = 0 38 | 1:0/0/terrains_peering_bit/right_side = 0 39 | 1:0/0/terrains_peering_bit/bottom_right_corner = 0 40 | 1:0/0/terrains_peering_bit/bottom_side = 0 41 | 1:0/0/custom_data_0 = 2 42 | 2:0/0 = 0 43 | 2:0/0/terrain_set = 0 44 | 2:0/0/terrain = 0 45 | 2:0/0/terrains_peering_bit/right_side = 0 46 | 2:0/0/terrains_peering_bit/bottom_right_corner = 0 47 | 2:0/0/terrains_peering_bit/bottom_side = 0 48 | 2:0/0/terrains_peering_bit/bottom_left_corner = 0 49 | 2:0/0/terrains_peering_bit/left_side = 0 50 | 2:0/0/custom_data_0 = 2 51 | 3:0/0 = 0 52 | 3:0/0/terrain_set = 0 53 | 3:0/0/terrain = 0 54 | 3:0/0/terrains_peering_bit/bottom_side = 0 55 | 3:0/0/terrains_peering_bit/bottom_left_corner = 0 56 | 3:0/0/terrains_peering_bit/left_side = 0 57 | 3:0/0/custom_data_0 = 2 58 | 4:0/0 = 0 59 | 4:0/0/terrain_set = 0 60 | 4:0/0/terrain = 0 61 | 4:0/0/terrains_peering_bit/bottom_side = 0 62 | 4:0/0/custom_data_0 = 2 63 | 5:0/0 = 0 64 | 5:0/0/terrain_set = 0 65 | 5:0/0/terrain = 0 66 | 5:0/0/terrains_peering_bit/right_side = 0 67 | 5:0/0/terrains_peering_bit/bottom_side = 0 68 | 5:0/0/custom_data_0 = 2 69 | 6:0/0 = 0 70 | 6:0/0/terrain_set = 0 71 | 6:0/0/terrain = 0 72 | 6:0/0/terrains_peering_bit/right_side = 0 73 | 6:0/0/terrains_peering_bit/bottom_side = 0 74 | 6:0/0/terrains_peering_bit/bottom_left_corner = 0 75 | 6:0/0/terrains_peering_bit/left_side = 0 76 | 6:0/0/custom_data_0 = 2 77 | 7:0/0 = 0 78 | 7:0/0/terrain_set = 0 79 | 7:0/0/terrain = 0 80 | 7:0/0/terrains_peering_bit/right_side = 0 81 | 7:0/0/terrains_peering_bit/bottom_right_corner = 0 82 | 7:0/0/terrains_peering_bit/bottom_side = 0 83 | 7:0/0/terrains_peering_bit/left_side = 0 84 | 7:0/0/custom_data_0 = 2 85 | 8:0/0 = 0 86 | 8:0/0/terrain_set = 0 87 | 8:0/0/terrain = 0 88 | 8:0/0/terrains_peering_bit/bottom_side = 0 89 | 8:0/0/terrains_peering_bit/left_side = 0 90 | 8:0/0/custom_data_0 = 2 91 | 9:0/0 = 0 92 | 9:0/0/terrain_set = 0 93 | 9:0/0/terrain = 0 94 | 9:0/0/terrains_peering_bit/right_side = 0 95 | 9:0/0/terrains_peering_bit/bottom_side = 0 96 | 9:0/0/terrains_peering_bit/left_side = 0 97 | 9:0/0/custom_data_0 = 2 98 | 10:0/0 = 0 99 | 10:0/0/terrain_set = 0 100 | 10:0/0/terrain = 0 101 | 10:0/0/terrains_peering_bit/right_side = 0 102 | 10:0/0/terrains_peering_bit/bottom_right_corner = 0 103 | 10:0/0/terrains_peering_bit/bottom_side = 0 104 | 10:0/0/terrains_peering_bit/left_side = 0 105 | 10:0/0/terrains_peering_bit/top_left_corner = 0 106 | 10:0/0/terrains_peering_bit/top_side = 0 107 | 10:0/0/custom_data_0 = 2 108 | 13:0/0 = 0 109 | 13:0/0/terrain_set = 0 110 | 13:0/0/terrain = 1 111 | 13:0/0/terrains_peering_bit/right_side = 1 112 | 13:0/0/terrains_peering_bit/bottom_right_corner = 1 113 | 13:0/0/terrains_peering_bit/bottom_side = 1 114 | 13:0/0/custom_data_0 = 3 115 | 14:0/0 = 0 116 | 14:0/0/terrain_set = 0 117 | 14:0/0/terrain = 1 118 | 14:0/0/terrains_peering_bit/right_side = 1 119 | 14:0/0/terrains_peering_bit/bottom_right_corner = 1 120 | 14:0/0/terrains_peering_bit/bottom_side = 1 121 | 14:0/0/terrains_peering_bit/bottom_left_corner = 1 122 | 14:0/0/terrains_peering_bit/left_side = 1 123 | 14:0/0/custom_data_0 = 3 124 | 15:0/0 = 0 125 | 15:0/0/terrain_set = 0 126 | 15:0/0/terrain = 1 127 | 15:0/0/terrains_peering_bit/bottom_side = 1 128 | 15:0/0/terrains_peering_bit/bottom_left_corner = 1 129 | 15:0/0/terrains_peering_bit/left_side = 1 130 | 15:0/0/custom_data_0 = 3 131 | 16:0/0 = 0 132 | 16:0/0/terrain_set = 0 133 | 16:0/0/terrain = 1 134 | 16:0/0/terrains_peering_bit/bottom_side = 1 135 | 16:0/0/custom_data_0 = 3 136 | 17:0/0 = 0 137 | 17:0/0/terrain_set = 0 138 | 17:0/0/terrain = 1 139 | 17:0/0/terrains_peering_bit/right_side = 1 140 | 17:0/0/terrains_peering_bit/bottom_side = 1 141 | 17:0/0/custom_data_0 = 3 142 | 18:0/0 = 0 143 | 18:0/0/terrain_set = 0 144 | 18:0/0/terrain = 1 145 | 18:0/0/terrains_peering_bit/right_side = 1 146 | 18:0/0/terrains_peering_bit/bottom_side = 1 147 | 18:0/0/terrains_peering_bit/bottom_left_corner = 1 148 | 18:0/0/terrains_peering_bit/left_side = 1 149 | 18:0/0/custom_data_0 = 3 150 | 19:0/0 = 0 151 | 19:0/0/terrain_set = 0 152 | 19:0/0/terrain = 1 153 | 19:0/0/terrains_peering_bit/right_side = 1 154 | 19:0/0/terrains_peering_bit/bottom_right_corner = 1 155 | 19:0/0/terrains_peering_bit/bottom_side = 1 156 | 19:0/0/terrains_peering_bit/left_side = 1 157 | 19:0/0/custom_data_0 = 3 158 | 20:0/0 = 0 159 | 20:0/0/terrain_set = 0 160 | 20:0/0/terrain = 1 161 | 20:0/0/terrains_peering_bit/bottom_side = 1 162 | 20:0/0/terrains_peering_bit/left_side = 1 163 | 20:0/0/custom_data_0 = 3 164 | 21:0/0 = 0 165 | 21:0/0/terrain_set = 0 166 | 21:0/0/terrain = 1 167 | 21:0/0/terrains_peering_bit/right_side = 1 168 | 21:0/0/terrains_peering_bit/bottom_side = 1 169 | 21:0/0/terrains_peering_bit/left_side = 1 170 | 21:0/0/custom_data_0 = 3 171 | 22:0/0 = 0 172 | 22:0/0/terrain_set = 0 173 | 22:0/0/terrain = 1 174 | 22:0/0/terrains_peering_bit/right_side = 1 175 | 22:0/0/terrains_peering_bit/bottom_right_corner = 1 176 | 22:0/0/terrains_peering_bit/bottom_side = 1 177 | 22:0/0/terrains_peering_bit/left_side = 1 178 | 22:0/0/terrains_peering_bit/top_left_corner = 1 179 | 22:0/0/terrains_peering_bit/top_side = 1 180 | 22:0/0/custom_data_0 = 3 181 | 1:1/0 = 0 182 | 1:1/0/terrain_set = 0 183 | 1:1/0/terrain = 0 184 | 1:1/0/terrains_peering_bit/right_side = 0 185 | 1:1/0/terrains_peering_bit/bottom_right_corner = 0 186 | 1:1/0/terrains_peering_bit/bottom_side = 0 187 | 1:1/0/terrains_peering_bit/top_side = 0 188 | 1:1/0/terrains_peering_bit/top_right_corner = 0 189 | 1:1/0/custom_data_0 = 2 190 | 2:1/0 = 0 191 | 2:1/0/terrain_set = 0 192 | 2:1/0/terrain = 0 193 | 2:1/0/terrains_peering_bit/right_side = 0 194 | 2:1/0/terrains_peering_bit/bottom_right_corner = 0 195 | 2:1/0/terrains_peering_bit/bottom_side = 0 196 | 2:1/0/terrains_peering_bit/bottom_left_corner = 0 197 | 2:1/0/terrains_peering_bit/left_side = 0 198 | 2:1/0/terrains_peering_bit/top_left_corner = 0 199 | 2:1/0/terrains_peering_bit/top_side = 0 200 | 2:1/0/terrains_peering_bit/top_right_corner = 0 201 | 2:1/0/custom_data_0 = 2 202 | 3:1/0 = 0 203 | 3:1/0/terrain_set = 0 204 | 3:1/0/terrain = 0 205 | 3:1/0/terrains_peering_bit/bottom_side = 0 206 | 3:1/0/terrains_peering_bit/bottom_left_corner = 0 207 | 3:1/0/terrains_peering_bit/left_side = 0 208 | 3:1/0/terrains_peering_bit/top_left_corner = 0 209 | 3:1/0/terrains_peering_bit/top_side = 0 210 | 3:1/0/custom_data_0 = 2 211 | 4:1/0 = 0 212 | 4:1/0/terrain_set = 0 213 | 4:1/0/terrain = 0 214 | 4:1/0/terrains_peering_bit/bottom_side = 0 215 | 4:1/0/terrains_peering_bit/top_side = 0 216 | 4:1/0/custom_data_0 = 2 217 | 5:1/0 = 0 218 | 5:1/0/terrain_set = 0 219 | 5:1/0/terrain = 0 220 | 5:1/0/terrains_peering_bit/right_side = 0 221 | 5:1/0/terrains_peering_bit/bottom_side = 0 222 | 5:1/0/terrains_peering_bit/top_side = 0 223 | 5:1/0/terrains_peering_bit/top_right_corner = 0 224 | 5:1/0/custom_data_0 = 2 225 | 6:1/0 = 0 226 | 6:1/0/terrain_set = 0 227 | 6:1/0/terrain = 0 228 | 6:1/0/terrains_peering_bit/right_side = 0 229 | 6:1/0/terrains_peering_bit/bottom_side = 0 230 | 6:1/0/terrains_peering_bit/bottom_left_corner = 0 231 | 6:1/0/terrains_peering_bit/left_side = 0 232 | 6:1/0/terrains_peering_bit/top_left_corner = 0 233 | 6:1/0/terrains_peering_bit/top_side = 0 234 | 6:1/0/terrains_peering_bit/top_right_corner = 0 235 | 6:1/0/custom_data_0 = 2 236 | 7:1/0 = 0 237 | 7:1/0/terrain_set = 0 238 | 7:1/0/terrain = 0 239 | 7:1/0/terrains_peering_bit/right_side = 0 240 | 7:1/0/terrains_peering_bit/bottom_right_corner = 0 241 | 7:1/0/terrains_peering_bit/bottom_side = 0 242 | 7:1/0/terrains_peering_bit/left_side = 0 243 | 7:1/0/terrains_peering_bit/top_left_corner = 0 244 | 7:1/0/terrains_peering_bit/top_side = 0 245 | 7:1/0/terrains_peering_bit/top_right_corner = 0 246 | 7:1/0/custom_data_0 = 2 247 | 8:1/0 = 0 248 | 8:1/0/terrain_set = 0 249 | 8:1/0/terrain = 0 250 | 8:1/0/terrains_peering_bit/bottom_side = 0 251 | 8:1/0/terrains_peering_bit/left_side = 0 252 | 8:1/0/terrains_peering_bit/top_left_corner = 0 253 | 8:1/0/terrains_peering_bit/top_side = 0 254 | 8:1/0/custom_data_0 = 2 255 | 9:1/0 = 0 256 | 9:1/0/terrain_set = 0 257 | 9:1/0/terrain = 0 258 | 9:1/0/terrains_peering_bit/right_side = 0 259 | 9:1/0/terrains_peering_bit/bottom_side = 0 260 | 9:1/0/terrains_peering_bit/left_side = 0 261 | 9:1/0/terrains_peering_bit/top_left_corner = 0 262 | 9:1/0/terrains_peering_bit/top_side = 0 263 | 9:1/0/terrains_peering_bit/top_right_corner = 0 264 | 9:1/0/custom_data_0 = 2 265 | 10:1/0 = 0 266 | 10:1/0/terrain_set = 0 267 | 10:1/0/terrain = 0 268 | 10:1/0/terrains_peering_bit/right_side = 0 269 | 10:1/0/terrains_peering_bit/bottom_side = 0 270 | 10:1/0/terrains_peering_bit/bottom_left_corner = 0 271 | 10:1/0/terrains_peering_bit/left_side = 0 272 | 10:1/0/terrains_peering_bit/top_side = 0 273 | 10:1/0/terrains_peering_bit/top_right_corner = 0 274 | 10:1/0/custom_data_0 = 2 275 | 13:1/0 = 0 276 | 13:1/0/terrain_set = 0 277 | 13:1/0/terrain = 1 278 | 13:1/0/terrains_peering_bit/right_side = 1 279 | 13:1/0/terrains_peering_bit/bottom_right_corner = 1 280 | 13:1/0/terrains_peering_bit/bottom_side = 1 281 | 13:1/0/terrains_peering_bit/top_side = 1 282 | 13:1/0/terrains_peering_bit/top_right_corner = 1 283 | 13:1/0/custom_data_0 = 3 284 | 14:1/0 = 0 285 | 14:1/0/terrain_set = 0 286 | 14:1/0/terrain = 1 287 | 14:1/0/terrains_peering_bit/right_side = 1 288 | 14:1/0/terrains_peering_bit/bottom_right_corner = 1 289 | 14:1/0/terrains_peering_bit/bottom_side = 1 290 | 14:1/0/terrains_peering_bit/bottom_left_corner = 1 291 | 14:1/0/terrains_peering_bit/left_side = 1 292 | 14:1/0/terrains_peering_bit/top_left_corner = 1 293 | 14:1/0/terrains_peering_bit/top_side = 1 294 | 14:1/0/terrains_peering_bit/top_right_corner = 1 295 | 14:1/0/custom_data_0 = 3 296 | 15:1/0 = 0 297 | 15:1/0/terrain_set = 0 298 | 15:1/0/terrain = 1 299 | 15:1/0/terrains_peering_bit/bottom_side = 1 300 | 15:1/0/terrains_peering_bit/bottom_left_corner = 1 301 | 15:1/0/terrains_peering_bit/left_side = 1 302 | 15:1/0/terrains_peering_bit/top_left_corner = 1 303 | 15:1/0/terrains_peering_bit/top_side = 1 304 | 15:1/0/custom_data_0 = 3 305 | 16:1/0 = 0 306 | 16:1/0/terrain_set = 0 307 | 16:1/0/terrain = 1 308 | 16:1/0/terrains_peering_bit/bottom_side = 1 309 | 16:1/0/terrains_peering_bit/top_side = 1 310 | 16:1/0/custom_data_0 = 3 311 | 17:1/0 = 0 312 | 17:1/0/terrain_set = 0 313 | 17:1/0/terrain = 1 314 | 17:1/0/terrains_peering_bit/right_side = 1 315 | 17:1/0/terrains_peering_bit/bottom_side = 1 316 | 17:1/0/terrains_peering_bit/top_side = 1 317 | 17:1/0/terrains_peering_bit/top_right_corner = 1 318 | 17:1/0/custom_data_0 = 3 319 | 18:1/0 = 0 320 | 18:1/0/terrain_set = 0 321 | 18:1/0/terrain = 1 322 | 18:1/0/terrains_peering_bit/right_side = 1 323 | 18:1/0/terrains_peering_bit/bottom_side = 1 324 | 18:1/0/terrains_peering_bit/bottom_left_corner = 1 325 | 18:1/0/terrains_peering_bit/left_side = 1 326 | 18:1/0/terrains_peering_bit/top_left_corner = 1 327 | 18:1/0/terrains_peering_bit/top_side = 1 328 | 18:1/0/terrains_peering_bit/top_right_corner = 1 329 | 18:1/0/custom_data_0 = 3 330 | 19:1/0 = 0 331 | 19:1/0/terrain_set = 0 332 | 19:1/0/terrain = 1 333 | 19:1/0/terrains_peering_bit/right_side = 1 334 | 19:1/0/terrains_peering_bit/bottom_right_corner = 1 335 | 19:1/0/terrains_peering_bit/bottom_side = 1 336 | 19:1/0/terrains_peering_bit/left_side = 1 337 | 19:1/0/terrains_peering_bit/top_left_corner = 1 338 | 19:1/0/terrains_peering_bit/top_side = 1 339 | 19:1/0/terrains_peering_bit/top_right_corner = 1 340 | 19:1/0/custom_data_0 = 3 341 | 20:1/0 = 0 342 | 20:1/0/terrain_set = 0 343 | 20:1/0/terrain = 1 344 | 20:1/0/terrains_peering_bit/bottom_side = 1 345 | 20:1/0/terrains_peering_bit/left_side = 1 346 | 20:1/0/terrains_peering_bit/top_left_corner = 1 347 | 20:1/0/terrains_peering_bit/top_side = 1 348 | 20:1/0/custom_data_0 = 3 349 | 21:1/0 = 0 350 | 21:1/0/terrain_set = 0 351 | 21:1/0/terrain = 1 352 | 21:1/0/terrains_peering_bit/right_side = 1 353 | 21:1/0/terrains_peering_bit/bottom_side = 1 354 | 21:1/0/terrains_peering_bit/left_side = 1 355 | 21:1/0/terrains_peering_bit/top_left_corner = 1 356 | 21:1/0/terrains_peering_bit/top_side = 1 357 | 21:1/0/terrains_peering_bit/top_right_corner = 1 358 | 21:1/0/custom_data_0 = 3 359 | 22:1/0 = 0 360 | 22:1/0/terrain_set = 0 361 | 22:1/0/terrain = 1 362 | 22:1/0/terrains_peering_bit/right_side = 1 363 | 22:1/0/terrains_peering_bit/bottom_side = 1 364 | 22:1/0/terrains_peering_bit/bottom_left_corner = 1 365 | 22:1/0/terrains_peering_bit/left_side = 1 366 | 22:1/0/terrains_peering_bit/top_side = 1 367 | 22:1/0/terrains_peering_bit/top_right_corner = 1 368 | 22:1/0/custom_data_0 = 3 369 | 1:2/0 = 0 370 | 1:2/0/terrain_set = 0 371 | 1:2/0/terrain = 0 372 | 1:2/0/terrains_peering_bit/right_side = 0 373 | 1:2/0/terrains_peering_bit/top_side = 0 374 | 1:2/0/terrains_peering_bit/top_right_corner = 0 375 | 1:2/0/custom_data_0 = 2 376 | 2:2/0 = 0 377 | 2:2/0/terrain_set = 0 378 | 2:2/0/terrain = 0 379 | 2:2/0/terrains_peering_bit/right_side = 0 380 | 2:2/0/terrains_peering_bit/left_side = 0 381 | 2:2/0/terrains_peering_bit/top_left_corner = 0 382 | 2:2/0/terrains_peering_bit/top_side = 0 383 | 2:2/0/terrains_peering_bit/top_right_corner = 0 384 | 2:2/0/custom_data_0 = 2 385 | 3:2/0 = 0 386 | 3:2/0/terrain_set = 0 387 | 3:2/0/terrain = 0 388 | 3:2/0/terrains_peering_bit/left_side = 0 389 | 3:2/0/terrains_peering_bit/top_left_corner = 0 390 | 3:2/0/terrains_peering_bit/top_side = 0 391 | 3:2/0/custom_data_0 = 2 392 | 4:2/0 = 0 393 | 4:2/0/terrain_set = 0 394 | 4:2/0/terrain = 0 395 | 4:2/0/terrains_peering_bit/top_side = 0 396 | 4:2/0/custom_data_0 = 2 397 | 5:2/0 = 0 398 | 5:2/0/terrain_set = 0 399 | 5:2/0/terrain = 0 400 | 5:2/0/terrains_peering_bit/right_side = 0 401 | 5:2/0/terrains_peering_bit/bottom_right_corner = 0 402 | 5:2/0/terrains_peering_bit/bottom_side = 0 403 | 5:2/0/terrains_peering_bit/top_side = 0 404 | 5:2/0/custom_data_0 = 2 405 | 6:2/0 = 0 406 | 6:2/0/terrain_set = 0 407 | 6:2/0/terrain = 0 408 | 6:2/0/terrains_peering_bit/right_side = 0 409 | 6:2/0/terrains_peering_bit/bottom_right_corner = 0 410 | 6:2/0/terrains_peering_bit/bottom_side = 0 411 | 6:2/0/terrains_peering_bit/bottom_left_corner = 0 412 | 6:2/0/terrains_peering_bit/left_side = 0 413 | 6:2/0/terrains_peering_bit/top_left_corner = 0 414 | 6:2/0/terrains_peering_bit/top_side = 0 415 | 6:2/0/custom_data_0 = 2 416 | 7:2/0 = 0 417 | 7:2/0/terrain_set = 0 418 | 7:2/0/terrain = 0 419 | 7:2/0/terrains_peering_bit/right_side = 0 420 | 7:2/0/terrains_peering_bit/bottom_right_corner = 0 421 | 7:2/0/terrains_peering_bit/bottom_side = 0 422 | 7:2/0/terrains_peering_bit/bottom_left_corner = 0 423 | 7:2/0/terrains_peering_bit/left_side = 0 424 | 7:2/0/terrains_peering_bit/top_side = 0 425 | 7:2/0/terrains_peering_bit/top_right_corner = 0 426 | 7:2/0/custom_data_0 = 2 427 | 8:2/0 = 0 428 | 8:2/0/terrain_set = 0 429 | 8:2/0/terrain = 0 430 | 8:2/0/terrains_peering_bit/bottom_side = 0 431 | 8:2/0/terrains_peering_bit/bottom_left_corner = 0 432 | 8:2/0/terrains_peering_bit/left_side = 0 433 | 8:2/0/terrains_peering_bit/top_side = 0 434 | 8:2/0/custom_data_0 = 2 435 | 9:2/0 = 0 436 | 9:2/0/terrain_set = 0 437 | 9:2/0/terrain = 0 438 | 9:2/0/terrains_peering_bit/right_side = 0 439 | 9:2/0/terrains_peering_bit/bottom_right_corner = 0 440 | 9:2/0/terrains_peering_bit/bottom_side = 0 441 | 9:2/0/terrains_peering_bit/bottom_left_corner = 0 442 | 9:2/0/terrains_peering_bit/left_side = 0 443 | 9:2/0/terrains_peering_bit/top_side = 0 444 | 9:2/0/custom_data_0 = 2 445 | 10:2/0 = 0 446 | 10:2/0/terrain_set = 0 447 | 10:2/0/terrain = 0 448 | 10:2/0/terrains_peering_bit/right_side = 0 449 | 10:2/0/terrains_peering_bit/bottom_right_corner = 0 450 | 10:2/0/terrains_peering_bit/bottom_side = 0 451 | 10:2/0/terrains_peering_bit/left_side = 0 452 | 10:2/0/terrains_peering_bit/top_side = 0 453 | 10:2/0/custom_data_0 = 2 454 | 11:2/0 = 0 455 | 11:2/0/terrain_set = 0 456 | 11:2/0/terrain = 0 457 | 11:2/0/terrains_peering_bit/right_side = 0 458 | 11:2/0/terrains_peering_bit/bottom_side = 0 459 | 11:2/0/terrains_peering_bit/bottom_left_corner = 0 460 | 11:2/0/terrains_peering_bit/left_side = 0 461 | 11:2/0/terrains_peering_bit/top_side = 0 462 | 11:2/0/custom_data_0 = 2 463 | 13:2/0 = 0 464 | 13:2/0/terrain_set = 0 465 | 13:2/0/terrain = 1 466 | 13:2/0/terrains_peering_bit/right_side = 1 467 | 13:2/0/terrains_peering_bit/top_side = 1 468 | 13:2/0/terrains_peering_bit/top_right_corner = 1 469 | 13:2/0/custom_data_0 = 3 470 | 14:2/0 = 0 471 | 14:2/0/terrain_set = 0 472 | 14:2/0/terrain = 1 473 | 14:2/0/terrains_peering_bit/right_side = 1 474 | 14:2/0/terrains_peering_bit/left_side = 1 475 | 14:2/0/terrains_peering_bit/top_left_corner = 1 476 | 14:2/0/terrains_peering_bit/top_side = 1 477 | 14:2/0/terrains_peering_bit/top_right_corner = 1 478 | 14:2/0/custom_data_0 = 3 479 | 15:2/0 = 0 480 | 15:2/0/terrain_set = 0 481 | 15:2/0/terrain = 1 482 | 15:2/0/terrains_peering_bit/left_side = 1 483 | 15:2/0/terrains_peering_bit/top_left_corner = 1 484 | 15:2/0/terrains_peering_bit/top_side = 1 485 | 15:2/0/custom_data_0 = 3 486 | 16:2/0 = 0 487 | 16:2/0/terrain_set = 0 488 | 16:2/0/terrain = 1 489 | 16:2/0/terrains_peering_bit/top_side = 1 490 | 16:2/0/custom_data_0 = 3 491 | 17:2/0 = 0 492 | 17:2/0/terrain_set = 0 493 | 17:2/0/terrain = 1 494 | 17:2/0/terrains_peering_bit/right_side = 1 495 | 17:2/0/terrains_peering_bit/bottom_right_corner = 1 496 | 17:2/0/terrains_peering_bit/bottom_side = 1 497 | 17:2/0/terrains_peering_bit/top_side = 1 498 | 17:2/0/custom_data_0 = 3 499 | 18:2/0 = 0 500 | 18:2/0/terrain_set = 0 501 | 18:2/0/terrain = 1 502 | 18:2/0/terrains_peering_bit/right_side = 1 503 | 18:2/0/terrains_peering_bit/bottom_right_corner = 1 504 | 18:2/0/terrains_peering_bit/bottom_side = 1 505 | 18:2/0/terrains_peering_bit/bottom_left_corner = 1 506 | 18:2/0/terrains_peering_bit/left_side = 1 507 | 18:2/0/terrains_peering_bit/top_left_corner = 1 508 | 18:2/0/terrains_peering_bit/top_side = 1 509 | 18:2/0/custom_data_0 = 3 510 | 19:2/0 = 0 511 | 19:2/0/terrain_set = 0 512 | 19:2/0/terrain = 1 513 | 19:2/0/terrains_peering_bit/right_side = 1 514 | 19:2/0/terrains_peering_bit/bottom_right_corner = 1 515 | 19:2/0/terrains_peering_bit/bottom_side = 1 516 | 19:2/0/terrains_peering_bit/bottom_left_corner = 1 517 | 19:2/0/terrains_peering_bit/left_side = 1 518 | 19:2/0/terrains_peering_bit/top_side = 1 519 | 19:2/0/terrains_peering_bit/top_right_corner = 1 520 | 19:2/0/custom_data_0 = 3 521 | 20:2/0 = 0 522 | 20:2/0/terrain_set = 0 523 | 20:2/0/terrain = 1 524 | 20:2/0/terrains_peering_bit/bottom_side = 1 525 | 20:2/0/terrains_peering_bit/bottom_left_corner = 1 526 | 20:2/0/terrains_peering_bit/left_side = 1 527 | 20:2/0/terrains_peering_bit/top_side = 1 528 | 20:2/0/custom_data_0 = 3 529 | 21:2/0 = 0 530 | 21:2/0/terrain_set = 0 531 | 21:2/0/terrain = 1 532 | 21:2/0/terrains_peering_bit/right_side = 1 533 | 21:2/0/terrains_peering_bit/bottom_right_corner = 1 534 | 21:2/0/terrains_peering_bit/bottom_side = 1 535 | 21:2/0/terrains_peering_bit/bottom_left_corner = 1 536 | 21:2/0/terrains_peering_bit/left_side = 1 537 | 21:2/0/terrains_peering_bit/top_side = 1 538 | 21:2/0/custom_data_0 = 3 539 | 22:2/0 = 0 540 | 22:2/0/terrain_set = 0 541 | 22:2/0/terrain = 1 542 | 22:2/0/terrains_peering_bit/right_side = 1 543 | 22:2/0/terrains_peering_bit/bottom_right_corner = 1 544 | 22:2/0/terrains_peering_bit/bottom_side = 1 545 | 22:2/0/terrains_peering_bit/left_side = 1 546 | 22:2/0/terrains_peering_bit/top_side = 1 547 | 22:2/0/custom_data_0 = 3 548 | 23:2/0 = 0 549 | 23:2/0/terrain_set = 0 550 | 23:2/0/terrain = 1 551 | 23:2/0/terrains_peering_bit/right_side = 1 552 | 23:2/0/terrains_peering_bit/bottom_side = 1 553 | 23:2/0/terrains_peering_bit/bottom_left_corner = 1 554 | 23:2/0/terrains_peering_bit/left_side = 1 555 | 23:2/0/terrains_peering_bit/top_side = 1 556 | 23:2/0/custom_data_0 = 3 557 | 1:3/0 = 0 558 | 1:3/0/terrain_set = 0 559 | 1:3/0/terrain = 0 560 | 1:3/0/terrains_peering_bit/right_side = 0 561 | 1:3/0/custom_data_0 = 2 562 | 2:3/0 = 0 563 | 2:3/0/terrain_set = 0 564 | 2:3/0/terrain = 0 565 | 2:3/0/terrains_peering_bit/right_side = 0 566 | 2:3/0/terrains_peering_bit/left_side = 0 567 | 2:3/0/custom_data_0 = 2 568 | 3:3/0 = 0 569 | 3:3/0/terrain_set = 0 570 | 3:3/0/terrain = 0 571 | 3:3/0/terrains_peering_bit/left_side = 0 572 | 3:3/0/custom_data_0 = 2 573 | 4:3/0 = 0 574 | 4:3/0/terrain_set = 0 575 | 4:3/0/terrain = 0 576 | 4:3/0/custom_data_0 = 2 577 | 5:3/0 = 0 578 | 5:3/0/terrain_set = 0 579 | 5:3/0/terrain = 0 580 | 5:3/0/terrains_peering_bit/right_side = 0 581 | 5:3/0/terrains_peering_bit/top_side = 0 582 | 5:3/0/custom_data_0 = 2 583 | 6:3/0 = 0 584 | 6:3/0/terrain_set = 0 585 | 6:3/0/terrain = 0 586 | 6:3/0/terrains_peering_bit/right_side = 0 587 | 6:3/0/terrains_peering_bit/left_side = 0 588 | 6:3/0/terrains_peering_bit/top_left_corner = 0 589 | 6:3/0/terrains_peering_bit/top_side = 0 590 | 6:3/0/custom_data_0 = 2 591 | 7:3/0 = 0 592 | 7:3/0/terrain_set = 0 593 | 7:3/0/terrain = 0 594 | 7:3/0/terrains_peering_bit/right_side = 0 595 | 7:3/0/terrains_peering_bit/left_side = 0 596 | 7:3/0/terrains_peering_bit/top_side = 0 597 | 7:3/0/terrains_peering_bit/top_right_corner = 0 598 | 7:3/0/custom_data_0 = 2 599 | 8:3/0 = 0 600 | 8:3/0/terrain_set = 0 601 | 8:3/0/terrain = 0 602 | 8:3/0/terrains_peering_bit/left_side = 0 603 | 8:3/0/terrains_peering_bit/top_side = 0 604 | 8:3/0/custom_data_0 = 2 605 | 9:3/0 = 0 606 | 9:3/0/terrain_set = 0 607 | 9:3/0/terrain = 0 608 | 9:3/0/terrains_peering_bit/right_side = 0 609 | 9:3/0/terrains_peering_bit/left_side = 0 610 | 9:3/0/terrains_peering_bit/top_side = 0 611 | 9:3/0/custom_data_0 = 2 612 | 10:3/0 = 0 613 | 10:3/0/terrain_set = 0 614 | 10:3/0/terrain = 0 615 | 10:3/0/terrains_peering_bit/right_side = 0 616 | 10:3/0/terrains_peering_bit/bottom_side = 0 617 | 10:3/0/terrains_peering_bit/left_side = 0 618 | 10:3/0/terrains_peering_bit/top_side = 0 619 | 10:3/0/terrains_peering_bit/top_right_corner = 0 620 | 10:3/0/custom_data_0 = 2 621 | 11:3/0 = 0 622 | 11:3/0/terrain_set = 0 623 | 11:3/0/terrain = 0 624 | 11:3/0/terrains_peering_bit/right_side = 0 625 | 11:3/0/terrains_peering_bit/bottom_side = 0 626 | 11:3/0/terrains_peering_bit/left_side = 0 627 | 11:3/0/terrains_peering_bit/top_left_corner = 0 628 | 11:3/0/terrains_peering_bit/top_side = 0 629 | 11:3/0/custom_data_0 = 2 630 | 13:3/0 = 0 631 | 13:3/0/terrain_set = 0 632 | 13:3/0/terrain = 1 633 | 13:3/0/terrains_peering_bit/right_side = 1 634 | 13:3/0/custom_data_0 = 3 635 | 14:3/0 = 0 636 | 14:3/0/terrain_set = 0 637 | 14:3/0/terrain = 1 638 | 14:3/0/terrains_peering_bit/right_side = 1 639 | 14:3/0/terrains_peering_bit/left_side = 1 640 | 14:3/0/custom_data_0 = 3 641 | 15:3/0 = 0 642 | 15:3/0/terrain_set = 0 643 | 15:3/0/terrain = 1 644 | 15:3/0/terrains_peering_bit/left_side = 1 645 | 15:3/0/custom_data_0 = 3 646 | 16:3/0 = 0 647 | 16:3/0/terrain_set = 0 648 | 16:3/0/terrain = 1 649 | 16:3/0/custom_data_0 = 3 650 | 17:3/0 = 0 651 | 17:3/0/terrain_set = 0 652 | 17:3/0/terrain = 1 653 | 17:3/0/terrains_peering_bit/right_side = 1 654 | 17:3/0/terrains_peering_bit/top_side = 1 655 | 17:3/0/custom_data_0 = 3 656 | 18:3/0 = 0 657 | 18:3/0/terrain_set = 0 658 | 18:3/0/terrain = 1 659 | 18:3/0/terrains_peering_bit/right_side = 1 660 | 18:3/0/terrains_peering_bit/left_side = 1 661 | 18:3/0/terrains_peering_bit/top_left_corner = 1 662 | 18:3/0/terrains_peering_bit/top_side = 1 663 | 18:3/0/custom_data_0 = 3 664 | 19:3/0 = 0 665 | 19:3/0/terrain_set = 0 666 | 19:3/0/terrain = 1 667 | 19:3/0/terrains_peering_bit/right_side = 1 668 | 19:3/0/terrains_peering_bit/left_side = 1 669 | 19:3/0/terrains_peering_bit/top_side = 1 670 | 19:3/0/terrains_peering_bit/top_right_corner = 1 671 | 19:3/0/custom_data_0 = 3 672 | 20:3/0 = 0 673 | 20:3/0/terrain_set = 0 674 | 20:3/0/terrain = 1 675 | 20:3/0/terrains_peering_bit/left_side = 1 676 | 20:3/0/terrains_peering_bit/top_side = 1 677 | 20:3/0/custom_data_0 = 3 678 | 21:3/0 = 0 679 | 21:3/0/terrain_set = 0 680 | 21:3/0/terrain = 1 681 | 21:3/0/terrains_peering_bit/right_side = 1 682 | 21:3/0/terrains_peering_bit/left_side = 1 683 | 21:3/0/terrains_peering_bit/top_side = 1 684 | 21:3/0/custom_data_0 = 3 685 | 22:3/0 = 0 686 | 22:3/0/terrain_set = 0 687 | 22:3/0/terrain = 1 688 | 22:3/0/terrains_peering_bit/right_side = 1 689 | 22:3/0/terrains_peering_bit/bottom_side = 1 690 | 22:3/0/terrains_peering_bit/left_side = 1 691 | 22:3/0/terrains_peering_bit/top_side = 1 692 | 22:3/0/terrains_peering_bit/top_right_corner = 1 693 | 22:3/0/custom_data_0 = 3 694 | 23:3/0 = 0 695 | 23:3/0/terrain_set = 0 696 | 23:3/0/terrain = 1 697 | 23:3/0/terrains_peering_bit/right_side = 1 698 | 23:3/0/terrains_peering_bit/bottom_side = 1 699 | 23:3/0/terrains_peering_bit/left_side = 1 700 | 23:3/0/terrains_peering_bit/top_left_corner = 1 701 | 23:3/0/terrains_peering_bit/top_side = 1 702 | 23:3/0/custom_data_0 = 3 703 | 5:4/0 = 0 704 | 5:4/0/terrain_set = 0 705 | 5:4/0/terrain = 0 706 | 5:4/0/terrains_peering_bit/right_side = 0 707 | 5:4/0/terrains_peering_bit/bottom_side = 0 708 | 5:4/0/terrains_peering_bit/top_side = 0 709 | 5:4/0/custom_data_0 = 2 710 | 6:4/0 = 0 711 | 6:4/0/terrain_set = 0 712 | 6:4/0/terrain = 0 713 | 6:4/0/terrains_peering_bit/right_side = 0 714 | 6:4/0/terrains_peering_bit/bottom_side = 0 715 | 6:4/0/terrains_peering_bit/bottom_left_corner = 0 716 | 6:4/0/terrains_peering_bit/left_side = 0 717 | 6:4/0/terrains_peering_bit/top_left_corner = 0 718 | 6:4/0/terrains_peering_bit/top_side = 0 719 | 6:4/0/custom_data_0 = 2 720 | 7:4/0 = 0 721 | 7:4/0/terrain_set = 0 722 | 7:4/0/terrain = 0 723 | 7:4/0/terrains_peering_bit/right_side = 0 724 | 7:4/0/terrains_peering_bit/bottom_right_corner = 0 725 | 7:4/0/terrains_peering_bit/bottom_side = 0 726 | 7:4/0/terrains_peering_bit/left_side = 0 727 | 7:4/0/terrains_peering_bit/top_side = 0 728 | 7:4/0/terrains_peering_bit/top_right_corner = 0 729 | 7:4/0/custom_data_0 = 2 730 | 8:4/0 = 0 731 | 8:4/0/terrain_set = 0 732 | 8:4/0/terrain = 0 733 | 8:4/0/terrains_peering_bit/bottom_side = 0 734 | 8:4/0/terrains_peering_bit/left_side = 0 735 | 8:4/0/terrains_peering_bit/top_side = 0 736 | 8:4/0/custom_data_0 = 2 737 | 9:4/0 = 0 738 | 9:4/0/terrain_set = 0 739 | 9:4/0/terrain = 0 740 | 9:4/0/terrains_peering_bit/right_side = 0 741 | 9:4/0/terrains_peering_bit/bottom_side = 0 742 | 9:4/0/terrains_peering_bit/left_side = 0 743 | 9:4/0/terrains_peering_bit/top_side = 0 744 | 9:4/0/custom_data_0 = 2 745 | 17:4/0 = 0 746 | 17:4/0/terrain_set = 0 747 | 17:4/0/terrain = 1 748 | 17:4/0/terrains_peering_bit/right_side = 1 749 | 17:4/0/terrains_peering_bit/bottom_side = 1 750 | 17:4/0/terrains_peering_bit/top_side = 1 751 | 17:4/0/custom_data_0 = 3 752 | 18:4/0 = 0 753 | 18:4/0/terrain_set = 0 754 | 18:4/0/terrain = 1 755 | 18:4/0/terrains_peering_bit/right_side = 1 756 | 18:4/0/terrains_peering_bit/bottom_side = 1 757 | 18:4/0/terrains_peering_bit/bottom_left_corner = 1 758 | 18:4/0/terrains_peering_bit/left_side = 1 759 | 18:4/0/terrains_peering_bit/top_left_corner = 1 760 | 18:4/0/terrains_peering_bit/top_side = 1 761 | 18:4/0/custom_data_0 = 3 762 | 19:4/0 = 0 763 | 19:4/0/terrain_set = 0 764 | 19:4/0/terrain = 1 765 | 19:4/0/terrains_peering_bit/right_side = 1 766 | 19:4/0/terrains_peering_bit/bottom_right_corner = 1 767 | 19:4/0/terrains_peering_bit/bottom_side = 1 768 | 19:4/0/terrains_peering_bit/left_side = 1 769 | 19:4/0/terrains_peering_bit/top_side = 1 770 | 19:4/0/terrains_peering_bit/top_right_corner = 1 771 | 19:4/0/custom_data_0 = 3 772 | 20:4/0 = 0 773 | 20:4/0/terrain_set = 0 774 | 20:4/0/terrain = 1 775 | 20:4/0/terrains_peering_bit/bottom_side = 1 776 | 20:4/0/terrains_peering_bit/left_side = 1 777 | 20:4/0/terrains_peering_bit/top_side = 1 778 | 20:4/0/custom_data_0 = 3 779 | 21:4/0 = 0 780 | 21:4/0/terrain_set = 0 781 | 21:4/0/terrain = 1 782 | 21:4/0/terrains_peering_bit/right_side = 1 783 | 21:4/0/terrains_peering_bit/bottom_side = 1 784 | 21:4/0/terrains_peering_bit/left_side = 1 785 | 21:4/0/terrains_peering_bit/top_side = 1 786 | 21:4/0/custom_data_0 = 3 787 | 0:6/0 = 0 788 | 0:6/0/material = SubResource("ShaderMaterial_0flk2") 789 | 0:6/0/y_sort_origin = 4 790 | 1:6/0 = 0 791 | 1:6/0/terrain_set = 0 792 | 1:6/0/terrain = 2 793 | 1:6/0/terrains_peering_bit/right_side = 2 794 | 1:6/0/terrains_peering_bit/bottom_right_corner = 2 795 | 1:6/0/terrains_peering_bit/bottom_side = 2 796 | 1:6/0/custom_data_0 = 4 797 | 2:6/0 = 0 798 | 2:6/0/terrain_set = 0 799 | 2:6/0/terrain = 2 800 | 2:6/0/terrains_peering_bit/right_side = 2 801 | 2:6/0/terrains_peering_bit/bottom_right_corner = 2 802 | 2:6/0/terrains_peering_bit/bottom_side = 2 803 | 2:6/0/terrains_peering_bit/bottom_left_corner = 2 804 | 2:6/0/terrains_peering_bit/left_side = 2 805 | 2:6/0/custom_data_0 = 4 806 | 3:6/0 = 0 807 | 3:6/0/terrain_set = 0 808 | 3:6/0/terrain = 2 809 | 3:6/0/terrains_peering_bit/bottom_side = 2 810 | 3:6/0/terrains_peering_bit/bottom_left_corner = 2 811 | 3:6/0/terrains_peering_bit/left_side = 2 812 | 3:6/0/custom_data_0 = 4 813 | 4:6/0 = 0 814 | 4:6/0/terrain_set = 0 815 | 4:6/0/terrain = 2 816 | 4:6/0/terrains_peering_bit/bottom_side = 2 817 | 4:6/0/custom_data_0 = 4 818 | 5:6/0 = 0 819 | 5:6/0/terrain_set = 0 820 | 5:6/0/terrain = 2 821 | 5:6/0/terrains_peering_bit/right_side = 2 822 | 5:6/0/terrains_peering_bit/bottom_side = 2 823 | 5:6/0/custom_data_0 = 4 824 | 6:6/0 = 0 825 | 6:6/0/terrain_set = 0 826 | 6:6/0/terrain = 2 827 | 6:6/0/terrains_peering_bit/right_side = 2 828 | 6:6/0/terrains_peering_bit/bottom_side = 2 829 | 6:6/0/terrains_peering_bit/bottom_left_corner = 2 830 | 6:6/0/terrains_peering_bit/left_side = 2 831 | 6:6/0/custom_data_0 = 4 832 | 7:6/0 = 0 833 | 7:6/0/terrain_set = 0 834 | 7:6/0/terrain = 2 835 | 7:6/0/terrains_peering_bit/right_side = 2 836 | 7:6/0/terrains_peering_bit/bottom_right_corner = 2 837 | 7:6/0/terrains_peering_bit/bottom_side = 2 838 | 7:6/0/terrains_peering_bit/left_side = 2 839 | 7:6/0/custom_data_0 = 4 840 | 8:6/0 = 0 841 | 8:6/0/terrain_set = 0 842 | 8:6/0/terrain = 2 843 | 8:6/0/terrains_peering_bit/bottom_side = 2 844 | 8:6/0/terrains_peering_bit/left_side = 2 845 | 8:6/0/custom_data_0 = 4 846 | 9:6/0 = 0 847 | 9:6/0/terrain_set = 0 848 | 9:6/0/terrain = 2 849 | 9:6/0/terrains_peering_bit/right_side = 2 850 | 9:6/0/terrains_peering_bit/bottom_side = 2 851 | 9:6/0/terrains_peering_bit/left_side = 2 852 | 9:6/0/custom_data_0 = 4 853 | 10:6/0 = 0 854 | 10:6/0/terrain_set = 0 855 | 10:6/0/terrain = 2 856 | 10:6/0/terrains_peering_bit/right_side = 2 857 | 10:6/0/terrains_peering_bit/bottom_right_corner = 2 858 | 10:6/0/terrains_peering_bit/bottom_side = 2 859 | 10:6/0/terrains_peering_bit/left_side = 2 860 | 10:6/0/terrains_peering_bit/top_left_corner = 2 861 | 10:6/0/terrains_peering_bit/top_side = 2 862 | 10:6/0/custom_data_0 = 4 863 | 12:6/0 = 0 864 | 12:6/0/material = SubResource("ShaderMaterial_ukhf3") 865 | 12:6/0/y_sort_origin = 4 866 | 13:6/0 = 0 867 | 13:6/0/terrain_set = 0 868 | 13:6/0/terrain = 3 869 | 13:6/0/terrains_peering_bit/right_side = 3 870 | 13:6/0/terrains_peering_bit/bottom_right_corner = 3 871 | 13:6/0/terrains_peering_bit/bottom_side = 3 872 | 13:6/0/custom_data_0 = 4 873 | 14:6/0 = 0 874 | 14:6/0/terrain_set = 0 875 | 14:6/0/terrain = 3 876 | 14:6/0/terrains_peering_bit/right_side = 3 877 | 14:6/0/terrains_peering_bit/bottom_right_corner = 3 878 | 14:6/0/terrains_peering_bit/bottom_side = 3 879 | 14:6/0/terrains_peering_bit/bottom_left_corner = 3 880 | 14:6/0/terrains_peering_bit/left_side = 3 881 | 14:6/0/custom_data_0 = 4 882 | 15:6/0 = 0 883 | 15:6/0/terrain_set = 0 884 | 15:6/0/terrain = 3 885 | 15:6/0/terrains_peering_bit/bottom_side = 3 886 | 15:6/0/terrains_peering_bit/bottom_left_corner = 3 887 | 15:6/0/terrains_peering_bit/left_side = 3 888 | 15:6/0/custom_data_0 = 4 889 | 16:6/0 = 0 890 | 16:6/0/terrain_set = 0 891 | 16:6/0/terrain = 3 892 | 16:6/0/terrains_peering_bit/bottom_side = 3 893 | 16:6/0/custom_data_0 = 4 894 | 17:6/0 = 0 895 | 17:6/0/terrain_set = 0 896 | 17:6/0/terrain = 3 897 | 17:6/0/terrains_peering_bit/right_side = 3 898 | 17:6/0/terrains_peering_bit/bottom_side = 3 899 | 17:6/0/custom_data_0 = 4 900 | 18:6/0 = 0 901 | 18:6/0/terrain_set = 0 902 | 18:6/0/terrain = 3 903 | 18:6/0/terrains_peering_bit/right_side = 3 904 | 18:6/0/terrains_peering_bit/bottom_side = 3 905 | 18:6/0/terrains_peering_bit/bottom_left_corner = 3 906 | 18:6/0/terrains_peering_bit/left_side = 3 907 | 18:6/0/custom_data_0 = 4 908 | 19:6/0 = 0 909 | 19:6/0/terrain_set = 0 910 | 19:6/0/terrain = 3 911 | 19:6/0/terrains_peering_bit/right_side = 3 912 | 19:6/0/terrains_peering_bit/bottom_right_corner = 3 913 | 19:6/0/terrains_peering_bit/bottom_side = 3 914 | 19:6/0/terrains_peering_bit/left_side = 3 915 | 19:6/0/custom_data_0 = 4 916 | 20:6/0 = 0 917 | 20:6/0/terrain_set = 0 918 | 20:6/0/terrain = 3 919 | 20:6/0/terrains_peering_bit/bottom_side = 3 920 | 20:6/0/terrains_peering_bit/left_side = 3 921 | 20:6/0/custom_data_0 = 4 922 | 21:6/0 = 0 923 | 21:6/0/terrain_set = 0 924 | 21:6/0/terrain = 3 925 | 21:6/0/terrains_peering_bit/right_side = 3 926 | 21:6/0/terrains_peering_bit/bottom_side = 3 927 | 21:6/0/terrains_peering_bit/left_side = 3 928 | 21:6/0/custom_data_0 = 4 929 | 22:6/0 = 0 930 | 22:6/0/terrain_set = 0 931 | 22:6/0/terrain = 3 932 | 22:6/0/terrains_peering_bit/right_side = 3 933 | 22:6/0/terrains_peering_bit/bottom_right_corner = 3 934 | 22:6/0/terrains_peering_bit/bottom_side = 3 935 | 22:6/0/terrains_peering_bit/left_side = 3 936 | 22:6/0/terrains_peering_bit/top_left_corner = 3 937 | 22:6/0/terrains_peering_bit/top_side = 3 938 | 22:6/0/custom_data_0 = 4 939 | 0:7/0 = 0 940 | 0:7/0/material = SubResource("ShaderMaterial_6fm7e") 941 | 0:7/0/y_sort_origin = 5 942 | 1:7/0 = 0 943 | 1:7/0/terrain_set = 0 944 | 1:7/0/terrain = 2 945 | 1:7/0/terrains_peering_bit/right_side = 2 946 | 1:7/0/terrains_peering_bit/bottom_right_corner = 2 947 | 1:7/0/terrains_peering_bit/bottom_side = 2 948 | 1:7/0/terrains_peering_bit/top_side = 2 949 | 1:7/0/terrains_peering_bit/top_right_corner = 2 950 | 1:7/0/custom_data_0 = 4 951 | 2:7/0 = 0 952 | 2:7/0/terrain_set = 0 953 | 2:7/0/terrain = 2 954 | 2:7/0/terrains_peering_bit/right_side = 2 955 | 2:7/0/terrains_peering_bit/bottom_right_corner = 2 956 | 2:7/0/terrains_peering_bit/bottom_side = 2 957 | 2:7/0/terrains_peering_bit/bottom_left_corner = 2 958 | 2:7/0/terrains_peering_bit/left_side = 2 959 | 2:7/0/terrains_peering_bit/top_left_corner = 2 960 | 2:7/0/terrains_peering_bit/top_side = 2 961 | 2:7/0/terrains_peering_bit/top_right_corner = 2 962 | 2:7/0/custom_data_0 = 4 963 | 3:7/0 = 0 964 | 3:7/0/terrain_set = 0 965 | 3:7/0/terrain = 2 966 | 3:7/0/terrains_peering_bit/bottom_side = 2 967 | 3:7/0/terrains_peering_bit/bottom_left_corner = 2 968 | 3:7/0/terrains_peering_bit/left_side = 2 969 | 3:7/0/terrains_peering_bit/top_left_corner = 2 970 | 3:7/0/terrains_peering_bit/top_side = 2 971 | 3:7/0/custom_data_0 = 4 972 | 4:7/0 = 0 973 | 4:7/0/terrain_set = 0 974 | 4:7/0/terrain = 2 975 | 4:7/0/terrains_peering_bit/bottom_side = 2 976 | 4:7/0/terrains_peering_bit/top_side = 2 977 | 4:7/0/custom_data_0 = 4 978 | 5:7/0 = 0 979 | 5:7/0/terrain_set = 0 980 | 5:7/0/terrain = 2 981 | 5:7/0/terrains_peering_bit/right_side = 2 982 | 5:7/0/terrains_peering_bit/bottom_side = 2 983 | 5:7/0/terrains_peering_bit/top_side = 2 984 | 5:7/0/terrains_peering_bit/top_right_corner = 2 985 | 5:7/0/custom_data_0 = 4 986 | 6:7/0 = 0 987 | 6:7/0/terrain_set = 0 988 | 6:7/0/terrain = 2 989 | 6:7/0/terrains_peering_bit/right_side = 2 990 | 6:7/0/terrains_peering_bit/bottom_side = 2 991 | 6:7/0/terrains_peering_bit/bottom_left_corner = 2 992 | 6:7/0/terrains_peering_bit/left_side = 2 993 | 6:7/0/terrains_peering_bit/top_left_corner = 2 994 | 6:7/0/terrains_peering_bit/top_side = 2 995 | 6:7/0/terrains_peering_bit/top_right_corner = 2 996 | 6:7/0/custom_data_0 = 4 997 | 7:7/0 = 0 998 | 7:7/0/terrain_set = 0 999 | 7:7/0/terrain = 2 1000 | 7:7/0/terrains_peering_bit/right_side = 2 1001 | 7:7/0/terrains_peering_bit/bottom_right_corner = 2 1002 | 7:7/0/terrains_peering_bit/bottom_side = 2 1003 | 7:7/0/terrains_peering_bit/left_side = 2 1004 | 7:7/0/terrains_peering_bit/top_left_corner = 2 1005 | 7:7/0/terrains_peering_bit/top_side = 2 1006 | 7:7/0/terrains_peering_bit/top_right_corner = 2 1007 | 7:7/0/custom_data_0 = 4 1008 | 8:7/0 = 0 1009 | 8:7/0/terrain_set = 0 1010 | 8:7/0/terrain = 2 1011 | 8:7/0/terrains_peering_bit/bottom_side = 2 1012 | 8:7/0/terrains_peering_bit/left_side = 2 1013 | 8:7/0/terrains_peering_bit/top_left_corner = 2 1014 | 8:7/0/terrains_peering_bit/top_side = 2 1015 | 8:7/0/custom_data_0 = 4 1016 | 9:7/0 = 0 1017 | 9:7/0/terrain_set = 0 1018 | 9:7/0/terrain = 2 1019 | 9:7/0/terrains_peering_bit/right_side = 2 1020 | 9:7/0/terrains_peering_bit/bottom_side = 2 1021 | 9:7/0/terrains_peering_bit/left_side = 2 1022 | 9:7/0/terrains_peering_bit/top_left_corner = 2 1023 | 9:7/0/terrains_peering_bit/top_side = 2 1024 | 9:7/0/terrains_peering_bit/top_right_corner = 2 1025 | 9:7/0/custom_data_0 = 4 1026 | 10:7/0 = 0 1027 | 10:7/0/terrain_set = 0 1028 | 10:7/0/terrain = 2 1029 | 10:7/0/terrains_peering_bit/right_side = 2 1030 | 10:7/0/terrains_peering_bit/bottom_side = 2 1031 | 10:7/0/terrains_peering_bit/bottom_left_corner = 2 1032 | 10:7/0/terrains_peering_bit/left_side = 2 1033 | 10:7/0/terrains_peering_bit/top_side = 2 1034 | 10:7/0/terrains_peering_bit/top_right_corner = 2 1035 | 10:7/0/custom_data_0 = 4 1036 | 12:7/0 = 0 1037 | 12:7/0/material = SubResource("ShaderMaterial_y5xdi") 1038 | 12:7/0/y_sort_origin = 5 1039 | 13:7/0 = 0 1040 | 13:7/0/terrain_set = 0 1041 | 13:7/0/terrain = 3 1042 | 13:7/0/terrains_peering_bit/right_side = 3 1043 | 13:7/0/terrains_peering_bit/bottom_right_corner = 3 1044 | 13:7/0/terrains_peering_bit/bottom_side = 3 1045 | 13:7/0/terrains_peering_bit/top_side = 3 1046 | 13:7/0/terrains_peering_bit/top_right_corner = 3 1047 | 13:7/0/custom_data_0 = 4 1048 | 14:7/0 = 0 1049 | 14:7/0/terrain_set = 0 1050 | 14:7/0/terrain = 3 1051 | 14:7/0/terrains_peering_bit/right_side = 3 1052 | 14:7/0/terrains_peering_bit/bottom_right_corner = 3 1053 | 14:7/0/terrains_peering_bit/bottom_side = 3 1054 | 14:7/0/terrains_peering_bit/bottom_left_corner = 3 1055 | 14:7/0/terrains_peering_bit/left_side = 3 1056 | 14:7/0/terrains_peering_bit/top_left_corner = 3 1057 | 14:7/0/terrains_peering_bit/top_side = 3 1058 | 14:7/0/terrains_peering_bit/top_right_corner = 3 1059 | 14:7/0/custom_data_0 = 4 1060 | 15:7/0 = 0 1061 | 15:7/0/terrain_set = 0 1062 | 15:7/0/terrain = 3 1063 | 15:7/0/terrains_peering_bit/bottom_side = 3 1064 | 15:7/0/terrains_peering_bit/bottom_left_corner = 3 1065 | 15:7/0/terrains_peering_bit/left_side = 3 1066 | 15:7/0/terrains_peering_bit/top_left_corner = 3 1067 | 15:7/0/terrains_peering_bit/top_side = 3 1068 | 15:7/0/custom_data_0 = 4 1069 | 16:7/0 = 0 1070 | 16:7/0/terrain_set = 0 1071 | 16:7/0/terrain = 3 1072 | 16:7/0/terrains_peering_bit/bottom_side = 3 1073 | 16:7/0/terrains_peering_bit/top_side = 3 1074 | 16:7/0/custom_data_0 = 4 1075 | 17:7/0 = 0 1076 | 17:7/0/terrain_set = 0 1077 | 17:7/0/terrain = 3 1078 | 17:7/0/terrains_peering_bit/right_side = 3 1079 | 17:7/0/terrains_peering_bit/bottom_side = 3 1080 | 17:7/0/terrains_peering_bit/top_side = 3 1081 | 17:7/0/terrains_peering_bit/top_right_corner = 3 1082 | 17:7/0/custom_data_0 = 4 1083 | 18:7/0 = 0 1084 | 18:7/0/terrain_set = 0 1085 | 18:7/0/terrain = 3 1086 | 18:7/0/terrains_peering_bit/right_side = 3 1087 | 18:7/0/terrains_peering_bit/bottom_side = 3 1088 | 18:7/0/terrains_peering_bit/bottom_left_corner = 3 1089 | 18:7/0/terrains_peering_bit/left_side = 3 1090 | 18:7/0/terrains_peering_bit/top_left_corner = 3 1091 | 18:7/0/terrains_peering_bit/top_side = 3 1092 | 18:7/0/terrains_peering_bit/top_right_corner = 3 1093 | 18:7/0/custom_data_0 = 4 1094 | 19:7/0 = 0 1095 | 19:7/0/terrain_set = 0 1096 | 19:7/0/terrain = 3 1097 | 19:7/0/terrains_peering_bit/right_side = 3 1098 | 19:7/0/terrains_peering_bit/bottom_right_corner = 3 1099 | 19:7/0/terrains_peering_bit/bottom_side = 3 1100 | 19:7/0/terrains_peering_bit/left_side = 3 1101 | 19:7/0/terrains_peering_bit/top_left_corner = 3 1102 | 19:7/0/terrains_peering_bit/top_side = 3 1103 | 19:7/0/terrains_peering_bit/top_right_corner = 3 1104 | 19:7/0/custom_data_0 = 4 1105 | 20:7/0 = 0 1106 | 20:7/0/terrain_set = 0 1107 | 20:7/0/terrain = 3 1108 | 20:7/0/terrains_peering_bit/bottom_side = 3 1109 | 20:7/0/terrains_peering_bit/left_side = 3 1110 | 20:7/0/terrains_peering_bit/top_left_corner = 3 1111 | 20:7/0/terrains_peering_bit/top_side = 3 1112 | 20:7/0/custom_data_0 = 4 1113 | 21:7/0 = 0 1114 | 21:7/0/terrain_set = 0 1115 | 21:7/0/terrain = 3 1116 | 21:7/0/terrains_peering_bit/right_side = 3 1117 | 21:7/0/terrains_peering_bit/bottom_side = 3 1118 | 21:7/0/terrains_peering_bit/left_side = 3 1119 | 21:7/0/terrains_peering_bit/top_left_corner = 3 1120 | 21:7/0/terrains_peering_bit/top_side = 3 1121 | 21:7/0/terrains_peering_bit/top_right_corner = 3 1122 | 21:7/0/custom_data_0 = 4 1123 | 22:7/0 = 0 1124 | 22:7/0/terrain_set = 0 1125 | 22:7/0/terrain = 3 1126 | 22:7/0/terrains_peering_bit/right_side = 3 1127 | 22:7/0/terrains_peering_bit/bottom_side = 3 1128 | 22:7/0/terrains_peering_bit/bottom_left_corner = 3 1129 | 22:7/0/terrains_peering_bit/left_side = 3 1130 | 22:7/0/terrains_peering_bit/top_side = 3 1131 | 22:7/0/terrains_peering_bit/top_right_corner = 3 1132 | 22:7/0/custom_data_0 = 4 1133 | 0:8/0 = 0 1134 | 0:8/0/y_sort_origin = 4 1135 | 0:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-5.98462, -3.01481, 5.62465, -3.1948, 5.17467, 6.07462, -5.44466, 5.89463) 1136 | 0:8/0/custom_data_1 = true 1137 | 1:8/0 = 0 1138 | 1:8/0/terrain_set = 0 1139 | 1:8/0/terrain = 2 1140 | 1:8/0/terrains_peering_bit/right_side = 2 1141 | 1:8/0/terrains_peering_bit/top_side = 2 1142 | 1:8/0/terrains_peering_bit/top_right_corner = 2 1143 | 1:8/0/custom_data_0 = 4 1144 | 2:8/0 = 0 1145 | 2:8/0/terrain_set = 0 1146 | 2:8/0/terrain = 2 1147 | 2:8/0/terrains_peering_bit/right_side = 2 1148 | 2:8/0/terrains_peering_bit/left_side = 2 1149 | 2:8/0/terrains_peering_bit/top_left_corner = 2 1150 | 2:8/0/terrains_peering_bit/top_side = 2 1151 | 2:8/0/terrains_peering_bit/top_right_corner = 2 1152 | 2:8/0/custom_data_0 = 4 1153 | 3:8/0 = 0 1154 | 3:8/0/terrain_set = 0 1155 | 3:8/0/terrain = 2 1156 | 3:8/0/terrains_peering_bit/left_side = 2 1157 | 3:8/0/terrains_peering_bit/top_left_corner = 2 1158 | 3:8/0/terrains_peering_bit/top_side = 2 1159 | 3:8/0/custom_data_0 = 4 1160 | 4:8/0 = 0 1161 | 4:8/0/terrain_set = 0 1162 | 4:8/0/terrain = 2 1163 | 4:8/0/terrains_peering_bit/top_side = 2 1164 | 4:8/0/custom_data_0 = 4 1165 | 5:8/0 = 0 1166 | 5:8/0/terrain_set = 0 1167 | 5:8/0/terrain = 2 1168 | 5:8/0/terrains_peering_bit/right_side = 2 1169 | 5:8/0/terrains_peering_bit/bottom_right_corner = 2 1170 | 5:8/0/terrains_peering_bit/bottom_side = 2 1171 | 5:8/0/terrains_peering_bit/top_side = 2 1172 | 5:8/0/custom_data_0 = 4 1173 | 6:8/0 = 0 1174 | 6:8/0/terrain_set = 0 1175 | 6:8/0/terrain = 2 1176 | 6:8/0/terrains_peering_bit/right_side = 2 1177 | 6:8/0/terrains_peering_bit/bottom_right_corner = 2 1178 | 6:8/0/terrains_peering_bit/bottom_side = 2 1179 | 6:8/0/terrains_peering_bit/bottom_left_corner = 2 1180 | 6:8/0/terrains_peering_bit/left_side = 2 1181 | 6:8/0/terrains_peering_bit/top_left_corner = 2 1182 | 6:8/0/terrains_peering_bit/top_side = 2 1183 | 6:8/0/custom_data_0 = 4 1184 | 7:8/0 = 0 1185 | 7:8/0/terrain_set = 0 1186 | 7:8/0/terrain = 2 1187 | 7:8/0/terrains_peering_bit/right_side = 2 1188 | 7:8/0/terrains_peering_bit/bottom_right_corner = 2 1189 | 7:8/0/terrains_peering_bit/bottom_side = 2 1190 | 7:8/0/terrains_peering_bit/bottom_left_corner = 2 1191 | 7:8/0/terrains_peering_bit/left_side = 2 1192 | 7:8/0/terrains_peering_bit/top_side = 2 1193 | 7:8/0/terrains_peering_bit/top_right_corner = 2 1194 | 7:8/0/custom_data_0 = 4 1195 | 8:8/0 = 0 1196 | 8:8/0/terrain_set = 0 1197 | 8:8/0/terrain = 2 1198 | 8:8/0/terrains_peering_bit/bottom_side = 2 1199 | 8:8/0/terrains_peering_bit/bottom_left_corner = 2 1200 | 8:8/0/terrains_peering_bit/left_side = 2 1201 | 8:8/0/terrains_peering_bit/top_side = 2 1202 | 8:8/0/custom_data_0 = 4 1203 | 9:8/0 = 0 1204 | 9:8/0/terrain_set = 0 1205 | 9:8/0/terrain = 2 1206 | 9:8/0/terrains_peering_bit/right_side = 2 1207 | 9:8/0/terrains_peering_bit/bottom_right_corner = 2 1208 | 9:8/0/terrains_peering_bit/bottom_side = 2 1209 | 9:8/0/terrains_peering_bit/bottom_left_corner = 2 1210 | 9:8/0/terrains_peering_bit/left_side = 2 1211 | 9:8/0/terrains_peering_bit/top_side = 2 1212 | 9:8/0/custom_data_0 = 4 1213 | 10:8/0 = 0 1214 | 10:8/0/terrain_set = 0 1215 | 10:8/0/terrain = 2 1216 | 10:8/0/terrains_peering_bit/right_side = 2 1217 | 10:8/0/terrains_peering_bit/bottom_right_corner = 2 1218 | 10:8/0/terrains_peering_bit/bottom_side = 2 1219 | 10:8/0/terrains_peering_bit/left_side = 2 1220 | 10:8/0/terrains_peering_bit/top_side = 2 1221 | 10:8/0/custom_data_0 = 4 1222 | 11:8/0 = 0 1223 | 11:8/0/terrain_set = 0 1224 | 11:8/0/terrain = 2 1225 | 11:8/0/terrains_peering_bit/right_side = 2 1226 | 11:8/0/terrains_peering_bit/bottom_side = 2 1227 | 11:8/0/terrains_peering_bit/bottom_left_corner = 2 1228 | 11:8/0/terrains_peering_bit/left_side = 2 1229 | 11:8/0/terrains_peering_bit/top_side = 2 1230 | 11:8/0/custom_data_0 = 4 1231 | 13:8/0 = 0 1232 | 13:8/0/terrain_set = 0 1233 | 13:8/0/terrain = 3 1234 | 13:8/0/terrains_peering_bit/right_side = 3 1235 | 13:8/0/terrains_peering_bit/top_side = 3 1236 | 13:8/0/terrains_peering_bit/top_right_corner = 3 1237 | 13:8/0/custom_data_0 = 4 1238 | 14:8/0 = 0 1239 | 14:8/0/terrain_set = 0 1240 | 14:8/0/terrain = 3 1241 | 14:8/0/terrains_peering_bit/right_side = 3 1242 | 14:8/0/terrains_peering_bit/left_side = 3 1243 | 14:8/0/terrains_peering_bit/top_left_corner = 3 1244 | 14:8/0/terrains_peering_bit/top_side = 3 1245 | 14:8/0/terrains_peering_bit/top_right_corner = 3 1246 | 14:8/0/custom_data_0 = 4 1247 | 15:8/0 = 0 1248 | 15:8/0/terrain_set = 0 1249 | 15:8/0/terrain = 3 1250 | 15:8/0/terrains_peering_bit/left_side = 3 1251 | 15:8/0/terrains_peering_bit/top_left_corner = 3 1252 | 15:8/0/terrains_peering_bit/top_side = 3 1253 | 15:8/0/custom_data_0 = 4 1254 | 16:8/0 = 0 1255 | 16:8/0/terrain_set = 0 1256 | 16:8/0/terrain = 3 1257 | 16:8/0/terrains_peering_bit/top_side = 3 1258 | 16:8/0/custom_data_0 = 4 1259 | 17:8/0 = 0 1260 | 17:8/0/terrain_set = 0 1261 | 17:8/0/terrain = 3 1262 | 17:8/0/terrains_peering_bit/right_side = 3 1263 | 17:8/0/terrains_peering_bit/bottom_right_corner = 3 1264 | 17:8/0/terrains_peering_bit/bottom_side = 3 1265 | 17:8/0/terrains_peering_bit/top_side = 3 1266 | 17:8/0/custom_data_0 = 4 1267 | 18:8/0 = 0 1268 | 18:8/0/terrain_set = 0 1269 | 18:8/0/terrain = 3 1270 | 18:8/0/terrains_peering_bit/right_side = 3 1271 | 18:8/0/terrains_peering_bit/bottom_right_corner = 3 1272 | 18:8/0/terrains_peering_bit/bottom_side = 3 1273 | 18:8/0/terrains_peering_bit/bottom_left_corner = 3 1274 | 18:8/0/terrains_peering_bit/left_side = 3 1275 | 18:8/0/terrains_peering_bit/top_left_corner = 3 1276 | 18:8/0/terrains_peering_bit/top_side = 3 1277 | 18:8/0/custom_data_0 = 4 1278 | 19:8/0 = 0 1279 | 19:8/0/terrain_set = 0 1280 | 19:8/0/terrain = 3 1281 | 19:8/0/terrains_peering_bit/right_side = 3 1282 | 19:8/0/terrains_peering_bit/bottom_right_corner = 3 1283 | 19:8/0/terrains_peering_bit/bottom_side = 3 1284 | 19:8/0/terrains_peering_bit/bottom_left_corner = 3 1285 | 19:8/0/terrains_peering_bit/left_side = 3 1286 | 19:8/0/terrains_peering_bit/top_side = 3 1287 | 19:8/0/terrains_peering_bit/top_right_corner = 3 1288 | 19:8/0/custom_data_0 = 4 1289 | 20:8/0 = 0 1290 | 20:8/0/terrain_set = 0 1291 | 20:8/0/terrain = 3 1292 | 20:8/0/terrains_peering_bit/bottom_side = 3 1293 | 20:8/0/terrains_peering_bit/bottom_left_corner = 3 1294 | 20:8/0/terrains_peering_bit/left_side = 3 1295 | 20:8/0/terrains_peering_bit/top_side = 3 1296 | 20:8/0/custom_data_0 = 4 1297 | 21:8/0 = 0 1298 | 21:8/0/terrain_set = 0 1299 | 21:8/0/terrain = 3 1300 | 21:8/0/terrains_peering_bit/right_side = 3 1301 | 21:8/0/terrains_peering_bit/bottom_right_corner = 3 1302 | 21:8/0/terrains_peering_bit/bottom_side = 3 1303 | 21:8/0/terrains_peering_bit/bottom_left_corner = 3 1304 | 21:8/0/terrains_peering_bit/left_side = 3 1305 | 21:8/0/terrains_peering_bit/top_side = 3 1306 | 21:8/0/custom_data_0 = 4 1307 | 22:8/0 = 0 1308 | 22:8/0/terrain_set = 0 1309 | 22:8/0/terrain = 3 1310 | 22:8/0/terrains_peering_bit/right_side = 3 1311 | 22:8/0/terrains_peering_bit/bottom_right_corner = 3 1312 | 22:8/0/terrains_peering_bit/bottom_side = 3 1313 | 22:8/0/terrains_peering_bit/left_side = 3 1314 | 22:8/0/terrains_peering_bit/top_side = 3 1315 | 22:8/0/custom_data_0 = 4 1316 | 23:8/0 = 0 1317 | 23:8/0/terrain_set = 0 1318 | 23:8/0/terrain = 3 1319 | 23:8/0/terrains_peering_bit/right_side = 3 1320 | 23:8/0/terrains_peering_bit/bottom_side = 3 1321 | 23:8/0/terrains_peering_bit/bottom_left_corner = 3 1322 | 23:8/0/terrains_peering_bit/left_side = 3 1323 | 23:8/0/terrains_peering_bit/top_side = 3 1324 | 23:8/0/custom_data_0 = 4 1325 | 1:9/0 = 0 1326 | 1:9/0/terrain_set = 0 1327 | 1:9/0/terrain = 2 1328 | 1:9/0/terrains_peering_bit/right_side = 2 1329 | 1:9/0/custom_data_0 = 4 1330 | 2:9/0 = 0 1331 | 2:9/0/terrain_set = 0 1332 | 2:9/0/terrain = 2 1333 | 2:9/0/terrains_peering_bit/right_side = 2 1334 | 2:9/0/terrains_peering_bit/left_side = 2 1335 | 2:9/0/custom_data_0 = 4 1336 | 3:9/0 = 0 1337 | 3:9/0/terrain_set = 0 1338 | 3:9/0/terrain = 2 1339 | 3:9/0/terrains_peering_bit/left_side = 2 1340 | 3:9/0/custom_data_0 = 4 1341 | 4:9/0 = 0 1342 | 4:9/0/terrain_set = 0 1343 | 4:9/0/terrain = 2 1344 | 4:9/0/custom_data_0 = 4 1345 | 5:9/0 = 0 1346 | 5:9/0/terrain_set = 0 1347 | 5:9/0/terrain = 2 1348 | 5:9/0/terrains_peering_bit/right_side = 2 1349 | 5:9/0/terrains_peering_bit/top_side = 2 1350 | 5:9/0/custom_data_0 = 4 1351 | 6:9/0 = 0 1352 | 6:9/0/terrain_set = 0 1353 | 6:9/0/terrain = 2 1354 | 6:9/0/terrains_peering_bit/right_side = 2 1355 | 6:9/0/terrains_peering_bit/left_side = 2 1356 | 6:9/0/terrains_peering_bit/top_left_corner = 2 1357 | 6:9/0/terrains_peering_bit/top_side = 2 1358 | 6:9/0/custom_data_0 = 4 1359 | 7:9/0 = 0 1360 | 7:9/0/terrain_set = 0 1361 | 7:9/0/terrain = 2 1362 | 7:9/0/terrains_peering_bit/right_side = 2 1363 | 7:9/0/terrains_peering_bit/left_side = 2 1364 | 7:9/0/terrains_peering_bit/top_side = 2 1365 | 7:9/0/terrains_peering_bit/top_right_corner = 2 1366 | 7:9/0/custom_data_0 = 4 1367 | 8:9/0 = 0 1368 | 8:9/0/terrain_set = 0 1369 | 8:9/0/terrain = 2 1370 | 8:9/0/terrains_peering_bit/left_side = 2 1371 | 8:9/0/terrains_peering_bit/top_side = 2 1372 | 8:9/0/custom_data_0 = 4 1373 | 9:9/0 = 0 1374 | 9:9/0/terrain_set = 0 1375 | 9:9/0/terrain = 2 1376 | 9:9/0/terrains_peering_bit/right_side = 2 1377 | 9:9/0/terrains_peering_bit/left_side = 2 1378 | 9:9/0/terrains_peering_bit/top_side = 2 1379 | 9:9/0/custom_data_0 = 4 1380 | 10:9/0 = 0 1381 | 10:9/0/terrain_set = 0 1382 | 10:9/0/terrain = 2 1383 | 10:9/0/terrains_peering_bit/right_side = 2 1384 | 10:9/0/terrains_peering_bit/bottom_side = 2 1385 | 10:9/0/terrains_peering_bit/left_side = 2 1386 | 10:9/0/terrains_peering_bit/top_side = 2 1387 | 10:9/0/terrains_peering_bit/top_right_corner = 2 1388 | 10:9/0/custom_data_0 = 4 1389 | 11:9/0 = 0 1390 | 11:9/0/terrain_set = 0 1391 | 11:9/0/terrain = 2 1392 | 11:9/0/terrains_peering_bit/right_side = 2 1393 | 11:9/0/terrains_peering_bit/bottom_side = 2 1394 | 11:9/0/terrains_peering_bit/left_side = 2 1395 | 11:9/0/terrains_peering_bit/top_left_corner = 2 1396 | 11:9/0/terrains_peering_bit/top_side = 2 1397 | 11:9/0/custom_data_0 = 4 1398 | 13:9/0 = 0 1399 | 13:9/0/terrain_set = 0 1400 | 13:9/0/terrain = 3 1401 | 13:9/0/terrains_peering_bit/right_side = 3 1402 | 13:9/0/custom_data_0 = 4 1403 | 14:9/0 = 0 1404 | 14:9/0/terrain_set = 0 1405 | 14:9/0/terrain = 3 1406 | 14:9/0/terrains_peering_bit/right_side = 3 1407 | 14:9/0/terrains_peering_bit/left_side = 3 1408 | 14:9/0/custom_data_0 = 4 1409 | 15:9/0 = 0 1410 | 15:9/0/terrain_set = 0 1411 | 15:9/0/terrain = 3 1412 | 15:9/0/terrains_peering_bit/left_side = 3 1413 | 15:9/0/custom_data_0 = 4 1414 | 16:9/0 = 0 1415 | 16:9/0/terrain_set = 0 1416 | 16:9/0/terrain = 3 1417 | 16:9/0/custom_data_0 = 4 1418 | 17:9/0 = 0 1419 | 17:9/0/terrain_set = 0 1420 | 17:9/0/terrain = 3 1421 | 17:9/0/terrains_peering_bit/right_side = 3 1422 | 17:9/0/terrains_peering_bit/top_side = 3 1423 | 17:9/0/custom_data_0 = 4 1424 | 18:9/0 = 0 1425 | 18:9/0/terrain_set = 0 1426 | 18:9/0/terrain = 3 1427 | 18:9/0/terrains_peering_bit/right_side = 3 1428 | 18:9/0/terrains_peering_bit/left_side = 3 1429 | 18:9/0/terrains_peering_bit/top_left_corner = 3 1430 | 18:9/0/terrains_peering_bit/top_side = 3 1431 | 18:9/0/custom_data_0 = 4 1432 | 19:9/0 = 0 1433 | 19:9/0/terrain_set = 0 1434 | 19:9/0/terrain = 3 1435 | 19:9/0/terrains_peering_bit/right_side = 3 1436 | 19:9/0/terrains_peering_bit/left_side = 3 1437 | 19:9/0/terrains_peering_bit/top_side = 3 1438 | 19:9/0/terrains_peering_bit/top_right_corner = 3 1439 | 19:9/0/custom_data_0 = 4 1440 | 20:9/0 = 0 1441 | 20:9/0/terrain_set = 0 1442 | 20:9/0/terrain = 3 1443 | 20:9/0/terrains_peering_bit/left_side = 3 1444 | 20:9/0/terrains_peering_bit/top_side = 3 1445 | 20:9/0/custom_data_0 = 4 1446 | 21:9/0 = 0 1447 | 21:9/0/terrain_set = 0 1448 | 21:9/0/terrain = 3 1449 | 21:9/0/terrains_peering_bit/right_side = 3 1450 | 21:9/0/terrains_peering_bit/left_side = 3 1451 | 21:9/0/terrains_peering_bit/top_side = 3 1452 | 21:9/0/custom_data_0 = 4 1453 | 22:9/0 = 0 1454 | 22:9/0/terrain_set = 0 1455 | 22:9/0/terrain = 3 1456 | 22:9/0/terrains_peering_bit/right_side = 3 1457 | 22:9/0/terrains_peering_bit/bottom_side = 3 1458 | 22:9/0/terrains_peering_bit/left_side = 3 1459 | 22:9/0/terrains_peering_bit/top_side = 3 1460 | 22:9/0/terrains_peering_bit/top_right_corner = 3 1461 | 22:9/0/custom_data_0 = 4 1462 | 23:9/0 = 0 1463 | 23:9/0/terrain_set = 0 1464 | 23:9/0/terrain = 3 1465 | 23:9/0/terrains_peering_bit/right_side = 3 1466 | 23:9/0/terrains_peering_bit/bottom_side = 3 1467 | 23:9/0/terrains_peering_bit/left_side = 3 1468 | 23:9/0/terrains_peering_bit/top_left_corner = 3 1469 | 23:9/0/terrains_peering_bit/top_side = 3 1470 | 23:9/0/custom_data_0 = 4 1471 | 5:10/0 = 0 1472 | 5:10/0/terrain_set = 0 1473 | 5:10/0/terrain = 2 1474 | 5:10/0/terrains_peering_bit/right_side = 2 1475 | 5:10/0/terrains_peering_bit/bottom_side = 2 1476 | 5:10/0/terrains_peering_bit/top_side = 2 1477 | 5:10/0/custom_data_0 = 4 1478 | 6:10/0 = 0 1479 | 6:10/0/terrain_set = 0 1480 | 6:10/0/terrain = 2 1481 | 6:10/0/terrains_peering_bit/right_side = 2 1482 | 6:10/0/terrains_peering_bit/bottom_side = 2 1483 | 6:10/0/terrains_peering_bit/bottom_left_corner = 2 1484 | 6:10/0/terrains_peering_bit/left_side = 2 1485 | 6:10/0/terrains_peering_bit/top_left_corner = 2 1486 | 6:10/0/terrains_peering_bit/top_side = 2 1487 | 6:10/0/custom_data_0 = 4 1488 | 7:10/0 = 0 1489 | 7:10/0/terrain_set = 0 1490 | 7:10/0/terrain = 2 1491 | 7:10/0/terrains_peering_bit/right_side = 2 1492 | 7:10/0/terrains_peering_bit/bottom_right_corner = 2 1493 | 7:10/0/terrains_peering_bit/bottom_side = 2 1494 | 7:10/0/terrains_peering_bit/left_side = 2 1495 | 7:10/0/terrains_peering_bit/top_side = 2 1496 | 7:10/0/terrains_peering_bit/top_right_corner = 2 1497 | 7:10/0/custom_data_0 = 4 1498 | 8:10/0 = 0 1499 | 8:10/0/terrain_set = 0 1500 | 8:10/0/terrain = 2 1501 | 8:10/0/terrains_peering_bit/bottom_side = 2 1502 | 8:10/0/terrains_peering_bit/left_side = 2 1503 | 8:10/0/terrains_peering_bit/top_side = 2 1504 | 8:10/0/custom_data_0 = 4 1505 | 9:10/0 = 0 1506 | 9:10/0/terrain_set = 0 1507 | 9:10/0/terrain = 2 1508 | 9:10/0/terrains_peering_bit/right_side = 2 1509 | 9:10/0/terrains_peering_bit/bottom_side = 2 1510 | 9:10/0/terrains_peering_bit/left_side = 2 1511 | 9:10/0/terrains_peering_bit/top_side = 2 1512 | 9:10/0/custom_data_0 = 4 1513 | 17:10/0 = 0 1514 | 17:10/0/terrain_set = 0 1515 | 17:10/0/terrain = 3 1516 | 17:10/0/terrains_peering_bit/right_side = 3 1517 | 17:10/0/terrains_peering_bit/bottom_side = 3 1518 | 17:10/0/terrains_peering_bit/top_side = 3 1519 | 17:10/0/custom_data_0 = 4 1520 | 18:10/0 = 0 1521 | 18:10/0/terrain_set = 0 1522 | 18:10/0/terrain = 3 1523 | 18:10/0/terrains_peering_bit/right_side = 3 1524 | 18:10/0/terrains_peering_bit/bottom_side = 3 1525 | 18:10/0/terrains_peering_bit/bottom_left_corner = 3 1526 | 18:10/0/terrains_peering_bit/left_side = 3 1527 | 18:10/0/terrains_peering_bit/top_left_corner = 3 1528 | 18:10/0/terrains_peering_bit/top_side = 3 1529 | 18:10/0/custom_data_0 = 4 1530 | 19:10/0 = 0 1531 | 19:10/0/terrain_set = 0 1532 | 19:10/0/terrain = 3 1533 | 19:10/0/terrains_peering_bit/right_side = 3 1534 | 19:10/0/terrains_peering_bit/bottom_right_corner = 3 1535 | 19:10/0/terrains_peering_bit/bottom_side = 3 1536 | 19:10/0/terrains_peering_bit/left_side = 3 1537 | 19:10/0/terrains_peering_bit/top_side = 3 1538 | 19:10/0/terrains_peering_bit/top_right_corner = 3 1539 | 19:10/0/custom_data_0 = 4 1540 | 20:10/0 = 0 1541 | 20:10/0/terrain_set = 0 1542 | 20:10/0/terrain = 3 1543 | 20:10/0/terrains_peering_bit/bottom_side = 3 1544 | 20:10/0/terrains_peering_bit/left_side = 3 1545 | 20:10/0/terrains_peering_bit/top_side = 3 1546 | 20:10/0/custom_data_0 = 4 1547 | 21:10/0 = 0 1548 | 21:10/0/terrain_set = 0 1549 | 21:10/0/terrain = 3 1550 | 21:10/0/terrains_peering_bit/right_side = 3 1551 | 21:10/0/terrains_peering_bit/bottom_side = 3 1552 | 21:10/0/terrains_peering_bit/left_side = 3 1553 | 21:10/0/terrains_peering_bit/top_side = 3 1554 | 21:10/0/custom_data_0 = 4 1555 | 1556 | [sub_resource type="TileSetScenesCollectionSource" id="TileSetScenesCollectionSource_f07he"] 1557 | scenes/1/scene = ExtResource("2_pd1k1") 1558 | scenes/2/scene = ExtResource("4_gg5sm") 1559 | 1560 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_rwv2v"] 1561 | shader = ExtResource("3_mqjx0") 1562 | shader_parameter/range = 2.0 1563 | shader_parameter/speed = 1.2 1564 | 1565 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_307n7"] 1566 | shader = ExtResource("3_mqjx0") 1567 | shader_parameter/range = 1.8 1568 | shader_parameter/speed = 0.8 1569 | 1570 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_agqfu"] 1571 | texture = ExtResource("4_a880d") 1572 | 0:0/size_in_atlas = Vector2i(4, 10) 1573 | 0:0/next_alternative_id = 2 1574 | 0:0/0 = 0 1575 | 0:0/0/texture_origin = Vector2i(1, 50) 1576 | 0:0/0/material = SubResource("ShaderMaterial_rwv2v") 1577 | 0:0/0/y_sort_origin = 3 1578 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-5.03968, -4.90469, 4.22973, -5.08468, 4.49972, 3.64477, -5.03968, 3.46478) 1579 | 0:0/0/custom_data_1 = true 1580 | 0:0/1 = 1 1581 | 0:0/1/texture_origin = Vector2i(1, 50) 1582 | 0:0/1/material = SubResource("ShaderMaterial_307n7") 1583 | 0:0/1/y_sort_origin = 3 1584 | 0:0/1/physics_layer_0/polygon_0/points = PackedVector2Array(-5.30967, -6.88457, 3.86976, -6.61458, 3.86976, 2.11487, -5.12968, 2.29486) 1585 | 0:0/1/custom_data_1 = true 1586 | 1587 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_22b70"] 1588 | texture = ExtResource("5_rlseo") 1589 | 0:0/0 = 0 1590 | 0:0/0/terrain_set = 1 1591 | 0:0/0/terrain = 0 1592 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.9727, 0.286361, 8, 0.314981, 8, 4.9954, 1.84543, 4.9954, 1.70989, 8, -2.03634, 8) 1593 | 0:0/0/terrains_peering_bit/right_side = 0 1594 | 0:0/0/terrains_peering_bit/bottom_side = 0 1595 | 0:0/0/custom_data_1 = true 1596 | 1:0/0 = 0 1597 | 1:0/0/terrain_set = 1 1598 | 1:0/0/terrain = 0 1599 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 4.74085, -8, 0.286361, 8, 0.286361, 8, 4.74085) 1600 | 1:0/0/terrains_peering_bit/right_side = 0 1601 | 1:0/0/terrains_peering_bit/left_side = 0 1602 | 1:0/0/custom_data_1 = true 1603 | 2:0/0 = 0 1604 | 2:0/0/terrain_set = 1 1605 | 2:0/0/terrain = 0 1606 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 4.74085, -8, 0.604539, 1.9727, 0.540903, 1.9727, 8, -1.59089, 8, -1.7818, 4.9954) 1607 | 2:0/0/terrains_peering_bit/bottom_side = 0 1608 | 2:0/0/terrains_peering_bit/left_side = 0 1609 | 2:0/0/custom_data_1 = true 1610 | 3:0/0 = 0 1611 | 3:0/0/terrain_set = 1 1612 | 3:0/0/terrain = 0 1613 | 3:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.71816, 0.795445, 1.59089, 0.668174, 1.52726, 8, -1.90907, 8) 1614 | 3:0/0/terrains_peering_bit/bottom_side = 0 1615 | 3:0/0/custom_data_1 = true 1616 | 4:0/0 = 0 1617 | 4:0/0/terrain_set = 1 1618 | 4:0/0/terrain = 0 1619 | 4:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0.986352, -1.39998, 0.986352, -1.52726, -8, 1.71816, -8, 2.09998, 8, -1.7818, 8, -1.59089, 4.67722, -8, 4.67722) 1620 | 4:0/0/terrains_peering_bit/bottom_side = 0 1621 | 4:0/0/terrains_peering_bit/left_side = 0 1622 | 4:0/0/terrains_peering_bit/top_side = 0 1623 | 4:0/0/custom_data_1 = true 1624 | 0:1/0 = 0 1625 | 0:1/0/terrain_set = 1 1626 | 0:1/0/terrain = 0 1627 | 0:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.90907, -8, 1.71816, -8, 1.70989, 8, -2.03634, 8) 1628 | 0:1/0/terrains_peering_bit/bottom_side = 0 1629 | 0:1/0/terrains_peering_bit/top_side = 0 1630 | 0:1/0/custom_data_1 = true 1631 | 1:1/0 = 0 1632 | 1:1/0/terrain_set = 1 1633 | 1:1/0/terrain = 0 1634 | 1:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.59089, 2.13179, 1.65453, 2.13179, 1.7818, 5.44085, -1.59089, 5.24994) 1635 | 1:1/0/custom_data_1 = true 1636 | 2:1/0 = 0 1637 | 2:1/0/terrain_set = 1 1638 | 2:1/0/terrain = 0 1639 | 2:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0.604539, 1.7818, 0.540903, 1.71816, 4.9954, -8, 4.74085) 1640 | 2:1/0/terrains_peering_bit/left_side = 0 1641 | 2:1/0/custom_data_1 = true 1642 | 3:1/0 = 0 1643 | 3:1/0/terrain_set = 1 1644 | 3:1/0/terrain = 0 1645 | 3:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.71816, 0.795445, 1.59089, 0.668174, 8, 0.540903, 8, 4.35904, -1.65453, 4.48631) 1646 | 3:1/0/terrains_peering_bit/right_side = 0 1647 | 3:1/0/custom_data_1 = true 1648 | 4:1/0 = 0 1649 | 4:1/0/terrain_set = 1 1650 | 4:1/0/terrain = 0 1651 | 4:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0.986352, -1.90907, 0.922717, -1.71816, -8, 1.46362, -8, 1.46362, 0.859081, 8, 0.540903, 8, 4.35904, -8, 4.67722) 1652 | 4:1/0/terrains_peering_bit/right_side = 0 1653 | 4:1/0/terrains_peering_bit/left_side = 0 1654 | 4:1/0/terrains_peering_bit/top_side = 0 1655 | 4:1/0/custom_data_1 = true 1656 | 0:2/0 = 0 1657 | 0:2/0/terrain_set = 1 1658 | 0:2/0/terrain = 0 1659 | 0:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-2.03634, -8, 1.52726, -8, 1.71816, 0.286361, 8, 0.0954533, 8, 4.74085, 1.65453, 4.61358, 1.70989, 8, -2.03634, 8) 1660 | 0:2/0/terrains_peering_bit/right_side = 0 1661 | 0:2/0/terrains_peering_bit/top_side = 0 1662 | 0:2/0/custom_data_1 = true 1663 | 1:2/0 = 0 1664 | 1:2/0/terrain_set = 1 1665 | 1:2/0/terrain = 0 1666 | 1:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.59089, -8, 1.90907, -8, 1.84543, 4.86813, -1.59089, 5.24994) 1667 | 1:2/0/terrains_peering_bit/top_side = 0 1668 | 1:2/0/custom_data_1 = true 1669 | 2:2/0 = 0 1670 | 2:2/0/terrain_set = 1 1671 | 2:2/0/terrain = 0 1672 | 2:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 4.74085, -8, 0.604539, -1.59089, 0.286361, -1.59089, -8, 1.90907, -8, 1.84543, 4.86813, -1.20908, 4.80449) 1673 | 2:2/0/terrains_peering_bit/left_side = 0 1674 | 2:2/0/terrains_peering_bit/top_side = 0 1675 | 2:2/0/custom_data_1 = true 1676 | 3:2/0 = 0 1677 | 3:2/0/terrain_set = 1 1678 | 3:2/0/terrain = 0 1679 | 3:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0.986352, 8, 0.540903, 8, 4.35904, 1.84543, 4.80449, 2.09998, 8, -1.7818, 8, -1.59089, 4.67722, -8, 4.67722) 1680 | 3:2/0/terrains_peering_bit/right_side = 0 1681 | 3:2/0/terrains_peering_bit/bottom_side = 0 1682 | 3:2/0/terrains_peering_bit/left_side = 0 1683 | 3:2/0/custom_data_1 = true 1684 | 4:2/0 = 0 1685 | 4:2/0/terrain_set = 1 1686 | 4:2/0/terrain = 0 1687 | 4:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-1.52726, -8, 1.71816, -8, 1.84543, 0.986352, 8, 0.477267, 8, 3.65905, 1.52726, 4.2954, 1.71816, 8, -1.7818, 8) 1688 | 4:2/0/terrains_peering_bit/right_side = 0 1689 | 4:2/0/terrains_peering_bit/bottom_side = 0 1690 | 4:2/0/terrains_peering_bit/top_side = 0 1691 | 4:2/0/custom_data_1 = true 1692 | 0:3/0 = 0 1693 | 0:3/0/terrain_set = 1 1694 | 0:3/0/terrain = 0 1695 | 0:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0.604539, -1.71816, 0.795445, -1.71816, -8, 1.39998, -8, 1.59089, 0.668174, 8, 0.73181, 8, 4.67722, 1.84543, 4.86813, 1.52726, 8, -1.90907, 8, -1.71816, 4.80449, -8, 4.74085) 1696 | 0:3/0/terrains_peering_bit/right_side = 0 1697 | 0:3/0/terrains_peering_bit/bottom_side = 0 1698 | 0:3/0/terrains_peering_bit/left_side = 0 1699 | 0:3/0/terrains_peering_bit/top_side = 0 1700 | 0:3/0/custom_data_1 = true 1701 | 1702 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_cp4xv"] 1703 | texture = ExtResource("6_rgdkk") 1704 | 0:6/0 = 0 1705 | 0:6/0/terrain_set = 0 1706 | 0:6/0/terrain = 4 1707 | 0:6/0/terrains_peering_bit/right_side = 4 1708 | 0:6/0/terrains_peering_bit/bottom_right_corner = 4 1709 | 0:6/0/terrains_peering_bit/bottom_side = 4 1710 | 0:7/0 = 0 1711 | 0:7/0/terrain_set = 0 1712 | 0:7/0/terrain = 4 1713 | 0:7/0/terrains_peering_bit/right_side = 4 1714 | 0:7/0/terrains_peering_bit/bottom_right_corner = 4 1715 | 0:7/0/terrains_peering_bit/bottom_side = 4 1716 | 0:7/0/terrains_peering_bit/top_side = 4 1717 | 0:7/0/terrains_peering_bit/top_right_corner = 4 1718 | 1:6/0 = 0 1719 | 1:6/0/terrain_set = 0 1720 | 1:6/0/terrain = 4 1721 | 1:6/0/terrains_peering_bit/right_side = 4 1722 | 1:6/0/terrains_peering_bit/bottom_right_corner = 4 1723 | 1:6/0/terrains_peering_bit/bottom_side = 4 1724 | 1:6/0/terrains_peering_bit/bottom_left_corner = 4 1725 | 1:6/0/terrains_peering_bit/left_side = 4 1726 | 1:7/0 = 0 1727 | 1:7/0/terrain_set = 0 1728 | 1:7/0/terrain = 4 1729 | 1:7/0/terrains_peering_bit/right_side = 4 1730 | 1:7/0/terrains_peering_bit/bottom_right_corner = 4 1731 | 1:7/0/terrains_peering_bit/bottom_side = 4 1732 | 1:7/0/terrains_peering_bit/bottom_left_corner = 4 1733 | 1:7/0/terrains_peering_bit/left_side = 4 1734 | 1:7/0/terrains_peering_bit/top_left_corner = 4 1735 | 1:7/0/terrains_peering_bit/top_side = 4 1736 | 1:7/0/terrains_peering_bit/top_right_corner = 4 1737 | 2:6/0 = 0 1738 | 2:6/0/terrain_set = 0 1739 | 2:6/0/terrain = 4 1740 | 2:6/0/terrains_peering_bit/bottom_side = 4 1741 | 2:6/0/terrains_peering_bit/bottom_left_corner = 4 1742 | 2:6/0/terrains_peering_bit/left_side = 4 1743 | 2:7/0 = 0 1744 | 2:7/0/terrain_set = 0 1745 | 2:7/0/terrain = 4 1746 | 2:7/0/terrains_peering_bit/bottom_side = 4 1747 | 2:7/0/terrains_peering_bit/bottom_left_corner = 4 1748 | 2:7/0/terrains_peering_bit/left_side = 4 1749 | 2:7/0/terrains_peering_bit/top_left_corner = 4 1750 | 2:7/0/terrains_peering_bit/top_side = 4 1751 | 0:8/0 = 0 1752 | 0:8/0/terrain_set = 0 1753 | 0:8/0/terrain = 4 1754 | 0:8/0/terrains_peering_bit/right_side = 4 1755 | 0:8/0/terrains_peering_bit/top_side = 4 1756 | 0:8/0/terrains_peering_bit/top_right_corner = 4 1757 | 1:8/0 = 0 1758 | 1:8/0/terrain_set = 0 1759 | 1:8/0/terrain = 4 1760 | 1:8/0/terrains_peering_bit/right_side = 4 1761 | 1:8/0/terrains_peering_bit/left_side = 4 1762 | 1:8/0/terrains_peering_bit/top_left_corner = 4 1763 | 1:8/0/terrains_peering_bit/top_side = 4 1764 | 1:8/0/terrains_peering_bit/top_right_corner = 4 1765 | 2:8/0 = 0 1766 | 2:8/0/terrain_set = 0 1767 | 2:8/0/terrain = 4 1768 | 2:8/0/terrains_peering_bit/left_side = 4 1769 | 2:8/0/terrains_peering_bit/top_left_corner = 4 1770 | 2:8/0/terrains_peering_bit/top_side = 4 1771 | 0:9/0 = 0 1772 | 0:9/0/terrain_set = 0 1773 | 0:9/0/terrain = 4 1774 | 0:9/0/terrains_peering_bit/right_side = 4 1775 | 1:9/0 = 0 1776 | 1:9/0/terrain_set = 0 1777 | 1:9/0/terrain = 4 1778 | 1:9/0/terrains_peering_bit/right_side = 4 1779 | 1:9/0/terrains_peering_bit/left_side = 4 1780 | 2:9/0 = 0 1781 | 2:9/0/terrain_set = 0 1782 | 2:9/0/terrain = 4 1783 | 2:9/0/terrains_peering_bit/left_side = 4 1784 | 3:9/0 = 0 1785 | 3:9/0/terrain_set = 0 1786 | 3:9/0/terrain = 4 1787 | 3:8/0 = 0 1788 | 3:8/0/terrain_set = 0 1789 | 3:8/0/terrain = 4 1790 | 3:8/0/terrains_peering_bit/top_side = 4 1791 | 3:7/0 = 0 1792 | 3:7/0/terrain_set = 0 1793 | 3:7/0/terrain = 4 1794 | 3:7/0/terrains_peering_bit/bottom_side = 4 1795 | 3:7/0/terrains_peering_bit/top_side = 4 1796 | 3:6/0 = 0 1797 | 3:6/0/terrain_set = 0 1798 | 3:6/0/terrain = 4 1799 | 3:6/0/terrains_peering_bit/bottom_side = 4 1800 | 4:6/0 = 0 1801 | 4:6/0/terrain_set = 0 1802 | 4:6/0/terrain = 4 1803 | 4:6/0/terrains_peering_bit/right_side = 4 1804 | 4:6/0/terrains_peering_bit/bottom_side = 4 1805 | 5:6/0 = 0 1806 | 5:6/0/terrain_set = 0 1807 | 5:6/0/terrain = 4 1808 | 5:6/0/terrains_peering_bit/right_side = 4 1809 | 5:6/0/terrains_peering_bit/bottom_side = 4 1810 | 5:6/0/terrains_peering_bit/bottom_left_corner = 4 1811 | 5:6/0/terrains_peering_bit/left_side = 4 1812 | 6:6/0 = 0 1813 | 6:6/0/terrain_set = 0 1814 | 6:6/0/terrain = 4 1815 | 6:6/0/terrains_peering_bit/right_side = 4 1816 | 6:6/0/terrains_peering_bit/bottom_right_corner = 4 1817 | 6:6/0/terrains_peering_bit/bottom_side = 4 1818 | 6:6/0/terrains_peering_bit/left_side = 4 1819 | 7:6/0 = 0 1820 | 7:6/0/terrain_set = 0 1821 | 7:6/0/terrain = 4 1822 | 7:6/0/terrains_peering_bit/bottom_side = 4 1823 | 7:6/0/terrains_peering_bit/left_side = 4 1824 | 4:7/0 = 0 1825 | 4:7/0/terrain_set = 0 1826 | 4:7/0/terrain = 4 1827 | 4:7/0/terrains_peering_bit/right_side = 4 1828 | 4:7/0/terrains_peering_bit/bottom_side = 4 1829 | 4:7/0/terrains_peering_bit/top_side = 4 1830 | 4:7/0/terrains_peering_bit/top_right_corner = 4 1831 | 5:7/0 = 0 1832 | 5:7/0/terrain_set = 0 1833 | 5:7/0/terrain = 4 1834 | 5:7/0/terrains_peering_bit/right_side = 4 1835 | 5:7/0/terrains_peering_bit/bottom_side = 4 1836 | 5:7/0/terrains_peering_bit/bottom_left_corner = 4 1837 | 5:7/0/terrains_peering_bit/left_side = 4 1838 | 5:7/0/terrains_peering_bit/top_left_corner = 4 1839 | 5:7/0/terrains_peering_bit/top_side = 4 1840 | 5:7/0/terrains_peering_bit/top_right_corner = 4 1841 | 6:7/0 = 0 1842 | 6:7/0/terrain_set = 0 1843 | 6:7/0/terrain = 4 1844 | 6:7/0/terrains_peering_bit/right_side = 4 1845 | 6:7/0/terrains_peering_bit/bottom_right_corner = 4 1846 | 6:7/0/terrains_peering_bit/bottom_side = 4 1847 | 6:7/0/terrains_peering_bit/left_side = 4 1848 | 6:7/0/terrains_peering_bit/top_left_corner = 4 1849 | 6:7/0/terrains_peering_bit/top_side = 4 1850 | 6:7/0/terrains_peering_bit/top_right_corner = 4 1851 | 7:7/0 = 0 1852 | 7:7/0/terrain_set = 0 1853 | 7:7/0/terrain = 4 1854 | 7:7/0/terrains_peering_bit/bottom_side = 4 1855 | 7:7/0/terrains_peering_bit/left_side = 4 1856 | 7:7/0/terrains_peering_bit/top_left_corner = 4 1857 | 7:7/0/terrains_peering_bit/top_side = 4 1858 | 4:8/0 = 0 1859 | 4:8/0/terrain_set = 0 1860 | 4:8/0/terrain = 4 1861 | 4:8/0/terrains_peering_bit/right_side = 4 1862 | 4:8/0/terrains_peering_bit/bottom_right_corner = 4 1863 | 4:8/0/terrains_peering_bit/bottom_side = 4 1864 | 4:8/0/terrains_peering_bit/top_side = 4 1865 | 5:8/0 = 0 1866 | 5:8/0/terrain_set = 0 1867 | 5:8/0/terrain = 4 1868 | 5:8/0/terrains_peering_bit/right_side = 4 1869 | 5:8/0/terrains_peering_bit/bottom_right_corner = 4 1870 | 5:8/0/terrains_peering_bit/bottom_side = 4 1871 | 5:8/0/terrains_peering_bit/bottom_left_corner = 4 1872 | 5:8/0/terrains_peering_bit/left_side = 4 1873 | 5:8/0/terrains_peering_bit/top_left_corner = 4 1874 | 5:8/0/terrains_peering_bit/top_side = 4 1875 | 6:8/0 = 0 1876 | 6:8/0/terrain_set = 0 1877 | 6:8/0/terrain = 4 1878 | 6:8/0/terrains_peering_bit/right_side = 4 1879 | 6:8/0/terrains_peering_bit/bottom_right_corner = 4 1880 | 6:8/0/terrains_peering_bit/bottom_side = 4 1881 | 6:8/0/terrains_peering_bit/bottom_left_corner = 4 1882 | 6:8/0/terrains_peering_bit/left_side = 4 1883 | 6:8/0/terrains_peering_bit/top_side = 4 1884 | 6:8/0/terrains_peering_bit/top_right_corner = 4 1885 | 7:8/0 = 0 1886 | 7:8/0/terrain_set = 0 1887 | 7:8/0/terrain = 4 1888 | 7:8/0/terrains_peering_bit/bottom_side = 4 1889 | 7:8/0/terrains_peering_bit/bottom_left_corner = 4 1890 | 7:8/0/terrains_peering_bit/left_side = 4 1891 | 7:8/0/terrains_peering_bit/top_side = 4 1892 | 4:9/0 = 0 1893 | 4:9/0/terrain_set = 0 1894 | 4:9/0/terrain = 4 1895 | 4:9/0/terrains_peering_bit/right_side = 4 1896 | 4:9/0/terrains_peering_bit/top_side = 4 1897 | 5:9/0 = 0 1898 | 5:9/0/terrain_set = 0 1899 | 5:9/0/terrain = 4 1900 | 5:9/0/terrains_peering_bit/right_side = 4 1901 | 5:9/0/terrains_peering_bit/left_side = 4 1902 | 5:9/0/terrains_peering_bit/top_left_corner = 4 1903 | 5:9/0/terrains_peering_bit/top_side = 4 1904 | 6:9/0 = 0 1905 | 6:9/0/terrain_set = 0 1906 | 6:9/0/terrain = 4 1907 | 6:9/0/terrains_peering_bit/right_side = 4 1908 | 6:9/0/terrains_peering_bit/left_side = 4 1909 | 6:9/0/terrains_peering_bit/top_side = 4 1910 | 6:9/0/terrains_peering_bit/top_right_corner = 4 1911 | 7:9/0 = 0 1912 | 7:9/0/terrain_set = 0 1913 | 7:9/0/terrain = 4 1914 | 7:9/0/terrains_peering_bit/left_side = 4 1915 | 7:9/0/terrains_peering_bit/top_side = 4 1916 | 4:10/0 = 0 1917 | 4:10/0/terrain_set = 0 1918 | 4:10/0/terrain = 4 1919 | 4:10/0/terrains_peering_bit/right_side = 4 1920 | 4:10/0/terrains_peering_bit/bottom_side = 4 1921 | 4:10/0/terrains_peering_bit/top_side = 4 1922 | 5:10/0 = 0 1923 | 5:10/0/terrain_set = 0 1924 | 5:10/0/terrain = 4 1925 | 5:10/0/terrains_peering_bit/right_side = 4 1926 | 5:10/0/terrains_peering_bit/bottom_side = 4 1927 | 5:10/0/terrains_peering_bit/bottom_left_corner = 4 1928 | 5:10/0/terrains_peering_bit/left_side = 4 1929 | 5:10/0/terrains_peering_bit/top_left_corner = 4 1930 | 5:10/0/terrains_peering_bit/top_side = 4 1931 | 6:10/0 = 0 1932 | 6:10/0/terrain_set = 0 1933 | 6:10/0/terrain = 4 1934 | 6:10/0/terrains_peering_bit/right_side = 4 1935 | 6:10/0/terrains_peering_bit/bottom_right_corner = 4 1936 | 6:10/0/terrains_peering_bit/bottom_side = 4 1937 | 6:10/0/terrains_peering_bit/left_side = 4 1938 | 6:10/0/terrains_peering_bit/top_side = 4 1939 | 6:10/0/terrains_peering_bit/top_right_corner = 4 1940 | 7:10/0 = 0 1941 | 7:10/0/terrain_set = 0 1942 | 7:10/0/terrain = 4 1943 | 7:10/0/terrains_peering_bit/bottom_side = 4 1944 | 7:10/0/terrains_peering_bit/left_side = 4 1945 | 7:10/0/terrains_peering_bit/top_side = 4 1946 | 8:10/0 = 0 1947 | 8:10/0/terrain_set = 0 1948 | 8:10/0/terrain = 4 1949 | 8:10/0/terrains_peering_bit/right_side = 4 1950 | 8:10/0/terrains_peering_bit/bottom_side = 4 1951 | 8:10/0/terrains_peering_bit/left_side = 4 1952 | 8:10/0/terrains_peering_bit/top_side = 4 1953 | 8:9/0 = 0 1954 | 8:9/0/terrain_set = 0 1955 | 8:9/0/terrain = 4 1956 | 8:9/0/terrains_peering_bit/right_side = 4 1957 | 8:9/0/terrains_peering_bit/left_side = 4 1958 | 8:9/0/terrains_peering_bit/top_side = 4 1959 | 8:8/0 = 0 1960 | 8:8/0/terrain_set = 0 1961 | 8:8/0/terrain = 4 1962 | 8:8/0/terrains_peering_bit/right_side = 4 1963 | 8:8/0/terrains_peering_bit/bottom_right_corner = 4 1964 | 8:8/0/terrains_peering_bit/bottom_side = 4 1965 | 8:8/0/terrains_peering_bit/bottom_left_corner = 4 1966 | 8:8/0/terrains_peering_bit/left_side = 4 1967 | 8:8/0/terrains_peering_bit/top_side = 4 1968 | 8:7/0 = 0 1969 | 8:7/0/terrain_set = 0 1970 | 8:7/0/terrain = 4 1971 | 8:7/0/terrains_peering_bit/right_side = 4 1972 | 8:7/0/terrains_peering_bit/bottom_side = 4 1973 | 8:7/0/terrains_peering_bit/left_side = 4 1974 | 8:7/0/terrains_peering_bit/top_left_corner = 4 1975 | 8:7/0/terrains_peering_bit/top_side = 4 1976 | 8:7/0/terrains_peering_bit/top_right_corner = 4 1977 | 8:6/0 = 0 1978 | 8:6/0/terrain_set = 0 1979 | 8:6/0/terrain = 4 1980 | 8:6/0/terrains_peering_bit/right_side = 4 1981 | 8:6/0/terrains_peering_bit/bottom_side = 4 1982 | 8:6/0/terrains_peering_bit/left_side = 4 1983 | 9:6/0 = 0 1984 | 9:6/0/terrain_set = 0 1985 | 9:6/0/terrain = 4 1986 | 9:6/0/terrains_peering_bit/right_side = 4 1987 | 9:6/0/terrains_peering_bit/bottom_right_corner = 4 1988 | 9:6/0/terrains_peering_bit/bottom_side = 4 1989 | 9:6/0/terrains_peering_bit/left_side = 4 1990 | 9:6/0/terrains_peering_bit/top_left_corner = 4 1991 | 9:6/0/terrains_peering_bit/top_side = 4 1992 | 9:7/0 = 0 1993 | 9:7/0/terrain_set = 0 1994 | 9:7/0/terrain = 4 1995 | 9:7/0/terrains_peering_bit/right_side = 4 1996 | 9:7/0/terrains_peering_bit/bottom_side = 4 1997 | 9:7/0/terrains_peering_bit/bottom_left_corner = 4 1998 | 9:7/0/terrains_peering_bit/left_side = 4 1999 | 9:7/0/terrains_peering_bit/top_side = 4 2000 | 9:7/0/terrains_peering_bit/top_right_corner = 4 2001 | 9:8/0 = 0 2002 | 9:8/0/terrain_set = 0 2003 | 9:8/0/terrain = 4 2004 | 9:8/0/terrains_peering_bit/right_side = 4 2005 | 9:8/0/terrains_peering_bit/bottom_right_corner = 4 2006 | 9:8/0/terrains_peering_bit/bottom_side = 4 2007 | 9:8/0/terrains_peering_bit/left_side = 4 2008 | 9:8/0/terrains_peering_bit/top_side = 4 2009 | 9:9/0 = 0 2010 | 9:9/0/terrain_set = 0 2011 | 9:9/0/terrain = 4 2012 | 9:9/0/terrains_peering_bit/right_side = 4 2013 | 9:9/0/terrains_peering_bit/bottom_side = 4 2014 | 9:9/0/terrains_peering_bit/left_side = 4 2015 | 9:9/0/terrains_peering_bit/top_side = 4 2016 | 9:9/0/terrains_peering_bit/top_right_corner = 4 2017 | 10:9/0 = 0 2018 | 10:9/0/terrain_set = 0 2019 | 10:9/0/terrain = 4 2020 | 10:9/0/terrains_peering_bit/right_side = 4 2021 | 10:9/0/terrains_peering_bit/bottom_side = 4 2022 | 10:9/0/terrains_peering_bit/left_side = 4 2023 | 10:9/0/terrains_peering_bit/top_left_corner = 4 2024 | 10:9/0/terrains_peering_bit/top_side = 4 2025 | 10:8/0 = 0 2026 | 10:8/0/terrain_set = 0 2027 | 10:8/0/terrain = 4 2028 | 10:8/0/terrains_peering_bit/right_side = 4 2029 | 10:8/0/terrains_peering_bit/bottom_side = 4 2030 | 10:8/0/terrains_peering_bit/bottom_left_corner = 4 2031 | 10:8/0/terrains_peering_bit/left_side = 4 2032 | 10:8/0/terrains_peering_bit/top_side = 4 2033 | 0:0/size_in_atlas = Vector2i(1, 2) 2034 | 0:0/0 = 0 2035 | 0:0/0/texture_origin = Vector2i(0, 8) 2036 | 0:0/0/y_sort_origin = 6 2037 | 0:0/0/terrain_set = 1 2038 | 0:0/0/terrain = 1 2039 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2040 | 0:0/0/terrains_peering_bit/right_side = 1 2041 | 0:0/0/terrains_peering_bit/bottom_side = 1 2042 | 0:0/0/custom_data_1 = true 2043 | 2:0/size_in_atlas = Vector2i(1, 2) 2044 | 2:0/0 = 0 2045 | 2:0/0/texture_origin = Vector2i(0, 8) 2046 | 2:0/0/y_sort_origin = 6 2047 | 2:0/0/terrain_set = 1 2048 | 2:0/0/terrain = 1 2049 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2050 | 2:0/0/terrains_peering_bit/bottom_side = 1 2051 | 2:0/0/terrains_peering_bit/left_side = 1 2052 | 2:0/0/custom_data_1 = true 2053 | 3:0/size_in_atlas = Vector2i(1, 2) 2054 | 3:0/0 = 0 2055 | 3:0/0/texture_origin = Vector2i(0, 8) 2056 | 3:0/0/y_sort_origin = 6 2057 | 3:0/0/terrain_set = 1 2058 | 3:0/0/terrain = 1 2059 | 3:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2060 | 3:0/0/terrains_peering_bit/right_side = 1 2061 | 3:0/0/terrains_peering_bit/left_side = 1 2062 | 3:0/0/custom_data_1 = true 2063 | 4:0/size_in_atlas = Vector2i(1, 2) 2064 | 4:0/0 = 0 2065 | 4:0/0/texture_origin = Vector2i(0, 8) 2066 | 4:0/0/y_sort_origin = 6 2067 | 4:0/0/terrain_set = 1 2068 | 4:0/0/terrain = 1 2069 | 4:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2070 | 4:0/0/terrains_peering_bit/left_side = 1 2071 | 4:0/0/custom_data_1 = true 2072 | 5:0/size_in_atlas = Vector2i(1, 2) 2073 | 5:0/0 = 0 2074 | 5:0/0/texture_origin = Vector2i(0, 8) 2075 | 5:0/0/y_sort_origin = 6 2076 | 5:0/0/terrain_set = 1 2077 | 5:0/0/terrain = 1 2078 | 5:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2079 | 5:0/0/terrains_peering_bit/top_side = 1 2080 | 5:0/0/custom_data_1 = true 2081 | 6:0/size_in_atlas = Vector2i(1, 2) 2082 | 6:0/0 = 0 2083 | 6:0/0/texture_origin = Vector2i(0, 8) 2084 | 6:0/0/y_sort_origin = 6 2085 | 6:0/0/terrain_set = 1 2086 | 6:0/0/terrain = 1 2087 | 6:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2088 | 6:0/0/terrains_peering_bit/right_side = 1 2089 | 6:0/0/custom_data_1 = true 2090 | 7:0/size_in_atlas = Vector2i(1, 2) 2091 | 7:0/0 = 0 2092 | 7:0/0/texture_origin = Vector2i(0, 8) 2093 | 7:0/0/y_sort_origin = 6 2094 | 7:0/0/terrain_set = 1 2095 | 7:0/0/terrain = 1 2096 | 7:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2097 | 7:0/0/terrains_peering_bit/bottom_side = 1 2098 | 7:0/0/custom_data_1 = true 2099 | 0:3/size_in_atlas = Vector2i(1, 2) 2100 | 0:3/0 = 0 2101 | 0:3/0/texture_origin = Vector2i(0, 8) 2102 | 0:3/0/y_sort_origin = 6 2103 | 0:3/0/terrain_set = 1 2104 | 0:3/0/terrain = 1 2105 | 0:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2106 | 0:3/0/terrains_peering_bit/right_side = 1 2107 | 0:3/0/terrains_peering_bit/top_side = 1 2108 | 0:3/0/custom_data_1 = true 2109 | 2:3/size_in_atlas = Vector2i(1, 2) 2110 | 2:3/0 = 0 2111 | 2:3/0/texture_origin = Vector2i(0, 8) 2112 | 2:3/0/y_sort_origin = 6 2113 | 2:3/0/terrain_set = 1 2114 | 2:3/0/terrain = 1 2115 | 2:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2116 | 2:3/0/terrains_peering_bit/left_side = 1 2117 | 2:3/0/terrains_peering_bit/top_side = 1 2118 | 2:3/0/custom_data_1 = true 2119 | 3:2/size_in_atlas = Vector2i(1, 2) 2120 | 3:2/0 = 0 2121 | 3:2/0/texture_origin = Vector2i(0, 8) 2122 | 3:2/0/y_sort_origin = 6 2123 | 3:2/0/terrain_set = 1 2124 | 3:2/0/terrain = 1 2125 | 3:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2126 | 3:2/0/custom_data_1 = true 2127 | 4:2/size_in_atlas = Vector2i(1, 2) 2128 | 4:2/0 = 0 2129 | 4:2/0/texture_origin = Vector2i(0, 8) 2130 | 4:2/0/y_sort_origin = 6 2131 | 4:2/0/terrain_set = 1 2132 | 4:2/0/terrain = 1 2133 | 4:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2134 | 4:2/0/terrains_peering_bit/bottom_side = 1 2135 | 4:2/0/terrains_peering_bit/top_side = 1 2136 | 4:2/0/custom_data_1 = true 2137 | 5:2/size_in_atlas = Vector2i(1, 2) 2138 | 5:2/0 = 0 2139 | 5:2/0/texture_origin = Vector2i(0, 8) 2140 | 5:2/0/y_sort_origin = 6 2141 | 5:2/0/terrain_set = 1 2142 | 5:2/0/terrain = 1 2143 | 5:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2144 | 5:2/0/terrains_peering_bit/bottom_side = 1 2145 | 5:2/0/terrains_peering_bit/left_side = 1 2146 | 5:2/0/terrains_peering_bit/top_side = 1 2147 | 5:2/0/custom_data_1 = true 2148 | 6:2/size_in_atlas = Vector2i(1, 2) 2149 | 6:2/0 = 0 2150 | 6:2/0/texture_origin = Vector2i(0, 8) 2151 | 6:2/0/y_sort_origin = 6 2152 | 6:2/0/terrain_set = 1 2153 | 6:2/0/terrain = 1 2154 | 6:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2155 | 6:2/0/terrains_peering_bit/right_side = 1 2156 | 6:2/0/terrains_peering_bit/left_side = 1 2157 | 6:2/0/terrains_peering_bit/top_side = 1 2158 | 6:2/0/custom_data_1 = true 2159 | 7:2/size_in_atlas = Vector2i(1, 2) 2160 | 7:2/0 = 0 2161 | 7:2/0/texture_origin = Vector2i(0, 8) 2162 | 7:2/0/y_sort_origin = 6 2163 | 7:2/0/terrain_set = 1 2164 | 7:2/0/terrain = 1 2165 | 7:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2166 | 7:2/0/terrains_peering_bit/right_side = 1 2167 | 7:2/0/terrains_peering_bit/bottom_side = 1 2168 | 7:2/0/terrains_peering_bit/top_side = 1 2169 | 7:2/0/custom_data_1 = true 2170 | 3:4/size_in_atlas = Vector2i(1, 2) 2171 | 3:4/0 = 0 2172 | 3:4/0/texture_origin = Vector2i(0, 8) 2173 | 3:4/0/y_sort_origin = 6 2174 | 3:4/0/terrain_set = 1 2175 | 3:4/0/terrain = 1 2176 | 3:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2177 | 3:4/0/terrains_peering_bit/right_side = 1 2178 | 3:4/0/terrains_peering_bit/bottom_side = 1 2179 | 3:4/0/terrains_peering_bit/left_side = 1 2180 | 3:4/0/custom_data_1 = true 2181 | 4:4/size_in_atlas = Vector2i(1, 2) 2182 | 4:4/0 = 0 2183 | 4:4/0/texture_origin = Vector2i(0, 8) 2184 | 4:4/0/y_sort_origin = 6 2185 | 4:4/0/terrain_set = 1 2186 | 4:4/0/terrain = 1 2187 | 4:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8) 2188 | 4:4/0/terrains_peering_bit/right_side = 1 2189 | 4:4/0/terrains_peering_bit/bottom_side = 1 2190 | 4:4/0/terrains_peering_bit/left_side = 1 2191 | 4:4/0/terrains_peering_bit/top_side = 1 2192 | 4:4/0/custom_data_1 = true 2193 | 2194 | [resource] 2195 | physics_layer_0/collision_layer = 4 2196 | physics_layer_0/collision_mask = 3 2197 | terrain_set_0/mode = 0 2198 | terrain_set_0/terrain_0/name = "shallow_water" 2199 | terrain_set_0/terrain_0/color = Color(0.5, 0.34375, 0.25, 1) 2200 | terrain_set_0/terrain_1/name = "soil" 2201 | terrain_set_0/terrain_1/color = Color(0.90625, 0.76212, 0.329729, 1) 2202 | terrain_set_0/terrain_2/name = "grass1" 2203 | terrain_set_0/terrain_2/color = Color(0.870536, 0.587962, 0.351712, 1) 2204 | terrain_set_0/terrain_3/name = "grass2" 2205 | terrain_set_0/terrain_3/color = Color(0.551112, 0.365578, 0.685268, 1) 2206 | terrain_set_0/terrain_4/name = "floor" 2207 | terrain_set_0/terrain_4/color = Color(0.28125, 0.5, 0.25, 1) 2208 | terrain_set_1/mode = 2 2209 | terrain_set_1/terrain_0/name = "fence" 2210 | terrain_set_1/terrain_0/color = Color(0.371094, 0.665789, 0.875, 1) 2211 | terrain_set_1/terrain_1/name = "wall" 2212 | terrain_set_1/terrain_1/color = Color(0.344866, 0.5, 0.25, 1) 2213 | custom_data_layer_0/name = "tile_type" 2214 | custom_data_layer_0/type = 2 2215 | custom_data_layer_1/name = "obstacle" 2216 | custom_data_layer_1/type = 1 2217 | sources/0 = SubResource("TileSetAtlasSource_it2i8") 2218 | sources/1 = SubResource("TileSetScenesCollectionSource_f07he") 2219 | sources/3 = SubResource("TileSetAtlasSource_agqfu") 2220 | sources/5 = SubResource("TileSetAtlasSource_22b70") 2221 | sources/6 = SubResource("TileSetAtlasSource_cp4xv") 2222 | -------------------------------------------------------------------------------- /assets/tile_sets/tile_set_floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/tile_sets/tile_set_floor.png -------------------------------------------------------------------------------- /assets/tile_sets/tile_set_floor.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cdufvmgtmkiru" 6 | path="res://.godot/imported/tile_set_floor.png-2faa1a38cd8404f7dabd12f935e7ea27.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/tile_sets/tile_set_floor.png" 14 | dest_files=["res://.godot/imported/tile_set_floor.png-2faa1a38cd8404f7dabd12f935e7ea27.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/tile_sets/tile_set_grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/tile_sets/tile_set_grass.png -------------------------------------------------------------------------------- /assets/tile_sets/tile_set_grass.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bnvwfq446cri3" 6 | path="res://.godot/imported/tile_set_grass.png-35a9e87f94506846063fe45941279be4.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/tile_sets/tile_set_grass.png" 14 | dest_files=["res://.godot/imported/tile_set_grass.png-35a9e87f94506846063fe45941279be4.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/trees/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Wenge/Sandbox/d168fe8c02d91fbba2276c587ca3d85ccb04061a/assets/trees/tree.png -------------------------------------------------------------------------------- /assets/trees/tree.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://unn5ptujnbw5" 6 | path="res://.godot/imported/tree.png-47db4e75a1bf41e1336f642c7af42836.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/trees/tree.png" 14 | dest_files=["res://.godot/imported/tree.png-47db4e75a1bf41e1336f642c7af42836.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /global/global.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - GLOBAL 5 | # - 6 | # - 全局类,它会被添加到自动加载, 7 | # - 方便和各种功能交互,同时对各种坐标进行转换 8 | # - 9 | # - 区块坐标:每个区块的坐标,由区块大小决定, 10 | # - 比如10*10的区块大小就表示10个瓷砖宽和10个瓷砖高组成一个区块 11 | # - 12 | # - 瓷砖坐标:其实就是网格坐标,局部坐标就是每个区块的坐标, 13 | # - 比如区块大小为10*10,局部坐标就是0到10, 14 | # - 全局瓷砖坐标,全局空间中的网格坐标,比如区块大小为10*10, 15 | # - 区块坐标为1,1,局部瓷砖坐标为5,5,那么全局瓷砖坐标为15,15 16 | # - 17 | # ================================================ 18 | 19 | extends Node 20 | 21 | ## 玩家 22 | var player :Player = null 23 | 24 | ## 地图加载器 25 | var map_loader :MapLoader = null 26 | 27 | ## 瓷砖集 28 | var tile_set :TileSet = null 29 | 30 | ## 瓷砖大小 31 | var tile_size :Vector2i : 32 | get: 33 | return tile_set.tile_size 34 | 35 | ## A*寻路 36 | var astar :AStar2D = null 37 | 38 | ## 区块大小 39 | var block_size :Vector2i 40 | 41 | ## 全局瓷砖坐标转为区块坐标 42 | func global_tile_to_block(global: Vector2i) -> Vector2i: 43 | 44 | var vec := Vector2(global) / Vector2(block_size) 45 | return Vector2i(vec.floor()) 46 | 47 | ## 全局瓷砖坐标转为局部瓷砖坐标 48 | func global_tile_to_local(global: Vector2i) -> Vector2i: 49 | return Vector2i(wrapi(global.x,0,block_size.x),wrapi(global.y,0,block_size.y)) 50 | 51 | ## 全局像素坐标转为瓷砖坐标 52 | func global_to_tile(global: Vector2) -> Vector2i: 53 | 54 | var vec := global / Vector2(tile_size) 55 | return Vector2i(vec.floor()) 56 | 57 | ## 全局像素坐标转为区块坐标 58 | func global_to_block(global: Vector2) -> Vector2i: 59 | 60 | var size := block_size * tile_set.tile_size 61 | return Vector2(global/Vector2(size)).floor() 62 | 63 | ## 区块坐标转为全局瓷砖坐标 64 | func block_to_global_tile(block_coords: Vector2i) -> Vector2i: 65 | return block_coords * block_size 66 | 67 | ## 区块坐标转全局像素坐标 68 | func block_to_global(block_coords: Vector2i) -> Vector2: 69 | return Vector2(block_coords)*Vector2(block_size)*Vector2(tile_size) 70 | 71 | ## 获取全局位置对应的A*id,如果closest为true,并且所在的id不存在或被禁用,那就返回一个最近的id 72 | func get_target_astar_id(global: Vector2, closest:= true) -> int: 73 | 74 | var global_tile_coords := global_to_tile(global) 75 | var id := get_astar_id(global_tile_coords) 76 | 77 | if (not astar.has_point(id)) or astar.is_point_disabled(id) and closest: 78 | # 获取离global最近的点对应的id,后面的false表示不考虑禁用的点 79 | return astar.get_closest_point(global,false) 80 | 81 | return id 82 | 83 | ## 获取一条导航路径,需要提供起点和终点的全局像素位置 84 | func get_astar_path(start: Vector2, end: Vector2) -> PackedVector2Array: 85 | 86 | var from_id := get_target_astar_id(start) 87 | var to_id := get_target_astar_id(end) 88 | # 返回从from_id到to_id的路线,是一个二维向量数组,数组的每一个元素为瓷砖的全局像素中心坐标,在我们添加A*点时候提供的 89 | # 后面的true为当没有从from_id到to_id的路线时,它会返回离到to_id最近的路线,如果为false,并且没有路线,它会返回空的数组 90 | return astar.get_point_path(from_id,to_id,true) 91 | 92 | # -------------------------------------------------------------------------------------------------------->>> 93 | 94 | ## 使用全局瓷砖坐标获取A*的点id 95 | 96 | ## 每一个瓷砖都在A*中表示一个点, 97 | ## 将这些点连接就形成了路径, 98 | ## 在A*中每添加一个点就需要一个对应的id, 99 | ## 只有使用这个id才能获取或设置点的属性, 100 | ## 计算路线也需要提供起点和终点id,所以这个id非常重要, 101 | ## 注意这个id不能是一个负数,所以生成这个id的要求是,同一个坐标生成的id必须一样, 102 | ## 不同坐标生成的id必须不一样(在A*中id不能重复),id必须是大于或等于0的整数 103 | 104 | ## 此算法由B站的一位网友提供 105 | 106 | func get_astar_id(global_tile_coords: Vector2i) -> int: 107 | 108 | var x = 2 * global_tile_coords.x if global_tile_coords.x >= 0 else -2 * global_tile_coords.x - 1 109 | var y = 2 * global_tile_coords.y if global_tile_coords.y >= 0 else -2 * global_tile_coords.y - 1 110 | 111 | @warning_ignore("integer_division") 112 | 113 | return (x + y) * (x + y + 1) / 2 + y 114 | 115 | ## ----- 下面这个也可以实现 ----- >>> 116 | 117 | ## 使用全局瓷砖坐标获取A*的点id 118 | 119 | ## 每一个瓷砖都在A*中表示一个点, 120 | ## 将这些点连接就形成了路径, 121 | ## 在A*中每添加一个点就需要一个对应的id, 122 | ## 只有使用这个id才能获取或设置点的属性, 123 | ## 计算路线也需要提供起点和终点id,所以这个id非常重要, 124 | ## 注意这个id不能是一个负数,所以生成这个id的要求是,同一个坐标生成的id必须一样, 125 | ## 不同坐标生成的id必须不一样(在A*中id不能重复),id必须是大于或等于0的整数 126 | 127 | ## 在Godot中整数二维向量的x和y都各占用32位,而整数是占用64位, 128 | ## 我们可以使用整数的前32位存储x,后32位存储y,得到的新整数用作id, 129 | ## 但这样做的前提是这个x和y不能是负数,因为要进行位运算并且id本身不能是负数, 130 | ## 所以我们可以使用wrapi方法让x和y的值在一定的范围内循环,wrapi的使用方法为wrapi(值,最小值,最大值), 131 | ## 值会在最小和最大之间循环(包括最小值,但不包括最大值)比如像下面这样 132 | ## wrapi(0,0,2)结果为0,wrapi(1,0,2)结果为1,wrapi(2,0,2)结果为0,wrapi(-1,0,2)结果为1,小于最小值就会从最大开始循环,相反大于等于最大值就会从最小值开始循环 133 | ## 像下面这样我们让它在0到100000之间循环, 134 | ## 聪明的你可能发现,这样0,0坐标和100000,100000坐标得到的id不是一样的吗?,因为100000,100000会被循环到0,0坐标, 135 | ## 是的,0,0坐标和100000,100000坐标得到的id是一样的,但是我们每次加载的瓷砖是有限的,换句话说,当我们加载100000,100000处的瓷砖时,0,0处的瓷砖早就被卸载了, 136 | ## 所以此时100000,100000坐标的id在A*中就是唯一的! 137 | 138 | # func get_astar_id(global_tile_coords: Vector2i) -> int: 139 | 140 | # # 将x和y控制在0到100000之间 141 | # var coords := Vector2i(wrapi(global_tile_coords.x,0,100000),wrapi(global_tile_coords.y,0,100000)) 142 | 143 | # # 将整数的前32位存储x,后32位存储y 144 | # var id := 0 | coords.x 145 | # id <<= 32 146 | # id |= coords.y 147 | 148 | # return id 149 | 150 | # -------------------------------------------------------------------------------------------------------->>> 151 | -------------------------------------------------------------------------------- /global/global.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dq3ps3dn5wxpo 2 | -------------------------------------------------------------------------------- /icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cbucqqokrsmq6" 6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://icon.svg" 14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /modules/enemy.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - ENEMY 5 | # - 6 | # - 敌人,虽然叫敌人,但并不会攻击玩家, 7 | # - 在离玩家足够近时会跟随玩家, 8 | # - 反之会随机游荡, 9 | # - 如果超出活动的区域会被卸载 10 | # - 11 | # ================================================ 12 | 13 | class_name Enemy 14 | extends CharacterBody2D 15 | 16 | @onready var _sprite :AnimatedSprite2D = $Body/AnimatedSprite2D 17 | @onready var _shadow :Sprite2D = $Body/Shadow 18 | @onready var _shader :ShaderMaterial = $Body/AnimatedSprite2D.material 19 | 20 | # 游荡半径 21 | @export var _patrol_radius := 200.0 22 | # 跟随距离 23 | @export var _track_distance := 200.0 24 | 25 | var _jump_velocity := 0.0 26 | var _ground_height := 0.0 27 | var _height := 0.0 28 | 29 | var _water_depth := 0.0 30 | var _move_speed_scale := 1.0 31 | 32 | # 出生位置(如果离玩家足够远,它会在出生位置附近随机游荡) 33 | var _birth_position := Vector2.ZERO 34 | var _path := PackedVector2Array() 35 | 36 | # 获取路线的时间,不要每一帧都去获取路径,相反你应该在一个随机的时间获取, 37 | # 这样当你有很多的敌人(或着类似需要获取路线的节点)时,由于它们的获取时间是随机的, 38 | # 在同一帧只有少量的节点在获取路线,大大增加性能 39 | var _time := 0.0 40 | 41 | func _ready() -> void: 42 | 43 | _birth_position = global_position 44 | 45 | func _process(delta: float) -> void: 46 | 47 | # 如果没有在活动区域内,就卸载 48 | if not Global.map_loader.is_in_active(global_position): 49 | queue_free() 50 | 51 | # 更新时间 52 | if _time > 0.0: 53 | _time -= delta 54 | 55 | func _physics_process(delta: float) -> void: 56 | 57 | _shadow.position.y = _ground_height 58 | _sprite.position.y = _height 59 | 60 | _ground_height = move_toward(_ground_height,_water_depth,delta*100.0) 61 | 62 | if (not is_equal_approx(_height,_ground_height)) or not is_zero_approx(_jump_velocity): 63 | _jump_velocity += Player.GRAVITY * delta 64 | _height = min(_ground_height,_height+(_jump_velocity*delta)) 65 | if is_equal_approx(_height,_ground_height): 66 | _jump_velocity = 0.0 67 | 68 | # 传递水的深度给着色器 69 | _shader.set_shader_parameter("water_depth",_height*_sprite.scale.y) 70 | 71 | # 如果离玩家足够近就跟随玩家 72 | if global_position.distance_to(Global.player.global_position) < _track_distance: 73 | _track_player() 74 | else : 75 | # 反之随机游荡 76 | _patrol() 77 | 78 | # 更新动画 79 | if velocity.is_zero_approx() and not _sprite.animation == "idle": 80 | _sprite.play("idle") 81 | 82 | if (not velocity.is_zero_approx()) and not _sprite.animation == "run": 83 | _sprite.play("run") 84 | 85 | func _track_player() -> void: 86 | 87 | if global_position.distance_to(Global.player.global_position) < 20.0: 88 | velocity = Vector2.ZERO 89 | return 90 | 91 | # 如果时间小于或等于0那就获取一个随机的时间,并且更新路线 92 | if _time <= 0.0: 93 | _path = Global.get_astar_path(global_position,Global.player.global_position) 94 | 95 | # 如果路线不为空,并且路线的第一个位置和当前位置处于同一个瓷砖,那就移除第一个点,否则可能会有时不时往回走的Bug 96 | if not _path.is_empty(): 97 | var coords_a := Global.global_to_tile(_path[0]) 98 | var coords_b := Global.global_to_tile(global_position) 99 | if coords_a == coords_b: 100 | _path.remove_at(0) 101 | 102 | _time = randf()*0.3 103 | 104 | if _path.is_empty(): 105 | velocity = Vector2.ZERO 106 | return 107 | 108 | var dir := global_position.direction_to(_path[0]) 109 | velocity = dir * 80 * _move_speed_scale 110 | move_and_slide() 111 | 112 | if global_position.distance_to(_path[0]) < 8.0: 113 | _path.remove_at(0) 114 | 115 | func _patrol() -> void: 116 | 117 | # 获取游荡路线不需要更新,获取一次就可以了 118 | if _path.is_empty(): 119 | 120 | var target := _birth_position + Vector2(randf_range(-_patrol_radius,_patrol_radius),randf_range(-_patrol_radius,_patrol_radius)) 121 | _path = Global.get_astar_path(global_position,target) 122 | 123 | if _path.is_empty(): 124 | velocity = Vector2.ZERO 125 | return 126 | 127 | var dir := global_position.direction_to(_path[0]) 128 | velocity = dir * 80 * _move_speed_scale 129 | move_and_slide() 130 | 131 | if global_position.distance_to(_path[0]) < 8.0: 132 | _path.remove_at(0) 133 | 134 | # 更新移动速度规格和水的深度,由TileDetector发出,详情请看tile_detector.gd文件 135 | func _on_tile_change(_global_tile_coords:Vector2i, tile_info:Dictionary) -> void: 136 | 137 | if tile_info.is_empty(): 138 | return 139 | 140 | _move_speed_scale = tile_info["move_speed_scale"] 141 | 142 | var tile_type :MapLoader.TileType = tile_info["tile_type"] 143 | 144 | if tile_type == MapLoader.TileType.SHALLOW_WATER: 145 | _water_depth = 10 146 | _shadow.visible = true 147 | elif tile_type == MapLoader.TileType.WATER: 148 | _water_depth = 30 149 | _shadow.visible = false 150 | else : 151 | _water_depth = 0 152 | _shadow.visible = true 153 | -------------------------------------------------------------------------------- /modules/enemy.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b1p67yd3tes00 2 | -------------------------------------------------------------------------------- /modules/enemy.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=17 format=3 uid="uid://sqjhg6q65unh"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://fibedao7oqot" path="res://assets/shadow.png" id="1_1rsgj"] 4 | [ext_resource type="Script" path="res://modules/enemy.gd" id="1_dbkou"] 5 | [ext_resource type="Shader" path="res://shaders/character.gdshader" id="2_10d18"] 6 | [ext_resource type="Texture2D" uid="uid://chxs84wgtxo56" path="res://assets/characters/enemy/enemy.png" id="3_ji4b7"] 7 | [ext_resource type="Script" path="res://scripts/tile_detector.gd" id="5_e64d3"] 8 | 9 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_67qcl"] 10 | resource_local_to_scene = true 11 | shader = ExtResource("2_10d18") 12 | shader_parameter/water_color = Color(0, 0.611607, 1, 1) 13 | shader_parameter/water_edge_color = Color(1, 1, 1, 1) 14 | shader_parameter/water_edge_width = 1.0 15 | shader_parameter/water_depth = 0.0 16 | 17 | [sub_resource type="AtlasTexture" id="AtlasTexture_lxagy"] 18 | atlas = ExtResource("3_ji4b7") 19 | region = Rect2(0, 0, 32, 64) 20 | 21 | [sub_resource type="AtlasTexture" id="AtlasTexture_6b1bg"] 22 | atlas = ExtResource("3_ji4b7") 23 | region = Rect2(32, 0, 32, 64) 24 | 25 | [sub_resource type="AtlasTexture" id="AtlasTexture_pjel8"] 26 | atlas = ExtResource("3_ji4b7") 27 | region = Rect2(64, 0, 32, 64) 28 | 29 | [sub_resource type="AtlasTexture" id="AtlasTexture_7wvm6"] 30 | atlas = ExtResource("3_ji4b7") 31 | region = Rect2(96, 0, 32, 64) 32 | 33 | [sub_resource type="AtlasTexture" id="AtlasTexture_i3ixn"] 34 | atlas = ExtResource("3_ji4b7") 35 | region = Rect2(128, 0, 32, 64) 36 | 37 | [sub_resource type="AtlasTexture" id="AtlasTexture_c363a"] 38 | atlas = ExtResource("3_ji4b7") 39 | region = Rect2(160, 0, 32, 64) 40 | 41 | [sub_resource type="AtlasTexture" id="AtlasTexture_2l6jr"] 42 | atlas = ExtResource("3_ji4b7") 43 | region = Rect2(192, 0, 32, 64) 44 | 45 | [sub_resource type="AtlasTexture" id="AtlasTexture_xxut5"] 46 | atlas = ExtResource("3_ji4b7") 47 | region = Rect2(224, 0, 32, 64) 48 | 49 | [sub_resource type="SpriteFrames" id="SpriteFrames_yfwc5"] 50 | animations = [{ 51 | "frames": [{ 52 | "duration": 1.0, 53 | "texture": SubResource("AtlasTexture_lxagy") 54 | }, { 55 | "duration": 1.0, 56 | "texture": SubResource("AtlasTexture_6b1bg") 57 | }], 58 | "loop": true, 59 | "name": &"idle", 60 | "speed": 3.0 61 | }, { 62 | "frames": [{ 63 | "duration": 1.0, 64 | "texture": SubResource("AtlasTexture_pjel8") 65 | }, { 66 | "duration": 1.0, 67 | "texture": SubResource("AtlasTexture_7wvm6") 68 | }, { 69 | "duration": 1.0, 70 | "texture": SubResource("AtlasTexture_i3ixn") 71 | }, { 72 | "duration": 1.0, 73 | "texture": SubResource("AtlasTexture_c363a") 74 | }, { 75 | "duration": 1.0, 76 | "texture": SubResource("AtlasTexture_2l6jr") 77 | }, { 78 | "duration": 1.0, 79 | "texture": SubResource("AtlasTexture_xxut5") 80 | }], 81 | "loop": true, 82 | "name": &"run", 83 | "speed": 10.0 84 | }] 85 | 86 | [sub_resource type="CircleShape2D" id="CircleShape2D_gjxv7"] 87 | radius = 3.2 88 | 89 | [node name="Enemy" type="CharacterBody2D"] 90 | collision_layer = 2 91 | collision_mask = 4 92 | script = ExtResource("1_dbkou") 93 | 94 | [node name="Body" type="Node2D" parent="."] 95 | 96 | [node name="Shadow" type="Sprite2D" parent="Body"] 97 | texture_filter = 1 98 | scale = Vector2(0.5, 0.2) 99 | texture = ExtResource("1_1rsgj") 100 | 101 | [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="Body"] 102 | texture_filter = 1 103 | material = SubResource("ShaderMaterial_67qcl") 104 | scale = Vector2(0.8, 0.8) 105 | sprite_frames = SubResource("SpriteFrames_yfwc5") 106 | animation = &"idle" 107 | autoplay = "idle" 108 | frame_progress = 0.539762 109 | offset = Vector2(0, -32) 110 | 111 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 112 | shape = SubResource("CircleShape2D_gjxv7") 113 | 114 | [node name="TileDetector" type="Node2D" parent="."] 115 | script = ExtResource("5_e64d3") 116 | 117 | [connection signal="tile_change" from="TileDetector" to="." method="_on_tile_change"] 118 | -------------------------------------------------------------------------------- /modules/player.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - PLAYER 5 | # - 6 | # - 玩家,可以移动跳跃,和对导航进行测试 7 | # - 8 | # ================================================ 9 | 10 | class_name Player 11 | extends CharacterBody2D 12 | 13 | ## 按下交互键时发出的信号 14 | signal interaction() 15 | 16 | const GRAVITY := 800.0 17 | 18 | @onready var _line :Line2D = $Line2D 19 | @onready var _sprite :AnimatedSprite2D = $Body/AnimatedSprite2D 20 | @onready var _shadow :Sprite2D = $Body/Shadow 21 | @onready var _shader :ShaderMaterial = $Body/AnimatedSprite2D.material 22 | @onready var _label :Label = $Body/Label 23 | 24 | var _start_position := Vector2.ZERO 25 | 26 | var _jump_velocity := 0.0 27 | var _ground_height := 0.0 28 | var _height := 0.0 29 | 30 | var _water_depth := 0.0 31 | var _move_speed_scale := 1.0 32 | 33 | func _enter_tree() -> void: 34 | Global.player = self 35 | 36 | func _physics_process(delta: float) -> void: 37 | 38 | # 发出交互 39 | if Input.is_action_just_pressed("interaction"): 40 | interaction.emit() 41 | 42 | _shadow.position.y = _ground_height 43 | _sprite.position.y = _height 44 | _label.position.y = -55+_height 45 | 46 | _ground_height = move_toward(_ground_height,_water_depth,delta*100.0) 47 | 48 | if (not is_equal_approx(_height,_ground_height)) or not is_zero_approx(_jump_velocity): 49 | _jump_velocity += GRAVITY * delta 50 | _height = min(_ground_height,_height+(_jump_velocity*delta)) 51 | if is_equal_approx(_height,_ground_height): 52 | _jump_velocity = 0.0 53 | 54 | # 传递水的深度给着色器 55 | _shader.set_shader_parameter("water_depth",_height) 56 | 57 | # 跳跃 58 | if Input.is_action_just_pressed("jump"): 59 | _jump_velocity = -300.0 60 | 61 | # 记录当前位置 62 | if Input.is_action_just_pressed("start"): 63 | _start_position = global_position 64 | 65 | # 获取一条从开始位置到当前位置的路线,使用Line2D显示出来 66 | if Input.is_action_just_pressed("end"): 67 | 68 | _line.points = Global.get_astar_path(_start_position,global_position) 69 | 70 | # 将玩家的位置传递给地图加载器,让它加载玩家周围的地图区块 71 | Global.map_loader.target_position = global_position 72 | 73 | # 移动 74 | var vec := Input.get_vector("move_left","move_right","move_up","move_down") 75 | velocity = vec * 200.0 * _move_speed_scale 76 | move_and_slide() 77 | 78 | # 更新动画 79 | if velocity.is_zero_approx() and not _sprite.animation == "idle": 80 | _sprite.play("idle") 81 | 82 | if (not velocity.is_zero_approx()) and not _sprite.animation == "run": 83 | _sprite.play("run") 84 | 85 | # 更新移动速度规格和水的深度,由TileDetector发出,详情请看tile_detector.gd文件 86 | func _on_tile_detector_tile_change(_global_tile_coords:Vector2i, tile_info:Dictionary) -> void: 87 | 88 | if tile_info.is_empty(): 89 | return 90 | 91 | _move_speed_scale = tile_info["move_speed_scale"] 92 | 93 | var tile_type :MapLoader.TileType = tile_info["tile_type"] 94 | 95 | if tile_type == MapLoader.TileType.SHALLOW_WATER: 96 | _water_depth = 10 97 | _shadow.visible = true 98 | elif tile_type == MapLoader.TileType.WATER: 99 | _water_depth = 30 100 | _shadow.visible = false 101 | else : 102 | _water_depth = 0 103 | _shadow.visible = true 104 | 105 | ## 设置交互的文本 106 | func set_interaction_text(text: String) -> void: 107 | 108 | if text.is_empty(): 109 | _label.text = "" 110 | else : 111 | _label.text = "按F%s"%text 112 | -------------------------------------------------------------------------------- /modules/player.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dq2t4bt8hnoga 2 | -------------------------------------------------------------------------------- /modules/player.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=18 format=3 uid="uid://d34wbw00crsqs"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://fibedao7oqot" path="res://assets/shadow.png" id="1_ro21p"] 4 | [ext_resource type="Script" path="res://modules/player.gd" id="1_wsljf"] 5 | [ext_resource type="Shader" path="res://shaders/character.gdshader" id="3_k3w28"] 6 | [ext_resource type="Script" path="res://scripts/tile_detector.gd" id="5_0yll3"] 7 | [ext_resource type="FontFile" uid="uid://dti01c1qmahf1" path="res://assets/fonts/vonwaon_bitmap-12px.ttf" id="6_o7302"] 8 | [ext_resource type="Texture2D" uid="uid://djfsbbaouh6vm" path="res://assets/characters/player/player.png" id="6_rtv72"] 9 | 10 | [sub_resource type="CircleShape2D" id="CircleShape2D_j6r8e"] 11 | radius = 3.2 12 | 13 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_ouh5f"] 14 | shader = ExtResource("3_k3w28") 15 | shader_parameter/water_color = Color(0, 0.611607, 1, 1) 16 | shader_parameter/water_edge_color = Color(1, 1, 1, 1) 17 | shader_parameter/water_edge_width = 1.0 18 | shader_parameter/water_depth = 0.0 19 | 20 | [sub_resource type="AtlasTexture" id="AtlasTexture_03poj"] 21 | atlas = ExtResource("6_rtv72") 22 | region = Rect2(0, 0, 32, 64) 23 | 24 | [sub_resource type="AtlasTexture" id="AtlasTexture_ksc6y"] 25 | atlas = ExtResource("6_rtv72") 26 | region = Rect2(32, 0, 32, 64) 27 | 28 | [sub_resource type="AtlasTexture" id="AtlasTexture_monfn"] 29 | atlas = ExtResource("6_rtv72") 30 | region = Rect2(64, 0, 32, 64) 31 | 32 | [sub_resource type="AtlasTexture" id="AtlasTexture_72mpb"] 33 | atlas = ExtResource("6_rtv72") 34 | region = Rect2(96, 0, 32, 64) 35 | 36 | [sub_resource type="AtlasTexture" id="AtlasTexture_e0wfe"] 37 | atlas = ExtResource("6_rtv72") 38 | region = Rect2(128, 0, 32, 64) 39 | 40 | [sub_resource type="AtlasTexture" id="AtlasTexture_ihph7"] 41 | atlas = ExtResource("6_rtv72") 42 | region = Rect2(160, 0, 32, 64) 43 | 44 | [sub_resource type="AtlasTexture" id="AtlasTexture_fb1vi"] 45 | atlas = ExtResource("6_rtv72") 46 | region = Rect2(192, 0, 32, 64) 47 | 48 | [sub_resource type="AtlasTexture" id="AtlasTexture_6gnh7"] 49 | atlas = ExtResource("6_rtv72") 50 | region = Rect2(224, 0, 32, 64) 51 | 52 | [sub_resource type="SpriteFrames" id="SpriteFrames_4wvc3"] 53 | animations = [{ 54 | "frames": [{ 55 | "duration": 1.0, 56 | "texture": SubResource("AtlasTexture_03poj") 57 | }, { 58 | "duration": 1.0, 59 | "texture": SubResource("AtlasTexture_ksc6y") 60 | }], 61 | "loop": true, 62 | "name": &"idle", 63 | "speed": 3.0 64 | }, { 65 | "frames": [{ 66 | "duration": 1.0, 67 | "texture": SubResource("AtlasTexture_monfn") 68 | }, { 69 | "duration": 1.0, 70 | "texture": SubResource("AtlasTexture_72mpb") 71 | }, { 72 | "duration": 1.0, 73 | "texture": SubResource("AtlasTexture_e0wfe") 74 | }, { 75 | "duration": 1.0, 76 | "texture": SubResource("AtlasTexture_ihph7") 77 | }, { 78 | "duration": 1.0, 79 | "texture": SubResource("AtlasTexture_fb1vi") 80 | }, { 81 | "duration": 1.0, 82 | "texture": SubResource("AtlasTexture_6gnh7") 83 | }], 84 | "loop": true, 85 | "name": &"run", 86 | "speed": 10.0 87 | }] 88 | 89 | [node name="Player" type="CharacterBody2D"] 90 | collision_mask = 4 91 | script = ExtResource("1_wsljf") 92 | 93 | [node name="TileDetector" type="Node2D" parent="."] 94 | script = ExtResource("5_0yll3") 95 | 96 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 97 | shape = SubResource("CircleShape2D_j6r8e") 98 | 99 | [node name="Line2D" type="Line2D" parent="."] 100 | top_level = true 101 | width = 2.0 102 | default_color = Color(1, 0, 0, 1) 103 | 104 | [node name="Body" type="Node2D" parent="."] 105 | 106 | [node name="Shadow" type="Sprite2D" parent="Body"] 107 | texture_filter = 1 108 | scale = Vector2(0.5, 0.2) 109 | texture = ExtResource("1_ro21p") 110 | 111 | [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="Body"] 112 | texture_filter = 1 113 | material = SubResource("ShaderMaterial_ouh5f") 114 | scale = Vector2(0.8, 0.8) 115 | sprite_frames = SubResource("SpriteFrames_4wvc3") 116 | animation = &"run" 117 | autoplay = "idle" 118 | frame_progress = 0.083007 119 | offset = Vector2(0, -32) 120 | 121 | [node name="Label" type="Label" parent="Body"] 122 | texture_filter = 1 123 | offset_left = -50.0 124 | offset_top = -55.0 125 | offset_right = 50.0 126 | offset_bottom = -47.0 127 | theme_override_colors/font_color = Color(1, 1, 1, 1) 128 | theme_override_colors/font_outline_color = Color(0.169643, 0.169643, 0.169643, 1) 129 | theme_override_constants/outline_size = 2 130 | theme_override_fonts/font = ExtResource("6_o7302") 131 | theme_override_font_sizes/font_size = 8 132 | horizontal_alignment = 1 133 | 134 | [connection signal="tile_change" from="TileDetector" to="." method="_on_tile_detector_tile_change"] 135 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="Sandbox" 14 | run/main_scene="res://scenes/main_scene.tscn" 15 | config/features=PackedStringArray("4.4", "Forward Plus") 16 | config/icon="res://icon.svg" 17 | 18 | [autoload] 19 | 20 | Global="*res://global/global.gd" 21 | 22 | [display] 23 | 24 | window/size/viewport_width=480 25 | window/size/viewport_height=270 26 | window/size/always_on_top=true 27 | window/size/window_width_override=1920 28 | window/size/window_height_override=1080 29 | window/stretch/mode="canvas_items" 30 | 31 | [input] 32 | 33 | move_left={ 34 | "deadzone": 0.5, 35 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) 36 | ] 37 | } 38 | move_right={ 39 | "deadzone": 0.5, 40 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) 41 | ] 42 | } 43 | move_up={ 44 | "deadzone": 0.5, 45 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) 46 | ] 47 | } 48 | move_down={ 49 | "deadzone": 0.5, 50 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) 51 | ] 52 | } 53 | start={ 54 | "deadzone": 0.5, 55 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) 56 | ] 57 | } 58 | end={ 59 | "deadzone": 0.5, 60 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) 61 | ] 62 | } 63 | jump={ 64 | "deadzone": 0.5, 65 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) 66 | ] 67 | } 68 | interaction={ 69 | "deadzone": 0.5, 70 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null) 71 | ] 72 | } 73 | draw_change={ 74 | "deadzone": 0.5, 75 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null) 76 | ] 77 | } 78 | 79 | [layer_names] 80 | 81 | 2d_physics/layer_1="player" 82 | 2d_physics/layer_2="enemies" 83 | 2d_physics/layer_3="obstacle" 84 | -------------------------------------------------------------------------------- /scenes/main_scene.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - MAIN SCENE 5 | # - 6 | # - 主场景,会显示加载的界面,加载完成后会关闭这个界面 7 | # - 8 | # ================================================ 9 | 10 | extends Node2D 11 | 12 | @onready var _background :ColorRect = $CanvasLayer/Background 13 | @onready var _map_loader :MapLoader = $MapLoader 14 | @onready var _tile_type :Label = $CanvasLayer/VBoxContainer/TileType 15 | @onready var _layer :Label = $CanvasLayer/VBoxContainer/Layer 16 | 17 | func _ready() -> void: 18 | 19 | _background.visible = true 20 | 21 | # 初始区块加载完成后关闭加载界面 22 | _map_loader.initial_finished.connect( 23 | func () -> void: 24 | _background.visible = false 25 | ) 26 | 27 | # 更新绘制的类型和层,测试用 28 | _map_loader.draw_change.connect( 29 | func (layer: int, tile_name: String) -> void: 30 | _tile_type.text = "当前绘制的类型:%s" % tile_name 31 | _layer.text = "当前绘制的层:%s" % layer 32 | ) 33 | -------------------------------------------------------------------------------- /scenes/main_scene.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b6cnjwuroxmn6 2 | -------------------------------------------------------------------------------- /scenes/main_scene.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=11 format=3 uid="uid://cekkt5n6qhfw0"] 2 | 3 | [ext_resource type="Script" uid="uid://b6cnjwuroxmn6" path="res://scenes/main_scene.gd" id="1_e1633"] 4 | [ext_resource type="Script" uid="uid://b10r008um2ibm" path="res://scripts/map_loader.gd" id="1_v0c7k"] 5 | [ext_resource type="TileSet" uid="uid://dy1nypwbt8mye" path="res://assets/tile_sets/tile_set.tres" id="2_tbypy"] 6 | [ext_resource type="Script" uid="uid://bgslrau3qg01a" path="res://scripts/main_camera.gd" id="3_m5ka5"] 7 | [ext_resource type="PackedScene" uid="uid://sqjhg6q65unh" path="res://modules/enemy.tscn" id="4_inr4f"] 8 | [ext_resource type="PackedScene" uid="uid://d34wbw00crsqs" path="res://modules/player.tscn" id="6_c0ggf"] 9 | [ext_resource type="FontFile" uid="uid://dti01c1qmahf1" path="res://assets/fonts/vonwaon_bitmap-12px.ttf" id="7_dy848"] 10 | 11 | [sub_resource type="FastNoiseLite" id="FastNoiseLite_kh0rw"] 12 | frequency = 0.003 13 | 14 | [sub_resource type="FastNoiseLite" id="FastNoiseLite_tba6x"] 15 | seed = 1 16 | 17 | [sub_resource type="FastNoiseLite" id="FastNoiseLite_b36bx"] 18 | seed = 2 19 | frequency = 0.005 20 | 21 | [node name="MainScene" type="Node2D"] 22 | script = ExtResource("1_e1633") 23 | 24 | [node name="MapLoader" type="Node2D" parent="." node_paths=PackedStringArray("_world", "_block_parent")] 25 | script = ExtResource("1_v0c7k") 26 | _world = NodePath("../World") 27 | _block_parent = NodePath("../World/Blocks") 28 | _tile_set = ExtResource("2_tbypy") 29 | _load_range = 6 30 | _type_noise = SubResource("FastNoiseLite_kh0rw") 31 | _grass_noise = SubResource("FastNoiseLite_tba6x") 32 | _tree_noise = SubResource("FastNoiseLite_b36bx") 33 | _layer_count = 6 34 | _sort_layers = Array[int]([5]) 35 | _enemy_packed = ExtResource("4_inr4f") 36 | 37 | [node name="World" type="Node2D" parent="."] 38 | y_sort_enabled = true 39 | 40 | [node name="Player" parent="World" instance=ExtResource("6_c0ggf")] 41 | y_sort_enabled = true 42 | 43 | [node name="MainCamera" type="Camera2D" parent="World/Player"] 44 | script = ExtResource("3_m5ka5") 45 | 46 | [node name="Blocks" type="Node2D" parent="World"] 47 | y_sort_enabled = true 48 | 49 | [node name="CanvasLayer" type="CanvasLayer" parent="."] 50 | 51 | [node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer"] 52 | anchors_preset = 4 53 | anchor_top = 0.5 54 | anchor_bottom = 0.5 55 | offset_left = 10.0 56 | offset_top = -100.0 57 | offset_right = 90.0 58 | offset_bottom = 100.0 59 | grow_vertical = 2 60 | theme_override_constants/separation = 10 61 | alignment = 1 62 | 63 | [node name="Label" type="Label" parent="CanvasLayer/VBoxContainer"] 64 | layout_mode = 2 65 | theme_override_fonts/font = ExtResource("7_dy848") 66 | theme_override_font_sizes/font_size = 4 67 | text = "W,A,S,D移动" 68 | 69 | [node name="Label2" type="Label" parent="CanvasLayer/VBoxContainer"] 70 | layout_mode = 2 71 | theme_override_fonts/font = ExtResource("7_dy848") 72 | theme_override_font_sizes/font_size = 4 73 | text = "鼠标滚轮控制放大缩小" 74 | 75 | [node name="Label3" type="Label" parent="CanvasLayer/VBoxContainer"] 76 | layout_mode = 2 77 | theme_override_fonts/font = ExtResource("7_dy848") 78 | theme_override_font_sizes/font_size = 4 79 | text = "鼠标左键绘制右键擦除" 80 | 81 | [node name="Label4" type="Label" parent="CanvasLayer/VBoxContainer"] 82 | layout_mode = 2 83 | theme_override_fonts/font = ExtResource("7_dy848") 84 | theme_override_font_sizes/font_size = 4 85 | text = "Q键记录当前位置, 86 | 在按E键计算一条从开始到当前的路线" 87 | 88 | [node name="Label5" type="Label" parent="CanvasLayer/VBoxContainer"] 89 | layout_mode = 2 90 | theme_override_fonts/font = ExtResource("7_dy848") 91 | theme_override_font_sizes/font_size = 4 92 | text = "R键切换绘制的类型" 93 | 94 | [node name="TileType" type="Label" parent="CanvasLayer/VBoxContainer"] 95 | layout_mode = 2 96 | theme_override_fonts/font = ExtResource("7_dy848") 97 | theme_override_font_sizes/font_size = 4 98 | text = "当前绘制类型:" 99 | 100 | [node name="Layer" type="Label" parent="CanvasLayer/VBoxContainer"] 101 | layout_mode = 2 102 | theme_override_fonts/font = ExtResource("7_dy848") 103 | theme_override_font_sizes/font_size = 4 104 | text = "当前绘制的层:" 105 | 106 | [node name="Background" type="ColorRect" parent="CanvasLayer"] 107 | visible = false 108 | anchors_preset = 15 109 | anchor_right = 1.0 110 | anchor_bottom = 1.0 111 | grow_horizontal = 2 112 | grow_vertical = 2 113 | color = Color(0.129464, 0.129464, 0.129464, 1) 114 | 115 | [node name="Label" type="Label" parent="CanvasLayer/Background"] 116 | texture_filter = 1 117 | layout_mode = 1 118 | anchors_preset = 8 119 | anchor_left = 0.5 120 | anchor_top = 0.5 121 | anchor_right = 0.5 122 | anchor_bottom = 0.5 123 | offset_left = -30.0 124 | offset_top = -6.0 125 | offset_right = 30.0 126 | offset_bottom = 6.0 127 | grow_horizontal = 2 128 | grow_vertical = 2 129 | theme_override_fonts/font = ExtResource("7_dy848") 130 | theme_override_font_sizes/font_size = 12 131 | text = "加载中..." 132 | -------------------------------------------------------------------------------- /scripts/astar_agent.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - ASTAR AGENT 5 | # - 6 | # - A*的代理节点,可以动态的对A*进行更新, 7 | # - 并且可以更改移动速度规格和瓷砖类型等信息 8 | # - 9 | # - 注意!如果你使用代码添加这个节点,节点的位置在添加前就应该设置, 10 | # - 因为坐标会在进入时确定,之后在对这个节点进行移动将没有效果 11 | # - 12 | # - 有两个模式,Coords(坐标模式)和Shape(形状模式) 13 | # - 14 | # - Coords模式: 15 | # - 在这个模式下用户可以提供坐标进行精准的控制, 16 | # - 比如用户提供0,0处的坐标,它会注册所在全局瓷砖坐标, 17 | # - 如果是-1,0处的坐标,那就是所在的全局瓷砖左边偏移一个瓷砖的坐标, 18 | # - 可以添加多个坐标 19 | # - 20 | # - Shape模式: 21 | # - 在这个模式下用户需要提供一个形状, 22 | # - 它会自动计算所有和这个形状产生碰撞的瓷砖,让后对这些瓷砖进行注册 23 | # - 24 | # ================================================ 25 | 26 | @tool 27 | class_name AStarAgent 28 | extends Node2D 29 | 30 | # ---------下面这些属性在运行时可以更改,它们会及时更新------->>> 31 | 32 | ## 瓷砖类型,如果是IGNORE,将不会对瓷砖类型进行注册 33 | @export var tile_type :MapLoader.TileType : 34 | 35 | set(new_value): 36 | tile_type = new_value 37 | 38 | _tile_type_update = true 39 | _update = true 40 | 41 | ## 是否注册权重 42 | @export var register_weight := false : 43 | 44 | set(new_value): 45 | register_weight = new_value 46 | 47 | _weight_update = true 48 | _update = true 49 | 50 | ## 注册的权重 51 | @export var weight := 1.0 : 52 | 53 | set(new_value): 54 | weight = new_value 55 | 56 | _weight_update = true 57 | _update = true 58 | 59 | ## 是否注册移动速度规格 60 | @export var register_move_speed_scale := false : 61 | 62 | set(new_value): 63 | register_move_speed_scale = new_value 64 | 65 | _move_speed_scale_update = true 66 | _update = true 67 | 68 | ## 注册的移动速度规格 69 | @export var move_speed_scale := 1.0 : 70 | 71 | set(new_value): 72 | move_speed_scale = new_value 73 | 74 | _move_speed_scale_update = true 75 | _update = true 76 | 77 | ## 是否注册障碍物 78 | @export var register_obstacle := true : 79 | 80 | set(new_value): 81 | register_obstacle = new_value 82 | 83 | _obstacle_update = true 84 | _update = true 85 | 86 | ## 注册的障碍物 87 | @export var obstacle := true : 88 | 89 | set(new_value): 90 | obstacle = new_value 91 | 92 | _obstacle_update = true 93 | _update = true 94 | 95 | # ----------------------------------------------------->>> 96 | 97 | ## 模式,在进入场景前设置 98 | @export_enum("Shape","Coords") var _mode :int : 99 | 100 | set(new_value): 101 | _mode = new_value 102 | 103 | if _mode == 1: 104 | coordinates = [Vector2i.ZERO] 105 | 106 | notify_property_list_changed() 107 | 108 | ## 如果模式是Shape,就需要提供这个形状 109 | var shape :Shape2D = null : 110 | 111 | set(new_value): 112 | shape = new_value 113 | 114 | if is_instance_valid(shape): 115 | shape.changed.connect( 116 | func () -> void: 117 | queue_redraw() 118 | ) 119 | queue_redraw() 120 | 121 | ## 如果模式是Coords,需要提供的坐标 122 | var coordinates :Array[Vector2i] = [] 123 | 124 | var _update := false 125 | var _tile_type_update := false 126 | var _weight_update := false 127 | var _move_speed_scale_update := false 128 | var _obstacle_update := false 129 | 130 | ## 需要注册的全局瓷砖坐标数组 131 | var _tiles := [] 132 | 133 | func _ready() -> void: 134 | 135 | if Engine.is_editor_hint(): 136 | return 137 | 138 | _tiles.clear() 139 | 140 | # 模式是Shape,计算与形状产生碰撞的瓷砖 141 | if _mode == 0: 142 | 143 | var global_rect := get_global_transform() * shape.get_rect() 144 | 145 | var begin := Global.global_to_tile(global_rect.position) 146 | var end := Global.global_to_tile(global_rect.end)+Vector2i.ONE 147 | 148 | for x :int in range(begin.x,end.x): 149 | for y :int in range(begin.y,end.y): 150 | 151 | var rect := RectangleShape2D.new() 152 | rect.size = Global.map_loader._tile_set.tile_size 153 | 154 | var t := Transform2D(0.0,Vector2(x,y)*Vector2(Global.map_loader._tile_set.tile_size)+(Vector2(Global.map_loader._tile_set.tile_size)/2.0)) 155 | if shape.collide(get_global_transform(),rect,t): 156 | _tiles.append(Vector2i(x,y)) 157 | 158 | # 模式是Coords 159 | elif _mode == 1: 160 | 161 | var global_coords := Global.global_to_tile(global_position) 162 | for coords :Vector2i in coordinates: 163 | _tiles.append(coords+global_coords) 164 | 165 | _update_all() 166 | 167 | func _process(_delta: float) -> void: 168 | 169 | if Engine.is_editor_hint(): 170 | return 171 | 172 | if _update: 173 | _update = false 174 | 175 | for global_tile_coords: Vector2i in _tiles: 176 | 177 | if _tile_type_update: 178 | 179 | if tile_type == MapLoader.TileType.IGNORE: 180 | Global.map_loader.unregister_tile_type(get_instance_id(),global_tile_coords) 181 | else : 182 | Global.map_loader.register_tile_type(get_instance_id(),global_tile_coords,tile_type) 183 | 184 | if _weight_update: 185 | 186 | if register_weight: 187 | Global.map_loader.register_astar_weight(get_instance_id(),global_tile_coords,weight) 188 | else : 189 | Global.map_loader.unregister_astar_weight(get_instance_id(),global_tile_coords) 190 | 191 | if _move_speed_scale_update: 192 | 193 | if register_move_speed_scale: 194 | Global.map_loader.register_move_speed_scale(get_instance_id(),global_tile_coords,move_speed_scale) 195 | else : 196 | Global.map_loader.unregister_move_speed_scale(get_instance_id(),global_tile_coords) 197 | 198 | if _obstacle_update: 199 | 200 | if register_obstacle: 201 | Global.map_loader.register_astar_obstacle(get_instance_id(),global_tile_coords,obstacle) 202 | else : 203 | Global.map_loader.unregister_astar_obstacle(get_instance_id(),global_tile_coords) 204 | 205 | _tile_type_update = false 206 | _weight_update = false 207 | _move_speed_scale_update = false 208 | _obstacle_update = false 209 | 210 | 211 | func _exit_tree() -> void: 212 | 213 | if Engine.is_editor_hint(): 214 | return 215 | 216 | # 退出时记得注销 217 | tile_type = MapLoader.TileType.IGNORE 218 | register_weight = false 219 | register_move_speed_scale = false 220 | register_obstacle = false 221 | 222 | _update_all() 223 | 224 | func _update_all() -> void: 225 | 226 | for global_tile_coords: Vector2i in _tiles: 227 | 228 | if tile_type == MapLoader.TileType.IGNORE: 229 | Global.map_loader.unregister_tile_type(get_instance_id(),global_tile_coords) 230 | else : 231 | Global.map_loader.register_tile_type(get_instance_id(),global_tile_coords,tile_type) 232 | 233 | if register_weight: 234 | Global.map_loader.register_astar_weight(get_instance_id(),global_tile_coords,weight) 235 | else : 236 | Global.map_loader.unregister_astar_weight(get_instance_id(),global_tile_coords) 237 | 238 | if register_move_speed_scale: 239 | Global.map_loader.register_move_speed_scale(get_instance_id(),global_tile_coords,move_speed_scale) 240 | else : 241 | Global.map_loader.unregister_move_speed_scale(get_instance_id(),global_tile_coords) 242 | 243 | if register_obstacle: 244 | Global.map_loader.register_astar_obstacle(get_instance_id(),global_tile_coords,obstacle) 245 | else : 246 | Global.map_loader.unregister_astar_obstacle(get_instance_id(),global_tile_coords) 247 | 248 | func _draw() -> void: 249 | 250 | # 在编辑器内运行时绘制形状 251 | if Engine.is_editor_hint() and _mode == 0 and is_instance_valid(shape): 252 | shape.draw(get_canvas_item(),Color(1,0,0,0.5)) 253 | 254 | func _get_property_list() -> Array[Dictionary]: 255 | 256 | if not Engine.is_editor_hint(): 257 | return [] 258 | 259 | if _mode == 0: 260 | return [ 261 | { 262 | "name":"shape", 263 | "type":TYPE_OBJECT, 264 | "hint":PROPERTY_HINT_RESOURCE_TYPE, 265 | "hint_string":"Shape2D" 266 | } 267 | ] 268 | elif _mode == 1: 269 | return [ 270 | { 271 | "name":"coordinates", 272 | "type":TYPE_ARRAY 273 | } 274 | ] 275 | 276 | return [] 277 | 278 | func _get(property: StringName) -> Variant: 279 | 280 | if property == "shape": 281 | return shape 282 | 283 | if property == "coordinates": 284 | return coordinates 285 | 286 | return null 287 | 288 | func _set(property: StringName, value: Variant) -> bool: 289 | 290 | if property == "shape": 291 | shape = value 292 | return true 293 | 294 | if property == "coordinates": 295 | coordinates = value 296 | return true 297 | 298 | return false 299 | -------------------------------------------------------------------------------- /scripts/astar_agent.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cdghfj5qq5q3o 2 | -------------------------------------------------------------------------------- /scripts/auto_tile.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - AUTO TILE 5 | # - 6 | # - 自动瓷砖匹配节点(地形匹配) 7 | # - 它会将瓷砖数据(TileData)以id的形式进行存储, 8 | # - 方便后续快速找到这个数据 9 | # - 10 | # - 目前这个节点支持3*3(带边和角)和四方向(只有边)的地形 11 | # - 12 | # ================================================ 13 | 14 | class_name AutoTile 15 | extends Node 16 | 17 | ## 方向向量和对应的名称 18 | const DIRECTIONS := { 19 | Vector2i.LEFT:"left", 20 | Vector2i.LEFT+Vector2i.DOWN:"bottom_left", 21 | Vector2i.DOWN:"bottom", 22 | Vector2i.RIGHT+Vector2i.DOWN:"bottom_right", 23 | Vector2i.RIGHT:"right", 24 | Vector2i.RIGHT+Vector2i.UP:"top_right", 25 | Vector2i.UP:"top", 26 | Vector2i.LEFT+Vector2i.UP:"top_left" 27 | } 28 | 29 | # 瓷砖数据,键为id,值为TileData 30 | var _tiles := {} 31 | 32 | ## 构建这个节点 33 | func build() -> void: 34 | 35 | # 循环出所有的瓷砖 36 | for i :int in Global.tile_set.get_source_count(): 37 | 38 | var source_id := Global.tile_set.get_source_id(i) 39 | var ts :TileSetSource = Global.tile_set.get_source(source_id) 40 | 41 | # 只有图集瓷砖支持地形 42 | if ts is TileSetAtlasSource: 43 | 44 | var source :TileSetAtlasSource = ts 45 | 46 | for j :int in source.get_tiles_count(): 47 | var atlas_coords := source.get_tile_id(j) 48 | for n :int in source.get_alternative_tiles_count(atlas_coords): 49 | var alternative := source.get_alternative_tile_id(atlas_coords,n) 50 | 51 | var tile_data := source.get_tile_data(atlas_coords,alternative) 52 | var id := _get_tile_data_id(tile_data) 53 | 54 | if id >= 0: 55 | 56 | # 将绘制信息以元数据的形式存在TileData中 57 | tile_data.set_meta("source_id",source_id) 58 | tile_data.set_meta("atlas_coords",atlas_coords) 59 | tile_data.set_meta("alternative",alternative) 60 | _tiles[id] = tile_data 61 | 62 | # 获取瓷砖数据的id 63 | func _get_tile_data_id(tile_data: TileData) -> int: 64 | 65 | if tile_data.terrain_set == -1 or tile_data.terrain == -1: 66 | return -1 67 | 68 | # 如果是3*3地形,需要获取完整八个方向的连接情况 69 | if Global.tile_set.get_terrain_set_mode(tile_data.terrain_set) == TileSet.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES: 70 | return get_tile_id(tile_data.terrain_set,tile_data.terrain, 71 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_LEFT_SIDE) == tile_data.terrain, 72 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER) == tile_data.terrain, 73 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_BOTTOM_SIDE) == tile_data.terrain, 74 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER) == tile_data.terrain, 75 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_RIGHT_SIDE) == tile_data.terrain, 76 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER) == tile_data.terrain, 77 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_TOP_SIDE) == tile_data.terrain, 78 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER) == tile_data.terrain 79 | ) 80 | 81 | # 四方向地形,只需要获取上下左右的连接,四个角保持未连接状态 82 | if Global.tile_set.get_terrain_set_mode(tile_data.terrain_set) == TileSet.TERRAIN_MODE_MATCH_SIDES: 83 | return get_tile_id(tile_data.terrain_set,tile_data.terrain, 84 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_LEFT_SIDE) == tile_data.terrain,false, 85 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_BOTTOM_SIDE) == tile_data.terrain,false, 86 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_RIGHT_SIDE) == tile_data.terrain,false, 87 | tile_data.get_terrain_peering_bit(TileSet.CELL_NEIGHBOR_TOP_SIDE) == tile_data.terrain,false 88 | ) 89 | 90 | return -1 91 | 92 | # 使用地形集和地形以及周围八个方向的连接情况获取id,顺序一定要正确否则获取到的id会不一样 93 | func get_tile_id(terrain_set: int, terrain: int, 94 | left: bool, bottom_left: bool, bottom: bool, bottom_right: bool, right: bool, top_right: bool, top: bool, top_left: bool) -> int: 95 | 96 | var id :int = 0 | terrain_set 97 | id <<= 40 98 | id |= terrain 99 | 100 | id <<= 1 101 | id |= int(left) 102 | 103 | id <<= 1 104 | id |= int(bottom_left) 105 | 106 | id <<= 1 107 | id |= int(bottom) 108 | 109 | id <<= 1 110 | id |= int(bottom_right) 111 | 112 | id <<= 1 113 | id |= int(right) 114 | 115 | id <<= 1 116 | id |= int(top_right) 117 | 118 | id <<= 1 119 | id |= int(top) 120 | 121 | id <<= 1 122 | id |= int(top_left) 123 | 124 | return id 125 | 126 | # 标准化位,当角位为连接时,所对应的两条边也应该连接,否则这个角的连接是无效的 127 | func _normal_bits(bits: Dictionary) -> void: 128 | 129 | if bits["bottom_left"]: 130 | bits["bottom_left"] = bits["bottom"] and bits["left"] 131 | 132 | if bits["bottom_right"]: 133 | bits["bottom_right"] = bits["bottom"] and bits["right"] 134 | 135 | if bits["top_right"]: 136 | bits["top_right"] = bits["top"] and bits["right"] 137 | 138 | if bits["top_left"]: 139 | bits["top_left"] = bits["top"] and bits["left"] 140 | 141 | # 绘制地形,提供的参数分别是所有的区块数据,绘制的层,全局瓷砖坐标,地形集,地形,和是否把被绘制的区块数据标记被修改,同时你可以传入地形集和地形为-1来清除地形 142 | func draw_terrain(blocks_data: Dictionary, layer: int, global_tile_coords: Vector2i, terrain_set: int, terrain: int, modifie:= false) -> void: 143 | 144 | # 清除地形 145 | if terrain_set == -1 and terrain == -1: 146 | 147 | # 绘制的区块坐标和局部瓷砖坐标 148 | var block_coords :Vector2i= Global.global_tile_to_block(global_tile_coords) 149 | var tile_coords :Vector2i = Global.global_tile_to_local(global_tile_coords) 150 | 151 | # 绘制的区块数据 152 | var data :BlockData = blocks_data[block_coords] 153 | # 使用-1来清除瓷砖 154 | data.set_tile(tile_coords,layer,-1,Vector2i(-1,-1),-1,modifie) 155 | 156 | # 更新周围的瓷砖 157 | for dir :Vector2i in DIRECTIONS.keys(): 158 | 159 | var neighbor := global_tile_coords + dir 160 | 161 | block_coords = Global.global_tile_to_block(neighbor) 162 | tile_coords = Global.global_tile_to_local(neighbor) 163 | 164 | if blocks_data.has(block_coords): 165 | 166 | var block_data :BlockData = blocks_data[block_coords] 167 | var terrain_data := block_data.get_terrain_data(tile_coords,layer) 168 | 169 | if terrain_data["terrain_set"] >= 0 and terrain_data["terrain"] >= 0: 170 | update(blocks_data,layer,neighbor,modifie) 171 | 172 | return 173 | 174 | # 最终绘制的瓷砖连接情况 175 | var bits := { 176 | "left":false, 177 | "bottom_left":false, 178 | "bottom":false, 179 | "bottom_right":false, 180 | "right":false, 181 | "top_right":false, 182 | "top":false, 183 | "top_left":false 184 | } 185 | 186 | # 需要更新的全局瓷砖坐标 187 | var update_array :Array[Vector2i] = [] 188 | 189 | for dir :Vector2i in DIRECTIONS.keys(): 190 | 191 | # 如果这是一个四方向地形,那么忽略四个角的检测 192 | if Global.tile_set.get_terrain_set_mode(terrain_set) == TileSet.TERRAIN_MODE_MATCH_SIDES and dir in [Vector2i(-1,-1),Vector2i(-1,1),Vector2i(1,-1),Vector2i(1,1)]: 193 | continue 194 | 195 | var neighbor := global_tile_coords + dir 196 | 197 | var block_coords :Vector2i= Global.global_tile_to_block(neighbor) 198 | var tile_coords :Vector2i = Global.global_tile_to_local(neighbor) 199 | 200 | if blocks_data.has(block_coords): 201 | 202 | var block_data :BlockData = blocks_data[block_coords] 203 | var terrain_data := block_data.get_terrain_data(tile_coords,layer) 204 | 205 | # 如果周围瓷砖的地形集和地形和我们绘制的一样,那就将这个方向连接情况设置为连接,并且这个瓷砖需要更新 206 | if terrain_data["terrain_set"] == terrain_set and terrain_data["terrain"] == terrain: 207 | bits[DIRECTIONS[dir]] = true 208 | update_array.append(neighbor) 209 | 210 | # 标准化 211 | _normal_bits(bits) 212 | 213 | # 获取这个瓷砖的id 214 | var id := get_tile_id(terrain_set,terrain, 215 | bits["left"], 216 | bits["bottom_left"], 217 | bits["bottom"], 218 | bits["bottom_right"], 219 | bits["right"], 220 | bits["top_right"], 221 | bits["top"], 222 | bits["top_left"]) 223 | 224 | # 接下来取出这个瓷砖数据使用元数据进行设置瓷砖 225 | if _tiles.has(id): 226 | 227 | var tile_data :TileData = _tiles[id] 228 | 229 | var block_coords :Vector2i= Global.global_tile_to_block(global_tile_coords) 230 | var tile_coords :Vector2i = Global.global_tile_to_local(global_tile_coords) 231 | 232 | var data :BlockData = blocks_data[block_coords] 233 | 234 | data.set_tile(tile_coords,layer,tile_data.get_meta("source_id"),tile_data.get_meta("atlas_coords"),tile_data.get_meta("alternative"),modifie) 235 | 236 | # 设置完更新周围需要更新的瓷砖 237 | for coords :Vector2i in update_array: 238 | update(blocks_data,layer,coords,modifie) 239 | 240 | else : 241 | push_warning("找不到图块!%s" % bits) 242 | 243 | # 更新瓷砖(和绘制一样,只不过不需要提供地形集和地形) 244 | func update(blocks_data: Dictionary, layer:int, global_tile_coords: Vector2i, modifie:bool) -> void: 245 | 246 | # 所在的区块坐标和区块局部坐标 247 | var block_coords :Vector2i= Global.global_tile_to_block(global_tile_coords) 248 | var tile_coords :Vector2i = Global.global_tile_to_local(global_tile_coords) 249 | 250 | # 不存在不需要更新 251 | if not blocks_data.has(block_coords): 252 | return 253 | 254 | # 区块数据 255 | var block_data :BlockData = blocks_data[block_coords] 256 | 257 | # 取出它本身的地形集和地形 258 | var terrain_data := block_data.get_terrain_data(tile_coords,layer) 259 | var terrain_set :int = terrain_data["terrain_set"] 260 | var terrain :int = terrain_data["terrain"] 261 | 262 | if terrain_set == -1 or terrain == -1: 263 | return 264 | 265 | # 最终绘制的瓷砖连接情况 266 | var bits := { 267 | "left":false, 268 | "bottom_left":false, 269 | "bottom":false, 270 | "bottom_right":false, 271 | "right":false, 272 | "top_right":false, 273 | "top":false, 274 | "top_left":false 275 | } 276 | 277 | for dir :Vector2i in DIRECTIONS.keys(): 278 | 279 | # 如果这是一个四方向地形,那么忽略四个角的检测 280 | if Global.tile_set.get_terrain_set_mode(terrain_set) == TileSet.TERRAIN_MODE_MATCH_SIDES and dir in [Vector2i(-1,-1),Vector2i(-1,1),Vector2i(1,-1),Vector2i(1,1)]: 281 | continue 282 | 283 | var neighbor := global_tile_coords + dir 284 | 285 | var block_coords_ :Vector2i= Global.global_tile_to_block(neighbor) 286 | var tile_coords_ :Vector2i = Global.global_tile_to_local(neighbor) 287 | 288 | if blocks_data.has(block_coords_): 289 | 290 | var block_data_ :BlockData = blocks_data[block_coords_] 291 | var terrain_data_ := block_data_.get_terrain_data(tile_coords_,layer) 292 | 293 | # 如果周围瓷砖的地形集和地形和当前一样,那就将这个方向连接情况设置为连接 294 | if terrain_set == terrain_data_["terrain_set"] and terrain == terrain_data_["terrain"]: 295 | bits[DIRECTIONS[dir]] = true 296 | 297 | # 标准化 298 | _normal_bits(bits) 299 | 300 | # 获取这个瓷砖的id 301 | var id := get_tile_id(terrain_set,terrain, 302 | bits["left"], 303 | bits["bottom_left"], 304 | bits["bottom"], 305 | bits["bottom_right"], 306 | bits["right"], 307 | bits["top_right"], 308 | bits["top"], 309 | bits["top_left"]) 310 | 311 | # 接下来取出这个瓷砖数据使用元数据进行设置瓷砖 312 | if _tiles.has(id): 313 | 314 | var tile_data :TileData = _tiles[id] 315 | block_data.set_tile(tile_coords,layer,tile_data.get_meta("source_id"),tile_data.get_meta("atlas_coords"),tile_data.get_meta("alternative"),modifie) 316 | 317 | else : 318 | push_warning("找不到图块!%s" % bits) 319 | -------------------------------------------------------------------------------- /scripts/auto_tile.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dtqnnkd7m0o6k 2 | -------------------------------------------------------------------------------- /scripts/block_data.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - BLOCK DATA 5 | # - 6 | # - 区块数据,区块节点会使用这个类来生成TileMapLayer 7 | # - 8 | # ================================================ 9 | 10 | class_name BlockData 11 | extends Resource 12 | 13 | ## TileMapLayer使用的数据,每一个代表一个层 14 | @export var tile_data :Array[PackedByteArray] = [] 15 | ## 区块大小 16 | @export var block_size := Vector2i.ZERO 17 | ## 这个区块数据所在的区块坐标 18 | @export var block_coords := Vector2i.ZERO 19 | 20 | ## 是否需要更新,一旦将区块数据传递给区块节点,之后对区块数据的修改区块节点都不会更新, 21 | ## 因为对整个数据的更新代价是很大的,所以只会更新一次,一旦程序化完成,就会将这个设置为true 22 | @export var need_update := false 23 | 24 | ## 这个区块数据是否被修改,玩家的建造和破坏都会将它设置为true,MapLoader会使用这个变量来判断是否保存 25 | @export var modifie_data := false 26 | 27 | ## 更新的数据,一旦将need_update设置为true,后续对数据的修改都会存储在这个里面,区块节点会使用它来更新,而不是更新所有的数据 28 | var update_data :Array[Dictionary] = [] 29 | ## 更新数据的互斥锁,因为他会被多个线程同时修改 30 | var update_mutex := Mutex.new() 31 | 32 | ## 构建区块数据,提供层的数量 33 | func build(layer_count: int) -> void: 34 | 35 | tile_data.clear() 36 | tile_data.resize(layer_count) 37 | 38 | for layer :int in layer_count: 39 | 40 | var data := PackedByteArray() 41 | # 每一个瓷砖将使用12个字节存储,还需要额外的2个字节来存储版本相关的数据 42 | data.resize(block_size.x*block_size.y*12+2) 43 | # 将它们填充为-1 44 | data.fill(-1) 45 | # 版本相关存储在开头的两个字节中,4.3中它被设置为0 46 | data.encode_s16(0,0) 47 | tile_data[layer] = data 48 | 49 | ## 使用局部瓷砖坐标设置瓷砖 50 | func set_tile(coords: Vector2i, layer: int, source_id: int, atlas_coords: Vector2i, alternative_tile: int, modifie:= false) -> void: 51 | 52 | # 对局部坐标进行检测 53 | if not (coords.x >= 0 and coords.x < block_size.x and coords.y >= 0 and coords.y < block_size.y): 54 | push_warning("超出区块大小!") 55 | return 56 | 57 | # 偏移两个字节(它们被用来存储版本) 58 | var index := 2 59 | # 按照坐标计算数据开始位置 60 | index += (coords.y*block_size.x+coords.x) * 12 61 | 62 | # 使用层取出数据并设置瓷砖 63 | var data :PackedByteArray = tile_data[layer] 64 | data.encode_s16(index,coords.x) 65 | data.encode_s16(index+2,coords.y) 66 | 67 | data.encode_s16(index+4,source_id) 68 | 69 | data.encode_s16(index+6,atlas_coords.x) 70 | data.encode_s16(index+8,atlas_coords.y) 71 | 72 | data.encode_s16(index+10,alternative_tile) 73 | 74 | # 标记为被修改 75 | if modifie and not modifie_data: 76 | modifie_data = true 77 | 78 | # 如果需要更新 79 | if need_update: 80 | update_mutex.lock() 81 | update_data.append({ 82 | "coords":coords, 83 | "layer":layer, 84 | "source_id":source_id, 85 | "atlas_coords":atlas_coords, 86 | "alternative_tile":alternative_tile 87 | }) 88 | update_mutex.unlock() 89 | 90 | ## 使用局部瓷砖坐标获取瓷砖信息,以字典的形式返回 91 | func get_tile(coords: Vector2i, layer: int) -> Dictionary: 92 | 93 | # 对局部坐标进行检测 94 | if not (coords.x >= 0 and coords.x < block_size.x and coords.y >= 0 and coords.y < block_size.y): 95 | push_warning("超出区块大小!") 96 | return {} 97 | 98 | # 偏移两个字节(它们被用来存储版本) 99 | var index := 2 100 | # 按照坐标计算数据开始位置 101 | index += (coords.y*block_size.x+coords.x) * 12 102 | 103 | # 使用层取出数据 104 | var data :PackedByteArray = tile_data[layer] 105 | 106 | # 返回信息 107 | return { 108 | "source_id":data.decode_s16(index+4), 109 | "atlas_coords":Vector2i(data.decode_s16(index+6),data.decode_s16(index+8)), 110 | "alternative_tile":data.decode_s16(index+10) 111 | } 112 | 113 | ## 使用局部瓷砖坐标设置场景 114 | func set_scene(coords: Vector2i, layer: int, scene_set: int, scene: int, modifie:= false) -> void: 115 | 116 | # 对局部坐标进行检测 117 | if not (coords.x >= 0 and coords.x < block_size.x and coords.y >= 0 and coords.y < block_size.y): 118 | push_warning("超出区块大小!") 119 | return 120 | 121 | # 偏移两个字节(它们被用来存储版本) 122 | var index := 2 123 | # 按照坐标计算数据开始位置 124 | index += (coords.y*block_size.x+coords.x) * 12 125 | 126 | # 使用层取出数据并设置场景 127 | var data :PackedByteArray = tile_data[layer] 128 | data.encode_s16(index,coords.x) 129 | data.encode_s16(index+2,coords.y) 130 | data.encode_s16(index+4,scene_set) 131 | data.encode_s16(index+6,0) 132 | data.encode_s16(index+8,0) 133 | data.encode_s16(index+10,scene) 134 | 135 | # 标记为被修改 136 | if modifie and not modifie_data: 137 | modifie_data = true 138 | 139 | # 如果需要更新 140 | if need_update: 141 | update_mutex.lock() 142 | update_data.append({ 143 | "coords":coords, 144 | "layer":layer, 145 | "source_id":scene_set, 146 | "atlas_coords":Vector2i.ZERO, 147 | "alternative_tile":scene 148 | }) 149 | update_mutex.unlock() 150 | 151 | ## 使用局部瓷砖坐标获取地形信息 152 | func get_terrain_data(coords: Vector2i, layer: int) -> Dictionary: 153 | 154 | # 对局部坐标进行检测 155 | if not (coords.x >= 0 and coords.x < block_size.x and coords.y >= 0 and coords.y < block_size.y): 156 | push_warning("超出区块大小!") 157 | return { 158 | "terrain_set":-1, 159 | "terrain":-1 160 | } 161 | 162 | # 获取瓷砖信息 163 | var dict := get_tile(coords,layer) 164 | 165 | # 使用瓷砖信息从TileSet中获取地形信息 166 | if Global.tile_set.has_source(dict["source_id"]) and Global.tile_set.get_source(dict["source_id"]) is TileSetAtlasSource: 167 | var source :TileSetAtlasSource = Global.tile_set.get_source(dict["source_id"]) 168 | var tile_data_ :TileData = source.get_tile_data(dict["atlas_coords"],dict["alternative_tile"]) 169 | return { 170 | "terrain_set":tile_data_.terrain_set, 171 | "terrain":tile_data_.terrain 172 | } 173 | else: 174 | return { 175 | "terrain_set":-1, 176 | "terrain":-1 177 | } 178 | -------------------------------------------------------------------------------- /scripts/block_data.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dxcxb1fvgtoov 2 | -------------------------------------------------------------------------------- /scripts/block_node.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - BLOCK NODE 5 | # - 6 | # - 区块节点,使用区块数据生成TileMapLayer 7 | # - 8 | # ================================================ 9 | 10 | class_name BlockNode 11 | extends Node2D 12 | 13 | # 所有层的TileMapLayer 14 | var _layers :Array[TileMapLayer] = [] 15 | 16 | ## 区块数据 17 | var block_data :BlockData 18 | ## 需要进行y排序的层 19 | var sort_layers :Array[int] 20 | 21 | func _ready() -> void: 22 | 23 | y_sort_enabled = true 24 | 25 | # 设置这个节点的全局位置 26 | global_position = Global.block_to_global(block_data.block_coords) 27 | 28 | _layers.resize(block_data.tile_data.size()) 29 | 30 | # 使用区块数据生成TileMapLayer 31 | for layer :int in block_data.tile_data.size(): 32 | 33 | var node := TileMapLayer.new() 34 | node.tile_set = Global.tile_set 35 | node.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST 36 | node.tile_map_data = block_data.tile_data[layer] 37 | _layers[layer] = node 38 | 39 | # 禁用导航,我们不需要 40 | node.navigation_enabled = false 41 | 42 | # 如果需要y排序 43 | if layer in sort_layers: 44 | node.y_sort_enabled = true 45 | else : 46 | # 将不需要y排序的层显示在下面 47 | node.z_index = -1 48 | 49 | add_child(node) 50 | 51 | func _process(_delta: float) -> void: 52 | 53 | # 更新数据 54 | var update_data :Array[Dictionary] = [] 55 | 56 | # 尝试去拿区块数据的更新锁,不要强行拿,如果强行去拿,而此时锁被其它线程拿着,会造成卡顿 57 | if block_data.update_mutex.try_lock(): 58 | 59 | # 不要一直占着锁,先将数据拿到,将区块数据中的更新数据置空,然后将锁丢掉在更新 60 | update_data = block_data.update_data 61 | block_data.update_data = [] 62 | 63 | block_data.update_mutex.unlock() 64 | 65 | # 更新 66 | for dict :Dictionary in update_data: 67 | 68 | var tile_map :TileMapLayer = _layers[dict["layer"]] 69 | tile_map.set_cell(dict["coords"],dict["source_id"],dict["atlas_coords"],dict["alternative_tile"]) 70 | 71 | # 我们还需要通知地图加载器更新瓷砖 72 | var global_tile_coords :Vector2i = Global.block_to_global_tile(block_data.block_coords)+dict["coords"] 73 | Global.map_loader.update_tile(global_tile_coords) 74 | 75 | ## 使用局部瓷砖坐标获取瓷砖数据 76 | func get_tile_data(layer: int, coords: Vector2i) -> TileData: 77 | 78 | if not (coords.x >= 0 and coords.x < block_data.block_size.x and coords.y >= 0 and coords.y < block_data.block_size.y): 79 | push_warning("超出区块大小!") 80 | return null 81 | 82 | var tile_mpa :TileMapLayer = _layers[layer] 83 | return tile_mpa.get_cell_tile_data(coords) 84 | -------------------------------------------------------------------------------- /scripts/block_node.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dayaatqg8jjx1 2 | -------------------------------------------------------------------------------- /scripts/main_camera.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - MAIN CAMERA 5 | # - 6 | # - 主相机,可以使用鼠标滚轮控制缩放 7 | # - 8 | # ================================================ 9 | 10 | class_name MainCamera 11 | extends Camera2D 12 | 13 | func _input(event: InputEvent) -> void: 14 | 15 | if event is InputEventMouseButton: 16 | if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: 17 | zoom.x = clampf(zoom.x - 0.01,0.1,10.0) 18 | zoom.y = zoom.x 19 | if event.button_index == MOUSE_BUTTON_WHEEL_UP: 20 | zoom.x = clampf(zoom.x + 0.01,0.1,10.0) 21 | zoom.y = zoom.x 22 | -------------------------------------------------------------------------------- /scripts/main_camera.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bgslrau3qg01a 2 | -------------------------------------------------------------------------------- /scripts/map_loader.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - MAP LOADER 5 | # - 6 | # - 负责对地图进行加载和卸载, 7 | # - 用户只需要提供区块大小瓷砖集等信息即可 8 | # - 9 | # ================================================ 10 | 11 | class_name MapLoader 12 | extends Node2D 13 | 14 | ## 绘制的瓷砖发生改变是发出,提供绘制的层和瓷砖名称 15 | signal draw_change(layer: int, tile_name: String) 16 | 17 | ## 初始的区块加载完成时发出,可作为加载页面关闭的信号 18 | signal initial_finished() 19 | 20 | ## 区块加载完成时发出,提供加载完成的区块坐标 21 | signal block_load_finished(block_coords: Vector2i) 22 | 23 | ## 区块卸载完成时发出,提供卸载完成的区块坐标 24 | signal block_unload_finished(block_coords: Vector2i) 25 | 26 | ## 当瓷砖发生改变时发出,比如擦除瓷砖或者绘制瓷砖,提供全局的瓷砖坐标 27 | signal tile_change(global_tile_coords: Vector2i) 28 | 29 | ## 瓷砖类型,按照你的游戏进行设计 30 | enum TileType{ 31 | 32 | ## 不被考虑,应该被忽略的瓷砖 33 | IGNORE = 0, 34 | ## 水 35 | WATER = 1, 36 | ## 浅水 37 | SHALLOW_WATER = 2, 38 | ## 地面 39 | GROUND = 3, 40 | ## 草地 41 | GRASS = 4 42 | } 43 | 44 | ## 对应瓷砖的权重(不包括忽略的瓷砖类型),这个值越大移动到这个瓷砖的代价就越大,按照你的游戏进行设计 45 | const ASTAR_WEIGHT := [ 46 | 2.5, 47 | 1.8, 48 | 1.0, 49 | 1.2 50 | ] 51 | 52 | ## 对应瓷砖的移动速度规格(不包括忽略的瓷砖类型),权重越大这个值应该越小,按照你的游戏进行设置 53 | const MOVE_SPEED_SCALE := [ 54 | 1.0/2.5, 55 | 1.0/1.8, 56 | 1.0, 57 | 1.0/1.2 58 | ] 59 | 60 | # 自动瓷砖的匹配节点 61 | var _auto_tile :AutoTile 62 | 63 | # 生物会被添加到这个节点下面 64 | @export var _world :Node2D 65 | 66 | # 区块的父节点,区块节点会被添加到这个节点下面 67 | @export var _block_parent :Node2D 68 | 69 | # 提供的瓷砖集 70 | @export var _tile_set :TileSet 71 | 72 | # 区块大小,10*10表示10个瓷砖宽和10个瓷砖高组成一个区块, 73 | # 过大会导致区块加载过慢,过小会导致区块节点过多 74 | @export var _block_size := Vector2i(10,10) 75 | 76 | # 区块加载的范围,1表示加载目标周围一圈的区块,0表示只加载目标位置一个区块 77 | @export var _load_range := 1 78 | 79 | # 用来确定瓷砖类型的噪声 80 | @export var _type_noise :FastNoiseLite 81 | 82 | # 用来确定草地类型的噪声 83 | @export var _grass_noise :FastNoiseLite 84 | 85 | # 用来确定树的数量的噪声 86 | @export var _tree_noise :FastNoiseLite 87 | 88 | # 瓷砖层的数量 89 | @export var _layer_count :int 90 | 91 | # 需要进行y排序的层 92 | @export var _sort_layers :Array[int] 93 | 94 | # 敌人的场景 95 | @export var _enemy_packed :PackedScene 96 | 97 | # 当前的区块坐标 98 | var _block_coords := Vector2i.ZERO 99 | # 区块是否是第一次加载 100 | var _initialize := true 101 | # 已经加载的区块坐标 102 | var _blocks := [] 103 | # 初始的区块坐标 104 | var _initial_blocks := [] 105 | # 已经加载的区块节点,键是区块坐标,值是区块节点 106 | var _block_nodes := {} 107 | 108 | # 线程 109 | var _thread := Thread.new() 110 | # 线程是否退出 111 | var _thread_exit := false 112 | # 信号量,用来休眠或唤醒线程 113 | var _semaphore := Semaphore.new() 114 | # 区块数据,键是区块坐标,值是区块数据 115 | var _blocks_data := {} 116 | # 区块数据互斥锁 117 | var _data_mutex := Mutex.new() 118 | 119 | # 更新队列 120 | var _update_queue := [] 121 | # 更新队列互斥锁 122 | var _mutex := Mutex.new() 123 | 124 | ## 目标位置,使用这个位置进行区块加载 125 | var target_position := Vector2.ZERO 126 | 127 | # Godot内置的A*寻路算法 128 | var _astar := AStar2D.new() 129 | # 注册的瓷砖类型 130 | var _tile_types := {} 131 | # 注册的瓷砖权重 132 | var _astar_weights := {} 133 | # 注册的移动速度规格 134 | var _move_speed_scales := {} 135 | # 注册的障碍物 136 | var _astar_obstacles := {} 137 | 138 | # --- 用来演示建造的变量,在你的游戏中不需要添加 --- >>> 139 | 140 | # 绘制索引 141 | var _draw_index := 0 142 | # 绘制的全局瓷砖坐标 143 | var _draw_coords := Vector2i.ZERO 144 | # 绘制模式,0表示不绘制,1表示绘制,2表示擦除 145 | var _draw_mode := 0 146 | # 绘制信息,使用绘制索引取出 147 | var _draw_info := [ 148 | { 149 | "name":"地板", 150 | "mode":1, 151 | "layer":4, 152 | "terrain_set":0, 153 | "terrain":4 154 | }, 155 | { 156 | "name":"墙", 157 | "mode":1, 158 | "layer":5, 159 | "terrain_set":1, 160 | "terrain":1 161 | }, 162 | { 163 | "name":"栅栏", 164 | "mode":1, 165 | "layer":5, 166 | "terrain_set":1, 167 | "terrain":0 168 | }, 169 | { 170 | "name":"门", 171 | "mode":2, 172 | "layer":5, 173 | "scene_set":1, 174 | "scene":2 175 | }, 176 | { 177 | "name":"地面", 178 | "mode":1, 179 | "layer":1, 180 | "terrain_set":0, 181 | "terrain":1 182 | } 183 | ] 184 | 185 | func _enter_tree() -> void: 186 | 187 | # 将自己传递到全局 188 | Global.map_loader = self 189 | 190 | func _ready() -> void: 191 | 192 | # 创建地图数据保存路径 193 | DirAccess.make_dir_recursive_absolute("user://map") 194 | 195 | # 打印地图数据全局路径 196 | print("--------------------------存档存储路径---------------------->>>") 197 | print(ProjectSettings.globalize_path("user://map")) 198 | print("---------------------------------------------------------->>>") 199 | 200 | # 将信息传递给全局类 201 | Global.tile_set = _tile_set 202 | Global.block_size = _block_size 203 | Global.astar = _astar 204 | 205 | # 构建自动瓷砖匹配节点,并把它添加成子节点 206 | _auto_tile = AutoTile.new() 207 | _auto_tile.build() 208 | add_child(_auto_tile) 209 | 210 | # 启动线程 211 | _thread.start(_thread_run) 212 | 213 | func _exit_tree() -> void: 214 | 215 | # 当退出时将线程退出标记为是 216 | _thread_exit = true 217 | # 唤醒线程 218 | _semaphore.post() 219 | # 等待线程退出后释放线程 220 | _thread.wait_to_finish() 221 | 222 | func _input(event: InputEvent) -> void: 223 | 224 | if event is InputEventMouseButton: 225 | 226 | # 按下左键时将绘制模式设置为1并记录鼠标的全局瓷砖坐标 227 | if event.button_index == MOUSE_BUTTON_LEFT: 228 | 229 | _draw_coords= Global.global_to_tile(get_global_mouse_position()) 230 | 231 | if (_draw_mode == 0) and event.is_pressed(): 232 | # 如果按下,绘制模式设置为1反之设置为0 233 | _draw_mode = 1 if event.is_pressed() else 0 234 | # 如果是第一次按下还需要调用一次绘制地图 235 | _draw_map() 236 | 237 | # 如果按下,绘制模式设置为1反之设置为0 238 | _draw_mode = 1 if event.is_pressed() else 0 239 | 240 | # 按下右键时将绘制模式设置为2并记录鼠标的全局瓷砖坐标 241 | if event.button_index == MOUSE_BUTTON_RIGHT: 242 | 243 | _draw_coords= Global.global_to_tile(get_global_mouse_position()) 244 | 245 | if (_draw_mode == 0) and event.is_pressed(): 246 | # 如果按下,绘制模式设置为2反之设置为0 247 | _draw_mode = 2 if event.is_pressed() else 0 248 | # 如果是第一次按下还需要调用一次绘制地图 249 | _draw_map() 250 | 251 | # 如果按下,绘制模式设置为2反之设置为0 252 | _draw_mode = 2 if event.is_pressed() else 0 253 | 254 | func _process(_delta: float) -> void: 255 | 256 | # 当前鼠标的全局瓷砖坐标 257 | var cur_coords := Global.global_to_tile(get_global_mouse_position()) 258 | 259 | # 如果鼠标当前的全局瓷砖坐标和上一次的绘制坐标不一样就更新 260 | if cur_coords != _draw_coords: 261 | _draw_coords = cur_coords 262 | 263 | # 绘制鼠标的全局瓷砖矩形框 264 | queue_redraw() 265 | 266 | # 如果绘制模式不是0就重新调用绘制地图 267 | if _draw_mode > 0: 268 | _draw_map() 269 | 270 | # 切换绘制的瓷砖类型 271 | if Input.is_action_just_pressed("draw_change"): 272 | _draw_index = wrapi(_draw_index+1,0,_draw_info.size()) 273 | draw_change.emit(_draw_info[_draw_index]["layer"],_draw_info[_draw_index]["name"]) 274 | 275 | # 将目标位置转为区块坐标 276 | var coords :Vector2i = Global.global_to_block(target_position) 277 | 278 | # 区块坐标发生变化或第一次加载为true那就更新区块,不要每一帧都更新坐标 279 | if coords != _block_coords or _initialize: 280 | _block_coords = coords 281 | _update_block() 282 | 283 | func _draw() -> void: 284 | 285 | # 绘制鼠标的全局瓷砖矩形框 286 | var pos := _draw_coords * _tile_set.tile_size 287 | var rect := Rect2(pos,_tile_set.tile_size) 288 | draw_rect(rect,Color(0,1,0,1),false) 289 | 290 | ## 绘制地图,用于演示,在你的游戏中不用添加 291 | func _draw_map() -> void: 292 | 293 | # 取出绘制信息 294 | var info :Dictionary = _draw_info[_draw_index] 295 | var mode :int = info["mode"] 296 | 297 | # 用不同的绘制模式调用不同的绘制方法 298 | match mode: 299 | 0: 300 | if _draw_mode == 1: 301 | draw_tile(info["layer"],_draw_coords,info["source_id"],info["atlas_coords"],info["alternative_tile"]) 302 | else : 303 | erase_tile(info["layer"],_draw_coords) 304 | 1: 305 | if _draw_mode == 1: 306 | draw_terrain(info["layer"],_draw_coords,info["terrain_set"],info["terrain"]) 307 | else : 308 | erase_terrain(info["layer"],_draw_coords) 309 | 2: 310 | if _draw_mode == 1: 311 | draw_scene(info["layer"],_draw_coords,info["scene_set"],info["scene"]) 312 | else : 313 | erase_scene(info["layer"],_draw_coords) 314 | 315 | ## 目标位置是否在活动区域内 316 | func is_in_active(target: Vector2) -> bool: 317 | 318 | var up_left_margin := Vector2(_block_size * _tile_set.tile_size) * _load_range 319 | var down_right_margin := Vector2(_block_size * _tile_set.tile_size) * (_load_range+1) 320 | var global :Vector2= Vector2(Global.block_to_global_tile(_block_coords)) * Vector2(_tile_set.tile_size) 321 | var rect := Rect2() 322 | rect.position = global - up_left_margin 323 | rect.end = global + down_right_margin 324 | return rect.has_point(target) 325 | 326 | ## 绘制地形,区块数据会被标记为被修改,在游戏中玩家手动建造可以调用这个方法 327 | func draw_terrain(layer: int, global_tile_coords: Vector2i, terrain_set: int, terrain: int) -> void: 328 | 329 | _data_mutex.lock() 330 | 331 | _auto_tile.draw_terrain(_blocks_data,layer,global_tile_coords,terrain_set,terrain,true) 332 | 333 | _data_mutex.unlock() 334 | 335 | ## 擦除地形,区块数据会被标记为被修改,在游戏中玩家破坏瓷砖可以调用这个方法 336 | func erase_terrain(layer: int, global_tile_coords: Vector2i) -> void: 337 | 338 | _data_mutex.lock() 339 | 340 | _auto_tile.draw_terrain(_blocks_data,layer,global_tile_coords,-1,-1,true) 341 | 342 | _data_mutex.unlock() 343 | 344 | ## 绘制瓷砖,区块数据会被标记为被修改 345 | func draw_tile(layer: int, global_tile_coords: Vector2i, source_id: int, atlas_coords: Vector2i, alternative_tile: int) -> void: 346 | 347 | var block_coords :Vector2i = Global.global_tile_to_block(global_tile_coords) 348 | var tile_coords :Vector2i = Global.global_tile_to_local(global_tile_coords) 349 | 350 | _data_mutex.lock() 351 | 352 | if _blocks_data.has(block_coords): 353 | var data :BlockData = _blocks_data[block_coords] 354 | data.set_tile(tile_coords,layer,source_id,atlas_coords,alternative_tile,true) 355 | 356 | _data_mutex.unlock() 357 | 358 | ## 擦除瓷砖,区块数据会被标记为被修改 359 | func erase_tile(layer: int, global_tile_coords: Vector2i) -> void: 360 | 361 | var block_coords :Vector2i = Global.global_tile_to_block(global_tile_coords) 362 | var tile_coords :Vector2i = Global.global_tile_to_local(global_tile_coords) 363 | 364 | _data_mutex.lock() 365 | 366 | if _blocks_data.has(block_coords): 367 | var data :BlockData = _blocks_data[block_coords] 368 | data.set_tile(tile_coords,layer,-1,Vector2i(-1,1),-1,true) 369 | 370 | _data_mutex.unlock() 371 | 372 | ## 绘制场景,区块数据会被标记为被修改 373 | func draw_scene(layer: int, global_tile_coords: Vector2i, scene_set: int, scene: int) -> void: 374 | 375 | draw_tile(layer,global_tile_coords,scene_set,Vector2i.ZERO,scene) 376 | 377 | ## 擦除场景,区块数据会被标记为被修改 378 | func erase_scene(layer: int, global_tile_coords: Vector2i) -> void: 379 | 380 | erase_tile(layer,global_tile_coords) 381 | 382 | # 更新区块,不要每一帧都调用这个方法,相反你应该在所在区块坐标发生改变时调用 383 | func _update_block() -> void: 384 | 385 | # 按照当前所在区块坐标计算出的所有区块坐标 386 | var all_blocks :Array[Vector2i] = [] 387 | # 需要加载的区块坐标 388 | var load_arr :Array[Vector2i] = [] 389 | # 需要被卸载的区块坐标 390 | var unload_arr :Array[Vector2i] = [] 391 | 392 | # 按照区块坐标和加载范围计算出左上和右下的区块坐标 393 | var start := _block_coords - Vector2i(_load_range,_load_range) 394 | var end := _block_coords + Vector2i(_load_range,_load_range) + Vector2i.ONE 395 | 396 | # 按照左上和右下区块坐标计算出所有的区块坐标 397 | for x :int in range(start.x,end.x): 398 | for y :int in range(start.y,end.y): 399 | 400 | var coords := Vector2i(x,y) 401 | all_blocks.append(coords) 402 | 403 | # 如果已加载的坐标中没有这个坐标,那这个坐标是需要加载的坐标 404 | if not _blocks.has(coords): 405 | load_arr.append(coords) 406 | 407 | # 需要卸载的坐标 408 | for coords :Vector2i in _blocks: 409 | if not all_blocks.has(coords): 410 | unload_arr.append(coords) 411 | 412 | # 将需要加载的坐标添加到已加载的坐标中 413 | for coords: Vector2i in load_arr: 414 | _blocks.append(coords) 415 | 416 | # 移除要卸载的坐标 417 | for coords: Vector2i in unload_arr: 418 | _blocks.erase(coords) 419 | 420 | var dict := { 421 | "load":load_arr, 422 | "unload":unload_arr 423 | } 424 | 425 | # 如果是第一次加载,那就把需要加载的区块坐标保存到初始坐标中,并将第一次加载标记为否 426 | if _initialize: 427 | _initial_blocks = load_arr.duplicate() 428 | _initialize = false 429 | 430 | # 将更新信息添加到更新队列中,这个队列会同时被主线程和子线程修改,需要互斥锁 431 | _mutex.lock() 432 | _update_queue.append(dict) 433 | _mutex.unlock() 434 | 435 | # 需要更新,唤醒线程 436 | _semaphore.post() 437 | 438 | # 加载区块节点 439 | func _block_loaded(block_data: BlockData) -> void: 440 | 441 | # 如果初始区块不为空,并且初始区块中存在当前区块坐标,那就移除它 442 | if not _initial_blocks.is_empty(): 443 | 444 | if _initial_blocks.has(block_data.block_coords): 445 | _initial_blocks.erase(block_data.block_coords) 446 | 447 | # 如果移除后变成空的,那就发射初始完成信号 448 | if _initial_blocks.is_empty(): 449 | initial_finished.emit() 450 | 451 | # 使用区块数据创建区块节点 452 | var node := BlockNode.new() 453 | node.block_data = block_data 454 | node.sort_layers = _sort_layers 455 | 456 | # 添加区块节点 457 | _block_parent.add_child(node) 458 | _block_nodes[block_data.block_coords] = node 459 | 460 | # 加载A*寻路的区块 461 | _load_astar_block(block_data.block_coords) 462 | 463 | # 通知区块加载完成 464 | block_load_finished.emit(block_data.block_coords) 465 | 466 | # 区块加载完成后生成一定数量的敌人,按照你的游戏设计 467 | var size := Vector2(_block_size) * Vector2(_tile_set.tile_size) 468 | var global := Global.block_to_global_tile(block_data.block_coords) * _tile_set.tile_size 469 | 470 | if randf() > 0.1: 471 | return 472 | 473 | for i :int in randi_range(0,3): 474 | 475 | var target :Vector2 = Vector2(global) + Vector2(randf_range(0,size.x),randf_range(0,size.y)) 476 | var id := _astar.get_closest_point(target) 477 | 478 | var enemy :Enemy= _enemy_packed.instantiate() 479 | enemy.global_position = _astar.get_point_position(id) 480 | 481 | _world.add_child(enemy) 482 | 483 | # 卸载区块节点 484 | func _block_unloaded(block_coords: Vector2i) -> void: 485 | 486 | if not _block_nodes.has(block_coords): 487 | return 488 | 489 | # 卸载区块节点 490 | var node :BlockNode = _block_nodes[block_coords] 491 | node.queue_free() 492 | _block_nodes.erase(block_coords) 493 | 494 | # 卸载A*区块 495 | _unload_astar_block(block_coords) 496 | 497 | # 通知区块卸载完成 498 | block_unload_finished.emit(block_coords) 499 | 500 | # 使用区块坐标获取区块文件名称 501 | func _get_block_file_name(block_coords: Vector2i) -> String: 502 | return "block_data_%s_%s.res" % [block_coords.x,block_coords.y] 503 | 504 | # 程序化生成区块数据 505 | func _generate_block_data(block_coords: Vector2i, block_data: BlockData) -> void: 506 | 507 | # 使用噪声生成瓷砖 508 | 509 | _data_mutex.lock() 510 | 511 | _blocks_data[block_coords] = block_data 512 | 513 | var tiles :Array[Vector2i] = [] 514 | 515 | for x :int in range(0,_block_size.x): 516 | for y :int in range(0,_block_size.y): 517 | 518 | var tile_coords := Vector2i(x,y) 519 | var global_tile_coords :Vector2i = (block_coords * _block_size) + tile_coords 520 | 521 | var type_value := (_type_noise.get_noise_2dv(global_tile_coords)+1.0) / 2.0 522 | var grass_value := (_grass_noise.get_noise_2dv(global_tile_coords)+1.0) / 2.0 523 | 524 | if type_value < 0.4: 525 | block_data.set_tile(tile_coords,0,0,Vector2i.ZERO,0) 526 | elif type_value >= 0.4 and type_value < 0.5: 527 | _auto_tile.draw_terrain(_blocks_data,0,global_tile_coords,0,0) 528 | if type_value >= 0.45: 529 | _auto_tile.draw_terrain(_blocks_data,1,global_tile_coords,0,1) 530 | 531 | if type_value > 0.48: 532 | 533 | var gen := true 534 | 535 | if (grass_value >= 0.1 and grass_value < 0.2) or \ 536 | (grass_value >= 0.24 and grass_value < 0.26) or \ 537 | (grass_value >= 0.66 and grass_value < 0.7): 538 | gen = false 539 | 540 | if gen: 541 | if tile_coords.x != 0 and tile_coords.y != 0 and tile_coords.x != _block_size.x-1 and tile_coords.y != _block_size.y-1: 542 | if tile_coords.x % 2 == 0 and tile_coords.y % 2 == 0: 543 | tiles.append(tile_coords) 544 | 545 | if grass_value < 0.55 and gen: 546 | _auto_tile.draw_terrain(_blocks_data,2,global_tile_coords,0,2) 547 | 548 | if randf() < 0.01: 549 | block_data.set_tile(tile_coords,5,0,Vector2i(0,8),0) 550 | 551 | if randf() < 0.01: 552 | block_data.set_scene(tile_coords,5,1,1) 553 | 554 | if randf() < 0.3: 555 | if randf() < 0.7: 556 | block_data.set_tile(tile_coords,5,0,Vector2i(0,6),0) 557 | else : 558 | block_data.set_tile(tile_coords,5,0,Vector2i(0,7),0) 559 | 560 | if grass_value >= 0.45 and gen: 561 | _auto_tile.draw_terrain(_blocks_data,3,global_tile_coords,0,3) 562 | 563 | if randf() < 0.01: 564 | block_data.set_tile(tile_coords,5,0,Vector2i(0,8),0) 565 | 566 | if randf() < 0.01: 567 | block_data.set_scene(tile_coords,5,1,1) 568 | 569 | if randf() < 0.3: 570 | if randf() < 0.7: 571 | block_data.set_tile(tile_coords,5,0,Vector2i(12,6),0) 572 | else : 573 | block_data.set_tile(tile_coords,5,0,Vector2i(12,7),0) 574 | 575 | _data_mutex.unlock() 576 | 577 | var center := Global.block_to_global_tile(block_coords) + Vector2i(_block_size/2.0) 578 | var value := (_tree_noise.get_noise_2dv(center)+1.0)/2.0 579 | var count := randi_range(0,int(6.0*value)) 580 | 581 | var index := 0 582 | while index < count and not tiles.is_empty(): 583 | 584 | var i := randi() % tiles.size() 585 | var tile_coords := Global.global_tile_to_local(tiles[i]) 586 | tiles.remove_at(i) 587 | 588 | var global_tile_coords := Global.block_to_global_tile(block_coords)+tile_coords 589 | var type_value := (_type_noise.get_noise_2dv(global_tile_coords)+1.0) / 2.0 590 | 591 | if type_value >= 0.5: 592 | if randf() < 0.5: 593 | block_data.set_tile(tile_coords,5,3,Vector2i.ZERO,0) 594 | else : 595 | block_data.set_tile(tile_coords,5,3,Vector2i.ZERO,1) 596 | 597 | index += 1 598 | 599 | # 子线程的运行方法 600 | func _thread_run() -> void: 601 | 602 | # 死循环 603 | while true: 604 | 605 | # 休眠线程 606 | _semaphore.wait() 607 | 608 | # 如果退出线程被标记为true 609 | if _thread_exit: 610 | 611 | # 将已被修改的区块数据保存 612 | _data_mutex.lock() 613 | 614 | for block_coords :Vector2i in _blocks_data.keys(): 615 | var data :BlockData = _blocks_data[block_coords] 616 | if data.modifie_data: 617 | ResourceSaver.save(data,"user://map/%s"%_get_block_file_name(block_coords)) 618 | 619 | _data_mutex.unlock() 620 | 621 | # 退出循环 622 | break 623 | 624 | # 取出更新信息 625 | _mutex.lock() 626 | var dict :Dictionary = _update_queue[0] 627 | _update_queue.remove_at(0) 628 | _mutex.unlock() 629 | 630 | # 需要加载和卸载的区块坐标 631 | var load_blocks :Array[Vector2i] = dict["load"] 632 | var unload_blocks :Array[Vector2i] = dict["unload"] 633 | 634 | # 加载区块 635 | for block_coords :Vector2i in load_blocks: 636 | 637 | # 区块数据 638 | var block_data :BlockData 639 | 640 | # 如果这个区块数据文件存在,那就加载 641 | if ResourceLoader.exists("user://map/%s"%_get_block_file_name(block_coords)): 642 | 643 | block_data = load("user://map/%s"%_get_block_file_name(block_coords)) 644 | 645 | # 如果加载的数据区块大小和当前不一样就发出警告 646 | if block_data.block_size != _block_size: 647 | push_warning("加载的区块大小不符!") 648 | 649 | _data_mutex.lock() 650 | _blocks_data[block_coords] = block_data 651 | _data_mutex.unlock() 652 | 653 | # 更新这个区块数据周围的区块数据,让它们与这个区块数据相连 654 | for x :int in range(-1,_block_size.x+1): 655 | for y :int in [-1,_block_size.y]: 656 | 657 | var global_tile_coords :Vector2i = block_coords * _block_size + Vector2i(x,y) 658 | for layer :int in _layer_count: 659 | _auto_tile.update(_blocks_data,layer,global_tile_coords,false) 660 | 661 | # 更新这个区块数据周围的区块数据,让它们与这个区块数据相连 662 | for x :int in [-1,_block_size.x]: 663 | for y :int in range(-1,_block_size.y+1): 664 | 665 | var global_tile_coords :Vector2i = block_coords * _block_size + Vector2i(x,y) 666 | for layer :int in _layer_count: 667 | _auto_tile.update(_blocks_data,layer,global_tile_coords,false) 668 | else : 669 | 670 | # 如果文件不存在,那就程序化生成区块数据 671 | block_data = BlockData.new() 672 | block_data.block_coords = block_coords 673 | block_data.block_size = _block_size 674 | block_data.build(_layer_count) 675 | 676 | _generate_block_data(block_coords,block_data) 677 | 678 | # 将区块数据标记为需要更新 679 | block_data.need_update = true 680 | # 由主线程调用_block_loaded,并将区块数据传递出去生成区块节点 681 | call_deferred("_block_loaded",block_data) 682 | 683 | # 卸载区块 684 | for block_coords :Vector2i in unload_blocks: 685 | 686 | var data :BlockData = _blocks_data[block_coords] 687 | 688 | # 如果区块数据被标记为被修改,那就保存区块数据 689 | if data.modifie_data: 690 | ResourceSaver.save(data,"user://map/%s"%_get_block_file_name(block_coords)) 691 | 692 | _blocks_data.erase(block_coords) 693 | # 由主线程调用_block_unloaded,将区块坐标传递出去卸载区块节点 694 | call_deferred("_block_unloaded",block_coords) 695 | 696 | ## 注册A*权重信息,查看astar_agent.gd了解使用方法 697 | func register_astar_weight(id: int, global_tile_coords: Vector2i, weight: float) -> void: 698 | 699 | if not _astar_weights.has(global_tile_coords): 700 | _astar_weights[global_tile_coords] = {id:weight} 701 | else : 702 | _astar_weights[global_tile_coords][id] = weight 703 | 704 | # 更新A* 705 | update_astar(global_tile_coords) 706 | 707 | ## 注销A*权重信息,查看astar_agent.gd了解使用方法 708 | func unregister_astar_weight(id: int, global_tile_coords: Vector2i) -> void: 709 | 710 | if _astar_weights.has(global_tile_coords): 711 | _astar_weights[global_tile_coords].erase(id) 712 | 713 | if _astar_weights[global_tile_coords].is_empty(): 714 | _astar_weights.erase(global_tile_coords) 715 | 716 | # 更新A* 717 | update_astar(global_tile_coords) 718 | 719 | ## 注册A*障碍物,查看astar_agent.gd了解使用方法 720 | func register_astar_obstacle(id: int, global_tile_coords: Vector2i, obstacle: bool) -> void: 721 | 722 | if not _astar_obstacles.has(global_tile_coords): 723 | _astar_obstacles[global_tile_coords] = {id:obstacle} 724 | else : 725 | _astar_obstacles[global_tile_coords][id]=obstacle 726 | 727 | # 更新A* 728 | update_astar(global_tile_coords) 729 | 730 | ## 注销A*障碍物,查看astar_agent.gd了解使用方法 731 | func unregister_astar_obstacle(id: int, global_tile_coords: Vector2i) -> void: 732 | 733 | if _astar_obstacles.has(global_tile_coords): 734 | _astar_obstacles[global_tile_coords].erase(id) 735 | 736 | if _astar_obstacles[global_tile_coords].is_empty(): 737 | _astar_obstacles.erase(global_tile_coords) 738 | 739 | # 更新A* 740 | update_astar(global_tile_coords) 741 | 742 | ## 注册的瓷砖类型,查看astar_agent.gd了解使用方法 743 | func register_tile_type(id: int, global_tile_coords: Vector2i, tile_type: TileType) -> void: 744 | 745 | if not _tile_types.has(global_tile_coords): 746 | _tile_types[global_tile_coords] = {id:tile_type} 747 | else : 748 | _tile_types[global_tile_coords][id]=tile_type 749 | 750 | # 更新A* 751 | update_astar(global_tile_coords) 752 | 753 | ## 注销瓷砖类型,查看astar_agent.gd了解使用方法 754 | func unregister_tile_type(id: int, global_tile_coords: Vector2i) -> void: 755 | 756 | if _tile_types.has(global_tile_coords): 757 | _tile_types[global_tile_coords].erase(id) 758 | 759 | if _tile_types[global_tile_coords].is_empty(): 760 | _tile_types.erase(global_tile_coords) 761 | 762 | # 更新A* 763 | update_astar(global_tile_coords) 764 | 765 | ## 注册移动速度规格,查看astar_agent.gd了解使用方法 766 | func register_move_speed_scale(id: int, global_tile_coords: Vector2i, move_speed_scale: float) -> void: 767 | 768 | if not _move_speed_scales.has(global_tile_coords): 769 | _move_speed_scales[global_tile_coords] = {id:move_speed_scale} 770 | else : 771 | _move_speed_scales[global_tile_coords][id] = move_speed_scale 772 | 773 | 774 | update_astar(global_tile_coords) 775 | 776 | ## 注销移动速度规格,查看astar_agent.gd了解使用方法 777 | func unregister_move_speed_scale(id: int, global_tile_coords: Vector2i) -> void: 778 | 779 | if _move_speed_scales.has(global_tile_coords): 780 | _move_speed_scales[global_tile_coords].erase(id) 781 | 782 | if _move_speed_scales[global_tile_coords].is_empty(): 783 | _move_speed_scales.erase(global_tile_coords) 784 | 785 | update_astar(global_tile_coords) 786 | 787 | ## 使用全局瓷砖坐标获取瓷砖信息 788 | func get_tile_info(global_tile_coords: Vector2i) -> Dictionary: 789 | 790 | # 所在区块坐标 791 | var block_coords := Global.global_tile_to_block(global_tile_coords) 792 | # 所在的局部瓷砖坐标 793 | var tile_coords : = Global.global_tile_to_local(global_tile_coords) 794 | 795 | # 如果没有返回空 796 | if not _block_nodes.has(block_coords): 797 | return {} 798 | 799 | var info := {} 800 | 801 | # 如果有的话优先使用已注册的信息 802 | if _astar_weights.has(global_tile_coords): 803 | info["astar_weight"] = _astar_weights[global_tile_coords].values()[-1] 804 | 805 | if _astar_obstacles.has(global_tile_coords): 806 | info["obstacle"] = _astar_obstacles[global_tile_coords].values()[-1] 807 | 808 | if _tile_types.has(global_tile_coords): 809 | info["tile_type"] = _tile_types[global_tile_coords].values()[-1] 810 | 811 | if _move_speed_scales.has(global_tile_coords): 812 | info["move_speed_scale"] = _move_speed_scales[global_tile_coords].values()[-1] 813 | 814 | # 如果有瓷砖类型,但没有权重,那就使用瓷砖类型获取权重 815 | if (not info.has("astar_weight")) and info.has("tile_type"): 816 | info["astar_weight"] = ASTAR_WEIGHT[info["tile_type"]-1] 817 | 818 | # 如果有瓷砖类型,但没有移动速度规格,那就使用瓷砖类型获取移动速度规格 819 | if (not info.has("move_speed_scale")) and info.has("tile_type"): 820 | info["move_speed_scale"] = MOVE_SPEED_SCALE[info["tile_type"]-1] 821 | 822 | # 如果所有数据已获得直接返回 823 | if info.has("astar_weight") and info.has("obstacle") and info.has("tile_type") and info.has("move_speed_scale"): 824 | return info 825 | 826 | # 获取区块节点 827 | var block_node :BlockNode = _block_nodes[block_coords] 828 | 829 | # 从顶层往下获取 830 | for layer :int in range(_layer_count-1,-1,-1): 831 | 832 | # 瓷砖数据 833 | var tile_data :TileData = block_node.get_tile_data(layer,tile_coords) 834 | 835 | # 如果是空,那就直接进入下一个层 836 | if not is_instance_valid(tile_data): 837 | continue 838 | 839 | # 从瓷砖数据中获取瓷砖类型,详情请看TileSet的自定义数据 840 | var tile_type :TileType = tile_data.get_custom_data("tile_type") 841 | 842 | # 如果信息中没有障碍物信息(没有注册障碍物信息,如果注册了那就以注册信息为准)并且这个瓷砖被标记为是障碍物,那就添加障碍物为true 843 | if (not info.has("obstacle")) and tile_data.get_custom_data("obstacle"): 844 | info["obstacle"] = true 845 | 846 | # 如果瓷砖类型为忽略,那就直接进入下一层 847 | if tile_type == TileType.IGNORE: 848 | continue 849 | 850 | # 如果没有权重信息(没有注册权重信息,如果注册了那就以注册信息为准)使用瓷砖类型获取权重 851 | if not info.has("astar_weight"): 852 | info["astar_weight"] = ASTAR_WEIGHT[tile_type-1] 853 | 854 | # # 如果所有数据已获得直接返回 855 | # if info.has("astar_weight") and info.has("obstacle") and info.has("tile_type") and info.has("move_speed_scale"): 856 | # return info 857 | 858 | # 如果没有瓷砖类型信息那就设置 859 | if not info.has("tile_type"): 860 | info["tile_type"] = tile_type 861 | 862 | # 如果没有移动速度规格,那就使用瓷砖类型获取移动速度规格 863 | if not info.has("move_speed_scale"): 864 | info["move_speed_scale"] = MOVE_SPEED_SCALE[tile_type-1] 865 | 866 | # 所有其它信息已经准备好了,但还没有障碍物信息,那就设置为不是障碍物 867 | if not info.has("obstacle"): 868 | info["obstacle"]=false 869 | 870 | return info 871 | 872 | push_warning("没有找到图块!") 873 | 874 | return {} 875 | 876 | ## 更新指定全局瓷砖坐标的A* 877 | func update_astar(global_tile_coords: Vector2i) -> void: 878 | 879 | var id := Global.get_astar_id(global_tile_coords) 880 | 881 | # 如果没有这个点,那就不需要更新 882 | if not _astar.has_point(id): 883 | return 884 | 885 | # 获取此处的瓷砖信息 886 | var info := get_tile_info(global_tile_coords) 887 | 888 | # 如果信息为空,那就不更新 889 | if info.is_empty(): 890 | return 891 | 892 | # 更新权重信息 893 | _astar.set_point_weight_scale(id,info["astar_weight"]) 894 | # 更新障碍物信息 895 | _astar.set_point_disabled(id,info["obstacle"]) 896 | 897 | 898 | # 加载A*区块 899 | func _load_astar_block(block_coords: Vector2i) -> void: 900 | 901 | # 循环出这个区块的局部瓷砖坐标 902 | for x :int in _block_size.x: 903 | for y :int in _block_size.y: 904 | 905 | # 转为全局瓷砖坐标 906 | var global_tile_coords := block_coords * _block_size + Vector2i(x,y) 907 | # 获取全局瓷砖信息 908 | var tile_info := get_tile_info(global_tile_coords) 909 | 910 | if tile_info.is_empty(): 911 | continue 912 | 913 | # 获取这个全局瓷砖坐标对应的id 914 | var id := Global.get_astar_id(global_tile_coords) 915 | 916 | # 计算瓷砖的中心全局像素坐标,寻路是会将这些点连成路线,所以应该是中心位置 917 | var center_position := Vector2(global_tile_coords * _tile_set.tile_size) + (Vector2(_tile_set.tile_size)/2.0) 918 | 919 | # 添加点 920 | _astar.add_point(id,center_position,tile_info["astar_weight"]) 921 | # 按照障碍物确定是否禁用点,被禁用的点不会参与寻路(换句话说就是不可行走) 922 | _astar.set_point_disabled(id,tile_info["obstacle"]) 923 | 924 | # 与周围的四个邻居点建立连接,你可以与周围的八个点建立连接,但需要注意一些事项 925 | for dir :Vector2i in [Vector2i.LEFT,Vector2i.DOWN,Vector2i.RIGHT,Vector2i.UP]: 926 | 927 | var neighbor := global_tile_coords + dir 928 | var neighbor_id := Global.get_astar_id(neighbor) 929 | 930 | # 如果这个点存在并且没有连接,那就连接 931 | if _astar.has_point(neighbor_id) and not _astar.are_points_connected(id,neighbor_id): 932 | _astar.connect_points(id,neighbor_id) 933 | 934 | # 卸载A*区块 935 | func _unload_astar_block(block_coords: Vector2i) -> void: 936 | 937 | # 循环出这个区块的局部瓷砖坐标 938 | for x :int in _block_size.x: 939 | for y :int in _block_size.y: 940 | 941 | # 转为全局瓷砖坐标 942 | var global_tile_coords := block_coords * _block_size + Vector2i(x,y) 943 | # 获取这个全局瓷砖坐标对应的id 944 | var id := Global.get_astar_id(global_tile_coords) 945 | 946 | # 如果点存在那就移除点 947 | if _astar.has_point(id): 948 | _astar.remove_point(id) 949 | 950 | ## 更新指定全局瓷砖坐标的瓷砖瓷砖 951 | func update_tile(global_tile_coords: Vector2i) -> void: 952 | 953 | update_astar(global_tile_coords) 954 | tile_change.emit(global_tile_coords) 955 | -------------------------------------------------------------------------------- /scripts/map_loader.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b10r008um2ibm 2 | -------------------------------------------------------------------------------- /scripts/tile_detector.gd: -------------------------------------------------------------------------------- 1 | 2 | # ================================================ 3 | # - 4 | # - TILE DETECTOR 5 | # - 6 | # - 对所在的瓷砖进行检测,只有需要时才会更新 7 | # - 他不会每一帧更新,大大提高性能 8 | # - 可以将此节点添加到需要获取所在瓷砖信息的节点下,并连接信号 9 | # - 10 | # ================================================ 11 | 12 | class_name TileDetector 13 | extends Node2D 14 | 15 | ## 此节点所在的瓷砖坐标发生变化或需要更新时发出 16 | signal tile_change(global_tile_coords: Vector2i, tile_info: Dictionary) 17 | 18 | var _current_coords := Vector2i.ZERO 19 | var _current_block_coords := Vector2i.ZERO 20 | var _initialize := true 21 | 22 | func _enter_tree() -> void: 23 | 24 | # 此节点所在的区块可能还没有加载,当加载时需要更新 25 | Global.map_loader.block_load_finished.connect( 26 | func (block_coords: Vector2i) -> void: 27 | if block_coords == _current_block_coords: 28 | _update() 29 | ) 30 | 31 | # 瓷砖被修改时也需要更新 32 | Global.map_loader.tile_change.connect( 33 | func (global_tile_coords: Vector2i) -> void: 34 | if global_tile_coords == _current_coords: 35 | _update() 36 | ) 37 | 38 | func _process(_delta: float) -> void: 39 | 40 | var coords := Global.global_to_tile(global_position) 41 | var block_coords := Global.global_tile_to_block(coords) 42 | 43 | # 第一次或坐标发生变化时需要更新 44 | if coords != _current_coords or block_coords != _current_block_coords or _initialize: 45 | 46 | _initialize = false 47 | _current_block_coords = block_coords 48 | _current_coords = coords 49 | _update() 50 | 51 | func _update() -> void: 52 | 53 | tile_change.emit(_current_coords,Global.map_loader.get_tile_info(_current_coords)) 54 | 55 | -------------------------------------------------------------------------------- /scripts/tile_detector.gd.uid: -------------------------------------------------------------------------------- 1 | uid://fehoacun8fqs 2 | -------------------------------------------------------------------------------- /shaders/character.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | uniform vec4 water_color :source_color; 4 | uniform vec4 water_edge_color :source_color; 5 | uniform float water_edge_width = 1.0; 6 | uniform float water_depth = 0.0; 7 | 8 | void fragment() { 9 | 10 | vec4 color1 = texture(TEXTURE,UV); 11 | vec4 color2 = vec4(mix(color1.rgb,water_color.rgb,0.5),color1.a); 12 | float water_edge_value = step(1.0-UV.y,water_depth*TEXTURE_PIXEL_SIZE.y); 13 | float water_value = step(1.0-UV.y,water_depth*TEXTURE_PIXEL_SIZE.y-(water_edge_width*TEXTURE_PIXEL_SIZE.y)); 14 | 15 | color1 = vec4(mix(color1.rgb,water_edge_color.rgb,water_edge_value),color1.a); 16 | color1 = mix(color1,color2,water_value); 17 | 18 | COLOR = color1; 19 | } 20 | -------------------------------------------------------------------------------- /shaders/character.gdshader.uid: -------------------------------------------------------------------------------- 1 | uid://38h1y2ya0kj1 2 | -------------------------------------------------------------------------------- /shaders/door_focus.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | uniform float focus = 0.0; 4 | 5 | void fragment() { 6 | vec4 color = texture(TEXTURE,UV); 7 | 8 | float value = (sin(TIME*6.0)+1.0)/2.0; 9 | color.rgb *= mix(1.0,0.8+(0.5*value),focus); 10 | 11 | COLOR = color; 12 | } -------------------------------------------------------------------------------- /shaders/door_focus.gdshader.uid: -------------------------------------------------------------------------------- 1 | uid://cdybycue1n2cj 2 | -------------------------------------------------------------------------------- /shaders/sway.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | uniform float range:hint_range(0.0, 4.0, 0.1) = 1.0; 4 | uniform float speed:hint_range(0.0, 4.0, 0.1) = 1.0; 5 | 6 | void vertex() { 7 | VERTEX.x += sin(TIME*speed)*range*(1.0-UV.y); 8 | } 9 | -------------------------------------------------------------------------------- /shaders/sway.gdshader.uid: -------------------------------------------------------------------------------- 1 | uid://cm0sy5la8j5md 2 | --------------------------------------------------------------------------------