The Detach method is called on a child IAttachable to detach it from its Parent. Calling Detach has two effects:
Sets the calling IAttachable's ParentAsIAttachable (or Parent if using a PositionedObject) to null.
Removes the calling IAttachble from its parent's ChildrenAsIAttachables list (or Children if using a PositionedObject).
Assuming that childObject is attached to something, you can detach its follows:
The ParentRotationChangesPosition property controls whether a child IAttachable's absolute Position is modified by its Parent's rotation. By default this value is true, meaning that when an IAttachable's parent rotates, its absolute position will be calculated using its relative position as well as the parent's RelativeRotationMatrix.
To understand when ParentRotationChangesPosition is a useful property, consider the following situation. A top-down tank game uses tanks which can rotate freely. Each tank should have a health bar shown above the tank. The health bar is attached to the tank for convenience; however when the tank rotates, the health bar moves around the tank. To keep the health bar above the tank regardless of the tank's orientation, the health bar's ParentRotationChangesPosition can be set to false. Also, setting the health bar's ParentRotationChangesRotation is also probably needed in this situation.
The TopParent property returns the root of the attachment hierarchy. If the object has no attachment, then its TopParent property will be equal to itself.
IAttachables provide properties and methods to control attachments.
An attachment is a relationship between two PositionedObjects in which one is identified as the parent object and one as the child object. The child object's absolute rotation and position values become read-only and its position and rotation are controlled by its parent's absolute position and rotation values as well as its own relative position and rotation values. The following examples highlight some of the uses of attachments:
Relatively positioned objects: There are certain objects which should always be positioned relative to another object, like wings on an airplane. It doesn't matter if the airplane is positioned at x = 0 or 50, nor does it matter if the plane is rotated. The wings should always appear in the same relative position to the airplane. Furthermore, we would like the wings to move with the airplane, so that we don't have to readjust their position every frame.
Orbits: Attached PositionedObjects do not have to be touching for the attachment to be valid. We could easily have one object orbit around another by attaching the orbiting PositionedObject to an invisible, spinning PositionedObject positioned at the center of the orbit.
The relative values in an IAttachable are effective only if an IAttachable has a parent. Otherwise they sit idle and do nothing to the IAttachable.
The following code creates two Sprites. The larger Sprite is the parent Sprite. The smaller Sprite is the child Sprite which is attached to the parent Sprite. Notice that attachments are created through the child and not the parent.
The AttachTo method creates a child-parent relationship between to IAttachables. The child IAttachable creates the relationship by calling AttachTo and passing the parent as the first argument. A parent can have any number of children, but a child can only have one parent. Calling AttachTo a second time breaks the first child-parent relationship and creates a new attachment between the calling instance and the instance passed as the first argument to the AttachTo method. The second argument determines whether relative values change, which also determines whether absolute values remain the same before and after the AttachTo call. For more information see the AttachTo page.
All IAttachables have relative versions of position, velocity, acceleration, rotation, and rotational velocity. Relative properties are named the same as their absolute counterparts prefixed with the word "Relative". If the IAttachable is a PositionedObject as is the case with Sprites, Cameras, Text objects, and Emitters, then the following relationships hold:
"Absolute" Property
"Relative" Property
X
RelativeX
Y
RelativeY
Z
RelativeZ
XVelocity
RelativeXVelocity
YVelocity
RelativeYVelocity
ZVelocity
RelativeZVelocity
XAcceleration
RelativeXAcceleration
YAcceleration
RelativeYAcceleration
ZAcceleration
RelativeZAcceleration
RotationX
RelativeRotationX
RotationY
RelativeRotationY
RotationZ
RelativeRotationZ
RotationXVelocity
RelativeRotationXVelocity
RotationYVelocity
RelativeRotationYVelocity
RotationZVelocity
RelativeRotationZVelocity
As mentioned before, if a PositionedObject has a parent, then its absolute values are read only. For example, consider the X (or Position.X) value. If an object has a parent, then its X position (ignoring rotation) is:
Therefore, if your code sets the X value, it will just get overwritten before rendering by the above code. This is the same for:
position
velocity
acceleration
rotation
rotational velocity.
While absolute position and rotation values are read-only, velocity and acceleration values should not be used at all. Let's examine why velocity is not usable. As mentioned above, attachments result in the absolute position being set every frame according to the Parent's absolute position and the child's relative position. That means that the Position variable is reset every frame. But the Velocity variable also changes the variable every frame. That means that both attachments and Velocity will modify the absolute position of your object. So what happens if you have a non-zero Velocity? The Velocity will add itself (considering time) every frame, but just before drawing, attachments will set the Position property - overriding the changes that occurred earlier in the frame when Velocity was applied. Reading Velocity can also be misleading because velocity is not by default a "reactive" property. That means that if an object is moved by its Parent, the Velocity property will not automatically update itself according to the movement performed due to the attachment. However, making velocity reactive is possible using "Real" values.
By default all PositionedObjects are positioned at their center (the exception to this is the Text object). This can be changed using attachments. First, let's look at the default center and points of rotation. We'll use a Sprite to show how this works (Sprite inherits from PositionedObject which implements IAttachable.
Stop right there! The code shown above for attaching is as brief as possible and simply shows the raw syntax behind attachments. However, you may be using Glue, and if so you shouldn't be writing the code above. Instead, you will likely have the above situation mostly set up - the PositionedObject will be the Entity itself and the Sprite will be a Sprite (or Entire Scene) Object in Glue. Instead of doing this in code, you should simply offset the Sprite in the SpriteEditor. Then when the Entity rotates, the Sprite will rotate about an offset naturally.
Two-way relationships - Explains how two-way relationships work between IAttachables and the lists they belong to.
Did this article leave any questions unanswered? Post any question in our forums for a rapid response.
Attachments are an effective way to keep one PositionedObject in a given position or rotation relative to another PositionedObject. However, attachments do not immediately modify children positions. This article will discuss when attachments are applied by the engine, exceptions to this rule, and how this behavior can be modified.
The following diagram shows a high-level view of the execution of a FlatRedBall game.
Attachment code is executed in three places:
FlatRedBallServices.Update - RelativeVelocity is applied to modify RelativePosition and RelativeAcceleration is applied to modify RelativeVelocity and RelativePosition. Although Relative values change in this call, they are not used to modify absolute values yet.
Game-Specific Update - Game-specific code creates attachments and modifies relative values. Modifying relative values does not result in absolute values being modified yet.
FlatRedBallServices.Draw - Just prior to drawing, all relative values are applied and absolute values are updated.
The important thing to note is that relative values do not immediately modify absolute values. For performance reasons, absolute values are modified according to relative values only once per frame.
Although the engine automatically updates absolute values according to relative values just before drawing, it may be necessary to perform this update in game-specific code. If so, the ForceUpdateDependencies method can be called. See the ForceUpdateDependencies code.
The ParentRotationChangesRotation property tells an object whether its rotation should be relative to its parent rotation. This is true by default but it can be set to false.
This code could be used to tell a health bar to not rotate when whatever it is attached to rotates:
Attachments create a relationship in which the child is both positioned and rotated relative to the parent. In some cases it is useful to suppress some of this behavior.
The ParentRotationChangesRotation property controls whether the rotation of a child is modified by the parents' rotation. In the following example the ship (represented by the red ball) rotates and moves according to input from the keyboard. The is attached to the but does not rotate with it.
Declare the ship at class scope:
In Initialize:
In Update:
As expected the Sprite rotates about its center. To change the point that the Sprite rotates about, we need to use an additional PositionedObject. We'll add a simple PositionedObject, attach the Sprite to it, then make the PositionedObject rotate. Notice that we must add the PositionedObject to the SpriteManager or else the RotationZVelocity member will not apply automatically.
Notice that although the is attached to the ship , it does not rotate. Try setting the ParentRotationChangesRotation property to true and observe the behavior.