/// <summary> /// Attempts to calculate and update the transform. /// </summary> /// <param name="force"> /// <c>true</c> to force an update even if the same parent option is /// selected. The default is <c>false</c>. /// </param> public virtual void UpdateTransform(bool force = false) { // If there are no parent options, nothing to do if (parentOptions.Count == 0) { State = AlignmentState.Inhibited; Debug.LogWarning($"{nameof(MultiParentAlignment)}: No parent options to select from."); return; } // Validate the parent options ValidateParentOptions(); // Use virtual method to select the best parent option ParentAlignmentOptions parentOption = SelectParent(); // If no option could be found, fail if (parentOption == null) { State = AlignmentState.Inhibited; Debug.LogWarning($"{nameof(MultiParentAlignment)}: No parent could be found that meets the minimum criteria."); return; } else { // Actually apply the parent ApplyParent(parentOption, force: force); // Resolved State = AlignmentState.Tracking; } }
/// <summary> /// Applies the specified parent options to this object. /// </summary> /// <param name="parentOption"> /// The parent options to apply. /// </param> /// <param name="force"> /// <c>true</c> to force an update even if reusing the same option. /// The default is <c>false</c>. /// </param> /// <remarks> /// The default implementation of this method parents the transform /// and applies position, rotation and scale modifications. /// </remarks> protected virtual void ApplyParent(ParentAlignmentOptions parentOption, bool force = false) { // Validate if (parentOption == null) { throw new ArgumentNullException(nameof(parentOption)); } if (parentOption.Frame == null) { throw new InvalidOperationException($"{nameof(parentOption.Frame)} cannot be null."); } // If already parented to this object, no additional work needed if ((!force) && (currentParent == parentOption)) { return; } // Make our transform a child of the frame this.transform.SetParent(parentOption.Frame.transform, worldPositionStays: false); // Apply transform modifications this.transform.localPosition = parentOption.Position; this.transform.localRotation = Quaternion.Euler(parentOption.Rotation); this.transform.localScale = parentOption.Scale; // Notify of parent change CurrentParent = parentOption; // Done! }
/// <summary> /// Attempts to select the best parent option based on current settings. /// </summary> /// <returns> /// The <see cref="ParentAlignmentOptions"/> that represent the best parent, /// if found; otherwise <see langword = "null" />. /// </returns> /// <remarks> /// The default implementation examines all options where /// <see cref="ParentAlignmentOptions.IsValidTarget">IsValidTarget</see> /// returns <c>true</c> and selects the top option sorted by /// <see cref="ParentAlignmentOptions.SortOrder(Transform)">SortOrder</see>. /// </remarks> protected virtual ParentAlignmentOptions SelectParent() { // Attempt to get the reference transform Transform reference = GetReferenceTransform(); // If no transform, can't continue if (reference == null) { return(null); } // Placeholder ParentAlignmentOptions parentOption = null; // If only one parent option, always use that if (parentOptions.Count == 1) { // Use only parent option, if valid parentOption = (parentOptions[0].IsValidTarget() ? parentOptions[0] : null); } else { // Find the best valid parent, sorted by logic in the ParentAlignmentOption itself parentOption = (from o in ParentOptions where o.IsValidTarget() orderby o.SortOrder(reference) select o ).FirstOrDefault(); } // Done searching return(parentOption); }