/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.Character.Abilities { using Opsive.UltimateCharacterController.Objects.CharacterAssist; using UnityEngine; /// /// The AlignToGravityZone ability will orient the character to the direction of the gravity zones. /// [DefaultStartType(AbilityStartType.Manual)] public class AlignToGravityZone : AlignToGravity { private GravityZone[] m_GravityZones; private int m_GravityZoneCount; /// /// Registers a GravityZone with the ability. /// /// The GravityZone that should be registered. public void RegisterGravityZone(GravityZone gravityZone) { if (m_GravityZones == null) { m_GravityZones = new GravityZone[1]; } else if (m_GravityZones.Length == m_GravityZoneCount) { System.Array.Resize(ref m_GravityZones, m_GravityZoneCount + 1); } m_GravityZones[m_GravityZoneCount] = gravityZone; m_GravityZoneCount++; if (!IsActive) { StartAbility(); } } /// /// Unregisters a GravityZone with the ability. /// /// The GravityZone that should be unregistered. public void UnregisterGravityZone(GravityZone gravityZone) { for (int i = 0; i < m_GravityZoneCount; ++i) { if (m_GravityZones[i] != gravityZone) { continue; } // Shift all of the array elements down one. for (int j = i; j < m_GravityZoneCount - 1; ++j) { m_GravityZones[j] = m_GravityZones[j + 1]; } m_GravityZoneCount--; m_GravityZones[m_GravityZoneCount] = null; break; } if (m_GravityZoneCount == 0) { StopAbility(); } } /// /// Update the rotation forces. /// public override void UpdateRotation() { var targetNormal = m_Stopping ? (m_StopGravityDirection.sqrMagnitude > 0 ? -m_StopGravityDirection : -m_CharacterLocomotion.GravityDirection) : Vector3.zero; if (!m_Stopping) { var position = m_Transform.position; for (int i = 0; i < m_GravityZoneCount; ++i) { // If the character is on the ground then only one gravity zone can influence the character. This will prevent the character from orienting to a different direction // while on the ground. if (m_CharacterLocomotion.Grounded) { var normal = m_GravityZones[i].DetermineGravityDirection(position); if (normal.sqrMagnitude > targetNormal.sqrMagnitude) { targetNormal = normal; } } else { // The character is not on the ground - use the average of all of the directions. targetNormal += m_GravityZones[i].DetermineGravityDirection(position); } } if (targetNormal.sqrMagnitude == 0) { return; } targetNormal.Normalize(); m_CharacterLocomotion.GravityDirection = -targetNormal; } Rotate(targetNormal); } /// /// The ability is trying to stop. Ensure the character ends at the correct orientation. /// public override void WillTryStopAbility() { // If the gravity zone count isn't 0 then the ability will not be able to stop. if (m_GravityZoneCount > 0) { return; } base.WillTryStopAbility(); } /// /// Can the ability be stopped? /// /// True if the ability can be stopped. public override bool CanStopAbility() { if (!base.CanStopAbility()) { return false; } return m_GravityZoneCount == 0; } /// /// Can the ability be force stopped? /// /// True if the ability can be force stopped. public override bool CanForceStopAbility() { if (!base.CanForceStopAbility()) { return false; } return m_GravityZoneCount == 0; } /// /// The ability has stopped running. /// /// Was the ability force stopped? protected override void AbilityStopped(bool force) { base.AbilityStopped(force); if (!m_CharacterLocomotion.IsAbilityTypeActive()) { ResetAlignToGravity(); } } } }