/// <summary>
        /// Start the special mvoe
        /// </summary>
        override public void DoSpecialMove()
        {
            if (state == CeilingHangState.NONE)
            {
                state = CeilingHangState.HANG;
                character.SetVelocityX(0);
                character.SetVelocityY(0);
                character.Translate(0, yOffset, true);

                for (int i = 0; i < character.Colliders.Length; i++)
                {
                    if (character.Colliders[i].RaycastType == RaycastType.HEAD)
                    {
                        RaycastHit2D hit = character.GetClosestCollision(i);
                        if (hit.collider != null)
                        {
                            Platform tmpPlatform = hit.collider.GetComponent <Platform>();
                            if (tmpPlatform != null && !tmpPlatform.IgnoreCollision(character, character.Colliders[i]))
                            {
                                PlatformCollisionArgs platformCollisionArgs = new PlatformCollisionArgs();
                                platformCollisionArgs.Character       = character;
                                platformCollisionArgs.RaycastCollider = character.Colliders[i];
                                platformCollisionArgs.Penetration     = 0;
                                bool parent = tmpPlatform.Collide(platformCollisionArgs);
                                if (parent)
                                {
                                    character.ParentPlatform    = tmpPlatform;
                                    character.ParentRaycastType = RaycastType.HEAD;
                                }
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Start the special mvoe
 /// </summary>
 override public void DoSpecialMove()
 {
     if (state == CeilingHangState.NONE)
     {
         state = CeilingHangState.HANG;
         character.SetVelocityX(0);
         character.SetVelocityY(0);
         character.Translate(0, yOffset, true);
     }
 }
        /// <summary>
        /// Gets a value indicating whether this movement wants to do a special move.
        /// </summary>
        /// <returns><c>true</c>, if special move was wanted, <c>false</c> otherwise.</returns>
        override public bool WantsSpecialMove()
        {
            if (fallTimer > 0)
            {
                return(false);
            }
            if (state == CeilingHangState.DONE)
            {
                return(false);
            }
            if (state == CeilingHangState.NONE)
            {
                // TODO Reevalaute these conditions
                if ((character.PreviousVelocity.y >= -1.0f || character.Velocity.y >= 1.0f || character.ActiveMovement is SpecialMovement_GrapplingHook) && CheckHeadCollisions())
                {
                    if (hangableLayers == 0 ||
                        ((1 << (currentHeadCollider.gameObject.layer)) & (int)hangableLayers) == ((1 << currentHeadCollider.gameObject.layer)))
                    {
                        return(true);
                    }
                }
                return(false);
            }

            else if (state == CeilingHangState.HANG)
            {
                // Down to release
                if (character.Input.VerticalAxisDigital == -1)
                {
                    fallTimer = fallTime;
                    state     = CeilingHangState.DROP;
                    return(false);
                }
                // Up to climb (second condition not required but makes it easier to understand)
                if (canClimb &&
                    character.Input.VerticalAxisState == ButtonState.DOWN &&
                    character.Input.VerticalAxisDigital == 1 &&
                    (climbableLayers == 0 || ((1 << (currentHeadCollider.gameObject.layer)) & (int)climbableLayers) == ((1 << currentHeadCollider.gameObject.layer))))
                {
                    state = CeilingHangState.CLIMB_START;
                }
            }
            return(true);
        }
 /// <summary>
 /// Checks for animation state transition. I.e. when  state should be changed based on the
 /// animation state.
 /// </summary>
 virtual protected void CheckForAnimationStateTransition()
 {
     if (state == CeilingHangState.CLIMB_START)
     {
         AnimatorStateInfo info = myAnimator.GetCurrentAnimatorStateInfo(0);
         if (info.IsName(AnimationState.CEILING_CLIMB.AsString()))
         {
             character.Translate(climbStartOffset.x, climbStartOffset.y, true);
             state = CeilingHangState.CLIMBING;
         }
     }
     else if (state == CeilingHangState.CLIMBING)
     {
         AnimatorStateInfo info = myAnimator.GetCurrentAnimatorStateInfo(0);
         if (info.normalizedTime >= 1.0f)
         {
             state = CeilingHangState.LAUNCH_START;
         }
     }
     else if (state == CeilingHangState.LAUNCH_START)
     {
         AnimatorStateInfo info = myAnimator.GetCurrentAnimatorStateInfo(0);
         if (info.IsName(AnimationState.CEILING_CLIMB_LAUNCH.AsString()))
         {
             character.Translate(climbEndOffset.x, climbEndOffset.y, true);
             state = CeilingHangState.LAUNCH;
         }
     }
     else if (state == CeilingHangState.LAUNCH)
     {
         AnimatorStateInfo info = myAnimator.GetCurrentAnimatorStateInfo(0);
         if (info.normalizedTime >= 1.0f)
         {
             state = CeilingHangState.DONE;
         }
     }
 }
 /// <summary>
 /// Called when the movement loses control.
 /// </summary>
 override public void LosingControl()
 {
     state = CeilingHangState.NONE;
 }