mirror of
https://gitlab.com/open-fpsz/open-fpsz.git
synced 2026-07-12 06:55:18 +00:00
96 lines
3.3 KiB
GDScript
96 lines
3.3 KiB
GDScript
# This file is part of open-fpsz.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
class_name Trail3D extends MeshInstance3D
|
|
|
|
@export var _trail_enabled : bool = true
|
|
|
|
@export var _start_width : float = 0.5
|
|
@export var _end_width : float = 0.0
|
|
|
|
@export_range(0.5, 1.5) var _scaling_acceleration : float = 0.5
|
|
|
|
@export var _motion_delta : float = 0.1 # Smoothness of trail
|
|
@export var _lifespan : float = 1.0 # Duration of trail
|
|
|
|
@export var _start_color : Color = Color(1.0, 1.0, 1.0, 1.0) # Start color
|
|
@export var _end_color : Color = Color(1.0, 1.0, 1.0, 1.0) # End color
|
|
|
|
var _previous_position : Vector3
|
|
var _points : Array
|
|
|
|
class PointData:
|
|
var position : Vector3
|
|
var width_0 : Vector3
|
|
var width_1 : Vector3
|
|
var lifespan : float = 0.0
|
|
|
|
func _append_point() -> void:
|
|
var point_data : PointData = PointData.new()
|
|
point_data.position = global_position
|
|
point_data.width_0 = global_basis.x * _start_width
|
|
point_data.width_1 = global_basis.x * _start_width - global_basis.x * _end_width
|
|
|
|
_points.append(point_data)
|
|
|
|
func _ready() -> void:
|
|
_previous_position = global_position
|
|
mesh = ImmediateMesh.new()
|
|
|
|
func _process(delta : float) -> void:
|
|
if(_previous_position - global_position).length() > _motion_delta and _trail_enabled:
|
|
_append_point()
|
|
_previous_position = global_position
|
|
|
|
_update_lifespans(delta)
|
|
_render_trail()
|
|
|
|
# Update all lifespans and use a mark-and-sweep algorithm to remove "expired" points
|
|
func _update_lifespans(delta : float) -> void:
|
|
var points_to_remove : Array = []
|
|
for point_data : PointData in _points:
|
|
point_data.lifespan += delta
|
|
if point_data.lifespan > _lifespan:
|
|
points_to_remove.append(point_data)
|
|
|
|
for point_data : PointData in points_to_remove:
|
|
_points.erase(point_data)
|
|
|
|
func _render_trail() -> void:
|
|
mesh.clear_surfaces()
|
|
|
|
var number_of_points : int = _points.size()
|
|
if number_of_points < 2:
|
|
return
|
|
|
|
# Render new mesh for each point, triangle strips draw 2 triangles each 4 points
|
|
# which is perfect for a trail
|
|
mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
|
|
|
|
for point_index in range(number_of_points):
|
|
var point_data : PointData = _points[point_index]
|
|
var t : float = float(point_index) / (number_of_points - 1.0)
|
|
var current_color : Color = _start_color.lerp(_end_color, 1 - t)
|
|
mesh.surface_set_color(current_color)
|
|
|
|
var current_width : Vector3 = point_data.width_0 - pow(1 - t, _scaling_acceleration) * point_data.width_1
|
|
|
|
var t0 : float = float(point_index) / float(number_of_points)
|
|
var t1 : float = t
|
|
|
|
mesh.surface_set_uv(Vector2(t0, 0))
|
|
mesh.surface_add_vertex(to_local(point_data.position + current_width))
|
|
mesh.surface_set_uv(Vector2(t1, 1))
|
|
mesh.surface_add_vertex(to_local(point_data.position - current_width))
|
|
mesh.surface_end()
|