Best approach to animating star trails?

Godot Version

v4.1.2.stable.official [399c9dc39]

Question

First of all hello guys.
I am in a process of learning Godot and I was following one tutorial (several to be frank) in making Asteroid shooter. I have made it and now I am looking for a way to enhancing bit the game (and learning new things).

I published the game on itch.io, you can have a look at it to better understand what I mean. (Space Shooter by HamziBeg's Wonder Shack***)

So, after reaching score 60, level should change with fade-out/fade-in transition screen and star trails (like warp speed). I used particles for that, but it is not supported in the browser. So I am looking for the way to animate it via script (tweens) or animation player.

I failed at both.

Tweens - once I instantiate the “trail” scene (which is SVG element, that I can scale on X/Y) I tried to tween the scale.y to make them elongate from certain point, and I would later move them on Y axis ( in the _process()) to appear like it is passing by. But when I try to tween instantiated element I always got an error when used tween (type mismatch NIL to float or something like that). I checked the game on runtime, elements do get spawned, I can inspect them in the error output, I see their properties. But I can’t figure out why it does not work. So I tried to…

AnimationPlayer - in the scene of the “trail” I animated scale and Y position so it appears like star trail… bet when I instantiate the scene everything is sped up. In the loop that instantiates “trail” scenes, I used pause function to slow the instantiate loop so I can see what is going on…

Please help. I am attaching project files related to this issue so you can look in to the code.

*** NOTE: I know game lags on the start because of the shaders. I fixed it by precalculating shaders, I will upload it once I update this issue with star trails.

Project files (related to this issue):
code_example.zip

Example of transition (with particles):
godot4_animation-example

It’s weird that particles don’t work for you, CPUParticles2D should work on all platforms.
Anyway, wanted to try achieve this effect in pure GDScript with elongating trails and dynamic opacity, so here my code:

extends Node2D
@onready var screen_size : Vector2 = get_viewport_rect().size
const SCR_MARGIN = 32 #how far away from screen borders to generate stars on x-axis
const STAR_COUNT = 64
const STAR_TRAIL = 300 #lenght of trail will be multiplied by star_pos.z
const MAX_SPEED : float = 1600.0
var offscreen_y : float #value for checking if star is offscreen on y axis, needs to be recalculated if viewport size changes
var star_pos : PackedVector3Array #array of stars position and speed modifier "z" value
var current_speed : float = 0.0
var delta_accumulator : float = 0.0
const ACCELERATION_TIME : float = 2.0 #time for full acceleration/deceleration in seconds
var speed_ease : float #calculated eased speed modifier
var acceleration_state : float = 1.0 #1.0 accelerating, -1.0 decelerating

func _ready() -> void:
	star_pos.resize(STAR_COUNT)
	offscreen_y = screen_size.y + (STAR_TRAIL * 1.5) #1.5 must be equal or more than max value of star_pos.z
	stars_init()

func _process(delta: float) -> void:
	if Input.is_action_just_pressed("ui_accept"): acceleration_toggle()
	if Input.is_action_just_pressed("ui_cancel"): stars_init()
	delta_accumulator += (delta * acceleration_state)
	speed_ease = ease((delta_accumulator / ACCELERATION_TIME), 2.4) #2.4 feels like best fit
	current_speed = MAX_SPEED * speed_ease
	if !current_speed: return #no need to calculate positions if speed is zero
	for i in star_pos.size():
		var pos_y = star_pos[i].y + (current_speed * star_pos[i].z) * delta
		if pos_y > offscreen_y:
			star_pos[i].y -= offscreen_y
			star_pos[i].x = randf_range(SCR_MARGIN, screen_size.x -SCR_MARGIN)
		else: star_pos[i].y = pos_y
		queue_redraw()

func _draw() -> void:
	if !current_speed: return # no need to draw if speed is zero
	for i in star_pos.size():
		var pos_start = Vector2(star_pos[i].x, star_pos[i].y)
		var pos_end = Vector2(star_pos[i].x, star_pos[i].y - STAR_TRAIL*(speed_ease*star_pos[i].z))
		draw_line( pos_start, pos_end, Color(1.0,1.0,1.0,current_speed/MAX_SPEED), 1.0, false) #antialiasing disabled for performance

func stars_init():
	delta_accumulator = 0.0
	current_speed = 0.0
	acceleration_state = 1.0
	for i in star_pos.size():
		star_pos[i].x = randf_range(SCR_MARGIN, screen_size.x -SCR_MARGIN)
		star_pos[i].y = randf_range(screen_size.y * -1.0, 0.0)
		star_pos[i].z = randf_range(0.5, 1.5)
		
func acceleration_toggle() -> void:
	if delta_accumulator > ACCELERATION_TIME: delta_accumulator = ACCELERATION_TIME
	elif delta_accumulator < 0.0: delta_accumulator = 0.0
	acceleration_state *= -1.0

Controls with default input layout:
ENTER - accelerate/decelerate
ESCAPE- reinitialize stars position

1 Like

Particles do work for Ä‘e (GPU and CPU) but this trails effect does not work on web platform. And it caused the game to freeze for a moment when transition is about to happen.

This effect os just one toggle in the particles.

Thank you. I was on a trip and away from this project. I will try it and come back with a feedback or more questions :grin:

Thank you a lot :heart: :heart: :heart:

It worked like a charm. I added a timer to activate acceleration_toggle() function, and it perfectly fit in to my project.

Your code is elegant, done by the hand of the wizard :magic_wand:

Link to updated version of the game:

Devlog:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.