• 2D
  • Rotate particles once on creation?

Hi, I asked this question over in the Godot community but apparently nobody knew a solution. Maybe anyone here can help? I'm trying to create a speed effect with "after-images" of the player. I'd like to use particles for this. The player is a 2D sprite, top-down view, and obviously rotates while moving. So each emitted particle should have the same rotation as the player. However, I can't seem to be able to do that. The particles are set to NOT use local coordinates (they're supposed to be left behind by the player like footsteps, basically). I tried manipulating the "angle" property of the process material, but that rotates ALL particles currently on the screen created by that emitter. I tried rotating the Particle2D node itself, but that doesn't do anything.

This is the effect I'm trying to create:

Does anyone have an idea how to do this (preferably in Godot Script).

Welcome to the forums @Irolan!

Maybe you could handle this through a particle shader? I don't have too much experience with it myself, but I think you may be able to pass the positions to each of the particles using the CUSTOM transform.

This tutorial in the documentation is for 3D, but it covers how to pass data to the CUSTOM transform, which may be helpful. Then, I think what you can do is just pass the positions you want for each of the particles in code, and then have the shader position the particles accordingly. Again though, I'm not totally positive this will work, but it's what I would look into :smile:

If you only need a few dozen sprites at most, using separate Sprite nodes modulated via code is probably fine performance-wise. Godot 3.3 and later features 2D batching in both the GLES3 and GLES2 backends, so rendering lots of sprites is fast.

If the CPU overhead turns out to be too high, you could use low-level servers instead of nodes. But first, I'd try to use Sprite nodes. You could even try out using instanced scenes, each with their own AnimationPlayer to fade out the after images.

@TwistedTwigleg said: Maybe you could handle this through a particle shader? I don't have too much experience with it myself, but I think you may be able to pass the positions to each of the particles using the CUSTOM transform.

It may be because I'm too new to Godot and haven't even touched shaders yet (I didn't really want to do anything that apparently complex for my first project, just sprites) but I don't even see how that would apply to my issue.

@Calinou said: If you only need a few dozen sprites at most, using separate Sprite nodes modulated via code is probably fine performance-wise. Godot 3.3 and later features 2D batching in both the GLES3 and GLES2 backends, so rendering lots of sprites is fast.

If the CPU overhead turns out to be too high, you could use low-level servers instead of nodes. But first, I'd try to use Sprite nodes. You could even try out using instanced scenes, each with their own AnimationPlayer to fade out the after images.

I thought about doing it this way, but somehow it doesn't feel right. It's like particles are destined for this but I need to resort to a very unelegant way just because I can't figure out how to do it properly.

Okay, so I gave up on the particle thing. It kinda felt like every idea I had (from rotating sprites to swapping sprites on the fly), the devs had forseen and actively prevented it. Godot does have a couple of strange decisions in there, this just seems to be one of them. I decided to create a trail effect using the Line2D node instead. It's not exactly the look I wanted, but it's a helluva lot better than creating a trail out of a couple dozen sprites. It might be feasible to do that but I just don't like the idea. Thanks for your suggestions everyone. Here's hoping that they'll add some more flexibility to particles in future versions.

Shame you couldn't get it to work how you originally intended, but I'm glad you still got an effect that looks good using a Line2D node! From what I remember reading, particles in Godot 4.0 are getting a lot easier to use and control, so fingers crossed that it makes effects easier to control.

@TwistedTwigleg said: Shame you couldn't get it to work how you originally intended, but I'm glad you still got an effect that looks good using a Line2D node! From what I remember reading, particles in Godot 4.0 are getting a lot easier to use and control, so fingers crossed that it makes effects easier to control.

Good to know. Looking forward to that then.

@TwistedLeg Okay, I got it. Your suggestion about shader and CUSTOM was right. Someone over at the Godot community explained how to do it. In case anyone has the same issue and stumbles across this thread, here's how to do it:

  1. Convert the process material to a shader material. (Click on the arrow next to "ParticlesMaterial and choose "Convert to Shader Materiual)

  2. Click on the textfile symbol next to "Shader", modify the following: uniform float initial_linear_velocity; uniform float emission_angle; // <<<<<<<<< Add this uniform float initial_angle;

  3. Inside the vertex function, somewhere below if (RESTART || restart) {, change the assignment of CUSTOM.x from base_angle degree_to_rad to (base_angle + emission_angle) degree_to_rad

  4. In the else bracket following the previous if, find where it says CUSTOM.x = base_angle degree_to_rad; and change it to CUSTOM.x += base_angle degree_to_rad;

After the changes are done, you can send the shader an angle parameter by calling $Particles2D.process_material.set_shader_param("emission_angle", your_angle_in_degrees) I used -global_rotation_degrees here, note I had to make it negative because it was rotating the other way.

Quite a lot of effort to do this, but it taught me how to use the Line2D node to create trails, which I'm certainly going to use. Also figured out how to edit the shader to make it fade over time:

  1. Add another variable: uniform float alpha_fade; 2: Find the line that says: COLOR = (hue_rot_mat color_value; and change it to COLOR = (hue_rot_mat color_value) - vec4(0, 0, 0, CUSTOM.y * alpha_fade); Took me a while to figure out that the variables CUSTOM.x, CUSTOM.y and CUSTOM.z do NOT refer to x-, y-, z-axis. CUSTOM.y is the particle's age.