Skip to content

Add sprite layer render order override and parent/child layer rendering#6341

Open
SlamBamActionman wants to merge 2 commits intospace-wizards:masterfrom
SlamBamActionman:layer-overrides
Open

Add sprite layer render order override and parent/child layer rendering#6341
SlamBamActionman wants to merge 2 commits intospace-wizards:masterfrom
SlamBamActionman:layer-overrides

Conversation

@SlamBamActionman
Copy link
Member

This PR adds two main features to SpriteComponent:

Sprite layer rendering order override

By default, a sprite renders the layers in the order they are in the List<Layer> Layers property.

There is now a new property added to LinkedList<int>? LayersOrderOverride. Its contents are meant to represent indexes of layers in the main Layers list. When set, instead of rendering the layers in the order of the Layers list, the sprite layers are rendered in the order their indexes are listed in the override. E.g. LayersOrderOverride = { 2, 0, 1 } will render the layers in that order.

Of note is that this order is only followed up until the highest index in the override. This means if an override's highest index is e.g. 2, any layer in the Layers list with a higher index will also render after the override (in the order listed in the Layers list). This is because these types of layers are often intended to be rendered on top of the existing sprite and may be difficult to account for in the override.

The LayersOrderOverride does not update automatically based on changes in the Layers list order. It is expected that whatever function sets it also accounts for changes throughout the codebase.
- Is this reasonable? Arguably one could also update the property if a layer is added/removed, but that might be a lot of overhead work. Let me know if we want this instead of updating via Content.

Parent/Child layers

A child layer is a layer that will always follow its parent in the layer order, regardless of its index (override or not). This is set in the child via the property int? ParentLayer and in the parent via List<int> ChildLayers.

These properties are inaccessible outside the API to (hopefully) avoid accidental endless recursion. When a layer is added, it can optionally include a parentIndex which refers to the index of a layer in the Layers list. The parent layer gets the new layer added as a child, and when processing the rendering order any child layer gets selected for rendering after the parent layer has been rendered.

Adding/removing layers will shift the parent/child indexes accordingly, similar to how the Index property is shifted. Removing a parent layer orphans any children it may have.

As a parent can have multiple children, each child will render in the order they are added to the parent. The function runs recursively, so a child can also be a parent.

There is also the SetToParent method which assigns an existing layer as a parent to another existing layer, using the indexes. Of note is that if the child already has a parent, the new parent is given the child's old parent as its parent. This means SetToParent can be used to insert a layer in the middle of a chain of parent-children relationship.
- This is necessary for displacement maps, as they require the layer sprite they're modifying to exist when being made, but prefer to be before said layer in the rendering order.
- SetToParent is potentially risky as I think it would be possible to create a Parent/Child recursive loop; I am not sure how to fool-proof this however outside of tracking which layers have already been rendered, and that seems unperformant.


Issues

Sprite rendering is an area that is meant for heavy optimization, and that is unfortunately not my forté. I've done my best to preserve what I hope are performant methods but I there are areas where I'm uncertain if it has been made worse.

LayerRenderingStrategy

My understanding is that generating the matrices is a bit of a heavy operation. Previously this was easily avoided since the layers rendered in a simple foreach loop, but now that the behavior is more complex I needed to find a way to pass these on to the actual RenderLayer function. I've opted to, in case GranularLayersRendering is false, include the calculated matrices in a Dictionary and then retrieve them later on when RenderLayer is called. I'm not sure the dict is performant here though.

Parent/Child architecture

I think there is a case one could make that defining either the parent or the child layer isn't necessary, or that making a parent able to have multiple children is a bad idea. It seems to me that including both allows for the most flexibility but they also aren't hard-coupled and there could theoretically be a situation where there's recursion or indexes point incorrectly. Let me know if this is wrong.

LayersOrderOverride doesn't update

As mentioned earlier, adding/removing layers doesn't update the override. In my implementation I update these in Content so that isn't an issue, but maybe they should here as well, similar to how Parent/Children/Index indexes are?


Why?

Being able to override the sprite layer order means we can make much nicer-looking content via directional sprites. There will be a Content PR up soon after this one that attempts this using the features here. The override ensures "bookmark" layers can layer sprites in the correct order depending on which direction a character is facing, while a parent/child relationship allows there to be further customization of the rendering order by not just moving the "bookmark" layers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant