Go, Go, Godot!
  • 0
Wave Shooter title screen

The Pause Handler: Working around Godot 4’s particle jitter bug

May 11, 2023

Godot Engine 4 has a bug (#50824) that causes particle jitter when the game is paused. It does look quite distracting.

The Bug in Action

This is a proof-of-concept wave shooter running in Godot Engine 4.0.2. Pausing the game was initially just a simple process_mode toggle. But as shown in the video clip above, there is a noticeable and quite distracting jitter for every particle effect that apparently stems from some interpolation issue.

To work around it, I wrote a small pause handler script that hides all the GPU particle effects:

class_name GGPauseHandler
extends Node

## The pause component allows you to toggle the game.
##
## While paused, it will hide particle effects to prevent visual jitter.
## The issue is present in Godot 4 (tested until 4.0.2).
##
## @tutorial(Github Issue #50824: Particle jitter on low speed scale or when the SceneTree is paused due to interpolation): https://github.com/godotengine/godot/issues/50824


signal pause_toggled(paused: bool)

## The nodes' meta data field used to keep state
const META_FIELD = "gg_pause"

## This game node will have its [member Node.process_mode] adjusted to pause the game
@export var game: Node

## The action name (in the [InputMap]) for pausing the game.
@export var pause_action_name: String = "pause"

## Hides/unhides particles when toggling to prevent jitter
@export var hide_particles: bool = true


func _ready():
	assert(game is Node, "Must specify the node that will be paused")
	assert(InputMap.has_action(pause_action_name), "Please ensure the action '%s' is configured (Project Settings..., Input Map)" % pause_action_name)


## Pragmatic way to listen to [InputEvent]s and check whether the pause key/button was pressed
func _input(event: InputEvent):
	if event is InputEventKey and event.is_action_pressed(pause_action_name):
		toggle_pause()


## Toggle pause
func toggle_pause():
	if game.process_mode == PROCESS_MODE_INHERIT:
		if hide_particles:
			_hide_particles()
		pause_toggled.emit(true)
		game.process_mode = PROCESS_MODE_DISABLED
	else:
		if hide_particles:
			_show_particles()
		pause_toggled.emit(false)
		game.process_mode = Node.PROCESS_MODE_INHERIT


## Find and hide all GPUParticle2D effects
func _hide_particles():
	for node in get_tree().root.find_children("*", "GPUParticles2D", true, false):
		node.set_meta(META_FIELD, node.visible)
		node.visible = false


## Restore visibility of all previously hidden GPUParticle2D effects
func _show_particles():
	for node in get_tree().root.find_children("*", "GPUParticles2D", true, false):
		if node.has_meta(META_FIELD):
			node.visible = node.get_meta(META_FIELD)
			node.remove_meta(META_FIELD)

Now when the game is paused, the jitter is hidden away from the player, making the experience much more pleasant. Once the bug is fixed, it’s easy to disable or remove the hiding logic. The result looks pretty good.

The pause_toggled signal allows other nodes to react to pausing as well, which I’m using to show/hide the UI accordingly.

The Workaround Applied

I’m only writing the code here. The assets used are:

  • Kenney’s Space Shooter Redux, Space Shooter Extension, and Sci-fi Sounds.
  • Music is Alexi Action – 80s Synth Wave via Pixabay.
  • Background shader: Starfield.

The ship controls and wave transitions are loosely inspired by Galactix, a game released in 1993 (and set in the far-away future of 2019).

Galactix – 90s wave shooter

developer experiencegodotprogramming
Posted in DX, Godot.
Share
PreviousPixabay’s New Design is a step down for UX
NextIntroducing GodotBuilder: Custom Export Templates built on demand

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related Posts

  • July 17, 2023

    Terrain3D for Godot has been released

    The Terrain3D addon for Godot lets you create and manage 3D terrains within Godot. It looks quite promising for making landscapes, hills, valleys, and other natural environments. The addon provides tools for sculpting the terrain, and you can paint different textures like grass, dirt, or rock, and blend them smoothly. It also supports features like …

  • December 2, 2024

    Inventory System v1.18.1 available (and v2 progress update)

    I’m wrapping up development on version 1 of the Inventory System, which is currently at v1.18.1. All core functionality is in place, and it provides many quality-of-life features. The guide covers and walks through most of the code base, and the demo projects show off a lot of use cases. This first version has been …

  • December 23, 2023

    godot-matcha: Free multiplayer without a server

    Godot-matcha is an addon that lets you use WebRTC for multiplayer games by handling matchmaking using WebTorrent trackers. Conceptually it’s quite an interesting, novel approach. WebTorrent uses a modified BitTorrent protocol that allows it to work with WebSockets. A WebTorrent tracker is essentially a directory service that keeps track of torrents offered by users. A …

  • March 11, 2025

    Update all resources after modifying a resource class

    Godot’s resources are quite powerful. However, modifying a resource class doesn’t automatically update any corresponding .tres files, unless you happen to edit a scene that uses that resource in some way. This doesn’t impact runtime behavior — the game still runs as expected. But it can impact version control and result in a messier diff …

    © 2025 GoGoGodot.io. All rights reserved.