Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The LayerCameraSettings property is of type FlatRedBall.Graphics.LayerCameraSettings which can be used to override the settings of the Camera when rendering the particular Layer. For more information on how to use this, see the LayerCameraSettings page.
The Remove method is responsible for removing the argument object from the calling Layer. Remove has the following signatures:
Calling Remove is usually not necessary. The reason is because the internal list that Layers use to keep track of objects is a two-way list. In other words, consider the following code:
Therefore, you will not need to call Remove to take a Sprite off of a Layer if you are using the SpriteManager to remove it. However, Remove can be useful if you would like to move a Sprite from one Layer to another:
Layers provide a way to force a particular order of drawing on a single Camera. While the concept is fairly straight-forward, things can become more complicated when objects are moved from being layered to unlayered, or when objects have presence on multiple layers. Since there are a variety of ways to layer and unlayer objects, this article will present a number of small code blocks and explain what each one does.
First, let's start with some common code that all samples below will use. Consider the following line of code:
Okay, so far we have two layers that have been added to the SpriteManager. Keep in mind that secondLayer will actually be drawn on top of firstLayer - they are drawn in the order that they are created, so first is drawn first, then second is drawn on top of first.
Here's a very common setup (of course, assuming the lines above are still in the code).
As you may have guessed, the above code creates a Sprite which is managed and drawn, but not layered. We can show the membership as follows:
Category
Is a member
Managed by SpriteManager
X
Drawn unlayered
X
Drawn on firstLayer
Drawn on secondLayer
This table is just another way of showing what we mentioned before.
There are two ways to make a layered Sprite. The first is to use the AddToLayer method:
The AddToLayer method in the SpriteManager as well as all other Managers does two things:
Adds the Sprite (or other object) to the argument Layer
Removes the Sprite (or other object) from unlayered drawing
The result:
Category
Is a member
Managed by SpriteManager
X
Drawn unlayered
Drawn on firstLayer
X
Drawn on secondLayer
The SpriteManager provides a shortcut method for adding a Sprite directly to a Layer:
This code does the exact same thing if used instead of the two lines of code above. That is, this method both adds the Sprite for membership as well as adds it to the firstLayer but not to unlayered drawing.
Category
Is a member
Managed by SpriteManager
X
Drawn unlayered
Drawn on firstLayer
X
Drawn on secondLayer
The AddToLayer method does remove the argument Sprite from unlayered drawing, but it does not remove the argument Sprite from any other Layers that it belongs to. Therefore, a Sprite can be added to two Layers simply by calling AddToLayer twice:
The result:
Category
Is a member
Managed by SpriteManager
X
Drawn unlayered
Drawn on firstLayer
X
Drawn on secondLayer
X
To remove a Sprite (or any other object) from a Layer, simply call the Remove method. Keep in mind that calling Remove will not re-add the object to unlayered drawing.
As shown below, this makes the Sprite managed, but it will not be drawn.
Category
Is a member
Managed by SpriteManager
X
Drawn unlayered
Drawn on firstLayer
Drawn on secondLayer
Having an object be drawn layered an unlayered is not something supported by the FlatRedBall Engine. One reason for this is that in most cases, this is an undesirable behavior. It can hurt performance, as well as result in unexpected graphical behavior. But we're going to cover this anyway because it may help expose bugs that you are experiencing if you've tried this (or stumbled across it unintentionally).
This code needs some explanation. The first line makes the Sprite managed and drawn unlayered. The second line makes the Sprite layered, but removes it from unlayered drawing. Now, you may be thinking "Ok, the last line just re-adds the Sprite to the SpriteManager so it is drawn unlayered." Well, you're half right. The second AddSprite call does add the Sprite to be drawn, but it also has a nasty side-effect. The Sprite will actually be added to the SpriteManager twice. It was added once on the first line, and once again on the third line. This means that the Sprite will have its every-frame management performed twice. Not only does this hurt performance, but it results in properties like Velocity and Acceleration applied twice. In other words, you may get very unexpected behavior if you do this.
Category
Is a member
Managed by SpriteManager
X X
Drawn unlayered
X
Drawn on firstLayer
X
Drawn on secondLayer
The AddToLayer method has a little bit of inconsistent behavior. Let's explore it a little bit. FlatRedBall assumes that in most cases whenever you want an object drawn, you also want it managed. So, let's look at the following code:
So it's a safe bet that the Sprite will be drawn on the firstLayer, but what about management? Is it managed by the SpriteManager? We never called AddSprite. Drum roll please...
Category
Is a member
Managed by SpriteManager
X
Drawn unlayered
Drawn on firstLayer
X
Drawn on secondLayer
The SpriteManager actually added the object both to the layer as well as to itself for management. This behavior is present because it's assumed that drawn objects should be managed. There is one exception, however. The ShapeManager's AddToLayer method. Shapes have somewhat unique behavior in that they are most often used for collision, and many times they can exist and be used, but not be managed by the ShapeManager for performance reasons. Therefore, the ShapeManager does not add a shape for management unless you explicitly tell it to do so. In other words, adding a shape to a layer, but not to the ShapeManager results in the shape being drawn, but not managed. For more information on the reasoning behind this type of behavior, see the "Why Limit Shape Management" section of the ShapeManager page.
The Sprites collection provides access to all ordered Sprites stored within this layer. This is a read-only collection so it cannot be directly modified through the layer. Note that this list only contains ordered sprites. Z-buffered sprites are stored in the Layer's ZBufferedSprites property.
The Sprites property can be used to check if a Sprite is being displayed on a layer. The following code shows how to check if a Sprite is on a Layer.
Each Layer can have its own SortType which controls how Sprites, Text, and IDrawableBatches sort. This property allows each Layer to have its own Sort type. By default objects on Layers will be sorted by their Z values - objects with smaller Z values (which are in the distance) will draw behind objects which have larger Z values (which are closer to the Camera).
For general information abou tthe SortTypes property, see the SpriteManager's OrderedSortType property article. This article will discuss how sorting can be modified. Keep in mind that the SpriteManager article linked here discusses object sorting and uses the SpriteManager's OrderedSortType property which only controls how unlayered objects sort. In other words, changing the SpriteManager's OrderedSortType will not impact how Layers sort. Unlayered objects can sort differently than Layered objects, and each Layer can specify its own SortType.
If a Camera is unrotated, then the default SortType (Z) will work well. However, if your game uses a camera which can be rotated, then the default SortType may no longer produce desired results. For example, in a typical 3D game the Camera can face in any direction. When this occurs, objects with larger Z values are not guaranteed to be closer to the Camera than objects with smaller Z values. This is very noticeable when working with UI elements which are attached to the Camera. This is the main reason for the DistanceAlongForwardVector SortType. In most you can resolve ordering issues on UI/HUD elements which are attached to a rotated Camera by setting the Layer's SortType to DistanceAlongForwardVector:
Layers can be used to control the order of visual objects on screen. Typically objects with a larger Z value appear on top of objects with smaller Z values, but this relationship is only true if the objects are on the same layer.
Layers take priority over the Z value of objects when performing rendering. Typically Layers are used to force groups of visual objects to draw on top of other objects. For example, a HUD layer can be used to force HUD UI such as score and health bars to appear on top of everything else in a game regardless of Z value.
Layers can be added in the FlatRedBall Editor or in code through the SpriteManager. For information on how to use Layers in the FRB Editor, see this article.
To create a new Layer:
Expand the Screen which should contain a layer. Note that layers are usually added to GameScreen and not Level screens unless you need to have a layer specific to a level.
Right-click on the Objects folder and select Add Object
Find the Layer type
Enter a name for the Layer
Click OK
The following types can be added to Layers:
Additionally, Entities can be added to shapes through the FlatRedBall Editor, or through their MoveToLayer method.
Layers are used only to control the drawing order of objects. This means that layers have nothing to do with the position of the objects that they contain. For example, objects in an entity which are attached to the root entity can span multiple layers despite having their positions controlled by the parent/child relationship. For example we can consider a typical entity which is made up of three (3) objects:
The Entity itself
The visible representation which is attached to the Entity, such as a Sprite
The collision object which is also attached to the Entity, such as an AxisAlignedRectangle
Of these three, only the visible representation needs to be layered. You can add the collision to a Layer, but this does not have any impact on the behavior of your collision. The only reason you might want to add the collision object to a layer is so it will be drawn if on the same layer as the visible representation if you desire to have it drawn for debugging reasons. To clarify, adding the collision to a Layer does not impact collision. Two entities on different Layers will still be able to have their collision objects collide. The collision objects do not consider Layers when performing collision.
In code, layers are created through the SpriteManager. The following code creates a layer and two Sprites. Although the Sprite named nearSprite is closer than the Sprite named farSprite, farSprite is not hidden by nearSprite.
SpriteManager.AddToLayer - Responsible for adding SpriteFrames, Sprites, and IDrawableBatches to Layers.
TextManager.AddToLayer - Responsible for adding Texts to Layers.
Similar to Sprite and Texts, PositionedModels can also be layered. The following code creates a PositionedModel and adds it to a layer.
There are two ways to remove objects from Layers:
Completely remove the object from the engine and its Layer(s)
Remove the object just from the Layer but keep it in the engine
For reference, let's use the following setup to discuss this point:
This is the most common method of removing an object. It's usually what you'll do if you're manually handling the removal of your objects (as opposed to letting Glue do it for you). To do this, simply use the manager removal methods:
In other words, remove your objects just like normal - they'll automatically get removed from their Layers too.
Objects can be removed from Layers through the Remove method.
Now the Sprite and Text object are no longer on the layer, so they will not be drawn. However, the two objects have not been removed from their respective managers so they are still in memory and still managed every frame!
Multiple layers can exist at a given time. Calling AddLayer multiple times creates multiple layers. The newest layer is always on top while the oldest is on bottom.
This section discusses sorting objects (such as Sprites within a Layer. For information on how to control the order that Layers are drawn, see the SpriteManager MoveToBack and MoveToFront page. While Layers represent Lists in some ways, they cannot sort objects that they hold (like SpriteLists or PositionedObjectLists). The reason for this is because the internal SpriteList that a Layer references is used directly by the engine to draw the Layer. The engine may perform sorting on this list to ensure proper overlapping and to improve runtime performance so user-controlled sorting of the SpriteList may disrupt this behavior. If objects in a Layer need to be sorted they should be added to a separate SpriteList and sorted there.
If you are using Glue then you can add an Entity to a Layer. See this article for information on this.
Layers will render to the full screen by default. Layers can be adjusted to only render to part of the Screen. For more information see the LayerCameraSettings destination coordinate page.
For more information, see the Adding Gum Components to Layers page.
The UsePixelCoordinates can be used to easily create a 2D Layer. This method is often used in combination with attaching Entities to a Camera so that they can be placed in screen space. This method is used by Glue if a given Layer's "Is 2D" property is set true.
The following example shows a situation where a Camera which is 3D (default) draws a 2D layer which contains some text. Add the following using statement:
Add the following to Initialize after initializing FlatRedBall:
The code above creates two different coordinate systems; however, if the Camera is moved, then the Text that is on the 2D layer will also be affected. Usually when creating 2D HUD and UI elements, they should also be attached to the Camera. If an object is attached to the Camera, it will always stay in the same place on-screen even if the Camera moves or rotates. Therefore, the positioning code could be modified as follows:
The RenderTarget property can be set so a given Layer renders to the RenderTarget rather than to screen. The RenderTarget property can be used for a number of reasons:
To create textures used in a multi-pass rendering system, such as to apply layer-wide effects like color tinting or bloom
To improve the performance of complicated, static visuals on a Layer by eliminating the management of multiple objects and multiple draw calls with a single object and draw call (for a collection of objects which do not require every-frame activity)
If a Layer's RenderTarget is set, then the Layer will not render directly to the screen. Instead, the contents of the Layer are rendered to the RenderTarget which must then be rendered to the screen using another graphical object such as a FlatRedBall Sprite, a Gum Sprite, or SpriteBatch.
The Layer's RenderTarget property is used to render a layer to a RenderTarget. For more information about rendering your entire FlatRedBall game to a RenderTarget, see the SetRenderTarget page.
To set a RenderTarget in the FRB Editor:
Create a RenderTarget object
Create a Layer instance
Set the RenderTarget property on the layer to the previously-created RenderTarget
As mentioned above, the contents of the Layer are rendered to its RenderTarget instead of the screen. The easiest way to see the contents of the RenderTarget is to add a Sprite and use the RenderTarget as its Texture.
The following code shows how a RenderTarget2D can be created and assigned to the Layer.RenderTarget property. This Layer contains a single Circle which is drawn with a separate unlayered Sprite:
Note that the above code creates a Layer in code instead of creating one in the FRB editor. This is done purely to keep the example short - Layer instances created in the FRB editor can be used as well.
RenderTarget instances can be updated every-frame, or can be rendered just one time (if the contents of the render target never change). The following code example shows how to create a RenderTarget which is used as the target only one time. This example differs in the following ways compared to the previous example:
The layer is only needed temporarily until the render is done.
The Renderer needs a temporary camera to perform rendering. While this example only uses a single Layer, multiple layers could be used to sort objects.
Any rendered objects (such as entities, sprites, or shapes) are only needed for the Draw call and can be destroyed afterwards.
The example above shows how to render an AxisAlignedRectangle using a one-time render to a RenderTarget. If entities (or other objects which have PositionedObject attachments) are rendered to a one-time render target, then dependencies (aka attachments) must be updated prior to rendering the render target. For example, the following snippet shows how multiple Ship instances might be rendered to a RenderTarget:
The RenderTarget2D constructor takes width and height parameters. These values can be as large as the current game's resolution, but they can also be smaller. If a smaller resolution is used, the Layer will be rendered at lower resolution, but the entire layer will still be drawn. For example, first we will modify the example above to no longer squash the Sprite:
We can adjust the RenderTarget2D constructor so the RenderTarget is 1/4 the resolution, as shown in the following code snippet:
Since the Sprite uses a TextureScale of 1, shrinking the RenderTarget2D will also shrink the Sprite:
To compensate for this, the Sprite.TextureScale property can be changed to 4. This will result in the RenderTarget2D being drawn at the same size as before, but it will be 1/4 the resolution, so it will appear pixellated (or blurred due to linear filtering):
Rendering to a RenderTarget2D which is smaller than the game's resolution can improve performance, especially if the RenderTarget2D is used with effects which do not need full-resolution images, such as blurring.