xiaohongshu
xiaohongshu
godot-profile-performance
Detects performance bottlenecks in Godot projects including expensive _process functions, get_node() calls in loops, instantiations in _process, and provides optimization suggestions with Godot profiler integration
Full skill instructions
Analyzes Godot projects to detect performance bottlenecks in GDScript code. Identifies expensive operations in frame-critical functions like _process, _physics_process, and _draw. Provides actionable optimization suggestions with before/after code examples and integrates with Godot's built-in profiler for validation.
Core principle: Frame time is precious—expensive operations belong in _ready or signal handlers, not per-frame callbacks.
Use when:
_process functions contain complex logicDon't use for:
Trigger: Functions with >15 lines of code in _process or _physics_process
Detection:
# Count lines in process functions
rg "^func _process" -A 50 --glob "*.gd" | wc -l
Thresholds:
Pattern:
# ❌ BAD: get_node() in _process
func _process(delta):
get_node("UI/HealthBar").value = health # Called every frame!
get_node("Player").position = position
Detection regex:
func _process.*\n(?:.*\n)*?\s+get_node\(
Pattern:
# ❌ BAD: Creating objects every frame
func _process(delta):
var bullet = Bullet.new() # Memory churn!
add_child(bullet)
Detection keywords:
.new() in _process or _physics_process.instantiate() in frame callbacksadd_child() or remove_child() in loopsAnti-patterns:
Steps:
Interpretation:
0.1ms: Needs optimization
Indicators:
Detection:
# Check for object creation in process functions
rg "\.new\(\)|instantiate\(\)" -B 5 -A 2 --glob "*.gd" | \
rg -A 10 "func _process|func _physics_process"
Check:
Optimization targets:
Red flags:
_physics_process doing non-physics workBefore:
extends CharacterBody2D
func _process(delta):
get_node("UI/HealthBar").value = health
get_node("UI/ManaBar").value = mana
get_node("UI/LevelLabel").text = str(level)
After:
extends CharacterBody2D
@onready var health_bar = $UI/HealthBar
@onready var mana_bar = $UI/ManaBar
@onready var level_label = $UI/LevelLabel
func _process(delta):
health_bar.value = health
mana_bar.value = mana
level_label.text = str(level)
Impact: Eliminates 3 node lookups per frame (~0.01ms each)
Before:
func _process(delta):
var gravity = ProjectSettings.get("physics/2d/default_gravity")
velocity.y += gravity * delta
After:
var gravity
func _ready():
gravity = ProjectSettings.get("physics/2d/default_gravity")
func _process(delta):
velocity.y += gravity * delta
Before:
func shoot():
var bullet = BulletScene.instantiate()
bullet.position = global_position
get_parent().add_child(bullet)
After:
var bullet_pool: Array[Bullet] = []
func _ready():
# Pre-instantiate bullets
for i in range(50):
var bullet = BulletScene.instantiate()
bullet.hide()
bullet_pool.append(bullet)
get_parent().add_child(bullet)
func shoot():
for bullet in bullet_pool:
if not bullet.visible:
bullet.position = global_position
bullet.show()
bullet.activate()
return
Impact: Eliminates instantiation overhead during gameplay
Before:
func _process(delta):
# Checking every frame if health changed
if health != previous_health:
update_health_bar()
previous_health = health
After:
signal health_changed(new_health)
var health = 100:
set(value):
if health != value:
health = value
health_changed.emit(health)
func _ready():
health_changed.connect(update_health_bar)
Before:
func _process(delta):
for enemy in enemies:
if enemy.position.distance_to(player.position) < 100:
enemy.target_player()
After:
var check_timer = 0.0
const CHECK_INTERVAL = 0.1 # Check 10x per second, not 60x
func _process(delta):
check_timer += delta
if check_timer >= CHECK_INTERVAL:
check_timer = 0
update_enemy_targets()
func update_enemy_targets():
for enemy in enemies:
if enemy.position.distance_to(player.position) < 100:
enemy.target_player()
Frame Time (ms):
Function Breakdown:
_process, _physics_process, _drawMemory Monitor:
1. Establish baseline (unoptimized)
└─ Record profiler data for 60 seconds
2. Identify top 3 time consumers
└─ Sort by "Time %" in profiler
3. Apply optimization
└─ Use patterns above
4. Validate improvement
└─ Profile again, compare metrics
└─ Verify frame time reduced
5. Repeat for next bottleneck
Problem:
# ui_controller.gd
extends Control
func _process(delta):
# Called every frame - 5 node lookups!
get_node("HealthBar").value = player.health
get_node("ManaBar").value = player.mana
get_node("LevelLabel").text = "Level: " + str(player.level)
get_node("XpBar").value = player.xp
get_node("GoldLabel").text = "Gold: " + str(player.gold)
Profiler Output:
Function | Time (ms) | Time %
----------------------------------------
_process | 0.18 | 12.3%
get_node | 0.15 | 10.2% (x5)
Optimized:
# ui_controller.gd
extends Control
@onready var health_bar = $HealthBar
@onready var mana_bar = $ManaBar
@onready var level_label = $LevelLabel
@onready var xp_bar = $XpBar
@onready var gold_label = $GoldLabel
func _ready():
# Connect to player signals instead of polling
player.health_changed.connect(_on_health_changed)
player.mana_changed.connect(_on_mana_changed)
player.leveled_up.connect(_on_leveled_up)
player.xp_changed.connect(_on_xp_changed)
player.gold_changed.connect(_on_gold_changed)
func _on_health_changed(value): health_bar.value = value
func _on_mana_changed(value): mana_bar.value = value
func _on_leveled_up(level): level_label.text = "Level: " + str(level)
func _on_xp_changed(value): xp_bar.value = value
func _on_gold_changed(value): gold_label.text = "Gold: " + str(value)
Result:
Function | Time (ms) | Time %
----------------------------------------
_process | 0.00 | 0.0% (removed!)
_on_health_changed| 0.01 | 0.7% (event-driven)
Problem:
# spawner.gd
extends Node2D
func _process(delta):
if enemies.size() < max_enemies:
var enemy = EnemyScene.instantiate() # Memory churn!
enemy.position = random_position()
add_child(enemy)
enemies.append(enemy)
Memory leak: Continuous instantiation without pooling
Optimized:
# spawner.gd
extends Node2D
var spawn_timer = 0.0
const SPAWN_RATE = 2.0 # Check spawn every 2 seconds
func _process(delta):
spawn_timer += delta
if spawn_timer >= SPAWN_RATE:
spawn_timer = 0
try_spawn()
func try_spawn():
if enemies.size() < max_enemies:
spawn_enemy()
func spawn_enemy():
# Consider object pool for frequent spawns
var enemy = EnemyScene.instantiate()
enemy.position = random_position()
add_child(enemy)
enemies.append(enemy)
Additional improvement: Use object pooling for frequently spawned enemies
Problem:
# player.gd
extends CharacterBody2D
func _physics_process(delta):
# Heavy calculation every physics frame
var nearby = get_tree().get_nodes_in_group("enemies")
for enemy in nearby:
if global_position.distance_to(enemy.global_position) < detection_radius:
enemy.set_target(self)
# Do physics
velocity.y += gravity * delta
move_and_slide()
Profiler Output:
Function | Time (ms) | Time %
--------------------------------------------
_physics_process | 0.45 | 28.5%
get_nodes_in_group | 0.25 | 15.8%
distance_to | 0.12 | 7.6%
Optimized:
# player.gd
extends CharacterBody2D
var detection_timer = 0.0
const DETECTION_RATE = 0.2 # 5x per second
func _physics_process(delta):
# Separate physics from AI
velocity.y += gravity * delta
move_and_slide()
# Run detection less frequently
detection_timer += delta
if detection_timer >= DETECTION_RATE:
detection_timer = 0
update_enemy_detection()
func update_enemy_detection():
var nearby = get_tree().get_nodes_in_group("enemies")
for enemy in nearby:
if global_position.distance_to(enemy.global_position) < detection_radius:
enemy.set_target(self)
Result: Physics frame time reduced by ~60%
A performance optimization is successful when:
_process function line count <15 linesget_node() calls in _process or _physics_process.new() or .instantiate() calls in frame callbacks_ready() or @onready_physics_process contains only physics-related code| Pattern | Detection | Fix | Impact |
|---|---|---|---|
| get_node() in _process | Search: get_node after _process | Cache in @onready | ~0.01ms per call |
| .new() in _process | Search: .new() in frame functions | Use object pooling | Eliminates GC pressure |
| Heavy _process | Count lines >15 | Move to signals/timers | Reduces per-frame load |
| Physics + AI | AI in _physics_process | Separate with timer | 5-10x reduction |
| Uncached settings | ProjectSettings.get() in loop | Cache in _ready | One-time cost |
Problem: Technical debt accumulates, harder to fix later Fix: Profile early and often, fix bottlenecks as they appear
Problem: Optimizing code that isn't a bottleneck Fix: Always profile first, focus on top time consumers
Problem: Spending hours to save 0.001ms Fix: Target functions >0.1ms, ignore the rest
Problem: Assuming optimization worked without measuring Fix: Always run profiler before and after
Problem: Debug builds have different performance characteristics Fix: Profile release builds for accurate data
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience