From e2651d53d28b67e130abab85256fecb4e0a7d7d9 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 22:00:34 +0300 Subject: [PATCH 01/25] Broke Fog of war manager to vision manager and fog of war node --- .../features/vision/fog_of_war.gd | 59 ++++++++ ...f_war_manager.gd.uid => fog_of_war.gd.uid} | 0 .../features/vision/fog_of_war.tscn | 28 ++++ .../vision/fog_of_war_manager.gdshader | 28 ---- .../vision/fog_of_war_manager.gdshader.uid | 1 - .../features/vision/fog_of_war_manager.tscn | 97 ------------- .../rts_framework/features/vision/minimap.gd | 81 +++++------ .../features/vision/minimap.tscn | 13 +- .../features/vision/unit_vision_data.gd | 128 ++++++++++++++++++ .../features/vision/unit_vision_data.gd.uid | 1 + .../vision/unit_vision_data_weak_ref.gd | 38 ++++++ .../vision/unit_vision_data_weak_ref.gd.uid | 1 + ...og_of_war_manager.gd => vision_manager.gd} | 85 +++++------- .../features/vision/vision_manager.gd.uid | 1 + .../features/vision/vision_manager.tscn | 100 ++++++++++++++ demo/game.tscn | 38 +++++- 16 files changed, 468 insertions(+), 231 deletions(-) create mode 100644 addons/rts_framework/features/vision/fog_of_war.gd rename addons/rts_framework/features/vision/{fog_of_war_manager.gd.uid => fog_of_war.gd.uid} (100%) create mode 100644 addons/rts_framework/features/vision/fog_of_war.tscn delete mode 100644 addons/rts_framework/features/vision/fog_of_war_manager.gdshader delete mode 100644 addons/rts_framework/features/vision/fog_of_war_manager.gdshader.uid delete mode 100644 addons/rts_framework/features/vision/fog_of_war_manager.tscn create mode 100644 addons/rts_framework/features/vision/unit_vision_data.gd create mode 100644 addons/rts_framework/features/vision/unit_vision_data.gd.uid create mode 100644 addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd create mode 100644 addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid rename addons/rts_framework/features/vision/{fog_of_war_manager.gd => vision_manager.gd} (69%) create mode 100644 addons/rts_framework/features/vision/vision_manager.gd.uid create mode 100644 addons/rts_framework/features/vision/vision_manager.tscn diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd new file mode 100644 index 0000000..d6777cd --- /dev/null +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -0,0 +1,59 @@ +@tool +extends MeshInstance3D +class_name FogOfWarManager +@export var vision_manager : VisionManager: + set(value): + vision_manager = value + var fog_texture_result = value.get_fog_texture() + if fog_texture_result: + fog_texture = fog_texture_result + get: + return vision_manager + +@export_category("Fog Values") + +## The size of a single pixel in the 3D world +@export_range(1, 10000, 1,"suffix:px/length") var texture_units_per_world_unit : int = 2 : # px/length + set(value): + material_override.set_shader_parameter("texture_units_per_world_unit", value) + texture_units_per_world_unit = value + +## Color of the generated fog +@export var fog_color : Color : + set(value): + material_override.set_shader_parameter("color", value) + get: + return material_override.get_shader_parameter("color") +## TODO add description for outer_margin_for_fade_out. +@export var outer_margin_for_fade_out : float : + set(value): + material_override.set_shader_parameter("outer_margin_for_fade_out", value) + get: + return material_override.get_shader_parameter("outer_margin_for_fade_out") + +@export_category("Debug Values") +## Shows small texture of the fog +@export var debug_texture_view : bool = false: + set(value): + material_override.set_shader_parameter("debug_texture_view", value) + get: + return material_override.get_shader_parameter("debug_texture_view") +## Shows small texture of the fog +@export_range(0, 1) var debug_texture_view_size : float = 0.2: + set(value): + material_override.set_shader_parameter("debug_texture_view_size", value) + get: + return material_override.get_shader_parameter("debug_texture_view_size") + +var fog_texture : ViewportTexture: + set(value): + material_override.set_shader_parameter("world_visibility_texture", value) + get: + return material_override.get_shader_parameter("world_visibility_texture") + + +func _ready() -> void: + await vision_manager + var fog_texture_result = vision_manager.get_fog_texture() + if fog_texture_result: + fog_texture = fog_texture_result diff --git a/addons/rts_framework/features/vision/fog_of_war_manager.gd.uid b/addons/rts_framework/features/vision/fog_of_war.gd.uid similarity index 100% rename from addons/rts_framework/features/vision/fog_of_war_manager.gd.uid rename to addons/rts_framework/features/vision/fog_of_war.gd.uid diff --git a/addons/rts_framework/features/vision/fog_of_war.tscn b/addons/rts_framework/features/vision/fog_of_war.tscn new file mode 100644 index 0000000..261ebf5 --- /dev/null +++ b/addons/rts_framework/features/vision/fog_of_war.tscn @@ -0,0 +1,28 @@ +[gd_scene load_steps=6 format=3 uid="uid://71g6dowvqb5i"] + +[ext_resource type="Script" uid="uid://de87xn1b8u07i" path="res://addons/rts_framework/features/vision/fog_of_war.gd" id="1_vrsar"] +[ext_resource type="Shader" uid="uid://cbo2vdgrqc60a" path="res://addons/rts_framework/features/vision/detailed_fog_of_war.gdshader" id="2_oehrr"] + +[sub_resource type="ViewportTexture" id="ViewportTexture_m5cnj"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_imaik"] +resource_local_to_scene = true +render_priority = 2 +shader = ExtResource("2_oehrr") +shader_parameter/color = Color(0, 0, 0, 1) +shader_parameter/world_visibility_texture = SubResource("ViewportTexture_m5cnj") +shader_parameter/texture_units_per_world_unit = 2 +shader_parameter/outer_margin_for_fade_out = 0.0 +shader_parameter/debug_texture_view = false +shader_parameter/debug_texture_view_size = 0.2 + +[sub_resource type="QuadMesh" id="QuadMesh_3f4cn"] +flip_faces = true +size = Vector2(2, 2) + +[node name="FogOfWar" type="MeshInstance3D"] +material_override = SubResource("ShaderMaterial_imaik") +cast_shadow = 0 +extra_cull_margin = 16384.0 +mesh = SubResource("QuadMesh_3f4cn") +script = ExtResource("1_vrsar") diff --git a/addons/rts_framework/features/vision/fog_of_war_manager.gdshader b/addons/rts_framework/features/vision/fog_of_war_manager.gdshader deleted file mode 100644 index 12ba7d9..0000000 --- a/addons/rts_framework/features/vision/fog_of_war_manager.gdshader +++ /dev/null @@ -1,28 +0,0 @@ -shader_type canvas_item; - -uniform float blurr_factor : hint_range(0.0, 10.0) = 2.0; -uniform bool remove_alpha = true; -uniform bool overlay = true; - -uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap; - -void fragment() -{ - vec4 blurred_color; - if (overlay) - { - blurred_color = textureLod(screen_texture, SCREEN_UV, blurr_factor); - } - else - { - blurred_color = textureLod(TEXTURE, UV, blurr_factor); - } - if (remove_alpha) - { - COLOR.rgb = blurred_color.rgb; - } - else - { - COLOR = blurred_color; - } -} diff --git a/addons/rts_framework/features/vision/fog_of_war_manager.gdshader.uid b/addons/rts_framework/features/vision/fog_of_war_manager.gdshader.uid deleted file mode 100644 index e7a5914..0000000 --- a/addons/rts_framework/features/vision/fog_of_war_manager.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cx0yukamm8x8x diff --git a/addons/rts_framework/features/vision/fog_of_war_manager.tscn b/addons/rts_framework/features/vision/fog_of_war_manager.tscn deleted file mode 100644 index f8ac39e..0000000 --- a/addons/rts_framework/features/vision/fog_of_war_manager.tscn +++ /dev/null @@ -1,97 +0,0 @@ -[gd_scene load_steps=9 format=3 uid="uid://71g6dowvqb5i"] - -[ext_resource type="Script" uid="uid://de87xn1b8u07i" path="res://addons/rts_framework/features/vision/fog_of_war_manager.gd" id="1_vrsar"] -[ext_resource type="PackedScene" uid="uid://clbjgy724q2si" path="res://addons/rts_framework/features/vision/dynamic_circle_2d.tscn" id="2_g5u0g"] -[ext_resource type="Shader" uid="uid://cbo2vdgrqc60a" path="res://addons/rts_framework/features/vision/detailed_fog_of_war.gdshader" id="2_oehrr"] -[ext_resource type="Shader" uid="uid://cx0yukamm8x8x" path="res://addons/rts_framework/features/vision/fog_of_war_manager.gdshader" id="3_rx4ay"] - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_sr23m"] -shader = ExtResource("3_rx4ay") -shader_parameter/blurr_factor = 1.0 -shader_parameter/remove_alpha = false -shader_parameter/overlay = true - -[sub_resource type="ViewportTexture" id="ViewportTexture_m5cnj"] -viewport_path = NodePath("CombinedViewport") - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_imaik"] -resource_local_to_scene = true -render_priority = 2 -shader = ExtResource("2_oehrr") -shader_parameter/color = Color(0, 0, 0, 1) -shader_parameter/world_visibility_texture = SubResource("ViewportTexture_m5cnj") -shader_parameter/texture_units_per_world_unit = 2 -shader_parameter/outer_margin_for_fade_out = 0.0 -shader_parameter/debug_texture_view = false -shader_parameter/debug_texture_view_size = 0.2 - -[sub_resource type="QuadMesh" id="QuadMesh_3f4cn"] -flip_faces = true -size = Vector2(2, 2) - -[node name="FogOfWarManager" type="Node"] -script = ExtResource("1_vrsar") - -[node name="CombinedViewport" type="SubViewport" parent="."] -disable_3d = true -handle_input_locally = false -size = Vector2i(500, 500) -render_target_update_mode = 4 - -[node name="Background" type="ColorRect" parent="CombinedViewport"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -color = Color(0, 0, 0, 1) - -[node name="FogViewportContainer" type="SubViewportContainer" parent="CombinedViewport"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="FogViewport" type="SubViewport" parent="CombinedViewport/FogViewportContainer"] -disable_3d = true -transparent_bg = true -handle_input_locally = false -size = Vector2i(500, 500) -render_target_clear_mode = 2 -render_target_update_mode = 4 - -[node name="EditorOnlyCircle" parent="CombinedViewport" instance=ExtResource("2_g5u0g")] -position = Vector2(30, 30) -radius = 25 - -[node name="Revealer" type="ColorRect" parent="CombinedViewport"] -visible = false -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -100.0 -offset_bottom = -100.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="BlurrOverlay" type="ColorRect" parent="CombinedViewport"] -material = SubResource("ShaderMaterial_sr23m") -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -100.0 -offset_bottom = -100.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="ScreenOverlay" type="MeshInstance3D" parent="."] -material_override = SubResource("ShaderMaterial_imaik") -cast_shadow = 0 -extra_cull_margin = 16384.0 -mesh = SubResource("QuadMesh_3f4cn") - -[node name="VisibilityField" type="Area3D" parent="."] - -[connection signal="body_entered" from="VisibilityField" to="." method="_on_visibility_field_body_entered"] -[connection signal="body_exited" from="VisibilityField" to="." method="_on_visibility_field_body_exited"] diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 937cf2a..1c508ab 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -8,9 +8,10 @@ class_name Minimap const DynamicCircle2D : PackedScene = preload("res://addons/rts_framework/features/vision/dynamic_circle_2d.tscn") -@export var fog_of_war_manager : FogOfWarManager +@export var vision_manager : VisionManager -var _unit_to_circles_mapping : Dictionary = {} +#var _unit_to_circles_mapping : Dictionary = {} +var _vision_data : Dictionary # Weak Ref for Dictionary{ BaseEntity : UnitVisionData } ## Texture representing the fog of war alpha layer ## @@ -35,37 +36,31 @@ var fog_texture : Texture2D : # fog_texture multiply the images above. This to f @onready var _minimap_viewport: SubViewport = find_child("CombinedViewport") as SubViewport func _ready() -> void: - assert(fog_of_war_manager != null, "Minimap missing fog of war manager node. Minimap Node Name: " + self.name) - var fog_of_war_combined_viewport = fog_of_war_manager.combined_viewport - if fog_of_war_combined_viewport: - var fog_texture_result = fog_of_war_manager.combined_viewport.get_texture() - if fog_texture_result: - fog_texture = fog_texture_result - else: - push_error("Failed to retrieve fog of war texture. Minimap Node Name: " + self.name) + assert(vision_manager != null, "Minimap missing vision manager node. Minimap Node Name: " + self.name) + await vision_manager + var fog_texture_result = vision_manager.get_fog_texture() + if fog_texture_result: + fog_texture = fog_texture_result else: - push_error("Failed to retrieve fog of war combined viewport. Minimap Node Name: " + self.name) + push_error("Failed to retrieve fog of war texture. Minimap Node Name: " + self.name) + _vision_data = vision_manager.get_vision_data() if not Engine.is_editor_hint(): var circle = find_child("EditorOnlyCircle") if circle: circle.queue_free() func _physics_process(_delta : float) -> void: - var visible_units : Dictionary = {} - var units_to_sync = fog_of_war_manager.get_visible_units() - for unit in units_to_sync: + for unit in _vision_data: if not unit.is_revealing(): continue - visible_units[unit] = 1 - if not _unit_is_mapped(unit): + if not _unit_is_minimap_mapped(unit): _map_unit_to_new_circles_body(unit) - _sync_vision_to_unit(unit) - for mapped_unit in _unit_to_circles_mapping: - if not mapped_unit in visible_units: - _cleanup_mapping(mapped_unit) -func _unit_is_mapped(unit : BaseEntity) -> bool: - return unit in _unit_to_circles_mapping +func _unit_is_minimap_mapped(unit : BaseEntity) -> bool: + if _vision_data != null: + if unit in _vision_data: + return _vision_data[unit].minimap_circle != null # If unit has minimap_circle + return false ## Creates visibility representation for a unit on the minimap ## Parameters: @@ -73,32 +68,18 @@ func _unit_is_mapped(unit : BaseEntity) -> bool: ## - default_color: The default color of the visibility circle ## - default_radius: The default radius of visibility func _map_unit_to_new_circles_body(unit : BaseEntity, default_color : Color = Color.BLUE, default_radius : int = 5) -> void: - var minimap_circle = DynamicCircle2D.instantiate() # Make a white circle 2D - - if unit.has_method("get_team_color"): # If unit has get_team_color, use that color - minimap_circle.color = unit.get_team_color() - else: # if doesn't have the function, use the default one - minimap_circle.color = default_color # Set color - - if unit.has_method("get_sight_range"): # Set circle size to world units and unit sight range - minimap_circle.radius = unit.get_sight_range() # If has sight range, then use it - else: - minimap_circle.radius = default_radius # If doesn't have sight range, then use default + if _vision_data != null: + var minimap_circle = DynamicCircle2D.instantiate() # Make a white circle 2D - _minimap_viewport.add_child(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. - _unit_to_circles_mapping[unit] = minimap_circle # Keep map to connect unit with fog of war view - -func _sync_vision_to_unit(unit : BaseEntity) -> void: - var unit_pos_3d = unit.global_transform.origin - var unit_pos_2d = Vector2(unit_pos_3d.x, unit_pos_3d.z) * fog_of_war_manager.texture_units_per_world_unit - _unit_to_circles_mapping[unit].position = unit_pos_2d - -func _cleanup_mapping(unit : BaseEntity) -> void: - _unit_to_circles_mapping[unit].queue_free() - _unit_to_circles_mapping.erase(unit) - -func _exit_tree() -> void: - # Clean up all remaining circles - for unit in _unit_to_circles_mapping.keys(): - _cleanup_mapping(unit) - _unit_to_circles_mapping.clear() + if unit.has_method("get_team_color"): # If unit has get_team_color, use that color + minimap_circle.color = unit.get_team_color() + else: # if doesn't have the function, use the default one + minimap_circle.color = default_color # Set color + + if unit.has_method("get_sight_range"): # Set circle size to world units and unit sight range + minimap_circle.radius = unit.get_sight_range() # If has sight range, then use it + else: + minimap_circle.radius = default_radius # If doesn't have sight range, then use default + + _minimap_viewport.add_child(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. + _vision_data[unit].minimap_circle = minimap_circle # Keep map to connect unit with fog of war view diff --git a/addons/rts_framework/features/vision/minimap.tscn b/addons/rts_framework/features/vision/minimap.tscn index 02a791a..cedcd92 100644 --- a/addons/rts_framework/features/vision/minimap.tscn +++ b/addons/rts_framework/features/vision/minimap.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=5 format=3 uid="uid://bo2b1x0u1j1dg"] +[gd_scene load_steps=6 format=3 uid="uid://bo2b1x0u1j1dg"] [ext_resource type="Script" uid="uid://bd3c10auv3sc0" path="res://addons/rts_framework/features/vision/minimap.gd" id="1_6mcq1"] [ext_resource type="PackedScene" uid="uid://clbjgy724q2si" path="res://addons/rts_framework/features/vision/dynamic_circle_2d.tscn" id="1_dqnbu"] @@ -10,6 +10,9 @@ viewport_path = NodePath("CombinedViewport") blend_mode = 3 light_mode = 1 +[sub_resource type="ViewportTexture" id="ViewportTexture_6mcq1"] +viewport_path = NodePath("SubViewport") + [node name="Minimap" type="TextureRect"] anchors_preset = 15 anchor_right = 1.0 @@ -39,7 +42,15 @@ color = Color(1, 0, 0, 1) material = SubResource("CanvasItemMaterial_5oxvc") offset_right = 40.0 offset_bottom = 40.0 +texture = SubResource("ViewportTexture_6mcq1") [node name="EditorOnlyCircle" parent="CombinedViewport" instance=ExtResource("1_dqnbu")] position = Vector2(50, 50) color = Color(0, 0, 1, 1) + +[node name="SubViewport" type="SubViewport" parent="."] + +[node name="ColorRect" type="ColorRect" parent="SubViewport"] +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(0, 0, 0, 1) diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd b/addons/rts_framework/features/vision/unit_vision_data.gd new file mode 100644 index 0000000..304a6b1 --- /dev/null +++ b/addons/rts_framework/features/vision/unit_vision_data.gd @@ -0,0 +1,128 @@ +extends Resource +class_name UnitVisionData + +var unit : BaseEntity = null +var fow_circle : Node2D = null +var shroud_circle : Node2D = null +var minimap_circle : Node2D = null +var shape_3d : CollisionShape3D = null + + +# fow_circle +var fow_circle_radius : float : + get: + if fow_circle == null: + return 0 + return fow_circle.radius + set(value): + if fow_circle == null: + return + fow_circle.radius = value + emit_changed() + +var fow_circle_color : Color : + get: + return fow_circle.color + set(value): + fow_circle.color = value + emit_changed() + +# shroud_circle +var shroud_circle_radius : float : + get: + if shroud_circle == null: + return 0 + return shroud_circle.radius + set(value): + if shroud_circle == null: + return + shroud_circle.radius = value + emit_changed() + +var shroud_circle_color : Color : + get: + return shroud_circle.color + set(value): + shroud_circle.color = value + emit_changed() + +# minimap_circle +var minimap_circle_radius : float : + get: + if minimap_circle == null: + return 0 + return minimap_circle.radius + set(value): + if minimap_circle == null: + return + minimap_circle.radius = value + emit_changed() + +var minimap_circle_color : Color : + get: + return minimap_circle.color + set(value): + minimap_circle.color = value + emit_changed() + +# shape_3d +var sight_range : float : + get: + if shape_3d == null || shape_3d.shape == null: + return 0 + return shape_3d.shape.radius + set(value): + if shape_3d == null || shape_3d.shape == null: + return + shape_3d.shape.radius = value + emit_changed() + +# All +var position : Vector3 : + get: + if shape_3d == null: + return Vector3.INF + return shape_3d.position + set(value): # Prevent setting + return + +static func create(unit, fow_circle, shroud_circle, shape_3d) -> UnitVisionData: + var instance = UnitVisionData.new() + instance.unit = unit + instance.fow_circle = fow_circle + instance.shroud_circle = shroud_circle + instance.shape_3d = shape_3d + return instance + +# TODO: Talk about having a RefCounted in the unit itself and +# in vision manager have weakref. +# That way, when unit is freed, it will automateclly free this resource +func _notification(what): + if what == NOTIFICATION_PREDELETE: + if fow_circle: + fow_circle.queue_free() + if shroud_circle: + shroud_circle.queue_free() + if minimap_circle: + minimap_circle.queue_free() + if shape_3d: + shape_3d.queue_free() + +func sync_position(texture_units_per_world_unit : int) -> void: + var unit_pos_3d = unit.global_transform.origin + var unit_pos_2d = Vector2(unit_pos_3d.x, unit_pos_3d.z) * texture_units_per_world_unit + var changed_flag = false + if fow_circle: + fow_circle.position = unit_pos_2d + changed_flag = true + if shroud_circle: + shroud_circle.position = unit_pos_2d + changed_flag = true + if minimap_circle: + minimap_circle.position = unit_pos_2d + changed_flag = true + if shape_3d: + shape_3d.position = unit_pos_3d + changed_flag = true + if changed_flag: + emit_changed() diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd.uid b/addons/rts_framework/features/vision/unit_vision_data.gd.uid new file mode 100644 index 0000000..b4c6215 --- /dev/null +++ b/addons/rts_framework/features/vision/unit_vision_data.gd.uid @@ -0,0 +1 @@ +uid://drtk5p4vt4s5s diff --git a/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd b/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd new file mode 100644 index 0000000..3e3e5c0 --- /dev/null +++ b/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd @@ -0,0 +1,38 @@ +extends WeakRef +class_name UnitVisionDataWeakRef + +# fow_circle +var fow_circle_radius : float : + get: + return get_ref().fow_circle.radius + set(value): + get_ref().fow_circle.radius = value + +var fow_circle_color : Color : + get: + return get_ref().fow_circle.color + set(value): + get_ref().fow_circle.color = value + +# shroud_circle +var shroud_circle_radius : float : + get: + return get_ref().shroud_circle.radius + set(value): + get_ref().shroud_circle.radius = value + +var shroud_circle_color : Color : + get: + return get_ref().shroud_circle.color + set(value): + get_ref().shroud_circle.color = value + +# shape_3d +var sight_range : float : + get: + return get_ref().shape_3d.shape.radius + set(value): + get_ref().shape_3d.shape.radius = value + +static func create(unit_vision_data : UnitVisionData) -> UnitVisionDataWeakRef: + return weakref(unit_vision_data) diff --git a/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid b/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid new file mode 100644 index 0000000..f427a5f --- /dev/null +++ b/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid @@ -0,0 +1 @@ +uid://c6ox46vndb2o8 diff --git a/addons/rts_framework/features/vision/fog_of_war_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd similarity index 69% rename from addons/rts_framework/features/vision/fog_of_war_manager.gd rename to addons/rts_framework/features/vision/vision_manager.gd index 16e4b07..d272ce4 100644 --- a/addons/rts_framework/features/vision/fog_of_war_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -1,7 +1,6 @@ @tool -@icon("res://addons/rts_framework/features/vision/fog_of_war_icon.svg") extends BaseManager -class_name FogOfWarManager +class_name VisionManager const DynamicCircle2D : PackedScene = preload("res://addons/rts_framework/features/vision/dynamic_circle_2d.tscn") @@ -18,8 +17,8 @@ const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) ## The size of a single pixel in the 3D world @export_range(1, 10000, 1,"suffix:px/length") var texture_units_per_world_unit : int = 2 : # px/length set(value): - find_child("ScreenOverlay").material_override.set_shader_parameter("texture_units_per_world_unit", value) texture_units_per_world_unit = value + ## AAA @export var map_mesh_node : MeshInstance3D: set(value): @@ -38,18 +37,6 @@ const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) if map_mesh_node.mesh: return map_mesh_node.mesh.size return fog_size -## Color of the generated fog -@export var fog_color : Color : - set(value): - find_child("ScreenOverlay").material_override.set_shader_parameter("color", value) - get: - return find_child("ScreenOverlay").material_override.get_shader_parameter("color") -## TODO add description for outer_margin_for_fade_out. -@export var outer_margin_for_fade_out : float : - set(value): - find_child("ScreenOverlay").material_override.set_shader_parameter("outer_margin_for_fade_out", value) - get: - return find_child("ScreenOverlay").material_override.get_shader_parameter("outer_margin_for_fade_out") @export_category("Debug Values") ## Revels the whole fog. @@ -58,18 +45,6 @@ const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) find_child("Revealer").set_visible(value) get: return find_child("Revealer").is_visible() -## Shows small texture of the fog -@export var debug_texture_view : bool = false: - set(value): - find_child("ScreenOverlay").material_override.set_shader_parameter("debug_texture_view", value) - get: - return find_child("ScreenOverlay").material_override.get_shader_parameter("debug_texture_view") -## Shows small texture of the fog -@export_range(0, 1) var debug_texture_view_size : float = 0.2: - set(value): - find_child("ScreenOverlay").material_override.set_shader_parameter("debug_texture_view_size", value) - get: - return find_child("ScreenOverlay").material_override.get_shader_parameter("debug_texture_view_size") @export_group("Editor Only Circle") ## TODO: Add description @@ -91,15 +66,12 @@ const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) get: return find_child("EditorOnlyCircle").position -#TODO Think if to merge both Dictionary or not -var _unit_to_circles_mapping : Dictionary = {} -var _unit_to_shape_3d_mapping : Dictionary = {} +var _unit_to_vision_data : Dictionary = {} @onready var _revealer : ColorRect = find_child("Revealer") @onready var _fog_viewport : SubViewport = find_child("FogViewport") @onready var _fog_viewport_container : SubViewportContainer = find_child("FogViewportContainer") @onready var _combined_viewport : SubViewport = find_child("CombinedViewport") -@onready var _screen_overlay : MeshInstance3D = find_child("ScreenOverlay") @onready var _visibility_field : Area3D = find_child("VisibilityField") # No set function, to prevent setting from outside @@ -108,9 +80,6 @@ var combined_viewport : SubViewport : return _combined_viewport as SubViewport func _ready() -> void: - _screen_overlay.material_override.set_shader_parameter( - "texture_units_per_world_unit", texture_units_per_world_unit - ) if not Engine.is_editor_hint(): _revealer.hide() var circle = find_child("EditorOnlyCircle") @@ -128,10 +97,11 @@ func _physics_process(_delta : float) -> void: if not _unit_is_mapped(unit): _map_unit_to_new_circles_body(unit) _sync_vision_to_unit(unit) - for mapped_unit in _unit_to_circles_mapping: + for mapped_unit in _unit_to_vision_data: if not mapped_unit in units_synced: _cleanup_mapping(mapped_unit) else: + update_configuration_warnings() if map_mesh_node: # If there is a map mesh, then update in editor the size if map_mesh_node.mesh: fog_size = map_mesh_node.mesh.size @@ -148,40 +118,39 @@ func resize(map_size: Vector2) -> void: func _unit_is_mapped(unit : BaseEntity) -> bool: - return unit in _unit_to_circles_mapping + return unit in _unit_to_vision_data # Create a fog of war visibility circles and visibility shape 3d func _map_unit_to_new_circles_body(unit : BaseEntity) -> void: var effective_sight_range = unit.sight_range * texture_units_per_world_unit; + var shroud_circle = DynamicCircle2D.instantiate() # Make a white circle 2D shroud_circle.color = fog_circle_color # Set color shroud_circle.radius = effective_sight_range # Set circle size to world units and unit sight range _fog_viewport.add_child(shroud_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. + var fow_circle = DynamicCircle2D.instantiate() fow_circle.color = shroud_circle_color fow_circle.radius = effective_sight_range _fog_viewport_container.add_sibling(fow_circle) - _unit_to_circles_mapping[unit] = [shroud_circle, fow_circle] # Keep map to connect unit with fog of war view + var visibility_shape_3d = VisibilityShape3D.instantiate() # Make a cylinder visibility_shape_3d.shape.radius = effective_sight_range # Cylinder radius equal to sight range _visibility_field.add_child(visibility_shape_3d) # Add the shape to the VisibilityField(Area3D node type) - _unit_to_shape_3d_mapping[unit] = visibility_shape_3d # Map unit and shape + + #_unit_to_shape_3d_mapping[unit] = visibility_shape_3d # Map unit and shape + #_unit_to_circles_mapping[unit] = [shroud_circle, fow_circle] # Keep map to connect unit with fog of war view + #_unit_to_circles_mapping[unit] = [shroud_circle, fow_circle] # Keep map to connect unit with fog of war view + + _unit_to_vision_data[unit] = UnitVisionData.create(unit, fow_circle, shroud_circle, visibility_shape_3d) func _sync_vision_to_unit(unit : BaseEntity) -> void: - var unit_pos_3d = unit.global_transform.origin - var unit_pos_2d = Vector2(unit_pos_3d.x, unit_pos_3d.z) * texture_units_per_world_unit - _unit_to_circles_mapping[unit][0].position = unit_pos_2d - _unit_to_circles_mapping[unit][1].position = unit_pos_2d - _unit_to_shape_3d_mapping[unit].position = unit_pos_3d + _unit_to_vision_data[unit].sync_position(texture_units_per_world_unit) func _cleanup_mapping(unit : BaseEntity) -> void: - _unit_to_circles_mapping[unit][0].queue_free() - _unit_to_circles_mapping[unit][1].queue_free() - _unit_to_circles_mapping.erase(unit) - _unit_to_shape_3d_mapping[unit].queue_free() - _unit_to_shape_3d_mapping.erase(unit) + _unit_to_vision_data.erase(unit) func get_visible_units() -> Array[Node3D]: @@ -202,3 +171,23 @@ func _on_visibility_field_body_exited(body: Node3D) -> void: #print_debug("_on_visibility_field_body_exited") if body is UnitEntity: body.visible = false + +func get_vision_data() -> Dictionary: + return _unit_to_vision_data + + +func get_fog_texture() -> ViewportTexture: + var fog_texture_result + if combined_viewport: + fog_texture_result = combined_viewport.get_texture() + else: + fog_texture_result = $CombinedViewport.get_texture() + if fog_texture_result: + return fog_texture_result + return null + +func _get_configuration_warnings() -> PackedStringArray: + var warnings : Array[String] = [] + if fog_size == DEFAULT_SIZE: + warnings.append("Fog of war size is default size") + return warnings diff --git a/addons/rts_framework/features/vision/vision_manager.gd.uid b/addons/rts_framework/features/vision/vision_manager.gd.uid new file mode 100644 index 0000000..aebfb0b --- /dev/null +++ b/addons/rts_framework/features/vision/vision_manager.gd.uid @@ -0,0 +1 @@ +uid://cwlqpivbl7yqa diff --git a/addons/rts_framework/features/vision/vision_manager.tscn b/addons/rts_framework/features/vision/vision_manager.tscn new file mode 100644 index 0000000..9b0ab3c --- /dev/null +++ b/addons/rts_framework/features/vision/vision_manager.tscn @@ -0,0 +1,100 @@ +[gd_scene load_steps=5 format=3 uid="uid://c58yspxllteqr"] + +[ext_resource type="Script" uid="uid://cwlqpivbl7yqa" path="res://addons/rts_framework/features/vision/vision_manager.gd" id="1_m01pg"] +[ext_resource type="PackedScene" uid="uid://clbjgy724q2si" path="res://addons/rts_framework/features/vision/dynamic_circle_2d.tscn" id="2_7q840"] + +[sub_resource type="Shader" id="Shader_w8nhr"] +code = "shader_type canvas_item; + +uniform float blurr_factor : hint_range(0.0, 10.0) = 2.0; +uniform bool remove_alpha = true; +uniform bool overlay = true; + +uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap; + +void fragment() +{ + vec4 blurred_color; + if (overlay) + { + blurred_color = textureLod(screen_texture, SCREEN_UV, blurr_factor); + } + else + { + blurred_color = textureLod(TEXTURE, UV, blurr_factor); + } + if (remove_alpha) + { + COLOR.rgb = blurred_color.rgb; + } + else + { + COLOR = blurred_color; + } +} +" + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_jyswr"] +shader = SubResource("Shader_w8nhr") +shader_parameter/blurr_factor = 1.0 +shader_parameter/remove_alpha = false +shader_parameter/overlay = true + +[node name="VisionManager" type="Node"] +script = ExtResource("1_m01pg") +metadata/_custom_type_script = "uid://cg181bb316phb" + +[node name="CombinedViewport" type="SubViewport" parent="."] +disable_3d = true +handle_input_locally = false +size = Vector2i(500, 500) +render_target_update_mode = 4 + +[node name="Background" type="ColorRect" parent="CombinedViewport"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 1) + +[node name="FogViewportContainer" type="SubViewportContainer" parent="CombinedViewport"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="FogViewport" type="SubViewport" parent="CombinedViewport/FogViewportContainer"] +disable_3d = true +transparent_bg = true +handle_input_locally = false +size = Vector2i(500, 500) +render_target_clear_mode = 2 +render_target_update_mode = 4 + +[node name="EditorOnlyCircle" parent="CombinedViewport" instance=ExtResource("2_7q840")] +position = Vector2(30, 30) +radius = 25 + +[node name="Revealer" type="ColorRect" parent="CombinedViewport"] +visible = false +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -100.0 +offset_bottom = -100.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="BlurrOverlay" type="ColorRect" parent="CombinedViewport"] +material = SubResource("ShaderMaterial_jyswr") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -100.0 +offset_bottom = -100.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VisibilityField" type="Area3D" parent="."] diff --git a/demo/game.tscn b/demo/game.tscn index 7c5f38f..96daa2b 100644 --- a/demo/game.tscn +++ b/demo/game.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=18 format=3 uid="uid://c4by2q2g1r3em"] +[gd_scene load_steps=22 format=3 uid="uid://c4by2q2g1r3em"] [ext_resource type="Texture2D" uid="uid://cj6w0rv0tko5d" path="res://demo/assets/textures/green.png" id="1_0crr1"] [ext_resource type="Script" uid="uid://cuyhslhlbyrr2" path="res://demo/scripts/rts_controller.gd" id="2_yunhj"] @@ -9,7 +9,9 @@ [ext_resource type="PackedScene" uid="uid://bdjx0t2xkn5gg" path="res://addons/rts_framework/features/camera/camera_controller.tscn" id="6_3gdxu"] [ext_resource type="PackedScene" uid="uid://ctoeptkckw6xq" path="res://addons/rts_framework/features/selection/selection_box.tscn" id="6_x1kyj"] [ext_resource type="PackedScene" uid="uid://d1t1ag5bk5u53" path="res://demo/scenes/entities/units/soldier.tscn" id="7_p3hpf"] -[ext_resource type="PackedScene" uid="uid://71g6dowvqb5i" path="res://addons/rts_framework/features/vision/fog_of_war_manager.tscn" id="8_12bj3"] +[ext_resource type="PackedScene" uid="uid://71g6dowvqb5i" path="res://addons/rts_framework/features/vision/fog_of_war.tscn" id="8_12bj3"] +[ext_resource type="PackedScene" uid="uid://c58yspxllteqr" path="res://addons/rts_framework/features/vision/vision_manager.tscn" id="8_fqft5"] +[ext_resource type="Shader" uid="uid://cbo2vdgrqc60a" path="res://addons/rts_framework/features/vision/detailed_fog_of_war.gdshader" id="9_wlnpp"] [ext_resource type="PackedScene" uid="uid://bo2b1x0u1j1dg" path="res://addons/rts_framework/features/vision/minimap.tscn" id="11_hn7rm"] [sub_resource type="Environment" id="Environment_tavya"] @@ -32,6 +34,20 @@ size = Vector2(500, 500) [sub_resource type="BoxShape3D" id="BoxShape3D_m28nb"] size = Vector3(100, 0.1, 100) +[sub_resource type="ViewportTexture" id="ViewportTexture_fqft5"] +viewport_path = NodePath("CombinedViewport") + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ri1tv"] +resource_local_to_scene = true +render_priority = 2 +shader = ExtResource("9_wlnpp") +shader_parameter/color = Color(0, 0, 0, 1) +shader_parameter/world_visibility_texture = SubResource("ViewportTexture_fqft5") +shader_parameter/texture_units_per_world_unit = 2 +shader_parameter/outer_margin_for_fade_out = 0.0 +shader_parameter/debug_texture_view = false +shader_parameter/debug_texture_view_size = 0.0 + [sub_resource type="ViewportTexture" id="ViewportTexture_wlnpp"] viewport_path = NodePath("CombinedViewport") @@ -61,15 +77,18 @@ shape = SubResource("BoxShape3D_m28nb") [node name="Soldier" parent="Entities" instance=ExtResource("7_p3hpf")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.92926, 0.211501, 6.07202) +visible = true material = ExtResource("3_1d533") [node name="Soldier2" parent="Entities" instance=ExtResource("7_p3hpf")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.94615, 0.211501, 6.07202) +visible = true material = ExtResource("4_6ku06") team = 1 [node name="Soldier3" parent="Entities" groups=["revealed_units"] instance=ExtResource("7_p3hpf")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.5574, 0.211501, 6.07202) +visible = true material = ExtResource("3_1d533") [node name="RTSController" type="Node" parent="."] @@ -82,8 +101,15 @@ selection_box = NodePath("../../SelectionBox") [node name="CommandManager" type="Node" parent="RTSController"] script = ExtResource("4_lcg0b") -[node name="FogOfWarManager" parent="RTSController" instance=ExtResource("8_12bj3")] -fog_size = Vector2i(300, 300) +[node name="VisionManager" parent="RTSController" node_paths=PackedStringArray("map_mesh_node") instance=ExtResource("8_fqft5")] +map_mesh_node = NodePath("../../Map/NavigationRegion3D/MeshInstance3D") +fog_size = Vector2i(500, 500) + +[node name="FogOfWar" parent="." node_paths=PackedStringArray("vision_manager") instance=ExtResource("8_12bj3")] +material_override = SubResource("ShaderMaterial_ri1tv") +skeleton = NodePath("../RTSController") +vision_manager = NodePath("../RTSController/VisionManager") +debug_texture_view_size = 0.0 [node name="CameraHolder" parent="." instance=ExtResource("6_3gdxu")] @@ -108,7 +134,7 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="Minimap" parent="HUD/Panel/CenterContainer" node_paths=PackedStringArray("fog_of_war_manager") instance=ExtResource("11_hn7rm")] +[node name="Minimap" parent="HUD/Panel/CenterContainer" node_paths=PackedStringArray("vision_manager") instance=ExtResource("11_hn7rm")] layout_mode = 2 texture = SubResource("ViewportTexture_wlnpp") -fog_of_war_manager = NodePath("../../../../RTSController/FogOfWarManager") +vision_manager = NodePath("../../../../RTSController/VisionManager") From 9b74bf71f7c6b295aa1049dfe3cfabc28c54b194 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 22:21:21 +0300 Subject: [PATCH 02/25] removed add addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd --- .../vision/unit_vision_data_weak_ref.gd | 38 ------------------- .../vision/unit_vision_data_weak_ref.gd.uid | 1 - 2 files changed, 39 deletions(-) delete mode 100644 addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd delete mode 100644 addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid diff --git a/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd b/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd deleted file mode 100644 index 3e3e5c0..0000000 --- a/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd +++ /dev/null @@ -1,38 +0,0 @@ -extends WeakRef -class_name UnitVisionDataWeakRef - -# fow_circle -var fow_circle_radius : float : - get: - return get_ref().fow_circle.radius - set(value): - get_ref().fow_circle.radius = value - -var fow_circle_color : Color : - get: - return get_ref().fow_circle.color - set(value): - get_ref().fow_circle.color = value - -# shroud_circle -var shroud_circle_radius : float : - get: - return get_ref().shroud_circle.radius - set(value): - get_ref().shroud_circle.radius = value - -var shroud_circle_color : Color : - get: - return get_ref().shroud_circle.color - set(value): - get_ref().shroud_circle.color = value - -# shape_3d -var sight_range : float : - get: - return get_ref().shape_3d.shape.radius - set(value): - get_ref().shape_3d.shape.radius = value - -static func create(unit_vision_data : UnitVisionData) -> UnitVisionDataWeakRef: - return weakref(unit_vision_data) diff --git a/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid b/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid deleted file mode 100644 index f427a5f..0000000 --- a/addons/rts_framework/features/vision/unit_vision_data_weak_ref.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c6ox46vndb2o8 From 5eeb5eb62ad90f68fd240ab2e48d86b8a8862d01 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 22:22:14 +0300 Subject: [PATCH 03/25] I worte await vision_manager and forgot .ready --- addons/rts_framework/features/vision/fog_of_war.gd | 2 +- addons/rts_framework/features/vision/minimap.gd | 2 +- addons/rts_framework/features/vision/minimap.tscn | 13 +------------ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd index d6777cd..ec9ba2b 100644 --- a/addons/rts_framework/features/vision/fog_of_war.gd +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -53,7 +53,7 @@ var fog_texture : ViewportTexture: func _ready() -> void: - await vision_manager + await vision_manager.ready var fog_texture_result = vision_manager.get_fog_texture() if fog_texture_result: fog_texture = fog_texture_result diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 1c508ab..d4cf7f0 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -37,7 +37,7 @@ var fog_texture : Texture2D : # fog_texture multiply the images above. This to f func _ready() -> void: assert(vision_manager != null, "Minimap missing vision manager node. Minimap Node Name: " + self.name) - await vision_manager + await vision_manager.ready var fog_texture_result = vision_manager.get_fog_texture() if fog_texture_result: fog_texture = fog_texture_result diff --git a/addons/rts_framework/features/vision/minimap.tscn b/addons/rts_framework/features/vision/minimap.tscn index cedcd92..02a791a 100644 --- a/addons/rts_framework/features/vision/minimap.tscn +++ b/addons/rts_framework/features/vision/minimap.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=6 format=3 uid="uid://bo2b1x0u1j1dg"] +[gd_scene load_steps=5 format=3 uid="uid://bo2b1x0u1j1dg"] [ext_resource type="Script" uid="uid://bd3c10auv3sc0" path="res://addons/rts_framework/features/vision/minimap.gd" id="1_6mcq1"] [ext_resource type="PackedScene" uid="uid://clbjgy724q2si" path="res://addons/rts_framework/features/vision/dynamic_circle_2d.tscn" id="1_dqnbu"] @@ -10,9 +10,6 @@ viewport_path = NodePath("CombinedViewport") blend_mode = 3 light_mode = 1 -[sub_resource type="ViewportTexture" id="ViewportTexture_6mcq1"] -viewport_path = NodePath("SubViewport") - [node name="Minimap" type="TextureRect"] anchors_preset = 15 anchor_right = 1.0 @@ -42,15 +39,7 @@ color = Color(1, 0, 0, 1) material = SubResource("CanvasItemMaterial_5oxvc") offset_right = 40.0 offset_bottom = 40.0 -texture = SubResource("ViewportTexture_6mcq1") [node name="EditorOnlyCircle" parent="CombinedViewport" instance=ExtResource("1_dqnbu")] position = Vector2(50, 50) color = Color(0, 0, 1, 1) - -[node name="SubViewport" type="SubViewport" parent="."] - -[node name="ColorRect" type="ColorRect" parent="SubViewport"] -offset_right = 40.0 -offset_bottom = 40.0 -color = Color(0, 0, 0, 1) From 4435b9002628bd3af2fbba31ca47e755e57689e7 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 22:30:47 +0300 Subject: [PATCH 04/25] Enchanced how null treated in UnitVisionData class --- .../features/vision/unit_vision_data.gd | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd b/addons/rts_framework/features/vision/unit_vision_data.gd index 304a6b1..5c217d4 100644 --- a/addons/rts_framework/features/vision/unit_vision_data.gd +++ b/addons/rts_framework/features/vision/unit_vision_data.gd @@ -1,6 +1,11 @@ extends Resource class_name UnitVisionData +const EMPTY_RADUIS : float = -1 +const EMPTY_COLOR : Color = Color.TRANSPARENT +const EMPTY_VECTOR3 : Vector3 = Vector3.INF +const EMPTY_VECTOR2 : Vector2 = Vector2.INF + var unit : BaseEntity = null var fow_circle : Node2D = null var shroud_circle : Node2D = null @@ -12,7 +17,7 @@ var shape_3d : CollisionShape3D = null var fow_circle_radius : float : get: if fow_circle == null: - return 0 + return EMPTY_RADUIS return fow_circle.radius set(value): if fow_circle == null: @@ -22,8 +27,12 @@ var fow_circle_radius : float : var fow_circle_color : Color : get: + if fow_circle == null: + return EMPTY_COLOR return fow_circle.color set(value): + if fow_circle == null: + return fow_circle.color = value emit_changed() @@ -31,7 +40,7 @@ var fow_circle_color : Color : var shroud_circle_radius : float : get: if shroud_circle == null: - return 0 + return EMPTY_RADUIS return shroud_circle.radius set(value): if shroud_circle == null: @@ -41,8 +50,12 @@ var shroud_circle_radius : float : var shroud_circle_color : Color : get: + if shroud_circle == null: + return EMPTY_COLOR return shroud_circle.color set(value): + if shroud_circle == null: + return shroud_circle.color = value emit_changed() @@ -50,7 +63,7 @@ var shroud_circle_color : Color : var minimap_circle_radius : float : get: if minimap_circle == null: - return 0 + return EMPTY_RADUIS return minimap_circle.radius set(value): if minimap_circle == null: @@ -60,8 +73,12 @@ var minimap_circle_radius : float : var minimap_circle_color : Color : get: + if minimap_circle == null: + return EMPTY_COLOR return minimap_circle.color set(value): + if minimap_circle == null: + return minimap_circle.color = value emit_changed() @@ -69,7 +86,7 @@ var minimap_circle_color : Color : var sight_range : float : get: if shape_3d == null || shape_3d.shape == null: - return 0 + return EMPTY_RADUIS return shape_3d.shape.radius set(value): if shape_3d == null || shape_3d.shape == null: @@ -81,17 +98,19 @@ var sight_range : float : var position : Vector3 : get: if shape_3d == null: - return Vector3.INF + return EMPTY_VECTOR3 return shape_3d.position set(value): # Prevent setting return -static func create(unit, fow_circle, shroud_circle, shape_3d) -> UnitVisionData: +static func create(unit, fow_circle, shroud_circle, shape_3d, minimap_circle = null) -> UnitVisionData: var instance = UnitVisionData.new() instance.unit = unit instance.fow_circle = fow_circle instance.shroud_circle = shroud_circle instance.shape_3d = shape_3d + if minimap_circle != null: + instance.minimap_circle = minimap_circle return instance # TODO: Talk about having a RefCounted in the unit itself and From 532b524c7fb753cf003b2c369bdea15c41175dfb Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 22:32:53 +0300 Subject: [PATCH 05/25] Enchanced how UnitVisionData class position sync func chekck if emit change --- .../rts_framework/features/vision/unit_vision_data.gd | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd b/addons/rts_framework/features/vision/unit_vision_data.gd index 5c217d4..c9d3741 100644 --- a/addons/rts_framework/features/vision/unit_vision_data.gd +++ b/addons/rts_framework/features/vision/unit_vision_data.gd @@ -130,18 +130,17 @@ func _notification(what): func sync_position(texture_units_per_world_unit : int) -> void: var unit_pos_3d = unit.global_transform.origin var unit_pos_2d = Vector2(unit_pos_3d.x, unit_pos_3d.z) * texture_units_per_world_unit - var changed_flag = false + + # Check if any component exists to determine if we need to emit a change + var should_emit = fow_circle != null || shroud_circle != null || minimap_circle != null || shape_3d != null + if fow_circle: fow_circle.position = unit_pos_2d - changed_flag = true if shroud_circle: shroud_circle.position = unit_pos_2d - changed_flag = true if minimap_circle: minimap_circle.position = unit_pos_2d - changed_flag = true if shape_3d: shape_3d.position = unit_pos_3d - changed_flag = true - if changed_flag: + if should_emit: emit_changed() From 3ea9fdea8600a8cccc6ee25a68a07470d17b316f Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 23:20:07 +0300 Subject: [PATCH 06/25] Changed according to coderabbitai PR --- .../features/vision/fog_of_war.gd | 34 +++++++++++++------ .../rts_framework/features/vision/minimap.gd | 4 +-- .../features/vision/unit_vision_data.gd | 3 +- .../features/vision/vision_manager.gd | 10 ++---- demo/game.tscn | 5 +-- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd index ec9ba2b..14a1500 100644 --- a/addons/rts_framework/features/vision/fog_of_war.gd +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -1,22 +1,27 @@ @tool extends MeshInstance3D class_name FogOfWarManager + @export var vision_manager : VisionManager: set(value): - vision_manager = value - var fog_texture_result = value.get_fog_texture() - if fog_texture_result: - fog_texture = fog_texture_result + _vision_manager = value + _apply_fog_texture_from_vision_manager() get: - return vision_manager + return _vision_manager + +# Private backing field +var _vision_manager : VisionManager @export_category("Fog Values") ## The size of a single pixel in the 3D world +var _texture_units_per_world_unit: int = 2 @export_range(1, 10000, 1,"suffix:px/length") var texture_units_per_world_unit : int = 2 : # px/length - set(value): - material_override.set_shader_parameter("texture_units_per_world_unit", value) - texture_units_per_world_unit = value + set(value): + material_override.set_shader_parameter("texture_units_per_world_unit", value) + _texture_units_per_world_unit = value + get: + return _texture_units_per_world_unit ## Color of the generated fog @export var fog_color : Color : @@ -45,11 +50,15 @@ class_name FogOfWarManager get: return material_override.get_shader_parameter("debug_texture_view_size") +# Private backing field to store the texture +var _fog_texture : ViewportTexture var fog_texture : ViewportTexture: set(value): - material_override.set_shader_parameter("world_visibility_texture", value) + _fog_texture = value # Store in backing field + if material_override: # Check if material exists + material_override.set_shader_parameter("world_visibility_texture", value) get: - return material_override.get_shader_parameter("world_visibility_texture") + return _fog_texture # Return from backing field func _ready() -> void: @@ -57,3 +66,8 @@ func _ready() -> void: var fog_texture_result = vision_manager.get_fog_texture() if fog_texture_result: fog_texture = fog_texture_result + +func _apply_fog_texture_from_vision_manager() -> void: + var fog_texture_result = _vision_manager.get_fog_texture() + if fog_texture_result: + fog_texture = fog_texture_result diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index d4cf7f0..59b7984 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -10,8 +10,7 @@ const DynamicCircle2D : PackedScene = preload("res://addons/rts_framework/featur @export var vision_manager : VisionManager -#var _unit_to_circles_mapping : Dictionary = {} -var _vision_data : Dictionary # Weak Ref for Dictionary{ BaseEntity : UnitVisionData } +var _vision_data : Dictionary ## Texture representing the fog of war alpha layer ## @@ -37,7 +36,6 @@ var fog_texture : Texture2D : # fog_texture multiply the images above. This to f func _ready() -> void: assert(vision_manager != null, "Minimap missing vision manager node. Minimap Node Name: " + self.name) - await vision_manager.ready var fog_texture_result = vision_manager.get_fog_texture() if fog_texture_result: fog_texture = fog_texture_result diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd b/addons/rts_framework/features/vision/unit_vision_data.gd index c9d3741..b12296c 100644 --- a/addons/rts_framework/features/vision/unit_vision_data.gd +++ b/addons/rts_framework/features/vision/unit_vision_data.gd @@ -12,7 +12,6 @@ var shroud_circle : Node2D = null var minimap_circle : Node2D = null var shape_3d : CollisionShape3D = null - # fow_circle var fow_circle_radius : float : get: @@ -103,7 +102,7 @@ var position : Vector3 : set(value): # Prevent setting return -static func create(unit, fow_circle, shroud_circle, shape_3d, minimap_circle = null) -> UnitVisionData: +static func create(unit : BaseEntity, fow_circle : Node2D, shroud_circle : Node2D, shape_3d : CollisionShape3D , minimap_circle : Node2D = null) -> UnitVisionData: var instance = UnitVisionData.new() instance.unit = unit instance.fow_circle = fow_circle diff --git a/addons/rts_framework/features/vision/vision_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd index d272ce4..248ed0f 100644 --- a/addons/rts_framework/features/vision/vision_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -66,7 +66,7 @@ const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) get: return find_child("EditorOnlyCircle").position -var _unit_to_vision_data : Dictionary = {} +var _unit_to_vision_data : Dictionary = {} # Dictionary @onready var _revealer : ColorRect = find_child("Revealer") @onready var _fog_viewport : SubViewport = find_child("FogViewport") @@ -138,11 +138,7 @@ func _map_unit_to_new_circles_body(unit : BaseEntity) -> void: var visibility_shape_3d = VisibilityShape3D.instantiate() # Make a cylinder visibility_shape_3d.shape.radius = effective_sight_range # Cylinder radius equal to sight range _visibility_field.add_child(visibility_shape_3d) # Add the shape to the VisibilityField(Area3D node type) - - #_unit_to_shape_3d_mapping[unit] = visibility_shape_3d # Map unit and shape - #_unit_to_circles_mapping[unit] = [shroud_circle, fow_circle] # Keep map to connect unit with fog of war view - #_unit_to_circles_mapping[unit] = [shroud_circle, fow_circle] # Keep map to connect unit with fog of war view - + _unit_to_vision_data[unit] = UnitVisionData.create(unit, fow_circle, shroud_circle, visibility_shape_3d) func _sync_vision_to_unit(unit : BaseEntity) -> void: @@ -190,4 +186,4 @@ func _get_configuration_warnings() -> PackedStringArray: var warnings : Array[String] = [] if fog_size == DEFAULT_SIZE: warnings.append("Fog of war size is default size") - return warnings + return PackedStringArray(warnings) diff --git a/demo/game.tscn b/demo/game.tscn index 96daa2b..646b281 100644 --- a/demo/game.tscn +++ b/demo/game.tscn @@ -48,7 +48,7 @@ shader_parameter/outer_margin_for_fade_out = 0.0 shader_parameter/debug_texture_view = false shader_parameter/debug_texture_view_size = 0.0 -[sub_resource type="ViewportTexture" id="ViewportTexture_wlnpp"] +[sub_resource type="ViewportTexture" id="ViewportTexture_ri1tv"] viewport_path = NodePath("CombinedViewport") [node name="Game" type="Node3D"] @@ -109,6 +109,7 @@ fog_size = Vector2i(500, 500) material_override = SubResource("ShaderMaterial_ri1tv") skeleton = NodePath("../RTSController") vision_manager = NodePath("../RTSController/VisionManager") +texture_units_per_world_unit = null debug_texture_view_size = 0.0 [node name="CameraHolder" parent="." instance=ExtResource("6_3gdxu")] @@ -136,5 +137,5 @@ grow_vertical = 2 [node name="Minimap" parent="HUD/Panel/CenterContainer" node_paths=PackedStringArray("vision_manager") instance=ExtResource("11_hn7rm")] layout_mode = 2 -texture = SubResource("ViewportTexture_wlnpp") +texture = SubResource("ViewportTexture_ri1tv") vision_manager = NodePath("../../../../RTSController/VisionManager") From 516096826f40b2beba30f93bfbfeb98d358f24de Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 23:33:00 +0300 Subject: [PATCH 07/25] fixed typo --- .../rts_framework/features/vision/unit_vision_data.gd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd b/addons/rts_framework/features/vision/unit_vision_data.gd index b12296c..97d4ce6 100644 --- a/addons/rts_framework/features/vision/unit_vision_data.gd +++ b/addons/rts_framework/features/vision/unit_vision_data.gd @@ -1,7 +1,7 @@ extends Resource class_name UnitVisionData -const EMPTY_RADUIS : float = -1 +const EMPTY_RADIUS : float = -1 const EMPTY_COLOR : Color = Color.TRANSPARENT const EMPTY_VECTOR3 : Vector3 = Vector3.INF const EMPTY_VECTOR2 : Vector2 = Vector2.INF @@ -16,7 +16,7 @@ var shape_3d : CollisionShape3D = null var fow_circle_radius : float : get: if fow_circle == null: - return EMPTY_RADUIS + return EMPTY_RADIUS return fow_circle.radius set(value): if fow_circle == null: @@ -39,7 +39,7 @@ var fow_circle_color : Color : var shroud_circle_radius : float : get: if shroud_circle == null: - return EMPTY_RADUIS + return EMPTY_RADIUS return shroud_circle.radius set(value): if shroud_circle == null: @@ -62,7 +62,7 @@ var shroud_circle_color : Color : var minimap_circle_radius : float : get: if minimap_circle == null: - return EMPTY_RADUIS + return EMPTY_RADIUS return minimap_circle.radius set(value): if minimap_circle == null: @@ -85,7 +85,7 @@ var minimap_circle_color : Color : var sight_range : float : get: if shape_3d == null || shape_3d.shape == null: - return EMPTY_RADUIS + return EMPTY_RADIUS return shape_3d.shape.radius set(value): if shape_3d == null || shape_3d.shape == null: From 2d96fc44f54d86d8548a490b18d974ee40c32d5a Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 23:37:13 +0300 Subject: [PATCH 08/25] Changed according to coderabbitai PR --- addons/rts_framework/features/vision/fog_of_war.gd | 5 ++++- .../features/vision/vision_manager.gd | 14 +++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd index 14a1500..c5e739d 100644 --- a/addons/rts_framework/features/vision/fog_of_war.gd +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -5,7 +5,8 @@ class_name FogOfWarManager @export var vision_manager : VisionManager: set(value): _vision_manager = value - _apply_fog_texture_from_vision_manager() + if _vision_manager: + _apply_fog_texture_from_vision_manager() get: return _vision_manager @@ -68,6 +69,8 @@ func _ready() -> void: fog_texture = fog_texture_result func _apply_fog_texture_from_vision_manager() -> void: + if _vision_manager == null: + return var fog_texture_result = _vision_manager.get_fog_texture() if fog_texture_result: fog_texture = fog_texture_result diff --git a/addons/rts_framework/features/vision/vision_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd index 248ed0f..daa41fd 100644 --- a/addons/rts_framework/features/vision/vision_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -8,16 +8,20 @@ const VisibilityShape3D : PackedScene = preload("res://addons/rts_framework/fea const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) -## Color of area the units saw and not seeing currenty. Can see in Debug Texture View +## Color of area the units saw and not seeing currently. Can see in Debug Texture View @export var fog_circle_color : Color = Color(0.25, 0.25, 0.25) ## Color of area the units see around them. Can see in Debug Texture View @export var shroud_circle_color : Color = Color(1.0, 1.0, 1.0) @export_category("Fog Values") ## The size of a single pixel in the 3D world -@export_range(1, 10000, 1,"suffix:px/length") var texture_units_per_world_unit : int = 2 : # px/length +@export_range(1, 10000, 1,"suffix:px/length") var texture_units_per_world_unit : int : # px/length set(value): - texture_units_per_world_unit = value + _texture_units_per_world_unit = value + get: + return _texture_units_per_world_unit +# private backing store +var _texture_units_per_world_unit: int = 2 ## AAA @export var map_mesh_node : MeshInstance3D: @@ -39,7 +43,7 @@ const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) return fog_size @export_category("Debug Values") -## Revels the whole fog. +## Reveals the whole fog. @export var revel_fog : bool = false: set(value): find_child("Revealer").set_visible(value) @@ -97,7 +101,7 @@ func _physics_process(_delta : float) -> void: if not _unit_is_mapped(unit): _map_unit_to_new_circles_body(unit) _sync_vision_to_unit(unit) - for mapped_unit in _unit_to_vision_data: + for mapped_unit in _unit_to_vision_data.keys(): if not mapped_unit in units_synced: _cleanup_mapping(mapped_unit) else: From 57f70bd15a9875cf74d4bf41b182c6968cdfcbcb Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sat, 19 Apr 2025 23:53:28 +0300 Subject: [PATCH 09/25] Changed according to coderabbitai PR --- .../features/vision/fog_of_war.gd | 26 ++++++++++++------- .../features/vision/unit_vision_data.gd | 17 +++++++++--- .../features/vision/vision_manager.gd | 2 +- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd index c5e739d..4d1563a 100644 --- a/addons/rts_framework/features/vision/fog_of_war.gd +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -19,7 +19,8 @@ var _vision_manager : VisionManager var _texture_units_per_world_unit: int = 2 @export_range(1, 10000, 1,"suffix:px/length") var texture_units_per_world_unit : int = 2 : # px/length set(value): - material_override.set_shader_parameter("texture_units_per_world_unit", value) + if material_override: + material_override.set_shader_parameter("texture_units_per_world_unit", value) _texture_units_per_world_unit = value get: return _texture_units_per_world_unit @@ -27,13 +28,15 @@ var _texture_units_per_world_unit: int = 2 ## Color of the generated fog @export var fog_color : Color : set(value): - material_override.set_shader_parameter("color", value) + if material_override: + material_override.set_shader_parameter("color", value) get: return material_override.get_shader_parameter("color") ## TODO add description for outer_margin_for_fade_out. @export var outer_margin_for_fade_out : float : set(value): - material_override.set_shader_parameter("outer_margin_for_fade_out", value) + if material_override: + material_override.set_shader_parameter("outer_margin_for_fade_out", value) get: return material_override.get_shader_parameter("outer_margin_for_fade_out") @@ -41,13 +44,15 @@ var _texture_units_per_world_unit: int = 2 ## Shows small texture of the fog @export var debug_texture_view : bool = false: set(value): - material_override.set_shader_parameter("debug_texture_view", value) + if material_override: + material_override.set_shader_parameter("debug_texture_view", value) get: return material_override.get_shader_parameter("debug_texture_view") ## Shows small texture of the fog @export_range(0, 1) var debug_texture_view_size : float = 0.2: set(value): - material_override.set_shader_parameter("debug_texture_view_size", value) + if material_override: + material_override.set_shader_parameter("debug_texture_view_size", value) get: return material_override.get_shader_parameter("debug_texture_view_size") @@ -63,10 +68,13 @@ var fog_texture : ViewportTexture: func _ready() -> void: - await vision_manager.ready - var fog_texture_result = vision_manager.get_fog_texture() - if fog_texture_result: - fog_texture = fog_texture_result + if vision_manager: + await vision_manager.ready + var fog_texture_result = vision_manager.get_fog_texture() + if fog_texture_result: + fog_texture = fog_texture_result + else: + push_warning("FogOfWarManager: 'vision_manager' is not assigned – fog texture cannot be applied.") func _apply_fog_texture_from_vision_manager() -> void: if _vision_manager == null: diff --git a/addons/rts_framework/features/vision/unit_vision_data.gd b/addons/rts_framework/features/vision/unit_vision_data.gd index 97d4ce6..48da065 100644 --- a/addons/rts_framework/features/vision/unit_vision_data.gd +++ b/addons/rts_framework/features/vision/unit_vision_data.gd @@ -96,9 +96,9 @@ var sight_range : float : # All var position : Vector3 : get: - if shape_3d == null: - return EMPTY_VECTOR3 - return shape_3d.position + if shape_3d: + return shape_3d.position + return EMPTY_VECTOR3 set(value): # Prevent setting return @@ -131,15 +131,24 @@ func sync_position(texture_units_per_world_unit : int) -> void: var unit_pos_2d = Vector2(unit_pos_3d.x, unit_pos_3d.z) * texture_units_per_world_unit # Check if any component exists to determine if we need to emit a change - var should_emit = fow_circle != null || shroud_circle != null || minimap_circle != null || shape_3d != null + var should_emit : bool = false if fow_circle: + should_emit = should_emit_sync_position_helper(should_emit, fow_circle.position, unit_pos_2d) fow_circle.position = unit_pos_2d if shroud_circle: + should_emit = should_emit_sync_position_helper(should_emit, shroud_circle.position, unit_pos_2d) shroud_circle.position = unit_pos_2d if minimap_circle: + should_emit = should_emit_sync_position_helper(should_emit, minimap_circle.position, unit_pos_2d) minimap_circle.position = unit_pos_2d if shape_3d: + should_emit = should_emit_sync_position_helper(should_emit, shape_3d.position, unit_pos_3d) shape_3d.position = unit_pos_3d if should_emit: emit_changed() + +func should_emit_sync_position_helper(should_emit : bool, preview, current) -> bool: + if !should_emit: + return preview != current + return true diff --git a/addons/rts_framework/features/vision/vision_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd index daa41fd..ba2496c 100644 --- a/addons/rts_framework/features/vision/vision_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -44,7 +44,7 @@ var _texture_units_per_world_unit: int = 2 @export_category("Debug Values") ## Reveals the whole fog. -@export var revel_fog : bool = false: +@export var reveal_fog : bool = false: set(value): find_child("Revealer").set_visible(value) get: From 0398535ead7480ac1aa416a121f389efa3f35056 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sun, 20 Apr 2025 00:00:07 +0300 Subject: [PATCH 10/25] Added guard material_override in getters --- .../rts_framework/features/vision/fog_of_war.gd | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd index 4d1563a..df2a86b 100644 --- a/addons/rts_framework/features/vision/fog_of_war.gd +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -31,14 +31,18 @@ var _texture_units_per_world_unit: int = 2 if material_override: material_override.set_shader_parameter("color", value) get: - return material_override.get_shader_parameter("color") + if material_override: + return material_override.get_shader_parameter("color") + return Color.BLACK ## TODO add description for outer_margin_for_fade_out. @export var outer_margin_for_fade_out : float : set(value): if material_override: material_override.set_shader_parameter("outer_margin_for_fade_out", value) get: - return material_override.get_shader_parameter("outer_margin_for_fade_out") + if material_override: + return material_override.get_shader_parameter("outer_margin_for_fade_out") + return 0.0 @export_category("Debug Values") ## Shows small texture of the fog @@ -47,14 +51,18 @@ var _texture_units_per_world_unit: int = 2 if material_override: material_override.set_shader_parameter("debug_texture_view", value) get: - return material_override.get_shader_parameter("debug_texture_view") + if material_override: + return material_override.get_shader_parameter("debug_texture_view") + return false ## Shows small texture of the fog @export_range(0, 1) var debug_texture_view_size : float = 0.2: set(value): if material_override: material_override.set_shader_parameter("debug_texture_view_size", value) get: - return material_override.get_shader_parameter("debug_texture_view_size") + if material_override: + return material_override.get_shader_parameter("debug_texture_view_size") + return 0.2 # Private backing field to store the texture var _fog_texture : ViewportTexture From 0f55b319c1a120b0495c316cdfc0ef4771fc4e9e Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sun, 20 Apr 2025 00:05:10 +0300 Subject: [PATCH 11/25] Updated comments in code --- addons/rts_framework/features/vision/fog_of_war.gd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/rts_framework/features/vision/fog_of_war.gd b/addons/rts_framework/features/vision/fog_of_war.gd index df2a86b..5e7532c 100644 --- a/addons/rts_framework/features/vision/fog_of_war.gd +++ b/addons/rts_framework/features/vision/fog_of_war.gd @@ -34,7 +34,8 @@ var _texture_units_per_world_unit: int = 2 if material_override: return material_override.get_shader_parameter("color") return Color.BLACK -## TODO add description for outer_margin_for_fade_out. + +## Controls the size of the fade-out effect at the edges of the visible area, creating a smooth transition between visible and fog areas. @export var outer_margin_for_fade_out : float : set(value): if material_override: @@ -54,7 +55,8 @@ var _texture_units_per_world_unit: int = 2 if material_override: return material_override.get_shader_parameter("debug_texture_view") return false -## Shows small texture of the fog + +## Controls the size of the debug texture view when enabled @export_range(0, 1) var debug_texture_view_size : float = 0.2: set(value): if material_override: From 7a74ac1038a9b021d4b1aa99fe5a1668353ddf42 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Sun, 20 Apr 2025 02:05:12 +0300 Subject: [PATCH 12/25] demo/game.tscn --- demo/game.tscn | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/game.tscn b/demo/game.tscn index 646b281..702e65b 100644 --- a/demo/game.tscn +++ b/demo/game.tscn @@ -102,6 +102,7 @@ selection_box = NodePath("../../SelectionBox") script = ExtResource("4_lcg0b") [node name="VisionManager" parent="RTSController" node_paths=PackedStringArray("map_mesh_node") instance=ExtResource("8_fqft5")] +texture_units_per_world_unit = null map_mesh_node = NodePath("../../Map/NavigationRegion3D/MeshInstance3D") fog_size = Vector2i(500, 500) From 43f517a11ff70963dc35c57e3766f5be069102a9 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Mon, 21 Apr 2025 23:47:24 +0300 Subject: [PATCH 13/25] Connected VisibilityField's signals to VisionManager --- addons/rts_framework/features/vision/vision_manager.tscn | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/rts_framework/features/vision/vision_manager.tscn b/addons/rts_framework/features/vision/vision_manager.tscn index 9b0ab3c..8ea795f 100644 --- a/addons/rts_framework/features/vision/vision_manager.tscn +++ b/addons/rts_framework/features/vision/vision_manager.tscn @@ -42,6 +42,7 @@ shader_parameter/overlay = true [node name="VisionManager" type="Node"] script = ExtResource("1_m01pg") +texture_units_per_world_unit = 2 metadata/_custom_type_script = "uid://cg181bb316phb" [node name="CombinedViewport" type="SubViewport" parent="."] @@ -98,3 +99,6 @@ grow_horizontal = 2 grow_vertical = 2 [node name="VisibilityField" type="Area3D" parent="."] + +[connection signal="body_entered" from="VisibilityField" to="." method="_on_visibility_field_body_entered"] +[connection signal="body_exited" from="VisibilityField" to="." method="_on_visibility_field_body_exited"] From 13de27feb80fef8723a4a58f21ae6e8473ae06c3 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 23 Apr 2025 22:22:51 +0300 Subject: [PATCH 14/25] Added draw_node_on_minimap function for other scripts to able to draw on minimap. Example draw alert of been attacked in the minimap. --- addons/rts_framework/features/vision/minimap.gd | 13 +++++++++++-- demo/game.tscn | 3 +-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 59b7984..e1d622c 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -78,6 +78,15 @@ func _map_unit_to_new_circles_body(unit : BaseEntity, default_color : Color = Co minimap_circle.radius = unit.get_sight_range() # If has sight range, then use it else: minimap_circle.radius = default_radius # If doesn't have sight range, then use default - - _minimap_viewport.add_child(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. + + draw_node_on_minimap(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. _vision_data[unit].minimap_circle = minimap_circle # Keep map to connect unit with fog of war view + +## Addes draw_node(:CanvasItem) in way to draw it over other (preview) things in the minimap +## +## Return true on success, false on fail +func draw_node_on_minimap(draw_node : CanvasItem) -> bool: + if _minimap_viewport: + add_child(draw_node) + return true + return false diff --git a/demo/game.tscn b/demo/game.tscn index 702e65b..4c9ab0b 100644 --- a/demo/game.tscn +++ b/demo/game.tscn @@ -102,15 +102,14 @@ selection_box = NodePath("../../SelectionBox") script = ExtResource("4_lcg0b") [node name="VisionManager" parent="RTSController" node_paths=PackedStringArray("map_mesh_node") instance=ExtResource("8_fqft5")] -texture_units_per_world_unit = null map_mesh_node = NodePath("../../Map/NavigationRegion3D/MeshInstance3D") fog_size = Vector2i(500, 500) [node name="FogOfWar" parent="." node_paths=PackedStringArray("vision_manager") instance=ExtResource("8_12bj3")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.242398, 0, 0) material_override = SubResource("ShaderMaterial_ri1tv") skeleton = NodePath("../RTSController") vision_manager = NodePath("../RTSController/VisionManager") -texture_units_per_world_unit = null debug_texture_view_size = 0.0 [node name="CameraHolder" parent="." instance=ExtResource("6_3gdxu")] From aa9f3e3804f7a9d3a1ac3e16844ce58453848e35 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Thu, 24 Apr 2025 04:38:42 +0300 Subject: [PATCH 15/25] Fixed bug. Prefore this commit, the function adds as child to wrong node. --- addons/rts_framework/features/vision/minimap.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index e1d622c..ec085d9 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -87,6 +87,6 @@ func _map_unit_to_new_circles_body(unit : BaseEntity, default_color : Color = Co ## Return true on success, false on fail func draw_node_on_minimap(draw_node : CanvasItem) -> bool: if _minimap_viewport: - add_child(draw_node) + _minimap_viewport.add_child(draw_node) return true return false From d3a7235511f08cd6b9b881b003db63d73870e9f6 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 7 May 2025 20:22:57 +0300 Subject: [PATCH 16/25] Minimap now validate in ready function, if vision_data from vision manager isn't null --- addons/rts_framework/features/vision/minimap.gd | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index ec085d9..f8dcf63 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -42,6 +42,10 @@ func _ready() -> void: else: push_error("Failed to retrieve fog of war texture. Minimap Node Name: " + self.name) _vision_data = vision_manager.get_vision_data() + assert(_vision_data != null, "VisionManager returned null vision data for minimap '" + name + "'") + if _vision_data == null: + return # Abort further initialisation – minimap cannot function without data + if not Engine.is_editor_hint(): var circle = find_child("EditorOnlyCircle") if circle: @@ -51,6 +55,9 @@ func _physics_process(_delta : float) -> void: for unit in _vision_data: if not unit.is_revealing(): continue + #if _unit_is_minimap_mapped(unit): # not unit.is_revealing() and _unit_is_minimap_mapped(unit) + #_vision_data[unit].minimap_circle.queue_free() + #_vision_data[unit].minimap_circle = null if not _unit_is_minimap_mapped(unit): _map_unit_to_new_circles_body(unit) From f481f22209e70720cd805d61735ec4c0a31f4508 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 7 May 2025 20:24:20 +0300 Subject: [PATCH 17/25] cleaning units which stop revealing --- addons/rts_framework/features/vision/vision_manager.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rts_framework/features/vision/vision_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd index ba2496c..9aa6c59 100644 --- a/addons/rts_framework/features/vision/vision_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -102,7 +102,7 @@ func _physics_process(_delta : float) -> void: _map_unit_to_new_circles_body(unit) _sync_vision_to_unit(unit) for mapped_unit in _unit_to_vision_data.keys(): - if not mapped_unit in units_synced: + if (not mapped_unit in units_synced) or (not mapped_unit.is_revealing()): _cleanup_mapping(mapped_unit) else: update_configuration_warnings() From 9f09b639bd75e4eb9e0798946217be69e4c3f1fd Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 7 May 2025 20:24:35 +0300 Subject: [PATCH 18/25] removed comments in code --- addons/rts_framework/features/vision/minimap.gd | 3 --- 1 file changed, 3 deletions(-) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index f8dcf63..4baeb51 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -55,9 +55,6 @@ func _physics_process(_delta : float) -> void: for unit in _vision_data: if not unit.is_revealing(): continue - #if _unit_is_minimap_mapped(unit): # not unit.is_revealing() and _unit_is_minimap_mapped(unit) - #_vision_data[unit].minimap_circle.queue_free() - #_vision_data[unit].minimap_circle = null if not _unit_is_minimap_mapped(unit): _map_unit_to_new_circles_body(unit) From 2c97cf51771adcb3efe5730858e6ddea1c23e220 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 7 May 2025 21:22:44 +0300 Subject: [PATCH 19/25] Changes according to Coderabbitai PR --- addons/rts_framework/features/vision/minimap.gd | 4 ++-- .../rts_framework/features/vision/vision_manager.gd | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 4baeb51..38afaa5 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -42,8 +42,8 @@ func _ready() -> void: else: push_error("Failed to retrieve fog of war texture. Minimap Node Name: " + self.name) _vision_data = vision_manager.get_vision_data() - assert(_vision_data != null, "VisionManager returned null vision data for minimap '" + name + "'") if _vision_data == null: + push_error("VisionManager returned null vision data for minimap: " + self.name) return # Abort further initialisation – minimap cannot function without data if not Engine.is_editor_hint(): @@ -52,7 +52,7 @@ func _ready() -> void: circle.queue_free() func _physics_process(_delta : float) -> void: - for unit in _vision_data: + for unit in _vision_data.keys(): if not unit.is_revealing(): continue if not _unit_is_minimap_mapped(unit): diff --git a/addons/rts_framework/features/vision/vision_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd index 9aa6c59..7fbeb9b 100644 --- a/addons/rts_framework/features/vision/vision_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -177,14 +177,9 @@ func get_vision_data() -> Dictionary: func get_fog_texture() -> ViewportTexture: - var fog_texture_result - if combined_viewport: - fog_texture_result = combined_viewport.get_texture() - else: - fog_texture_result = $CombinedViewport.get_texture() - if fog_texture_result: - return fog_texture_result - return null + var viewport = combined_viewport if combined_viewport else $CombinedViewport + var texture = viewport.get_texture() if viewport else null + return texture func _get_configuration_warnings() -> PackedStringArray: var warnings : Array[String] = [] From 24476c38380a3ac194ca4f487cdc331d961a0158 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 7 May 2025 21:37:22 +0300 Subject: [PATCH 20/25] currected starting values of fog_circle_color and shroud_circle_color --- addons/rts_framework/features/vision/vision_manager.gd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/rts_framework/features/vision/vision_manager.gd b/addons/rts_framework/features/vision/vision_manager.gd index 7fbeb9b..f79eb7b 100644 --- a/addons/rts_framework/features/vision/vision_manager.gd +++ b/addons/rts_framework/features/vision/vision_manager.gd @@ -9,9 +9,9 @@ const VisibilityShape3D : PackedScene = preload("res://addons/rts_framework/fea const DEFAULT_SIZE : Vector2i = Vector2i(100, 100) ## Color of area the units saw and not seeing currently. Can see in Debug Texture View -@export var fog_circle_color : Color = Color(0.25, 0.25, 0.25) +@export var fog_circle_color : Color = Color(1.0, 1.0, 1.0) ## Color of area the units see around them. Can see in Debug Texture View -@export var shroud_circle_color : Color = Color(1.0, 1.0, 1.0) +@export var shroud_circle_color : Color = Color(0.25, 0.25, 0.25) @export_category("Fog Values") ## The size of a single pixel in the 3D world @@ -130,12 +130,12 @@ func _map_unit_to_new_circles_body(unit : BaseEntity) -> void: var effective_sight_range = unit.sight_range * texture_units_per_world_unit; var shroud_circle = DynamicCircle2D.instantiate() # Make a white circle 2D - shroud_circle.color = fog_circle_color # Set color + shroud_circle.color = shroud_circle_color# Set color shroud_circle.radius = effective_sight_range # Set circle size to world units and unit sight range _fog_viewport.add_child(shroud_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. var fow_circle = DynamicCircle2D.instantiate() - fow_circle.color = shroud_circle_color + fow_circle.color = fog_circle_color fow_circle.radius = effective_sight_range _fog_viewport_container.add_sibling(fow_circle) From 926d363190c184126febd511f9c925e2d0eceb90 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Wed, 7 May 2025 21:38:48 +0300 Subject: [PATCH 21/25] Disable physics processing on _vision_data == null --- addons/rts_framework/features/vision/minimap.gd | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 38afaa5..d007a0f 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -44,6 +44,7 @@ func _ready() -> void: _vision_data = vision_manager.get_vision_data() if _vision_data == null: push_error("VisionManager returned null vision data for minimap: " + self.name) + set_physics_process(false) # Disable physics processing to prevent runtime errors return # Abort further initialisation – minimap cannot function without data if not Engine.is_editor_hint(): From aa6671676c50def1289ab4e2ed1ff08c64863b64 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Thu, 8 May 2025 00:08:18 +0300 Subject: [PATCH 22/25] on adding new circle, sync circle's position --- addons/rts_framework/features/vision/minimap.gd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index d007a0f..4692d37 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -85,7 +85,10 @@ func _map_unit_to_new_circles_body(unit : BaseEntity, default_color : Color = Co minimap_circle.radius = default_radius # If doesn't have sight range, then use default draw_node_on_minimap(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. + _vision_data[unit].minimap_circle = minimap_circle # Keep map to connect unit with fog of war view + # place at the correct coordinates straight away + _vision_data[unit].sync_position(vision_manager.texture_units_per_world_unit) ## Addes draw_node(:CanvasItem) in way to draw it over other (preview) things in the minimap ## From 1e80d8176fe17af13533101cf425d9a366626796 Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Thu, 8 May 2025 00:34:04 +0300 Subject: [PATCH 23/25] changed how handles vision_manager == null --- addons/rts_framework/features/vision/minimap.gd | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 4692d37..4bd57d6 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -35,7 +35,10 @@ var fog_texture : Texture2D : # fog_texture multiply the images above. This to f @onready var _minimap_viewport: SubViewport = find_child("CombinedViewport") as SubViewport func _ready() -> void: - assert(vision_manager != null, "Minimap missing vision manager node. Minimap Node Name: " + self.name) + if vision_manager == null: + push_error("Minimap missing VisionManager – minimap will be disabled. Minimap Node Name: " + self.name) + set_physics_process(false) + return var fog_texture_result = vision_manager.get_fog_texture() if fog_texture_result: fog_texture = fog_texture_result @@ -43,7 +46,7 @@ func _ready() -> void: push_error("Failed to retrieve fog of war texture. Minimap Node Name: " + self.name) _vision_data = vision_manager.get_vision_data() if _vision_data == null: - push_error("VisionManager returned null vision data for minimap: " + self.name) + push_error("VisionManager returned null vision data. Minimap Node Name: " + self.name) set_physics_process(false) # Disable physics processing to prevent runtime errors return # Abort further initialisation – minimap cannot function without data From ede0e45a276cd1e122fbdf4b0c7dc640d4fb6feb Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Thu, 8 May 2025 01:56:12 +0300 Subject: [PATCH 24/25] when fails to draw circle on minimap delete the node --- addons/rts_framework/features/vision/minimap.gd | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index 4bd57d6..f74142c 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -87,11 +87,14 @@ func _map_unit_to_new_circles_body(unit : BaseEntity, default_color : Color = Co else: minimap_circle.radius = default_radius # If doesn't have sight range, then use default - draw_node_on_minimap(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. + var did_draw : bool = draw_node_on_minimap(minimap_circle) # Add the view circle 2D to fog of war viewport. In the fog of war viewport it create an image for the fog of war. - _vision_data[unit].minimap_circle = minimap_circle # Keep map to connect unit with fog of war view - # place at the correct coordinates straight away - _vision_data[unit].sync_position(vision_manager.texture_units_per_world_unit) + if did_draw: + _vision_data[unit].minimap_circle = minimap_circle # Keep map to connect unit with fog of war view + # place at the correct coordinates straight away + _vision_data[unit].sync_position(vision_manager.texture_units_per_world_unit) + else: + minimap_circle.queue_free() ## Addes draw_node(:CanvasItem) in way to draw it over other (preview) things in the minimap ## From eb6d81210c167fc72de0783577b928100ae2b7cf Mon Sep 17 00:00:00 2001 From: "sami.nosatzki" Date: Thu, 8 May 2025 01:57:01 +0300 Subject: [PATCH 25/25] when vision_manager is null, pause both physics and normal proccessing --- addons/rts_framework/features/vision/minimap.gd | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/rts_framework/features/vision/minimap.gd b/addons/rts_framework/features/vision/minimap.gd index f74142c..d1411f3 100644 --- a/addons/rts_framework/features/vision/minimap.gd +++ b/addons/rts_framework/features/vision/minimap.gd @@ -38,6 +38,7 @@ func _ready() -> void: if vision_manager == null: push_error("Minimap missing VisionManager – minimap will be disabled. Minimap Node Name: " + self.name) set_physics_process(false) + set_process(false) return var fog_texture_result = vision_manager.get_fog_texture() if fog_texture_result: