Performance in Godot – Complete Guide

In the evolving landscape of game development, staying on top of performance is crucial to delivering a smooth and engaging player experience. In this tutorial, we delve into the vital yet often overlooked aspect of game design: performance monitoring with Godot 4’s Performance class. Aimed at providing developers with actionable insights into their game’s operational metrics, this class is a powerful tool for optimizing games to run seamlessly across various devices. So, grab your coding hat, and let’s dive into the world of performance metrics in Godot 4!

What Is The Performance Class in Godot 4?

The Performance class in Godot 4 is your control room for monitoring game performance. By granting access to a suite of monitors, this class arms developers with detailed information regarding different performance aspects of a game such as FPS, memory usage, draw calls, and much more. It’s akin to having a dashboard that continuously updates you with the health metrics of your game’s engine – ensuring that you’re always informed about how well your game is running under the hood.

What Is It For?

Within the Performance class, a wealth of data awaits to reveal the impact of your code on the game’s behaviour. By tapping into monitors that report on memory consumption, object count, physics frame times, and more, you can perform targeted optimizations. For instance, if you recognize that your game is using more memory than anticipated, you could investigate and refine your asset management strategies to correct the course.

Why Should I Learn It?

Grasping the intricacies of the Performance class is pivotal for any game developer. Not only does it empower you to fine-tune your games, leading to better player experiences, but it also opens your eyes to the often non-obvious performance pitfalls that can make or break a game. When a game runs well, it’s a testament to both engrossing content and technical finesse – and learning to master the Performance class can get you there. Whether you’re just beginning your creative journey or looking to refine your skills, understanding the Performance class is a step towards becoming a more proficient and capable Godot developer.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Accessing Performance Metrics

To start utilizing the Performance class effectively, you need to know how to access the various metrics it provides. Here’s how you can do just that in Godot 4, along with explanations for what each metric represents.

Querying FPS:
One of the most common metrics you’ll check is the Frames Per Second (FPS). Here’s how to get the current FPS:

var current_fps = Performance.get_monitor(Performance.TIME_FPS)
print("Current FPS: " + str(current_fps))

This metric is crucial for ensuring your game runs smoothly, typically aiming for a stable 60 FPS for a fluid experience.

Memory Usage:
Understanding how your game consumes memory can help prevent crashes and slowdowns. To see the total memory used:

var memory_used = Performance.get_monitor(Performance.MEMORY_STATIC)
print("Memory Used: " + str(memory_used) + " bytes")

You might want to regularly log this during a play session to spot memory spikes.

Draw Calls:
Draw calls are a measure of how many rendering actions are happening per frame. Too many can slow down your game significantly:

var draw_calls = Performance.get_monitor(Performance.RENDER_DRAW_CALLS)
print("Draw Calls: " + str(draw_calls))

Optimizing draw calls usually involves merging objects or reducing the complexity of your scenes.

Performance in Real-World Scenarios

Let’s explore how you can apply this knowledge to analyze and optimize a running game. Here are some practical examples illustrating how to use the Performance class during different stages of your game.

Detecting Performance Bottlenecks:
You can log out performance metrics after a heavy in-game event to detect bottlenecks.

func _heavy_event_finished():
    var fps_after_event = Performance.get_monitor(Performance.TIME_FPS)
    print("FPS after event: " + str(fps_after_event))

If the FPS drops significantly, it’s time to look closer at what occurred during the event.

Monitoring Physics Performance:
To ensure that your physics calculations aren’t taking too long, check the physics frame time:

var physics_frame_time = Performance.get_monitor(Performance.PHYSICS_FRAME_TIME)
print("Physics frame time: " + str(physics_frame_time) + " seconds")

High physics frame times might indicate a need to simplify collision shapes or physics interactions.

Object Count:
Keeping track of how many objects are in your scene at any time can help identify if a leak or overload is occurring.

var object_count = Performance.get_monitor(Performance.OBJECT_COUNT)
print("Object count: " + str(object_count))

A sudden increase in object count could suggest that objects aren’t being freed properly.

Using Monitors to Profile Your Game:
You can create a simple profiler to regularly output various performance metrics, giving you an ongoing overview.

func _process(delta):
    # Every second, print out important performance metrics
    if Engine.get_frames_drawn() % 60 == 0:
        print("FPS: " + str(Performance.get_monitor(Performance.TIME_FPS)))
        print("Memory Used: " + str(Performance.get_monitor(Performance.MEMORY_STATIC)) + " bytes")
        print("Draw Calls: " + str(Performance.get_monitor(Performance.RENDER_DRAW_CALLS)))

With a profiler like this, you’ll be able to watch how performance fluctuates in real-time as different events and actions occur within your game.Understanding the importance of optimization, let’s delve deeper with practical examples utilizing Godot 4’s Performance class features. These examples will showcase how to access other key metrics, effectively use them, and implement a proactive approach to performance management.

Tracking Texture Memory Usage:
Heavy use of textures can lead to increased memory usage. Tracking this helps you understand texture impact:

var texture_memory_used = Performance.get_monitor(Performance.RENDER_TEXTURE_MEM_USED)
print("Texture Memory Used: " + str(texture_memory_used) + " bytes")

If texture memory is high, consider using lower resolution textures or implementing texture compression.

Monitoring Video Memory:
Especially important for games with 3D graphics, keeping an eye on video memory ensures your game runs smoothly on different graphics cards:

var video_mem_used = Performance.get_monitor(Performance.RENDER_VIDEO_MEM_USED)
print("Video Memory Used: " + str(video_mem_used) + " bytes")

This could reveal video memory spikes prompting you to optimize your 3D models or shaders.

Analysing Active Objects:
Active objects are often dynamic elements like NPCs or projectiles. Monitoring their count can prevent overpopulation:

var active_objects = Performance.get_monitor(Performance.OBJECTS_ACTIVE)
print("Active Objects: " + str(active_objects))

An unexpectedly high number might indicate that objects are not being deleted or pooled correctly.

Examining Vertex and Face Counts:
These metrics shine a light on the complexity of your game’s meshes – the less complex, the better for performance:

var vertex_count = Performance.get_monitor(Performance.RENDER_VERTICES_IN_FRAME)
print("Vertices in Frame: " + str(vertex_count))

var face_count = Performance.get_monitor(Performance.RENDER_FACES_IN_FRAME)
print("Faces in Frame: " + str(face_count))

Reducing vertex and face counts through level-of-detail (LOD) systems can improve rendering times dramatically.

Assessing The Frame Time:
Knowing how long each frame takes to process can help identify if certain game sequences are too demanding:

var frame_time = Performance.get_monitor(Performance.TIME_FRAME)
print("Frame Time: " + str(frame_time) + " seconds")

Long frame times indicate that there’s room for efficiency improvements in rendering or script execution.

Identifying Spike in Functions Calls:
A sudden increase in function calls per second could lead to unexpected slowdowns:

var function_calls = Performance.get_monitor(Performance.TIMES_FUNCTION_CALLS)
print("Function Calls: " + str(function_calls))

To reduce function calls, consider streamlining scripts and avoiding unnecessary calls within your _process or _physics_process functions.

Using Real-Time Adjustments for Performance:
Lastly, use the performance data to make adjustments in real-time. For instance, if frame rate drops, lower visual fidelity:

func _process(delta):
    var fps = Performance.get_monitor(Performance.TIME_FPS)
    if fps < 60:
        # Adjust graphics settings for performance
        lower_graphics_settings()
        
func lower_graphics_settings():
    # Example function to reduce graphics quality
    var quality_settings = Engine.get_singleton('QualitySettings')
    quality_settings.texture_quality = QualitySettings.QUALITY_LOW
    print("Graphics quality lowered for performance.")

By keeping an eye on these metrics and acting upon them, you’ll not only ensure a stable game experience but also gain a deeper understanding of how your game interacts with the hardware resources, enabling you to develop even more optimized games in the future.Performance monitoring helps maintain the balance between visual fidelity and smooth gameplay. Here are additional examples illustrating how to leverage Godot 4’s Performance class to ensure your game achieves this balance.

Adaptive Detail Levels Based on Monitor:
You can adapt the level of detail in real-time based on the monitor’s feedback. This ensures maintaining performance without significantly impacting visuals:

func _process(delta):
    var fps = Performance.get_monitor(Performance.TIME_FPS)
    if fps  50:
        increase_detail_level()

func decrease_detail_level():
    # Code to decrease the level of detail
    # This could include turning off shadows, reducing texture resolution, etc.
    print("Detail level has been decreased to improve FPS.")

func increase_detail_level():
    # Code to increase the level of detail
    # This could include enabling shadows, increasing texture resolution, etc.
    print("Detail level has been increased due to high FPS.")

Dynamic Physics Step Adjustments:
If the physics simulation is taking too long per frame, you might want to adjust the physics FPS dynamically:

var target_physics_fps = 60
var max_physics_step = 1.0 / target_physics_fps

func _ready():
    set_physics_process_internal(true)

func _physics_process(delta):
    var physics_frame_time = Performance.get_monitor(Performance.PHYSICS_FRAME_TIME)
    if physics_frame_time > max_physics_step:
        target_physics_fps -= 1
        max_physics_step = 1.0 / target_physics_fps
        Engine.iterations_per_second = target_physics_fps
        print("Physics FPS decreased to: " + str(target_physics_fps))

Optimizing Shader Compilation:
Shaders can take some time to compile, which might result in hiccups. Use monitoring to check for shader compilation times and optimize accordingly:

var shader_compiling_time = Performance.get_monitor(Performance.RENDER_SHADER_COMPILING_TIME)
print("Shader Compiling Time: " + str(shader_compiling_time) + " seconds")

If this metric is high, consider using fewer shaders or look into ways of pre-compiling them if possible.

Detecting Audio Playback Issues:
Audio can also impact performance. Monitor playback to ensure your audio isn’t causing any issues:

var audio_latency = Performance.get_monitor(Performance.AUDIO_OUTPUT_LATENCY)
print("Audio Output Latency: " + str(audio_latency) + " seconds")

High latency can be indicative of performance problems, in which case you may need to optimize your audio mix or settings.

Ensuring Smooth Network Operations:
For multiplayer games, network performance is critical. Monitoring network packets and bandwidth use can inform about potential lags:

# In a multiplayer game, regularly check the network metrics
var network_packets_in = Performance.get_monitor(Performance.NETWORK_PACKETS_IN)
var network_packets_out = Performance.get_monitor(Performance.NETWORK_PACKETS_OUT)

func _process(delta):
    if OS.get_ticks_msec() % 1000 == 0:  # Every second
        print("Packets In: " + str(network_packets_in))
        print("Packets Out: " + str(network_packets_out))

These examples provide a solid foundation for integrating the Performance class into your GameDev routine in Godot 4, ensuring your creations are not only beautiful to look at but also beautifully performant under various conditions. Armed with these tools, you can fine-tune your project to the pinnacle of performance, delivering a seamless gaming experience players will appreciate.

Where to Go Next

Performance monitoring with Godot 4’s Performance class is an important step in polishing your games to perfection. But don’t let your learning journey end here! If you’re keen on taking your Godot knowledge to the next level and building your own cross-platform games, our Godot Game Development Mini-Degree is the perfect next step.

This tailor-made program covers a broad array of essential topics, including 2D and 3D game creation, GDScript, and rich gameplay mechanics ranging from RPGs to platformers. And the best part is, it’s crafted to cater to all skill levels, whether you’re starting from scratch or looking to expand your current game development prowess. All courses are flexible and available 24/7, so you can progress at a pace that suits you.

For those looking to broaden their horizons within the Godot ecosystem, explore our extensive collection of Godot courses. Our content ranges from the very basics to more advanced topics, ensuring that no matter where you are in your game development journey, Zenva has something to offer. Start creating, learning, and paving your way to becoming a proficient game developer with us today!

Conclusion

In the realm of game development, mastering the tools of the trade is as thrilling as it is essential. Being able to see under the hood of your game with Godot 4’s Performance class not only boosts your developer toolkit but also unlocks a new layer of fineship in game creation. Whether you wish to elevate the player experience or optimize for the vast sea of devices out there, performance monitoring is a skill that places you at the helm of your game’s potential.

As we wrap up this exploration of performance monitoring with Godot 4, remember that this is just one piece of the vast puzzle of game development. Embrace the journey ahead; refine your skills with our Godot Game Development Mini-Degree, and let every challenge enhance your craft. With Zenva by your side, you’re not just making games—you’re shaping worlds.

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.