SubViewportContainers in Godot 4 offer a unique and powerful way to manage different visual elements within your games or applications. These special containers allow developers to create and handle multiple viewports within a single scene, enabling a diverse range of functionalities, from split-screen experiences to minimaps or even rendering 3D objects on a 2D plane. By grasping the capabilities of SubViewportContainers, you’ll unlock new creative possibilities and refine the visual structure of your projects. Let’s dive into the world of Godot’s SubViewportContainer and see how it can enhance your development experience!
Table of contents
What is a SubViewportContainer?
A SubViewportContainer in Godot is a type of node that serves as a container for displaying the contents of its child SubViewport nodes. This allows developers to neatly organize and display multiple camera views or UI elements that exist outside of the main game scene.
What is it for?
The SubViewportContainer can be incredibly useful for various scenarios in game development:
- Achieving split-screen effects in multiplayer games, where each player has their own viewport.
- Creating picture-in-picture displays, such as minimaps or secondary camera angles.
- Rendering 3D models over 2D environments for a unique look or gameplay mechanics.
Why Should I Learn It?
Understanding how to use SubViewportContainers can drastically increase the polish and professionalism of your games. With the power to manipulate multiple views:
- You gain control over complex scene compositions.
- You can create more engaging player experiences.
- You will have the ability to optimize performance by selectively rendering elements.
SubViewportContainers combine both technical prowess and artistic design, making them an essential tool in any Godot developer’s toolkit. Whether you’re a beginner looking to explore new features or an experienced coder aiming to push the limits of what’s possible, mastering SubViewportContainers is a journey well worth embarking on.
Creating a SubViewportContainer
First things first, we need to create a SubViewportContainer and a SubViewport within our Godot project. This is the foundation from which we build our multiple view scenarios.
var sub_viewport_container = SubViewportContainer.new() var sub_viewport = SubViewport.new() sub_viewport_container.add_child(sub_viewport) get_root().add_child(sub_viewport_container)
Notice how we create these nodes using Godot’s script which allows us a great deal of control. Adding them to the root ensures they are part of our scene tree.
Configuring the SubViewport
It’s not enough to just create the SubViewport; we also need to configure it so it displays what we want. We’ll need to set the size and whether it handles input. For a split-screen setup, you might do something like this:
sub_viewport.size = Vector2(512, 512) sub_viewport.disable_input = true
Here, we determine the size of our SubViewport and choose whether it should receive input.
Adding a Camera to the SubViewport
For the SubViewport to display anything, we need to have a Camera. We’ll add a camera node as a child of our SubViewport.
var camera = Camera.new() sub_viewport.add_child(camera) camera.make_current()
This block of code creates a new Camera node, attaches it to our SubViewport, and sets it as the active camera. With this, our SubViewport will now display what the Camera sees.
Displaying the SubViewport’s Content
Now that we have our SubViewport with a Camera, we’ll need to ensure that its content is visible on the screen. For that, we must add the SubViewportContainer to our main scene and align it as desired.
sub_viewport_container.rect_position = Vector2(0, 0) sub_viewport_container.rect_size = sub_viewport.size
Here, we set the position of the SubViewportContainer to the top-left corner and its size to match the SubViewport.
Rendering 3D in 2D
If we want to display a 3D model in a 2D environment, we need to ensure the setup is correct. Here’s how you could set up a SubViewportContainer to show a 3D object on a 2D user interface:
var sprite_3d = Sprite3D.new() sub_viewport.add_child(sprite_3d) sprite_3d.set_texture(your_3d_content)
This demonstrates adding a 3D sprite to the SubViewport. Make sure your 3D content has been set up previously, with textures and materials as needed.
Handling Input in SubViewports
In some cases, you may want the SubViewport to receive input, especially in split-screen scenarios. Here’s how you can route input to a SubViewport:
sub_viewport.gui_disable_input = false sub_viewport.input_pass_on_gui_click = true
This configuration allows GUI input to be processed by the SubViewport and passes mouse clicks through to the GUI elements within it.
In these examples, you’ve seen how to set up and configure a SubViewportContainer, add and configure a SubViewport, attach a camera, render 3D content on 2D planes, and handle input. These basic operations form the building blocks you will use to create sophisticated rendering setups in your Godot projects.As we dive further into the capabilities of the SubViewportContainer in Godot 4, let’s explore additional functionalities that are critical for game development, such as rendering optimizations, offscreen rendering, dealing with global vs. local space and more.
Optimizing SubViewport Rendering
Optimizations are key in game development. One of the optimizations for SubViewports is the usage of the `render_target_update_mode` property. This property controls when the SubViewport is updated. For instance, you may want a minimap that only updates every few seconds.
sub_viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
Alternatively, you could have use cases where the SubViewport should always be updated:
sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
SubViewportContainers can be used for offscreen rendering, which is useful for creating textures dynamically or pre-rendering scenes.
sub_viewport.render_target_v_flip = true sub_viewport.render_target_clear_on_new_frame = false sub_viewport.render_target_undo_redraw = true
These settings flip the vertical rendering to match the OpenGL convention, determine whether the target is cleared between frames, and set the container to reuse the previous frame if nothing has changed.
Global vs. Local Space
When working with SubViewports, you may find that you need to convert coordinates between the global space of the main viewport and the local space of the SubViewport.
var local_mouse_position = sub_viewport.get_local_mouse_position()
This line of code retrieves the mouse position within the SubViewport’s local space. You can use this information to react to mouse input for elements within the SubViewport.
Drawing on SubViewports
If you need to draw on a SubViewport, perhaps to overlay information on a camera’s view, you use the `draw()` function within a `CanvasItem` that is a child of the SubViewport.
func _draw(): draw_circle(Vector2(10, 10), 5, Color(1, 0, 0))
This simple `_draw` function would draw a small red circle at the position (10,10) in the SubViewport.
Using SubViewports for UI Elements
UI elements that are only required in certain contexts, such as an in-game computer screen or a pop-up map, can be organized within a SubViewport. This separation provides better control over when and how these elements are displayed.
var ui_subviewport = SubViewport.new() ui_subviewport.size = Vector2(200, 100) ui_subviewport_container.add_child(ui_subviewport) ui_subviewport_displayer.texture = ui_subviewport.get_texture()
Here, we create a new SubViewport specifically for our UI element, set its size, and display its contents using another node (like `SubViewportContainer` or `TextureRect`).
Scene Instancing in SubViewports
Sometimes we might want to instance a complex scene within a SubViewport separately from our main game scene.
var scene_instance = preload("res://my_scene.tscn").instance() sub_viewport.add_child(scene_instance)
With this approach, we can add a fully-featured scene as a child of the SubViewport, essentially maintaining its own contained world within your larger game.
Layering with SubViewports
A creative use of SubViewports is layering; for instance, applying post-processing effects or rendering 3D objects above a 2D plane without affecting the background.
sub_viewport.layer = 1 sub_viewport.use_own_world = true
These settings will ensure that our SubViewport’s content is rendered on its own layer and even in a separate world if needed—key for post-processing or complex rendering arrangements.
The examples provided showcase a variety of ways SubViewports can extend the capabilities of your Godot projects, from performance considerations to innovative rendering techniques. Understanding and leveraging these features will certainly broaden the scope of what you can achieve visually and functionally in your games.Using SubViewports also enables us to manage rendering layers for specific objects. Let’s illustrate this with an example of rendering a character in 3D on top of a 2D game environment.
// Assuming sub_viewport is already added and configured var character_scene = preload("res://character.tscn").instance() sub_viewport.add_child(character_scene) character_scene.translation = Vector3(0, 0, 10) // Set the character's position in 3D space
In the above setup, by adding a 3D character to the SubViewport, it will be rendered above the 2D environment, assuming the main game is in 2D and the character is in 3D.
Another practical application for SubViewports is handling offscreen rendering for reflection or refraction effects. Here, let me show how you can render a scene to a texture for dynamic reflections:
// Create a viewport for rendering our reflection offscreen var reflection_viewport = SubViewport.new() reflection_viewport.size = Vector2(512, 512) // Set the desired reflection resolution var reflection_texture = reflection_viewport.get_texture()
We then assign this `reflection_texture` to a material that would be used on a surface to create the reflective effect.
When working with 3D games, we often need to handle a UI system that renders on top of our 3D world. The SubViewportContainer can be used to overlay UI elements, like health bars or ammo counts:
// Assuming ui_subviewport is already created and configured var health_bar_scene = preload("res://ui/health_bar.tscn").instance() ui_subviewport.add_child(health_bar_scene) // Position the health bar within the SubViewport health_bar_scene.rect_position = Vector2(10, ui_subviewport.size.y - 50)
It’s worth noting that if you want the UI to be responsive and adapt to the SubViewport size, make sure to enable the right anchoring or use a `Control` node with a full rect stretch mode.
Another important aspect is how you can control when your SubViewport updates. For UI elements that update frequently, such as a score counter or a timer, you will need them to refresh regularly:
ui_subviewport.render_target_update_mode = SubViewport.UPDATE_WHEN_VISIBLE
On the other hand, for elements that rarely change or only need to be updated under specific conditions, you might opt to update manually:
// Let's say we only want to update our SubViewport when the score changes func _on_score_changed(new_score): ui_subviewport.update()
Lastly, if you’re dealing with physics simulations that render in a separate SubViewport, you will need to ensure that the physics within this SubViewport are stepped properly:
// Step the physics within the SubViewport manually func _physics_process(delta): sub_viewport.physics_object_2d_set_space_override_mode(SpaceOverride.COMBINED) sub_viewport.physics_object_2d_step(delta)
These code examples show how you can effectively harness the power of SubViewportContainers in Godot to create complex visual arrangements, optimize performance, and craft immersive experiences for players. The flexibility that SubViewports provide can significantly expand the creative boundaries of your game designs.
Keep Advancing Your Godot Skills
Embarking on your game development journey with the Godot engine opens up a world of creativity and challenge. As you continue to build your skills and explore the vast capabilities of Godot, know that Zenva is here to support your learning path every step of the way.
For those looking to deepen their understanding of Godot and expand their development expertise, our Godot Game Development Mini-Degree is an excellent next step. This comprehensive collection of courses will guide you through creating your own 2D and 3D games, covering everything from asset management to GDScript, gameplay mechanics, and beyond. You’ll have the flexibility to learn at your own pace, build a robust portfolio, and gain the hands-on experience necessary to excel in the game development arena.
If you’re eager to explore a broader range of topics within Godot, we invite you to check out our full catalog of Godot courses. Whether you’re just starting or looking to specialize in a particular area, our courses are designed to meet you where you are in your learning journey. Dive in, create, and transform your game development dreams into reality with Zenva.
The power of Godot’s SubViewportContainer is undeniable, offering an array of possibilities for bringing your game visions to life. Whether it’s to implement split-screen multiplayer, render 3D elements in a 2D world, or optimize your game’s UI, mastering SubViewports can be a game-changer. Remember, the voyage through game development is a continuous learning experience; each new skill paves the way for more complex and captivating creations.
As you stride forward, let Zenva be your companion and guide in the captivating world of game development. Expand your horizons and enforce your game dev superpowers by diving into our Godot Game Development Mini-Degree. Don’t just play games, create them—turn imagination into playable reality and shape the future of interactive entertainment with the knowledge you gain.
FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.