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
|
||||
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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue