Godot Signals

by Aendawyn

10

banner

ci
Discord Shield

A powerful signal system for Godot Engine that provides efficient signal handling with support for filtering, mapping, centralized event management, and high-performance signal processing.

๐Ÿ›ฃ๏ธ Roadmap

Here are some planned features and improvements:

  • ๐Ÿ”„ Broker Binding: Possibility to bind to the broker and receive a GSignal instance
  • โšก Extended Operations: Add more operations to GSignal such as debounce, merge, and more
  • ๐Ÿ” Suggest a feature by opening an issue on GitHub!

โœจ Features

  • ๐Ÿ”„ Signal Processing: Create signal processing chains with filter and map operations
  • ๐Ÿ“ก Signal Broker: Connect signals across your game without direct object references
  • โšก Smart Connection Types: Automatically optimizes for high or low frequency signals
  • ๐Ÿ” Pattern Matching: Subscribe to signals using wildcard patterns
  • ๐Ÿท๏ธ Alias System: Identify objects by name, groups, or custom aliases
  • ๐Ÿš€ Optimized Performance: Reduced overhead and minimal allocations for efficient processing

๐Ÿš€ Quick Start

๐Ÿ”„ Signal Processing

Create powerful signal processing chains with just a few lines of code:

# Filter, transform, and react to signals
GSignals.from(damage_signal)
    .filter(func(amount: int) -> bool: return amount >= 10)
    .map(func(amount: int) -> int: return amount * critical_multiplier)
    .bind(func(final_damage: int): apply_damage(final_damage))

๐Ÿ“ก Signal Broker

Connect components without direct references:

# Broadcasting side: Register player node's signals with the broker
GBroker.broadcast_signals_of(player_node, "player")

# Listening side: Subscribe to player damage events anywhere in your code
GBroker.subscribe("player:damage_taken", func(amount): update_health_ui(amount))

๐Ÿ“ฅ Installation

  1. Download or clone this repository
  2. Copy the addons/godot-signals folder into your project's addons directory
  3. Enable the plugin in Project Settings > Plugins

๐Ÿ“– Tutorial

๐Ÿ”„ Signal Processing

๐Ÿ”Œ Basic Signal Connection

# Connect to a signal with a simple callback
GSignals.from(player.health_changed)
    .bind(func(new_health): update_health_bar(new_health))

๐Ÿ” Filtering Signals

# Only process signals where the value meets certain criteria
GSignals.from(enemy.attack)
    .filter(func(damage: int) -> bool: return damage > 5)
    .bind(func(damage): play_heavy_hit_sound())

๐Ÿ”„ Transforming Signals

# Transform signal data before processing
GSignals.from(position_changed)
    .map(func(pos: Vector2) -> float: return pos.distance_to(Vector2.ZERO))
    .bind(func(distance: float): set_volume(100 - distance))

โฑ๏ธ Delaying Signals

# Delay signal processing by a specific time
GSignals.from(damage_taken)
    .delay(0.5)  # Delay by 0.5 seconds
    .bind(func(amount): play_delayed_damage_effect(amount))

๐Ÿ›‘ Debouncing Signals

# Debounce rapid signal emissions
GSignals.from(mouse_moved)
    .debounce(0.1)  # Only process after 0.1s of inactivity
    .bind(func(position): update_hover_effect(position))

๐ŸŽ›๏ธ Connection Management

# Store and manage connections
var connection = GSignals.from(timer.timeout).bind(func(): spawn_enemy())

# Temporarily disable connection
connection.stop()

# Re-enable connection
connection.start()

๐Ÿ“ก Signal Broker

๐Ÿ“ฃ Broadcasting Signals

# Register an object's signals with the broker
GBroker.broadcast_signals_of(
    player,                   # The object whose signals will be broadcasted
    "player",                 # Alias for identifying the object (optional)
    GBroker.GBrokerBroadcastFlags.SCRIPT_ONLY  # Which signals to broadcast
)

๐Ÿท๏ธ Setting Multiple Aliases

# Register with multiple aliases for more flexible subscription patterns
GBroker.broadcast_signals_of(
    boss_entity,
    ["boss", "enemy", "entity"]
)

๐Ÿ‘‚ Subscribing to Signals

# Subscribe to specific signals
GBroker.subscribe("player:health_changed", func(new_health): update_health_ui(new_health))

# Use wildcard patterns to subscribe to multiple signals
GBroker.subscribe("player:*", func(emitter, signal_name, args): print("Player signal: ", signal_name))
GBroker.subscribe("*:damage_taken", func(damage): update_global_damage_counter(damage))

๐Ÿงน Cleanup

# Clear all subscriptions and signal handlers when switching scenes
func _exit_tree():
    GBroker.reset()

๐Ÿ”ฌ Advanced Broker Usage

๐Ÿ“Š Callback Arguments Handling

The broker intelligently handles callback arguments depending on how many parameters your callback function accepts:

# Just receive the signal arguments (most common)
GBroker.subscribe("player:health_changed", func(health_amount): update_ui(health_amount))

# Receive emitter object, signal name, and arguments
GBroker.subscribe("player:*", func(emitter, signal_name, args):
    print("Signal %s from %s with args %s" % [signal_name, emitter.name, args])
)

# Mixed patterns with different argument counts
GBroker.subscribe("enemy:hit", func(damage, hit_position):
    spawn_particle(hit_position)
    apply_damage(damage)
)

# Missing arguments are filled with null
GBroker.subscribe("*:*", func(emitter, signal_name, arg1, arg2, arg3):
    # arg2 and arg3 will be null if the signal emits less than 3 arguments
    print("%s emitted %s with up to 3 args: %s, %s, %s" % [
        emitter.name, signal_name, arg1, arg2, arg3
    ])
)
๐Ÿ“ Notes on argument handling:
  • If the callback has fewer parameters than the signal provides, extra signal arguments are ignored
  • If the callback has more parameters than the signal provides, extra callback parameters receive null
  • The first callback parameter can receive the emitter object if an extra parameter is available
  • The second parameter can receive the signal name if additional parameters are available
  • Subsequent parameters receive the signal arguments

๐Ÿ”ง Advanced Features

โšก Custom Signal Frequency Optimization

# Optimize for high-frequency signals (e.g., position updates)
GSignals.from(position_changed, GSignals.GSignalsBindFlags.HIGH_FREQUENCY_HINT)

๐Ÿค– Automatic Alias Detection

When no alias is provided, the broker automatically uses:

  • ๐Ÿ‘ฅ The node's groups (except internal groups)
  • ๐Ÿ“› The node's name
  • ๐Ÿ”ค Snake case version of the node's name
# For a node named "PlayerCharacter" in group "characters"
GBroker.broadcast_signals_of(player_node)
# This will automatically register with aliases:
# - "characters" (from group)
# - "PlayerCharacter" (from name)
# - "player_character" (snake case conversion)

โš™๏ธ Performance Considerations

  • ๐Ÿ”— Chain operations carefully as each adds processing overhead
  • ๐ŸŽ๏ธ Use the HIGH_FREQUENCY_HINT flag for signals that emit multiple times per frame
  • ๐Ÿง  The pattern matching system uses caching to optimize frequent signal matches
  • ๐Ÿ”Œ Direct signal connections with GSignals are more efficient than broker subscriptions when you have direct references

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Version

0.1.0

Engine

4.4

Category

Scripts

Download

Version0.1.0
Download Now

Support

If you need help or have questions about this plugin, please contact the author.

Contact Author