Improve trails
This commit is contained in:
parent
fd16f3b9fc
commit
94994177bf
14 changed files with 239 additions and 50 deletions
105
scenes/line_trail/line_trail_2d.gd
Normal file
105
scenes/line_trail/line_trail_2d.gd
Normal file
|
@ -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
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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")
|
|
10
scenes/ships_fleet/ship/ship.gd
Normal file
10
scenes/ships_fleet/ship/ship.gd
Normal file
|
@ -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)
|
BIN
scenes/ships_fleet/ship/ship.png
Normal file
BIN
scenes/ships_fleet/ship/ship.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 B |
34
scenes/ships_fleet/ship/ship.png.import
Normal file
34
scenes/ships_fleet/ship/ship.png.import
Normal file
|
@ -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
|
31
scenes/ships_fleet/ship/ship.tscn
Normal file
31
scenes/ships_fleet/ship/ship.tscn
Normal file
|
@ -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)
|
BIN
scenes/ships_fleet/ship/ship_trail.png
Normal file
BIN
scenes/ships_fleet/ship/ship_trail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
34
scenes/ships_fleet/ship/ship_trail.png.import
Normal file
34
scenes/ships_fleet/ship/ship_trail.png.import
Normal file
|
@ -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
|
8
scenes/ships_fleet/ship/trail.gdshader
Normal file
8
scenes/ships_fleet/ship/trail.gdshader
Normal file
|
@ -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.);
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
extends Node2D
|
extends Node2D
|
||||||
class_name ShipsFleet
|
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
|
@export var from: Vector2
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class_name ShipsFleet
|
||||||
@export var count: int :
|
@export var count: int :
|
||||||
set(value):
|
set(value):
|
||||||
count = value
|
count = value
|
||||||
_update__instances_count()
|
_update_instances_count()
|
||||||
|
|
||||||
@export var trail: Trail
|
@export var trail: Trail
|
||||||
|
|
||||||
|
@ -36,14 +36,16 @@ var _instances: Array[Node2D] = []
|
||||||
|
|
||||||
@export var ship_template: PackedScene
|
@export var ship_template: PackedScene
|
||||||
|
|
||||||
func _update__instances_count() -> void:
|
func _update_instances_count() -> void:
|
||||||
var diff = count - _instances.size()
|
var diff = count - _instances.size()
|
||||||
|
|
||||||
for i in range(diff):
|
for i in range(diff):
|
||||||
var j = float(1 + _instances.size())
|
var j = float(1 + _instances.size())
|
||||||
var ship := ship_template.instantiate()
|
var ship: Ship = ship_template.instantiate()
|
||||||
|
ship.color = player.color
|
||||||
add_child(ship)
|
add_child(ship)
|
||||||
ship.position = Vector2.from_angle(j) * j * 2.
|
ship.position = Vector2.from_angle(j) * j * 2.
|
||||||
|
ship.look_at(to - from)
|
||||||
_instances.push_back(ship)
|
_instances.push_back(ship)
|
||||||
|
|
||||||
for i in range(-diff):
|
for i in range(-diff):
|
||||||
|
@ -59,10 +61,9 @@ func _update_position(tick: int) -> void:
|
||||||
position = lerp(from, to, smoothstep(0., 1., progress))
|
position = lerp(from, to, smoothstep(0., 1., progress))
|
||||||
if tick >= arrives_at:
|
if tick >= arrives_at:
|
||||||
_arrived = true
|
_arrived = true
|
||||||
trail.show = false
|
trail.show_trail = false
|
||||||
|
|
||||||
for ship in _instances:
|
# TODO: fade out ships.
|
||||||
ship.emitting = false
|
|
||||||
|
|
||||||
await get_tree().create_timer(5.).timeout
|
await get_tree().create_timer(5.).timeout
|
||||||
queue_free()
|
queue_free()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://cpffyaoh8x5bp"]
|
[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="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"]
|
[node name="ShipsFleet" type="Node2D"]
|
||||||
script = ExtResource("1_qfy0m")
|
script = ExtResource("1_qfy0m")
|
||||||
|
|
|
@ -8,9 +8,9 @@ static var _inv_texture_width := NAN
|
||||||
color = value
|
color = value
|
||||||
_update_color(color)
|
_update_color(color)
|
||||||
|
|
||||||
@export var show: bool = true :
|
@export var show_trail: bool = true :
|
||||||
set(value):
|
set(value):
|
||||||
show = value
|
show_trail = value
|
||||||
visible = true
|
visible = true
|
||||||
|
|
||||||
@export var auto_free: bool
|
@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.)
|
scale = Vector2((end - start).length() * _inv_texture_width, 1.)
|
||||||
|
|
||||||
func _update_color(color: Color) -> void:
|
func _update_color(trail_color: Color) -> void:
|
||||||
var c := Color(color.r, color.g, color.b, color.a * _opacity)
|
var c := Color(trail_color.r, trail_color.g, trail_color.b, trail_color.a * _opacity)
|
||||||
material.set_shader_parameter('color', c)
|
material.set_shader_parameter('color', c)
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
var prev_opacity := _opacity
|
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 != prev_opacity:
|
||||||
if _opacity < .01:
|
if _opacity < .01:
|
||||||
_opacity = 0.
|
_opacity = 0.
|
||||||
|
|
|
@ -72,8 +72,8 @@ func _on_planet_pointer_exited(planet: ControlPlanet) -> void:
|
||||||
#region Trail
|
#region Trail
|
||||||
|
|
||||||
func _update_trail(delta: float, snap_position: bool) -> void:
|
func _update_trail(delta: float, snap_position: bool) -> void:
|
||||||
_trail.show = _dragging_from_planet and _selected_planet != null and _selected_planet.player is LocalPlayer
|
_trail.show_trail = _dragging_from_planet and _selected_planet != null and _selected_planet.player is LocalPlayer
|
||||||
if _trail.show:
|
if _trail.show_trail:
|
||||||
_trail.color = _selected_planet.player.color
|
_trail.color = _selected_planet.player.color
|
||||||
var target_position = _last_cursor_position if _pointed_planet == null else _pointed_planet.global_position
|
var target_position = _last_cursor_position if _pointed_planet == null else _pointed_planet.global_position
|
||||||
_trail.start_position = _selected_planet.global_position
|
_trail.start_position = _selected_planet.global_position
|
||||||
|
|
Loading…
Reference in a new issue