The ShapeDrawingOrder controls whether all Shapes are drawn under or over other FlatRedBall-drawn objects (for example Sprites, Models, and Texts). Currently shape drawing order cannot be controlled by the shape's Z value; however, as of the June 2009 release of FlatRedBall, most shapes can be placed on layers which provides some control over ordering.
The ShapeDrawingOrder has two options:
UnderEverything
OverEverything (default)
Since the default for the ShapeManager's ShapeDrawingOrder is OverEverything, then all shape drawing will appear on top of other objects.
The following example adds a Sprite and a Line, then sets ShapeDrawingOrder to UnderEverything so that the added Line appears under the Sprite.
Add the following using statements:
Add the following to Initialize after initializing FlatRedBall:
The ShapeManager is responsible for managing "Shapes". Shapes are most often used for collision between objects. Objects which belong to the Shape categorization are:
All of these objects share the PositionedObject base class. These are the only objects which the ShapeManager manages. Although there is no "Shape" class, these objects are often referred to as shapes.
Any shape added to the FlatRedBall Editor (either as part of a Screen or Entity) will also be added to the ShapeManager by default. For example, the Player entity in the following screenshot contains an AxisAlignedRectangle which is automatically added to the ShapeManager.
The ShapeManager can add any shape through its Add methods. The following code creates a Circle. Add the following using statement:
Add the following using statement:
Adding a Shape to the ShapeManager will automatically make the shape visible. For example, the following code results in a visible Circle:
To properly control visibility, set the value after a shape to the ShapeManager:
The ShapeManager can remove shapes that have been previously added to it through its Remove method. Assuming circle is an instance of a Circle that has been created through the ShapeManager:
Aside from addition and removal of shapes, the ShapeManager is responsible for drawing and managing Sprites. Calling AddPolygon, AddAxisAlignedRectangle, and AddCircle results in the ShapeManager managing and drawing the Sprite added or created by the method. It is possible to create manage-only or draw-only as shown by the following code:
Note that circle2 is never explicitly added to the ShapeManager, but it will still be drawn. This behavior differs from other FlatRedBall objects such as Sprites which must be added explicitly to their respective manager to be drawn.
Shape Management can be a complicated topic because shapes can be managed in a number of different ways. The reason this complexity exists is because games often include a very large number of shapes for collision. For example, a tile-based game may include hundreds or thousands of shapes as part of a TileShapeCollection. Games with a large number of collidable entities (such as twin stick shooters) may similarly have hundreds or thousands of live shapes. Therefore, shape management can be customized for performance and functionality as necessary. The term management can refer to any number of every-frame operations which can be performed on a shape. These can be grouped into a number of categories:
Parent/Child Relationship Management - this results in a shape's position being updated according to its parent - usually an Entity instance.
Visibility/Drawing Management - this management results in the shape being drawn to the screen
Velocity/Physics Management - this management results in a shape's physics values such as Velocity, Acceleration, and Drag being applied every frame
Games which are concerned with performance should only apply every-frame management as necessary for shapes. Unnecessary management can lower the frame rate of your game, in some cases to the point of making the game unplayable. Shape management management can be performed in a number of ways:
Adding a Shape to the ShapeManager - this results in all management being applied, which is handy if you need all types, but this is expensive if shapes do not need full management.
Setting a shape's Visible to true - this adds a shape to the ShapeManager, but only to be drawn. A visible shape which is not explicitly added to the ShapeManager will only be drawn but other forms of management such as physics are not applied. Note that this is true unless the ShapeManager's SuppressAddingOnVisibilityTrue is set to true. See the SuppressAddingOnVisibilityTrue page for more information.
Attaching a shape to a collidable entity - collision functions perform parent/child relationship updates automatically because these types of relationships are very common.
Performing management in generated code - the FlatRedBall Editor provides functionality for performing management in generated code. This approach as the benefit of selectively applying updates only to properties which need management.
Performing management in custom code - custom code can perform custom management just like generated code. This is effective if you would like complete control over management.
Making shapes visible can be beneficial for debugging collisions. For the final version most games will want shapes to be invisible. Invisible shapes will collide the same as visible ones so in most cases visibility is useful simply during development. Of course, shapes can also be used to draw on-screen line graphics.
The source of some confusion is what happens when a Shape is attached to a PositionedObject (like an Entity), but not added to the ShapeManager. If you write code which attaches a shape to an Entity, set the shape's Visible to true, then move the entity, you will notice that the shape does not move. As mentioned above there are two ways to update a shape's parent/child relationship:
By being added to the ShapeManager
By calling one of their collision methods or passing them as arguments to a collision method.
Since the shape is neither part of the ShapeManager nor having any Collision methods called, then its dependencies are never updated - so the position of the parent has no affect on the child Shape. If you are interested in seeing the shape move with its parent, simply add it to the ShapeManager. If this shape is going to be used for collisions, then there is no need to add it to the ShapeManager - calling collision methods will automatically manage the dependency. This behavior will also be present if the shape is not visible, but you depend on the shape's absolute position. If you're depending on the shape's position outside of collision, be sure to add it to the ShapeManager.
Did this article leave any questions unanswered? Post any question in our forums for a rapid response.
The Remove method can be used to remove a shape from the ShapeManager. The Remove method will perform the following:
Remove the shape from being automatically updated by the ShapeManager (velocity, acceleration, attachments, etc)
Remove the shape from being drawn
Remove the shape from any PositionedObjectList it is a part of, including any objects that it is attached to
The following shows how to remove a shape:
One of the most common (incorrect) assumptions about shapes is that a removed shape will not collide with any other shapes. This is incorrect - collision does not require ShapeManager membership. Consider the following code:
When a collision between two shapes is performed, the collision code simply checks the shapes positions, rotations (if appropriate), and size values (such as ScaleX or Radius if appropriate) to see if there is any overlap. In the case of a Circle, the position and radius doesn't change when it is removed from the ShapeManager. The same goes for any other shape - removing a shape from the ShapeManager does not modify the shape and collision methods will still work.
The behavior described above may seem inconvenient. However, in most cases shapes exist in one of two places:
PositionedObjectLists inside a Screen or collision management class
Objects inside an Entity
Games may include a PositionedObjectList or ShapeCollection containing shapes. The behavior of Shapes which are removed from the ShapeManager is the same in either case. Remember, PositionedObjectLists and ShapeCollections both have two-way relationships with objects that they contain, so removing a shape from the ShapeManager will result in the shape also being removed from any PositionedObjectList or ShapeCollection that it is a part of.
If you have an Entity with a shape Object (which may be called "Collision"), removing the shape from the ShapeManager will not remove the shape from the Entity. This means that the Entity's Collision member will still be valid and report collisions. In this case, it is up to you to write logic in your Entity to control whether collision should still be performed. For example, you may do something like this:
If you are storing a reference to a shape in a class (not as a list) and you are performing collision with that shape, you will need to somehow identify that the shape has been removed. For example:
If a Shape is added in code, it must be removed in code as well, typically in a Screen or Entity's CustomDestroy.