The MakeOneWay method makes the calling AttachbleList a one-way list. In other words, it means that the AttachableList will still contain all of the objects that it contained before calling MakeOneWay; however, the contained elements will no longer know that they belong to this List. This essentially makes the AttachableList behave like a regular List - at least until new objects are added to the List, or until MakeTwoWay is called.
The MakeOneWay method is useful if you have a list of IAttachables (such as Sprites) which you want to remove from their respective managers without having them removed from their List. In the following example, the element at index 0 will get removed:
To prevent the removal from the list, it can be made one way:
The FindByName method returns the first object in the list with the name matching the argument. The signature for the method is:
The FindByName method is most commonly used on AttachableLists which are populated by data which is loaded from file (or through the content pipeline), such as lists contained in Scenes or ShapeCollections. For example, a .scnx may be created as the level for a platform game. The goal of the level is to reach a door, which is a Sprite in the .scnx. This requires special logic (collision tests, then advancing to the next level on a successful collision). To perform this logic, the code that's loading the .scnx needs to have reference to the door Sprite. To accomplish this, the person assembling the .scnx should appropriately name the door and communicate this to the programmer. We'll assume that the door is named "door". Add the following code to get a handle to this object:
An AttachableList is a list which contains instances to IAttachables. Instances of IAttachables added to an AttachableList share a two-way relationship with the AttachableList by default. Common AttachableLists include the PositionedObjectList and SpriteList classes.
While this article goes into extensive detail about two-way relationships, this paragraph provides a quick explanation of what it means. In short, a two-way relationship means that IAttachables (this includes PositionedObjects such as Sprite, Shapes, and Entities) keep track of all PositionedObjectLists that they are a part of. The reason that this relationship exists is so that objects can remove themselves from all PositionedObjectLists that they are a part of automatically when removing them through the engine. Any "Remove" method offered by FlatRedBall managers will remove the argument object from all of its lists - at least for all PositionedObject-inheriting objects. A simple code example shows this functionality:
A two way relationship is a relationship between an object that implements the IAttachable interface and a class that inherits from the AttachableList class. Normally when objects are added to lists, the list stores any number of objects, but the objects themselves are not aware of which lists they belong to. These are known as "one-way" relationships: the knowledge of membership only exists in the list object. A two-way relationship, on the other hand, is one where the list stores all of its contained objects, and all of the contained objects are aware of all of the lists they belong to. When an IAttachable is added to an AttachableList, the following occurs:
The IAttachable is added to the collection of items that the AttachableList stores.
The IAttachable adds the AttachableList to its ListsBelongingTo list.
And similarly, when an IAttachable is removed from an AttachableList, the following occurs:
The AttachableList is removed from the IAttachable's ListsBelongingTo.
The IAttachable is removed from the AttachableList.
Two way relationships exist to eliminate scope problems when removing an IAttachable completely. The FlatRedBall Engine often uses AttachableLists internally to categorize Sprites. For example, Sprites which belong to the SpriteManager can be either automatically updated or manually updated. Each is stored in a different array. Similarly, it is common practice to create AttachableLists to organize objects by their behavior. Common examples include placing Polygons which represent triggers in a level in a PositionedObjectList or to organize player bullets and enemies in separate SpriteLists. A bullet and enemy SpriteList example clearly shows the kind of problems which can occur in the absence of two-way relationships. When a bullet collides with an enemy, it should be completely removed from the game. Not only does it have to be removed from any internal SpriteLists (such as lists in the SpriteManager), but also from the programmer-created list of bullets that it belongs to. In the absence of a two-way relationship, at least two calls would be required:
Remove the Sprite from the engine
Remove the Sprite from bullet list
This is inconvenient at best. It also requires code to be written in pairs (or more if an object is part of more lists). While the previous example highlights inconveniences, there is another practical reason for having two-way relationships. Sometimes the code that creates a PositionedObject and the code that destroys a PositionedObject may exist in two different areas of your project. The code that destroys a PositionedObject may not have access to all of the PositionedObjectLists that a given PositionedObject is a part of. The automatic removal enabled by two-way relationships enables removal without having to track down all lists. The two-way relationships between IAttachables and AttachableLists enables any method to remove objects from all lists both engine and user created through the use of globally-visible static managers such as the SpriteManager and TextManager. Simply calling Remove on an object's manager automatically removes it from all lists that it shares two-way relationships with. The following code creates a Sprite, adds it to the SpriteManager, adds it to a SpriteList, then removes it from the SpriteManager. Next the SpriteList is checked to see if it still has a reference to the Sprite. If it does, the application exits. Since it does not, your application will not exit.
IAttachables can also be added to AttachableLists creating one-way relationships using the AddOneWay method. In a one-way relationship, the AttachableList knows about its contained IAttachables, but the IAttachables do not know about their list. This is similar to how normal Arrays and Lists work. Usually one way relationships are useful when the scope of an AttachableList is brief - usually one frame or non-Main method. There are two common situations in which one-way AttachableLists are used:
Methods wich return AttachableLists usually fill them using AddOneWay. The assumption is that these lists will have a short lifespan.
Short-lifespan AttachableLists created outside of the engine should have elements added to them using one-way methods. Any AttachableList which has a lifespan of one frame or less should usually be populated using AddOneWay.
The reason for two-way relationships is to remove unused IAttachables from all AttachableLists which reference them. However, if an AttachableList has a short lifespan, then it will likely fall out of scope before any IAttachables that it references are removed. One reason to use one-way relationships for short-lifespan AttachableLists is to reduce the overhead of creating and managing two-way relationships. The Add method is slightly slower than AddOneWay as two-way relationships require two Add calls to internal List<> objects. Another reason is that additional references reduce the efficiency of the garbage collector. A third reason to avoid two-way relationships for short-lifespan AttachableLists is exemplified by the following code. First, consider what occurs when the following code is executed.
There are times when an AttachableList should be converted between a two-way and one-way AttachableList. One common scenario is when a one-way AttachableList returned from a method is going to be used for longer than one frame. In this example, all Sprites with the word "collision" in the first SpriteList are added to the second. Since FindSpritesWithNameContaining returns a one-way SpriteList, two-way relationships are created for all Sprites in the the second SpriteList.
Similarly, all AttachableLists have a MakeOneWay method which makes the relationship with all contained IAttachables one-way.
Using a foreach statement on an AttachableList will allocate memory. This is a very common gotcha when working with AttachableLists (and PositionedObjectLists). Consider the following to improve the performance of your application:
Did this article leave any questions unanswered? Post any question in our forums for a rapid response.
Now, consider the result of using AddOneWay instead of Add: