FlatRedBall.Math.PositionedObjectList

Introduction

The PositionedObjectList is an object which can store lists of PositionedObjects. It is the base class of the SpriteList class and is commonly used to store lists of Entities and shapes such as Polygons. The PositionedObjectList inherits from the AttachableList and it establishes two-way relationships with objects that are added to it.

Common Usage

Most FlatRedBall games use the PositionedObjectList. The PositionedObjectList is common both in custom code as well as in Glue generated code.

What types are stored in PositionedObjectLists

The PositionedObjectList is a dynamic list which is made to specifically store PositionedObjects and any classes which inherit from PositionedObject. The most common types stored in PositionedObjectLists are:

Sprites are usually stored in the FlatRedBall.SpriteList class; however since PositionedObjectList is the base class for SpriteList all of the information presented here applies to SpriteList as well.

Instantiating a PositionedObjectList

The PositionedObjectList class is a generic class. So, to instantiate one, you need to use the type that the PositionedObjectList will contain:

PositionedObjectLists in Custom Code

If a PositionedObjectList which holds entities is added to a Screen, then it will usually need to call Activity on the contained entities. For example, the following code shows how a PositionedObjectList of type Bullet (assuming Bullet is an Entity) can be added to a Screen.

 

Combined with FlatRedBall Patterns

The PositionedObjectList class is an essential part of the standard FlatRedBall Screen. For the rest of this discussion we’ll assume that you are using Screens and Entities.

PositionedObjectLists represent categories

Usually you will want to create one PositionedObjectList per category of object. What defines a category? A category of objects is anything which shares the same behavior. For example:

  • Enemy Bullets – All bullets in a space ship game probably need to test for collision against the player.
  • Moving Platforms – Platforms may need special logic performed on them so they move along a predetermined path.
  • Destroyable objects – Objects which can be destroyed by the player such as chairs and tables may need to have every-frame collision performed against any player attacks.
  • Particles with special behavior – Particles that have behavior not handled by the Emitter may need to be stored in a PositionedObjectList for their custom behavior. For example, you may need to perform collision between rain particles and the ground, and destroy the rain particle upon collision.

PositionedObjectList life

In most cases PositionedObjectLists should be defined at class (usually Screen scope. The reason for this is mainly because the categories that the PositionedObjectList represents will usually live the entire life of the Screen.

The objects within the PositionedObjectList may have a short life (bullets may only have a few seconds); however, the list itself should only be created in the Screen’s Initialize method.

All PositionedObjectLists should be emptied when their containing Screen is destroyed. See the next section for information about how to properly remove items from PositionedObjectLists.

Removing items from lists

This section might seem silly. You might be thinking, “I just call Remove, right?”. Actually, the Remove method in the PositionedObjectList class is almost never called explicitly.

Keep in mind that the PositionedObjectList is a AttachableList so that means that it shares a two-way relationship with all of its contained elements. That means that simply removing a PositionedObject from its manager will remove the PositionedObject from any list that it belongs to.

Let’s look at how this works in practice. In our first example we have a PositionedObjectList of Circles which represent enemy bullets. If the bullet collides with the player Entity, then the bullet should be destroyed. That means it should be removed from the engine as well as from any PositionedObjectLists that contain it.

Notice that we never remove the bullet from mBullets. That’s okay, this happens automatically when it is removed from its manager.

Let’s look at one more example – one using Entities. The common pattern for Entities is to include a Destroy method which can be called when the Entity is not needed anymore. The Destroy method is responsible for removing the Entity and any objects that it contains from their respective managers.

Let’s say that you have a game like Contra where enemies should be removed when they are out of the screen. For the sake of simplicity we’ll assume that the Enemy class has a IsInScreen method:

Clearing PositionedObjectLists

All PositionedObjectLists should be cleared when their containing Screen is destroyed. The following code can be used to clear a list of Enemies.

For a more detailed discussion of the Clear function and why it may not be a good idea to use it, see the Clear wiki page.

Reverse For Loops

One of the most common statements in programming is the incrementing for loop:

This is a very common way to have a particular action performed numberOfIterations times. It’s also used to traverse lists and perform actions on these lists. For example, if a game has a PositionedObjectList with Enemies, then each enemy should have its Activity method called. The following code would call Activity on each Enemy:

However, there is a subtle problem here. If the Activity method can result in the destruction of an Enemy (say by checking its health or some other condition), then mEnemies may be modified. Remember, since mEnemies is a PositionedObjectList, if an Enemy destroys itself, it will likely call the SpriteManager’s RemovePositionedObject method. This will remove itself from all PositionedObjectLists that it belongs to, including mEnemies.

Now, consider what happens when this occurs. Let’s say that i = 1, and mEnemies[1] is ready to be destroyed. When this occurs, the Enemy at index [2] “slides over” to index [1]. However, after the Activity is called, I increments to 2, which is the “new position” of the Enemy that was at index [3]. In other words, the removal of the enemy at index [1] caused the next Enemy to have its Activity method skipped over. Depending on your game this may be a very benign side-effect. That is, next frame the enemy that was moved to index [1] may get its Activity method called and all will be well; however, it may be the case that your Activity method needs to be called every frame. Or it may be the case that later on in development you add some logic to the Enemy class’s Activity method that causes problems if not called every frame.

In short, removal inside a forward for loop can cause inconsistent behavior, and this can potentially cause bugs – specifically bugs which can be very difficult to track down.

Fortunately, this can be remedied by a reverse for loop. The above code could be modified to be the following:

This guarantees that all Enemies will have their Activity methods called, even in the case of a removal. As in the example above, if the enemy at index [1] gets removed, then all Enemies with index greater than 1 will be “shifted” by one. However, that’s ok, because all enemies with index greater than 1 have already been tested in the loop. The next index to be tested is index [0], and the Enemy at index [0] is the same Enemy both before and after the removal of the enemy at index [1].

PositionedObjectList Members

Did this article leave any questions unanswered? Post any question in our forums for a rapid response.