diff --git a/scenes/line_trail/line_trail_2d.gd b/scenes/line_trail/line_trail_2d.gd new file mode 100644 index 0000000..337c16a --- /dev/null +++ b/scenes/line_trail/line_trail_2d.gd @@ -0,0 +1,105 @@ +class_name LineTrail2D +extends Line2D + +## Leave a trail behind this node. +@export var tracking: Node2D + +## Minimum distance before adding a new point to the trail line. +## 0 = always add a new point on each frame. +@export var min_distance: float = 1. + +## Maximum length of the trail before starting to trim. +## 0 = no length limit. +@export var max_length: float = 0. + +## Maximum lifetime of the trail (in seconds) before starting to trim. +## 0 = no lifetime limit. +@export var max_lifetime: float = 3. + +# Each index represents the remaining time in seconds before each point is +# removed from the line, starting to count after the previous point is removed. +# As an example: [1, 2, 2] means that the first point will be removed in 1 +# second; the second point 2 seconds after the first (so 3 seconds from now); +# and the third point 2 seconds after the second (so 5 seconds from now). +var _points_life := PackedFloat32Array() + +func _ready() -> void: + clear_points() + +func _process(delta: float) -> void: + global_transform = Transform2D.IDENTITY + + var new_position := tracking.global_position + + # Add new points. + var maybe_exceeds_max_length := false + if _points_life.size() == 0: + _add_point(new_position) + else: + var last_point := get_point_position(_points_life.size() - 1) + var distance_sqr := (new_position - last_point).length_squared() + if distance_sqr >= min_distance * min_distance: + _add_point(new_position) + maybe_exceeds_max_length = true + + # Reduce life and remove expired points. + var remove_count := 0 + if max_lifetime != 0.: + _decrease_life(delta) + remove_count += _count_expired_points(remove_count) + + # Check if line length exceeds max length. + if maybe_exceeds_max_length and max_length != 0.: + remove_count += _count_overlength_points(remove_count) + + # Remove expired or overlength points. + if remove_count > 0: + _remove_oldest_points(remove_count) + +func _add_point(point_position: Vector2) -> void: + add_point(point_position) + + var last_point_points_life := 0. + for time in _points_life: + last_point_points_life += time + + _points_life.append(max_lifetime - last_point_points_life) + +func _remove_oldest_points(remove_count: int) -> void: + if remove_count > 0: + points = points.slice(remove_count) + _points_life = _points_life.slice(remove_count) + +func _decrease_life(delta: float, start_at := 0) -> void: + var i := start_at + while _points_life.size() > i and delta > 0.: + var sub = minf(delta, _points_life[i]) + _points_life[i] -= sub + delta -= sub + i += 1 + +func _count_expired_points(start_at := 0) -> int: + var i := start_at + while i < _points_life.size() and _points_life[i] <= 0.: + i += 1 + + return i - start_at + +func _count_overlength_points(start_at := 0) -> int: + var length := 0. + + var all_points := points + var previous_point := all_points[start_at] + for i in range(start_at + 1, all_points.size()): + var point := all_points[i] + length += (point - previous_point).length() + previous_point = point + + var overlength_count := 0 + while length > max_length and overlength_count < all_points.size() - 1: + var removed_point = all_points[overlength_count] + var next_point = all_points[overlength_count + 1] + length -= (removed_point - next_point).length() + overlength_count += 1 + + return overlength_count diff --git a/scenes/ships_fleet/fading_trail.gdshader b/scenes/ships_fleet/fading_trail.gdshader deleted file mode 100644 index a45daec..0000000 --- a/scenes/ships_fleet/fading_trail.gdshader +++ /dev/null @@ -1,12 +0,0 @@ -shader_type canvas_item; - -float rand(vec2 co){ - return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453); -} - -void fragment() { - if (rand(SCREEN_UV) > COLOR.a - abs(UV.y * 2. - 1.)) - discard; - - COLOR = vec4(1., 1., 1., COLOR.a); -} diff --git a/scenes/ships_fleet/ship.tscn b/scenes/ships_fleet/ship.tscn deleted file mode 100644 index e5b1852..0000000 --- a/scenes/ships_fleet/ship.tscn +++ /dev/null @@ -1,22 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://ctybb4niolni3"] - -[ext_resource type="Shader" path="res://scenes/ships_fleet/fading_trail.gdshader" id="1_tajfm"] - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_ys3et"] -shader = ExtResource("1_tajfm") - -[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_gcgjo"] -size = Vector2(12, 4) - -[sub_resource type="Gradient" id="Gradient_6a1ig"] -colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0) - -[node name="Ship" type="CPUParticles2D"] -material = SubResource("ShaderMaterial_ys3et") -amount = 100 -lifetime = 3.0 -lifetime_randomness = 0.3 -texture = SubResource("PlaceholderTexture2D_gcgjo") -particle_flag_align_y = true -gravity = Vector2(0, 0) -color_ramp = SubResource("Gradient_6a1ig") diff --git a/scenes/ships_fleet/ship/ship.gd b/scenes/ships_fleet/ship/ship.gd new file mode 100644 index 0000000..f35601e --- /dev/null +++ b/scenes/ships_fleet/ship/ship.gd @@ -0,0 +1,10 @@ +class_name Ship +extends Node2D + +@export var color: Color : + set(value): + color = value + _update_color(color) + +func _update_color(ship_color: Color) -> void: + %LineTrail.material.set_shader_parameter('color', ship_color) diff --git a/scenes/ships_fleet/ship/ship.png b/scenes/ships_fleet/ship/ship.png new file mode 100644 index 0000000..ca298e1 Binary files /dev/null and b/scenes/ships_fleet/ship/ship.png differ diff --git a/scenes/ships_fleet/ship/ship.png.import b/scenes/ships_fleet/ship/ship.png.import new file mode 100644 index 0000000..81e3f13 --- /dev/null +++ b/scenes/ships_fleet/ship/ship.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b37ho2wwsaku2" +path="res://.godot/imported/ship.png-078d321c402a0152c6a650c49954073a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://scenes/ships_fleet/ship/ship.png" +dest_files=["res://.godot/imported/ship.png-078d321c402a0152c6a650c49954073a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=8 +detect_3d/compress_to=1 diff --git a/scenes/ships_fleet/ship/ship.tscn b/scenes/ships_fleet/ship/ship.tscn new file mode 100644 index 0000000..a6552bc --- /dev/null +++ b/scenes/ships_fleet/ship/ship.tscn @@ -0,0 +1,31 @@ +[gd_scene load_steps=7 format=3 uid="uid://ctybb4niolni3"] + +[ext_resource type="Script" path="res://scenes/ships_fleet/ship/ship.gd" id="1_h6q7s"] +[ext_resource type="Shader" path="res://scenes/ships_fleet/ship/trail.gdshader" id="2_vgm83"] +[ext_resource type="Texture2D" uid="uid://dp0ugxgq8stt1" path="res://scenes/ships_fleet/ship/ship_trail.png" id="3_hk6vp"] +[ext_resource type="Script" path="res://scenes/line_trail/line_trail_2d.gd" id="4_wo8wd"] +[ext_resource type="Texture2D" uid="uid://b37ho2wwsaku2" path="res://scenes/ships_fleet/ship/ship.png" id="5_fxsfx"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_bt3sr"] +resource_local_to_scene = true +shader = ExtResource("2_vgm83") +shader_parameter/color = Color(1, 0, 1, 1) + +[node name="Ship" type="Node2D"] +script = ExtResource("1_h6q7s") + +[node name="LineTrail" type="Line2D" parent="." node_paths=PackedStringArray("tracking")] +unique_name_in_owner = true +material = SubResource("ShaderMaterial_bt3sr") +points = PackedVector2Array(-128, 0, 0, 0) +width = 15.0 +texture = ExtResource("3_hk6vp") +texture_mode = 2 +script = ExtResource("4_wo8wd") +tracking = NodePath("..") +max_length = 128.0 + +[node name="Sprite" type="Sprite2D" parent="."] +texture_repeat = 1 +texture = ExtResource("5_fxsfx") +offset = Vector2(1.5, 0.5) diff --git a/scenes/ships_fleet/ship/ship_trail.png b/scenes/ships_fleet/ship/ship_trail.png new file mode 100644 index 0000000..1d6dab5 Binary files /dev/null and b/scenes/ships_fleet/ship/ship_trail.png differ diff --git a/scenes/ships_fleet/ship/ship_trail.png.import b/scenes/ships_fleet/ship/ship_trail.png.import new file mode 100644 index 0000000..3e9a568 --- /dev/null +++ b/scenes/ships_fleet/ship/ship_trail.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dp0ugxgq8stt1" +path="res://.godot/imported/ship_trail.png-f2252d97e1401056e3019455c7966396.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://scenes/ships_fleet/ship/ship_trail.png" +dest_files=["res://.godot/imported/ship_trail.png-f2252d97e1401056e3019455c7966396.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/scenes/ships_fleet/ship/trail.gdshader b/scenes/ships_fleet/ship/trail.gdshader new file mode 100644 index 0000000..729ff79 --- /dev/null +++ b/scenes/ships_fleet/ship/trail.gdshader @@ -0,0 +1,8 @@ +shader_type canvas_item; +render_mode blend_add; + +uniform vec3 color: source_color = vec3(1., 0., 1.); + +void fragment() { + COLOR = vec4(COLOR.r * color + COLOR.ggg, 1.); +} diff --git a/scenes/ships_fleet/ships_fleet.gd b/scenes/ships_fleet/ships_fleet.gd index 5425887..3f1f270 100644 --- a/scenes/ships_fleet/ships_fleet.gd +++ b/scenes/ships_fleet/ships_fleet.gd @@ -1,9 +1,9 @@ extends Node2D class_name ShipsFleet -@export var departed_at: float # Time.get_ticks_msec() +@export var departed_at: int # Time.get_ticks_msec() -@export var arrives_at: float # Time.get_ticks_msec() +@export var arrives_at: int # Time.get_ticks_msec() @export var from: Vector2 @@ -14,7 +14,7 @@ class_name ShipsFleet @export var count: int : set(value): count = value - _update__instances_count() + _update_instances_count() @export var trail: Trail @@ -36,14 +36,16 @@ var _instances: Array[Node2D] = [] @export var ship_template: PackedScene -func _update__instances_count() -> void: +func _update_instances_count() -> void: var diff = count - _instances.size() for i in range(diff): var j = float(1 + _instances.size()) - var ship := ship_template.instantiate() + var ship: Ship = ship_template.instantiate() + ship.color = player.color add_child(ship) ship.position = Vector2.from_angle(j) * j * 2. + ship.look_at(to - from) _instances.push_back(ship) for i in range(-diff): @@ -59,10 +61,9 @@ func _update_position(tick: int) -> void: position = lerp(from, to, smoothstep(0., 1., progress)) if tick >= arrives_at: _arrived = true - trail.show = false + trail.show_trail = false - for ship in _instances: - ship.emitting = false + # TODO: fade out ships. await get_tree().create_timer(5.).timeout queue_free() diff --git a/scenes/ships_fleet/ships_fleet.tscn b/scenes/ships_fleet/ships_fleet.tscn index d99bda5..63879b1 100644 --- a/scenes/ships_fleet/ships_fleet.tscn +++ b/scenes/ships_fleet/ships_fleet.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://cpffyaoh8x5bp"] [ext_resource type="Script" path="res://scenes/ships_fleet/ships_fleet.gd" id="1_qfy0m"] -[ext_resource type="PackedScene" uid="uid://ctybb4niolni3" path="res://scenes/ships_fleet/ship.tscn" id="2_6eafk"] +[ext_resource type="PackedScene" uid="uid://ctybb4niolni3" path="res://scenes/ships_fleet/ship/ship.tscn" id="2_6eafk"] [node name="ShipsFleet" type="Node2D"] script = ExtResource("1_qfy0m") diff --git a/scenes/trail/trail.gd b/scenes/trail/trail.gd index 088fa80..42574ac 100644 --- a/scenes/trail/trail.gd +++ b/scenes/trail/trail.gd @@ -8,9 +8,9 @@ static var _inv_texture_width := NAN color = value _update_color(color) -@export var show: bool = true : +@export var show_trail: bool = true : set(value): - show = value + show_trail = value visible = true @export var auto_free: bool @@ -36,13 +36,13 @@ func _update_transform(start: Vector2, end: Vector2) -> void: scale = Vector2((end - start).length() * _inv_texture_width, 1.) -func _update_color(color: Color) -> void: - var c := Color(color.r, color.g, color.b, color.a * _opacity) +func _update_color(trail_color: Color) -> void: + var c := Color(trail_color.r, trail_color.g, trail_color.b, trail_color.a * _opacity) material.set_shader_parameter('color', c) func _process(delta: float) -> void: var prev_opacity := _opacity - _opacity = Utils.damp(_opacity, 1. if show else 0., 1e-4, delta) + _opacity = Utils.damp(_opacity, 1. if show_trail else 0., 1e-4, delta) if _opacity != prev_opacity: if _opacity < .01: _opacity = 0. diff --git a/scripts/ui/planets_ui.gd b/scripts/ui/planets_ui.gd index df231df..e0d92a4 100644 --- a/scripts/ui/planets_ui.gd +++ b/scripts/ui/planets_ui.gd @@ -72,8 +72,8 @@ func _on_planet_pointer_exited(planet: ControlPlanet) -> void: #region Trail func _update_trail(delta: float, snap_position: bool) -> void: - _trail.show = _dragging_from_planet and _selected_planet != null and _selected_planet.player is LocalPlayer - if _trail.show: + _trail.show_trail = _dragging_from_planet and _selected_planet != null and _selected_planet.player is LocalPlayer + if _trail.show_trail: _trail.color = _selected_planet.player.color var target_position = _last_cursor_position if _pointed_planet == null else _pointed_planet.global_position _trail.start_position = _selected_planet.global_position