/// <summary> /// Allows to update the transformation of the entity. Accounts for the /// hierachy and uses flags to only update properties which really /// need a refresh. /// </summary> /// <param name="gameTime">A snapshot of timing values.</param> public override void Update(GameTime gameTime) { // Iterate all available child nodes for (int i = 0, n = _children.Count; i != n; ++i) { // Cache the currently iterated child node TransformComponent child = _children[i]; // Enforce an transformation update on the child node if any // of the properties have been modified if (_propertyChangedFlag != PropertyChangedFlag.None) child._dirtyFlag |= DirtyFlags.Transform; // Allow the child component to do the same if (child.Enabled) child.Update(gameTime); } // Notify subscribers that some properties changed if ((_propertyChangedFlag & PropertyChangedFlag.Scale) != 0 || (_propertyChangedFlag & PropertyChangedFlag.Orientation) != 0 || (_propertyChangedFlag & PropertyChangedFlag.Translation) != 0) OnChanged(); // Notify subscribers that the position changed if ((_propertyChangedFlag & PropertyChangedFlag.Translation) != 0) OnPositionChanged(); // Notify subscribers that the orientation changed if ((_propertyChangedFlag & PropertyChangedFlag.Orientation) != 0) OnRotationChanged(); // Reset the property changed flag _propertyChangedFlag = PropertyChangedFlag.None; }
/// <summary> /// Rotates the entity around a certain axis. /// </summary> /// <param name="axis">The axis to rotate around.</param> /// <param name="radians">The angle in radians.</param> public void RotateAround(Vector3 axis, float radians) { // Perform rotation Quaternion rotate; Quaternion.CreateFromAxisAngle(ref axis, radians, out rotate); Quaternion.Multiply(ref _rotation, ref rotate, out _rotation); // Accumulate for numerical errors _rotation.Normalize(); // Force an update of dependent properties _dirtyFlag |= (DirtyFlags.LocalAxis | DirtyFlags.Transform); _propertyChangedFlag |= PropertyChangedFlag.Orientation; }
/// <summary> /// Rotates the entity using roll, yaw and pitch values. /// </summary> /// <param name="x">The angle used to roll the entity in radians (rotate around x-Axis).</param> /// <param name="y">The angle used to yaw the entity in radians (rotate around y-Axis).</param> /// <param name="z">The angle used to pitch the entity in radians (rotate around z-Axis).</param> /// <param name="space">The coordinate system that should be used to rotate the entity: local or world space.</param> public void Rotate(float x, float y, float z, TransformationSpace space) { // Perform rotation Quaternion rotate = Quaternion.CreateFromYawPitchRoll(y, x, z); switch (space) { case TransformationSpace.Local: Quaternion.Multiply(ref _rotation, ref rotate, out _rotation); break; case TransformationSpace.World: Quaternion.Multiply(ref rotate, ref _rotation, out _rotation); break; } // Accumulate for numerical errors _rotation.Normalize(); // Force an update of dependent properties _dirtyFlag |= (DirtyFlags.LocalAxis | DirtyFlags.Transform); _propertyChangedFlag |= PropertyChangedFlag.Orientation; }
/// <summary> /// Resets the current component to its original state. /// </summary> public void Reset() { _scale = Vector3.One; _rotation = Quaternion.Identity; _translation = Vector3.Zero; _dirtyFlag = DirtyFlags.All; _propertyChangedFlag = PropertyChangedFlag.All; }
/// <summary> /// Moves the entity the specified amount into the specified /// direction. /// </summary> /// <param name="direction">The direction to move.</param> /// <param name="amount">The amount to move the entity into that direction.</param> /// <param name="space">The coordinate system that should be used to move the entity: local or world space.</param> public void Move(Vector3 direction, float amount, TransformationSpace space) { if (space == TransformationSpace.Local) { Vector3.Transform(ref direction, ref _rotation, out direction); direction.Normalize(); } _translation += direction * amount; _dirtyFlag |= DirtyFlags.Transform; _propertyChangedFlag |= PropertyChangedFlag.Translation; }
/// <summary> /// Forces the entity to look at the specified target position. /// </summary> /// <param name="target">The position to look at.</param> /// <param name="up">A vector which specifies the up direction of the entity.</param> public void LookAt(Vector3 target, Vector3 up) { // Calculate the new facing vector Vector3 forward = Vector3.Normalize(target - _translation); // Calculate the rotation axis Vector3 rotationAxis = Vector3.Normalize(Vector3.Cross(Forward, forward)); // Calculate the dot product which will be used to calculate the // rotation angle float dotProduct = Vector3.Dot(Forward, forward); // Ensure that the two forward vectors do not point in opposite // directions if (Math.Abs(dotProduct + 1f) < float.Epsilon) _rotation = new Quaternion(up, MathHelper.Pi); // Ensure that both forward vectors do not point in the same // direction else if (Math.Abs(dotProduct - 1f) < float.Epsilon) _rotation = Quaternion.Identity; // Calculate the absolute rotation to look at the target point else Quaternion.CreateFromAxisAngle(ref rotationAxis, (float)Math.Acos(dotProduct), out _rotation); // Force an update of dependent properties _dirtyFlag |= (DirtyFlags.LocalAxis | DirtyFlags.Transform); _propertyChangedFlag |= PropertyChangedFlag.Orientation; }