
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

using System;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework;
using GE.Message;
using GE.Input;
using GE.TimeClock;
using GE.Visualisation;
using GE.Physics.Shapes;
using GE.Physics;
using GE.Gui.Hud;
using GE.Manager;

namespace GE.World.Entities
{

    /// <summary>
    /// The player
    /// </summary>
    class PlayerEntity : WorldEntity
    {
        #region Enum

        /// <summary>
        /// Enumeration of the player's different states
        /// </summary>
        enum ePlayerState
        {
            Idle =          0x00000001,             //the player is not moving
            Run =           0x00000002,             //the player runs
            Jump =          0x00000004,             //the player jumps
            Fall =          0x00000008,             //the player falls
            StartDash =     0x00000010,            //The player starts to dash
            Dash =          0x00000020,            //The player is dashing
            StopDash =      0x00000040,            //The player stop the dash
            WallLanding =   0x00000080,            //The player jumped on the wall
            WallSliding =   0x00000100,            //The player slides down a wall
            WallJump =      0x00000200,            //Jumping from a wall slide
            IdleShoot =     0x00000400,            //the player shoots while he is not doing anything
            RunShoot =      0x00000800,            //the player shoots while running
            JumpShoot =     0x00001000,            //the player shoots while jumping
            FallShoot =     0x00002000,            //the player shoots while jumping
            WallShoot =     0x00004000,            //the player shoots while sliding on a wall
            Climb =         0x00008000,            //the player climbs a ladder
            Hurt =          0x00010000,            //the player is getting hurt
            StartMission =  0x00020000,             //Start the level
            Dead =          0x00040000,             //the player is dead
            GameOver =      0x00080000,             //game over
            Teleport  =     0x00100000,             //Zero teleports itself in the level
            StateCount
        }

        /// <summary>
        /// Represent the direction the player is facing
        /// </summary>
        enum ePlayerDirection
        {
            eDirectionLeft = -1,
            eDirectionRight = 1
        }

        /// <summary>
        /// List of animations
        /// </summary>
        enum eAnimationIndex
        {
            eAnimIDRunRight,
            eAnimIDIdleRight,
            eAnimIDJumpRight,
            eAnimIDFallRight,
            eAnimIDStartDashRight,
            eAnimIDDashRight,
            eAnimIDStopDashRight,
            eAnimIDWallLandRight,
            eAnimIDWallLoopRight,
            eAnimIDWallJumpRight,
            eAnimIDIdleShootRight,
            eAnimIDJumpOrFallShootRight,
            eAnimIDWallShootRight,
            eAnimIDClimb,
            eAnimIDHurtRight,
            eAnimIdMissionStart,
            eAnimIdMissionFailed,
            eAnimIdGameOver,
            eAnimIdTeleportRight,
            eAnimCount
        }
        #endregion

        #region States Structures

        /// <summary>
        /// Structure containing all the data used by the state Run and shoot
        /// </summary>
        struct structStateRunShoot
        {
            public int _iFrameStart;
        }

        /// <summary>
        /// Structure containing all the data used by the state climb
        /// </summary>
        struct structStateClimb
        {
            public bool _bClimbUp;
            public bool _bClimbDown;
            public bool _bClimbIdle;
            public LadderEntity _entityLadder;

            public void setClimbUp()
            {
                _bClimbDown = false;
                _bClimbIdle = false;
                _bClimbUp = true;
            }

            public void setClimbDown()
            {
                _bClimbDown = true;
                _bClimbIdle = false;
                _bClimbUp = false;
            }

            public void setClimbIdle()
            {
                _bClimbDown = false;
                _bClimbIdle = true;
                _bClimbUp = false;
            }
        }

        #endregion

        #region Variables

        /// <summary>
        /// Data used by the state climb
        /// </summary>
        structStateClimb _structClimb;

        /// <summary>
        /// Data used by the state run and shoot
        /// </summary>
        structStateRunShoot _structRunShoot;

        /// <summary>
        /// Array for the special animations (whe nthe player is shooting and running at the same time)
        /// </summary>
        int[] _iRunShootAnimationID;

        /// <summary>
        /// Flag set when the player has to shoot once more
        /// </summary>
        bool _bShootAgain;

        /// <summary>
        /// Lifetime for the state dead
        /// </summary>
        const int LIFETIME_STATE_DEAD = 3000;

        /// <summary>
        /// The current state birth time
        /// </summary>
        int _iBirthTimeState;

        /// <summary>
        /// Sprite mission failed
        /// </summary>
        int _iIdSpriteMissionFailed;

        /// <summary>
        /// Texture mission failed
        /// </summary>
        int _iIdTextureMissionFailed;

        /// <summary>
        /// Position for the mission start and mission failed animation
        /// </summary>
        Vector2 _v2MissionAnimationPosition;

        /// <summary>
        /// Position for the game over position
        /// </summary>
        Vector2 _v2GameOverPosition;

        /// <summary>
        /// Total health
        /// </summary>
        int _iTotalHealth;

        /// <summary>
        /// Position offset for the explosion animation
        /// </summary>
        Vector2 _v2AnimationExplosionOffset;

        /// <summary>
        /// Explosion id
        /// </summary>
        int _iIdAnimationExplosion;

        /// <summary>
        /// Time to spend between swapping tint color when invicible
        /// </summary>
        int _iTimeBetweenSwapTintColor;

        /// <summary>
        /// Last time the tint color was changed
        /// </summary>
        int _iLastTimeChangeTintColor;

        /// <summary>
        /// Tint color used to display animations and sprites
        /// </summary>
        Color _tintColor;

        /// <summary>
        /// Last time the player was hurt
        /// </summary>
        int _iLastTimeHurt;

        /// <summary>
        /// Time the player is invicible after the hurt state
        /// </summary>
        int _iTimeInvicibleAfterHurt;

        /// <summary>
        /// Flag set whe nthe player is invicible
        /// </summary>
        bool _bInvicible;

        /// <summary>
        /// Array of flags set when a button was pressed
        /// </summary>
        bool[] _bInputGameActionPressed;

        /// <summary>
        /// Array of falgs set when the button was released
        /// </summary>
        bool[] _bInputGameActionReleased;

        /// <summary>
        /// Bullet texture
        /// </summary>
        int _iIdTextureBullet;

        /// <summary>
        /// Bullet sprite
        /// </summary>
        int _iIdSpriteBullet;

        /// <summary>
        /// Ground entity the player is idling on or running on
        /// </summary>
        WorldEntity _entityGround;

        /// <summary>
        /// Flag set when a collision gotta be ignored
        /// </summary>
        bool _bIgnoreCollision;

        /// <summary>
        /// Array containing the animation ids
        /// </summary>
        int[] _iAnimationId;

        /// <summary>
        /// Running speed of the player
        /// </summary>
        Vector2 _v2RunningSpeed = new Vector2(3, 0);

        /// <summary>
        /// Animation to display
        /// </summary>
        ePlayerState _playerState;

        /// <summary>
        /// Current frame of animation displayed
        /// </summary>
        int _iAnimationCurrentFrame;

        /// <summary>
        /// Current elapsed time for the current animation's frame
        /// </summary>
        int _iAnimationCurrentTime;

        /// <summary>
        /// The direction the player is facing
        /// </summary>
        ePlayerDirection _playerDirection;

        /// <summary>
        /// Physic shape used to apply physics and collision to the player
        /// </summary>
        DynamicShapeRectangle _dshPhysicShape;

        /// <summary>
        /// Falling speed 
        /// </summary>
        Vector2 _v2FallingSpeed = new Vector2(0, 4);

        /// <summary>
        /// Jumping speed
        /// </summary>
        Vector2 _v2JumpingSpeed = new Vector2(0, -5);

        /// <summary>
        /// Flag for the prestate event. It means the player just got into a new state
        /// </summary>
        bool _bPreState;

        /// <summary>
        /// Falg to true when an animation is over
        /// </summary>
        bool _bAnimationOver;

        /// <summary>
        /// The start time of the jump (used to calculate the slow down in the jump speed)
        /// </summary>
        int _iJumpStartTime;

        /// <summary>
        /// The time to make a jump
        /// </summary>
        int _iJumpTime;

        /// <summary>
        /// Player's Dashing speed
        /// </summary>
        Vector2 _v2DashingSpeed = new Vector2(6, 0);

        /// <summary>
        /// The start the dash started
        /// </summary>
        int _iDashStartTime;

        /// <summary>
        /// The total time of a dash
        /// </summary>
        int _iDashTime;

        /// <summary>
        /// One third of the total time of dash
        /// </summary>
        int _iOneThirdDashTime;

        /// <summary>
        /// Two third of the total time of dash
        /// </summary>
        int _iTwoThirdDashTime;

        /// <summary>
        /// Player's speed falling along a wall
        /// </summary>
        Vector2 _v2WallFallingSpeed = new Vector2(0, 2);

        /// <summary>
        /// Start time of the wall jump
        /// </summary>
        int _iWallJumpStartTime;

        /// <summary>
        /// Total time of a wall jump
        /// </summary>
        int _iWallJumpTime;

        /// <summary>
        /// Up speed for a wall jump
        /// </summary>
        Vector2 _v2WallJumpingUpSpeed = new Vector2(0, -7);

        /// <summary>
        /// Side speed for a wall jump
        /// </summary>
        Vector2 _v2WallJumpingSideSpeed = new Vector2(1, 0);

        /// <summary>
        /// Save the dash frame
        /// </summary>
        int _iDashCurrentFrame;

        /// <summary>
        /// Store the previous frame to display the dash effect
        /// </summary>
        Vector2[] _v2DashPreviousFramePosition;

        /// <summary>
        /// Physic group to test collision with platforms only
        /// </summary>
        const int PHYSIC_GROUP_PLATFORM = (0xFFFFFF ^ (int)ePhysicGroup.ePhysicLadder) ^ (int)ePhysicGroup.ePhysicEnemy ^ (int)ePhysicGroup.ePhysicSpike;

        /// <summary>
        /// Physic groupfor the gravity
        /// </summary>
        const int STATE_GROUP_GRAVITY = (0xFFFFFF ^ (int)ePlayerState.Jump) ^ 
            (int)ePlayerState.JumpShoot ^ (int) ePlayerState.Hurt ^ (int)ePlayerState.Climb ^(int)ePlayerState.Fall ^
            (int)ePlayerState.FallShoot ^ (int)ePlayerState.WallLanding ^ (int)ePlayerState.WallSliding ^
            (int)ePlayerState.WallShoot ^ (int)ePlayerState.WallJump ^ (int)ePlayerState.StartMission ^ (int)ePlayerState.Teleport ^
            (int)ePlayerState.Dead ^ (int)ePlayerState.GameOver;

        #endregion

        #region Properties

        /// <summary>
        /// Get or set the total life
        /// </summary>
        public int TotalHealthPoint { set { _iTotalHealth = value; } get { return _iTotalHealth; } }

#if !GAME
        /// <summary>
        /// Property for the level editor, not used in the game
        /// </summary>
        public static string EDITOR_TILESET { get { return "zero_z1standardframes.xml"; } }
        public static string EDITOR_SPRITE { get { return "zero_idle_0"; } }
        
#endif
        #endregion

        /// <summary>
        /// set the position to the entity and to the shape
        /// </summary>
        /// <param name="newPos"></param>
        private void setPosition(Vector2 newPos)
        {
            _v2Position = newPos;
            _dshPhysicShape._v2position = newPos;
        }

        /// <summary>
        /// shoot a bullet
        /// </summary>
        /// <param name="spawnPosition">positon to spawn the bullet</param>
        /// <param name="direction">direction of the bullet</param>
        private void shoot(Vector2 spawnPosition, int direction)
        {
            BulletManager.Instance.activate(_iIdTextureBullet, _iIdSpriteBullet, 400, Damages, Vector2.UnitX * direction * 10, spawnPosition, eSide.eSidePlayer);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public PlayerEntity()
        {
            _structClimb = new structStateClimb();
            _structRunShoot = new structStateRunShoot();

            _bInputGameActionPressed = new bool[(int)GameAction.GameActionCount];
            _bInputGameActionReleased = new bool[(int)GameAction.GameActionCount];

            _entityType = eEntityType.eEntityPlayer;
            _playerState = ePlayerState.StartMission;
            _playerDirection = ePlayerDirection.eDirectionRight;
            _iAnimationCurrentFrame = -1;
            _iAnimationCurrentTime = -1;
            _iLastTimeHurt = -1;
            _iTimeInvicibleAfterHurt = 1000;
            _iTimeBetweenSwapTintColor = 100;
            _tintColor = Color.White;
            _bInvicible = false;
            
            _v2AnimationExplosionOffset = new Vector2(15, 18);

            _playerDirection = ePlayerDirection.eDirectionRight;
            
            _v2DashPreviousFramePosition = new Vector2[3];

            _bPreState = true;
            _iTotalHealth = 0;
            HP = 0;
  
        }

        /// <summary>
        /// Initialise the player entity
        /// </summary>
        public override void init()
        {
            //animation loading
            _iAnimationId = new int[(int)eAnimationIndex.eAnimCount];
            _iAnimationId[(int)eAnimationIndex.eAnimIDRunRight] = Visu.Instance.getAnimationID("Zero_Run");
            _iAnimationId[(int)eAnimationIndex.eAnimIDIdleRight] = Visu.Instance.getAnimationID("Zero_Idle");
            _iAnimationId[(int)eAnimationIndex.eAnimIDJumpRight] = Visu.Instance.getAnimationID("Zero_Jump");
            _iAnimationId[(int)eAnimationIndex.eAnimIDFallRight] = Visu.Instance.getAnimationID("Zero_Fall");
            _iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight] = Visu.Instance.getAnimationID("Zero_StartDash");
            _iAnimationId[(int)eAnimationIndex.eAnimIDDashRight] = Visu.Instance.getAnimationID("Zero_Dash");
            _iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight] = Visu.Instance.getAnimationID("Zero_StopDash");
            _iAnimationId[(int)eAnimationIndex.eAnimIDWallLandRight] = Visu.Instance.getAnimationID("Zero_Wallhang_Land");
            _iAnimationId[(int)eAnimationIndex.eAnimIDWallLoopRight] = Visu.Instance.getAnimationID("Zero_Wallhang_Loop");
            _iAnimationId[(int)eAnimationIndex.eAnimIDWallJumpRight] = Visu.Instance.getAnimationID("Zero_Walljump");
            _iAnimationId[(int)eAnimationIndex.eAnimIDIdleShootRight] = Visu.Instance.getAnimationID("Zero_Idle_Shoot");
            _iAnimationId[(int)eAnimationIndex.eAnimIDJumpOrFallShootRight] = Visu.Instance.getAnimationID("Zero_Jump_Shoot");
            _iAnimationId[(int)eAnimationIndex.eAnimIDWallShootRight] = Visu.Instance.getAnimationID("Zero_Wall_Shoot");
            _iAnimationId[(int)eAnimationIndex.eAnimIDClimb] = Visu.Instance.getAnimationID("Zero_Climb");
            _iAnimationId[(int)eAnimationIndex.eAnimIDHurtRight] = Visu.Instance.getAnimationID("Zero_Hurt");
            _iAnimationId[(int)eAnimationIndex.eAnimIdMissionStart] = Visu.Instance.getAnimationID("Mission_Start");
            _iAnimationId[(int)eAnimationIndex.eAnimIdMissionFailed] = Visu.Instance.getAnimationID("Mission_Failed");
            _iAnimationId[(int)eAnimationIndex.eAnimIdTeleportRight] = Visu.Instance.getAnimationID("Zero_Teleport");

            _iRunShootAnimationID = new int[10];
            _iRunShootAnimationID[0] = Visu.Instance.getAnimationID("Zero_Run_Shoot_0");
            _iRunShootAnimationID[1] = Visu.Instance.getAnimationID("Zero_Run_Shoot_1");
            _iRunShootAnimationID[2] = Visu.Instance.getAnimationID("Zero_Run_Shoot_2");
            _iRunShootAnimationID[3] = Visu.Instance.getAnimationID("Zero_Run_Shoot_3");
            _iRunShootAnimationID[4] = Visu.Instance.getAnimationID("Zero_Run_Shoot_4");
            _iRunShootAnimationID[5] = Visu.Instance.getAnimationID("Zero_Run_Shoot_5");
            _iRunShootAnimationID[6] = Visu.Instance.getAnimationID("Zero_Run_Shoot_6");
            _iRunShootAnimationID[7] = Visu.Instance.getAnimationID("Zero_Run_Shoot_7");
            _iRunShootAnimationID[8] = Visu.Instance.getAnimationID("Zero_Run_Shoot_8");
            _iRunShootAnimationID[9] = Visu.Instance.getAnimationID("Zero_Run_Shoot_9");

            _iIdTextureBullet = Visu.Instance.loadTilset("enemysheet.xml");
            _iIdSpriteBullet = Visu.Instance.getSpriteId(_iIdTextureBullet, "zero_bullet");

            _iIdAnimationExplosion = Visu.Instance.getAnimationID("Big_Explosion");

            _iIdTextureMissionFailed = Visu.Instance.loadTilset("missionsheet.xml");
            _iIdSpriteMissionFailed = Visu.Instance.getSpriteId(_iIdTextureMissionFailed, "mission_failed_9");

            Animation anim = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDJumpRight]);
            _iJumpTime = anim.FrameCount * anim.offsetTime;

            anim = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight]);
            _iDashTime = anim.FrameCount * anim.offsetTime;
            _iOneThirdDashTime = _iDashTime / 3;
            _iTwoThirdDashTime = 2 * _iOneThirdDashTime;

            anim = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDWallJumpRight]);
            _iWallJumpTime = anim.FrameCount * anim.offsetTime;

            //calculate the position for the mission start and mission failed animations
            int idTexture = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIdMissionStart]).indexTexture;
            int idSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIdMissionStart]).idFirstSprite;
            int iWidth = Visu.Instance.getSpriteWidth(idTexture, idSprite);
            int iHeight = Visu.Instance.getSpriteHeight(idTexture, idSprite);

            _v2MissionAnimationPosition = new Vector2(Visu.Instance.ScreenWidth / 2 - iWidth / 2, Visu.Instance.ScreenHeight / 2);

            //calculate the position for the game over animation
            idTexture = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIdGameOver]).indexTexture;
            idSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIdGameOver]).idFirstSprite;
            iWidth = Visu.Instance.getSpriteWidth(idTexture, idSprite);
            iHeight = Visu.Instance.getSpriteHeight(idTexture, idSprite);

            _v2GameOverPosition = new Vector2(Visu.Instance.ScreenWidth / 2 - iWidth / 2, Visu.Instance.ScreenHeight / 2);

            //calculate the physic shape
            _dshPhysicShape = (DynamicShapeRectangle)Physics.Physics.Instance.createDynamicRectangle(30, 37, new Vector2(-3, 0), this);
            _dshPhysicShape._bCollisionEnable = true;
            _dshPhysicShape._iGroup = (int)ePhysicGroup.ePhysicPlayer;
            base.init();
        }

        /// <summary>
        /// Activate the entity
        /// </summary>
        public override void activate()
        {
            _bActive = true;
            _dshPhysicShape._bCollisionEnable = true;
        }

        /// <summary>
        /// Update the inputs
        /// </summary>
        private void updateInputs()
        {
            foreach (Message.Message m in MessageSystem.Instance.getList(MessageReceiver.World))
            {
                //if the messages are from the inputs
                if (m.Type == MessageType.Input)
                {
                    bool bPressed = (m.C == 0) ? false : true;
                    _bInputGameActionPressed[(int)m.A] = bPressed;

                    if (!bPressed) _bInputGameActionReleased[(int)m.A] = true;
                }
                MessageSystem.Instance.popMessage(m.Index);
            }
        }

        /// <summary>
        /// update the invicible state
        /// </summary>
        private void updateInvicible()
        {
            if (!_bInvicible) return;

            //invicible time over
            if (TimeClock.Clock.instance.millisecs > _iTimeInvicibleAfterHurt + _iLastTimeHurt)
            {
                _bInvicible = false;
                _tintColor = Color.White;
            }
            else
            {
                if (TimeClock.Clock.instance.millisecs > _iLastTimeChangeTintColor + _iTimeBetweenSwapTintColor)
                {
                    _iLastTimeChangeTintColor = TimeClock.Clock.instance.millisecs;
                    if (_tintColor == Color.White)
                        _tintColor = Color.Transparent;
                    else
                        _tintColor = Color.White;

                }
            }
            
        }

        /// <summary>
        /// apply the gravitiy
        /// </summary>
        private void updateGravity()
        {
            if (((int)_playerState & STATE_GROUP_GRAVITY) != 0)
            {
                setPosition(Position + _v2FallingSpeed);

                //collision test with every group except ladders and enemies
                const int PHYSIC_GROUP = (0xFFFFFF ^ (int)ePhysicGroup.ePhysicLadder) ^ (int)ePhysicGroup.ePhysicEnemy;
                CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP);
                if (res != null)
                {
                    _entityGround = res.Entity;
                    if (res.Overlap.Y >= 0)
                        setPosition(_v2PreviousPosition);
                    else
                        setPosition(Position + new Vector2(0, res.Overlap.Y));

                }
                else
                {
                    changePlayerState(ePlayerState.Fall);
                }
            }
        }

        /// <summary>
        /// Update the player
        /// </summary>
        public override void update()
        {
            //save the previous position
            _v2PreviousPosition = _v2Position;

            //update the invicible state
            updateInvicible();

            //update inputs
            updateInputs();

            //apply gravity
            updateGravity();

            //update the current state
            switch (_playerState)
            {
                case ePlayerState.Dead:
                    updateStateDead();
                    break;

                case ePlayerState.Teleport:
                    updateStateTeleport();
                    break;

                case ePlayerState.StartMission:
                    updateStateStartMission();
                    break;

                case ePlayerState.Fall:
                    updateStateFall();
                    break;
                case ePlayerState.FallShoot:
                    updateStateFallShoot();
                    break;
                case ePlayerState.Idle:
                    updateStateIdle();
                    break;
                case ePlayerState.Run:
                    updateStateRun();
                    break;
                case ePlayerState.RunShoot:
                    updateStateRunShoot();
                    break;
                case ePlayerState.Jump:
                    updateStateJump();
                    break;
                case ePlayerState.JumpShoot:
                    updateStateJumpShoot();
                    break;
                case ePlayerState.StartDash:
                    updateStateStartDash();
                    break;
                case ePlayerState.Dash:
                    updateStateDash();
                    break;
                case ePlayerState.StopDash:
                    updateStateStopDash();
                    break;
                case ePlayerState.WallLanding:
                    updateStateWallLanding();
                    break;
                case ePlayerState.WallSliding:
                    updateStateWallSliding();
                    break;
                case ePlayerState.WallShoot:
                    updateStateWallShoot();
                    break;
                case ePlayerState.WallJump:
                    updateStateWallJump();
                    break;
                case ePlayerState.IdleShoot:
                    updateStateIdleShoot();
                    break;
                case ePlayerState.Climb:
                    updateStateClimb();
                    break;
                case ePlayerState.Hurt:
                    updateStateHurt();
                    break;
            }
        }

        /// <summary>
        /// Change the state of the player and reset the variables to valid values
        /// </summary>
        /// <param name="newState"></param>
        private void changePlayerState(ePlayerState newState)
        {
            _iAnimationCurrentFrame = -1;
            _iAnimationCurrentTime = -1;
            _playerState = newState;
            _bPreState = true;
        }

        /// <summary>
        /// Hurt the player and apply the damages
        /// </summary>
        /// <param name="damages"></param>
        public override void hurt(int damages)
        {
            if (_playerState == ePlayerState.Hurt) return;
            if (_bInvicible) return;

            changePlayerState(ePlayerState.Hurt);

            _iHealthPoint -= damages;
            if (_iHealthPoint <= 0) die();
        }

        /// <summary>
        /// Update the state dead
        /// </summary>
        private void updateStateDead()
        {
            if (_bPreState)
            {
                _bPreState = false;
                _iBirthTimeState = Clock.instance.millisecs;
            }

            if (Clock.instance.millisecs > _iBirthTimeState + LIFETIME_STATE_DEAD) 
                World.Instance.goToMainMenu();
        }

        /// <summary>
        /// Update the state teleport
        /// </summary>
        private void updateStateTeleport()
        {
            if (_bAnimationOver)
                changePlayerState(ePlayerState.Idle);
        }

        /// <summary>
        /// Update the state Mission start
        /// </summary>
        private void updateStateStartMission()
        {
            if (_bAnimationOver)
                changePlayerState(ePlayerState.Teleport);
        }

        /// <summary>
        /// Update the player when its state is hurt
        /// </summary>
        private void updateStateHurt()
        {
            //if the animation is over, quit the hurt state
            if (_bAnimationOver)
            {
                _bInvicible = true;
                _iLastTimeHurt = TimeClock.Clock.instance.millisecs;
                _iLastTimeChangeTintColor = _iLastTimeHurt;
                changePlayerState(ePlayerState.Fall);
            }

            //move the player
            int speedSide = 1;
            float speedUp = -0.2f;
            if (_playerDirection == ePlayerDirection.eDirectionRight)
                setPosition(Position + new Vector2(-speedSide, speedUp));
            else
                setPosition(Position + new Vector2(speedSide, speedUp));

            //check collision
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, (int)ePhysicGroup.ePhysicPlatform);
            if (res != null) setPosition(Position + res.Overlap);
        }

        /// <summary>
        /// Update the player when its state is WallJump
        /// </summary>
        private void updateStateWallJump()
        {
            if (_bPreState)
            {
                _bPreState = true;
                _bInputGameActionReleased[(int)GameAction.Jump] = false;
            }

            //the player entered this state
            if (_bPreState)
            {
                _bPreState = false;
                _bAnimationOver = false;
                _iWallJumpStartTime = Clock.instance.millisecs;
            }

            //the animation is over so the jump is over
            if (_bAnimationOver)
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }

            //Jump!!!!!!!!!!!!!!!!!!!!!
            int iElapsedTime = Clock.instance.millisecs - _iWallJumpStartTime; //elapsed time since the beginning of the jump

            //calculate the interpolation value to interpolate the jumping speed between [_v2JumpingSpeed; 0]
            float ratio = 1 - (float)iElapsedTime / (float)_iWallJumpTime;
            setPosition(Position + _v2WallJumpingUpSpeed * ratio); //apply the jump

            //push away from the wall
            if (_playerDirection == ePlayerDirection.eDirectionLeft)
                setPosition(Position + _v2WallJumpingSideSpeed);
            else
                setPosition(Position - _v2WallJumpingSideSpeed);

            //check collision
            CollisionResult w = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (w != null)//collision, so fall
            {
                setPosition(_v2PreviousPosition);
                changePlayerState(ePlayerState.Fall);
                return;
            }
        }

        /// <summary>
        /// Update the player when its state is WallSliding
        /// </summary>
        private void updateStateWallSliding()
        {

            //if the player don't press a direction, the player fall
            if (_playerDirection == ePlayerDirection.eDirectionLeft && !_bInputGameActionPressed[(int)GameAction.Left])
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }
            if (_playerDirection == ePlayerDirection.eDirectionRight && !_bInputGameActionPressed[(int)GameAction.Right])
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }

            //check if there is still a wall
            if (_bInputGameActionPressed[(int)GameAction.Left])
                setPosition(Position - _v2RunningSpeed);
            else
                setPosition(Position + _v2RunningSpeed);

            const int PHYSIC_GROUP = 0xFFFFFF ^ (int)ePhysicGroup.ePhysicLadder;
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
            else
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }

            //check for wall jump
            if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.WallJump);
                return;
            }
            
            //then we slides down
            setPosition(Position + _v2WallFallingSpeed);
            res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP);
            if (res != null)
            {
                //Position = _v2PreviousPosition;
                setPosition(Position + res.Overlap);
                changePlayerState(ePlayerState.Idle);
                return;
            }

            //shoot
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
            {
                changePlayerState(ePlayerState.WallShoot);
                return;
            }
        }

        private void updateStateWallShoot()
        {
            if (_bPreState)
            {
                _bPreState = false;
                _bInputGameActionReleased[(int)GameAction.Attack] = false;
                _bShootAgain = false;

                Vector2 spawnPosition = Position;
                int Y = 20;
                int X = 30;
                if (_playerDirection == ePlayerDirection.eDirectionRight)
                    spawnPosition += new Vector2(0, Y);
                else
                    spawnPosition += new Vector2(X, Y);
                shoot(spawnPosition, (int)_playerDirection * -1);
            }

            //shoot again
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                _bShootAgain = true;

            //if the player don't press a direction, the player fall
            if (_playerDirection == ePlayerDirection.eDirectionLeft && !_bInputGameActionPressed[(int)GameAction.Left])
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.FallShoot);
                else
                    changePlayerState(ePlayerState.Fall);
                return;
            }
            if (_playerDirection == ePlayerDirection.eDirectionRight && !_bInputGameActionPressed[(int)GameAction.Right])
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.FallShoot);
                else
                    changePlayerState(ePlayerState.Fall);
                return;
            }
            

            //check if there is still a wall
            if (_bInputGameActionPressed[(int)GameAction.Left])
                setPosition(Position - _v2RunningSpeed);
            else
                setPosition(Position + _v2RunningSpeed);
            CollisionResult res = Physics.Physics.Instance.checkRegisteredCollisionEx(_dshPhysicShape);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
            else
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.FallShoot);
                else
                    changePlayerState(ePlayerState.Fall);
                return;
            }

            //check for wall jump
            if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.WallJump);
                return;
            }

            //then we slides down
            setPosition(Position + _v2WallFallingSpeed);
            res = Physics.Physics.Instance.checkRegisteredCollisionEx(_dshPhysicShape);
            if (res != null)
            {
                
                setPosition(Position + res.Overlap);
                if (_bShootAgain)
                    changePlayerState(ePlayerState.IdleShoot);
                else
                    changePlayerState(ePlayerState.Idle);
            }

            if (_bAnimationOver)
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.WallShoot);
                else
                    changePlayerState(ePlayerState.WallSliding);
            }
        }

        /// <summary>
        /// Update the player when its state is WallLanding
        /// </summary>
        private void updateStateWallLanding()
        {
            
            //if the player don't press a direction, the player fall
            if (_playerDirection == ePlayerDirection.eDirectionLeft && !_bInputGameActionPressed[(int)GameAction.Left])
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }
            if (_playerDirection == ePlayerDirection.eDirectionRight && !_bInputGameActionPressed[(int)GameAction.Right])
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }

            //when the landing is over we slide down the wall
            if (_bAnimationOver)
            {
                changePlayerState(ePlayerState.WallSliding);
                return;
            }

            //check if there is still a wall
            if (_bInputGameActionPressed[(int)GameAction.Left])
                setPosition(Position - _v2RunningSpeed);
            else
                setPosition(Position + _v2RunningSpeed);
            const int PHYSIC_GROUP = 0xFFFFFF ^ (int)ePhysicGroup.ePhysicLadder;
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
            else
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }

            //check for wall jump
            if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.WallJump);
                return;
            }

            //then we slides down
            setPosition(Position + _v2WallFallingSpeed);
            res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
                changePlayerState(ePlayerState.Idle);
                return;
            }

            //shoot
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
            {
                changePlayerState(ePlayerState.WallShoot);
                return;
            }


        }

    
        /// <summary>
        /// Update the player when its status is StartDash
        /// </summary>
        private void updateStateStartDash()
        {
            //save the current frame
            _iDashCurrentFrame = _iAnimationCurrentFrame;

            if (_bAnimationOver)
            {
                changePlayerState(ePlayerState.Dash);
                _iDashCurrentFrame = -1;
                return;
            }

            //apply the games action
            if (!_bInputGameActionPressed[(int)GameAction.Dash])
            {
                changePlayerState(ePlayerState.StopDash);
                return;
            }
            if (_bInputGameActionPressed[(int)GameAction.Right] && _playerDirection == ePlayerDirection.eDirectionLeft)
                _playerDirection = ePlayerDirection.eDirectionRight;
            if (_bInputGameActionPressed[(int)GameAction.Left] && _playerDirection == ePlayerDirection.eDirectionRight)
                _playerDirection = ePlayerDirection.eDirectionLeft;
            if (_bInputGameActionPressed[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.Jump);
                return;
            }

            //apply the speed
            if (_playerDirection == ePlayerDirection.eDirectionRight)
                setPosition(Position + _v2DashingSpeed);
            else
                setPosition(Position - _v2DashingSpeed);
            
            updateDashEffectPosition();

            //check collisions
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
        }

        /// <summary>
        /// Update the player when its state is Dash
        /// </summary>
        private void updateStateDash()
        {
            //first dash update
            if (_bPreState)
            {
                _iDashStartTime = Clock.instance.millisecs;
                _bPreState = false;
            }

            if (_bAnimationOver)
            {
                changePlayerState(ePlayerState.StopDash);
                return;
            }

            if (!_bInputGameActionPressed[(int)GameAction.Dash])
            {
                changePlayerState(ePlayerState.StopDash);
                return;
            }
            if (_bInputGameActionPressed[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.Jump);
                return;
            }
            if (_bInputGameActionPressed[(int)GameAction.Left] && _playerDirection == ePlayerDirection.eDirectionRight)
                _playerDirection = ePlayerDirection.eDirectionLeft;
            if (_bInputGameActionPressed[(int)GameAction.Right] && _playerDirection == ePlayerDirection.eDirectionLeft)
                _playerDirection = ePlayerDirection.eDirectionRight;

            //apply the displacement
            if (_playerDirection == ePlayerDirection.eDirectionRight)
                setPosition(Position + _v2DashingSpeed);
            else
                setPosition(Position - _v2DashingSpeed);
            updateDashEffectPosition();

            //check collisions
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
        }

        /// <summary>
        /// Update the player when its state is StopDash
        /// </summary>
        private void updateStateStopDash()
        {
            if (_bAnimationOver)
            {
                changePlayerState(ePlayerState.Idle);
                return;
            }
            updateStopDashEffectPosition();

            //apply the games action
            if (_bInputGameActionPressed[(int)GameAction.Right] && _playerDirection == ePlayerDirection.eDirectionLeft)
                _playerDirection = ePlayerDirection.eDirectionRight;
            if (_bInputGameActionPressed[(int)GameAction.Left] && _playerDirection == ePlayerDirection.eDirectionRight)
                _playerDirection = ePlayerDirection.eDirectionLeft;
            if (_bInputGameActionPressed[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.Jump);  
            }

            //check collisions
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
        }

        /// <summary>
        /// Update the player when its state is JumpShoot
        /// </summary>
        private void updateStateJumpShoot()
        {
            //the player entered this state
            if (_bPreState)
            {
                _bPreState = false;
                _bInputGameActionReleased[(int)GameAction.Attack] = false;
                _bShootAgain = false;

                Vector2 spawnPosition = Position;
                int Y = 10;
                int X = 30;
                if (_playerDirection == ePlayerDirection.eDirectionLeft)
                    spawnPosition += new Vector2(0, Y);
                else
                    spawnPosition += new Vector2(X, Y);
                shoot(spawnPosition, (int)_playerDirection);
            }

            //shoot again
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                _bShootAgain = true;

            //shoot over
            if (_bAnimationOver)
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.JumpShoot);
                else
                    changePlayerState(ePlayerState.Jump);
            }

            //jump is over so fall
            if(Clock.instance.millisecs - _iJumpStartTime >= _iJumpTime && _bAnimationOver)
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.FallShoot);
                else
                    changePlayerState(ePlayerState.Fall);
                return;
            }

            //if the jump button is released, we got to the fall state
            if (!_bInputGameActionPressed[(int)GameAction.Jump])
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.FallShoot);
                else
                    changePlayerState(ePlayerState.Fall);
                return;
            }

            //Jump!!!!!!!!!!!!!!!!!!!!!
            int iElapsedTime = Clock.instance.millisecs - _iJumpStartTime; //elapsed time since the beginning of the jump

            //calculate the interpolation value to interpolate the jumping speed between [_v2JumpingSpeed; 0]
            float ratio = 1 - (float)iElapsedTime / (float)_iJumpTime; 
            setPosition(Position + _v2JumpingSpeed*ratio); //apply the jump

            //bool bGoToFallState = true;
            if (_bInputGameActionPressed[(int)GameAction.Left]) //move left
            {
                setPosition(Position - _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionLeft;
            }
            else if (_bInputGameActionPressed[(int)GameAction.Right])//move right
            {
                setPosition(Position + _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionRight;
            }

            //collision test with every group except ladders
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            bool bGoToFallState = false;
            if (res != null && !_bIgnoreCollision)
            {
                
                if (res.Side == eCollisionSide.eLeft || res.Side == eCollisionSide.eRight)
                {
                    setPosition(Position + res.Overlap);
                    changePlayerState(ePlayerState.WallLanding);
                }
                else
                    bGoToFallState = true;
            
            }
            if (bGoToFallState)
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.FallShoot);
                else
                    changePlayerState(ePlayerState.Fall);
            }
            
        }

        /// <summary>
        /// Update the player when it's state is jump
        /// </summary>
        private void updateStateJump()
        {
            //the player entered this state
            if (_bPreState)
            {
                _bPreState = false;
                _iJumpStartTime = Clock.instance.millisecs;
                _bIgnoreCollision = false; // this flag is set to true when the player is going through a hook entity
                _bInputGameActionReleased[(int)GameAction.Jump] = false;
            }

            //the animation is over so the jump is over
            if (Clock.instance.millisecs - _iJumpStartTime >= _iJumpTime)
            {
                changePlayerState(ePlayerState.Fall);
                return;
            }

            //apply the jump
            float iElapsedTime = Clock.instance.millisecs - _iJumpStartTime; //elapsed time since the beginning of the jump
            float ratio = 1 - iElapsedTime / _iJumpTime;//calculate the interpolation value [_v2JumpingSpeed; 0]
            setPosition(Position + _v2JumpingSpeed * ratio); //apply the jump

            //apply left and right
            bool bGoToFallState = true;
            if (_bInputGameActionPressed[(int)GameAction.Left])
            {
                setPosition(Position - _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionLeft;
            }
            else if (_bInputGameActionPressed[(int)GameAction.Right])
            {
                setPosition(Position + _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionRight;
            }
            //if the jump button is released, we got to the fall state
            if (_bInputGameActionPressed[(int)GameAction.Jump])
                bGoToFallState = false;

            //collision test with every group except ladders
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null && !_bIgnoreCollision)
            {
                if (res.Side == eCollisionSide.eLeft || res.Side == eCollisionSide.eRight)
                {
                    setPosition(Position + res.Overlap);
                    changePlayerState(ePlayerState.WallLanding);
                }
                else
                    bGoToFallState = true;
            }
            
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                changePlayerState(ePlayerState.JumpShoot);
            if (bGoToFallState)
                changePlayerState(ePlayerState.Fall);
        }

        /// <summary>
        /// Update the player when its state is Fall
        /// </summary>
        private void updateStateFall()
        {
            //apply gravity
            setPosition(Position + _v2FallingSpeed);
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);

            //collision
            if (res != null)
            {
                if (res.Side == eCollisionSide.eBottom)
                {
                    if (res.Overlap.Y >= 0)
                        setPosition( _v2PreviousPosition);
                    else
                        setPosition(Position + new Vector2(0, res.Overlap.Y));

                    //move left
                    if (_bInputGameActionPressed[(int)GameAction.Left] || _bInputGameActionPressed[(int)GameAction.Right])
                    {
                        changePlayerState(ePlayerState.Run);
                    }
                    else
                        changePlayerState(ePlayerState.Idle);
                    _entityGround = res.Entity;
                    return;
                }
            }

            //move left
            if (_bInputGameActionPressed[(int)GameAction.Left])
            {
                setPosition(Position - _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionLeft;
            }
            //move right
            else if (_bInputGameActionPressed[(int)GameAction.Right])
            {
                setPosition(Position + _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionRight;
            }
            //else if (_bInputGameActionPressed[(int)GameAction.Up] && _bInputGameActionReleased[(int)GameAction.Jump])
            else if (_bInputGameActionPressed[(int)GameAction.Up])
            {
                res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, (int)ePhysicGroup.ePhysicLadder);
                if (res != null)
                {
                    LadderEntity e = (LadderEntity)res.Entity;
                    if (canClimb(e))
                    {
                        setPosition(new Vector2(e.PositionXMin, Position.Y));
                        _structClimb._entityLadder = e;
                        changePlayerState(ePlayerState.Climb);
                        return;
                    }
                }
            }

            //collision test with every group except ladders
            res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
                
                if(res.Side == eCollisionSide.eRight || res.Side == eCollisionSide.eLeft)
                {
                    setPosition(Position + res.Overlap);
                    changePlayerState(ePlayerState.WallLanding);
                }
                else
                {
                    setPosition(Position + res.Overlap);
                        
                }
     
            }

            //shoot
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                changePlayerState(ePlayerState.FallShoot);
        }

        /// <summary>
        /// Update the player when he is in state FallShoot
        /// </summary>
        private void updateStateFallShoot()
        {
            if (_bPreState)
            {
                _bPreState = false;
                _bShootAgain = false;
                _bInputGameActionReleased[(int)GameAction.Attack] = false;

                Vector2 spawnPosition = Position;
                int Y = 10;
                int X = 30;
                if (_playerDirection == ePlayerDirection.eDirectionLeft)
                    spawnPosition += new Vector2(0, Y);
                else
                    spawnPosition += new Vector2(X, Y);
                shoot(spawnPosition, (int)_playerDirection);
            }

            //apply gravity
            setPosition(Position + _v2FallingSpeed);
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);

            //collision
            if (res != null)
            {
                if(res.Side == eCollisionSide.eBottom)
                {
                    if (res.Overlap.Y >= 0)
                        setPosition( _v2PreviousPosition);
                    else
                        setPosition(Position + new Vector2(0, res.Overlap.Y));

                    if (!_bShootAgain)
                        changePlayerState(ePlayerState.Idle);
                    else
                        changePlayerState(ePlayerState.IdleShoot);
                    _entityGround = res.Entity;
                    return;
                }
            }

            if (_bAnimationOver)
            {
                if (!_bShootAgain)
                    changePlayerState(ePlayerState.Fall);
                else
                    changePlayerState(ePlayerState.FallShoot);
            }

            //move left
            if (_bInputGameActionPressed[(int)GameAction.Left])
            {
                setPosition(Position - _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionLeft;
            }
            //move right
            else if (_bInputGameActionPressed[(int)GameAction.Right])
            {
                setPosition(Position + _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionRight;
            }
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                _bShootAgain = true;


            //collision test with every group except ladders
            res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
               
                if (res.Side == eCollisionSide.eRight || res.Side == eCollisionSide.eLeft)
                {
                    setPosition(Position + res.Overlap);
                    changePlayerState(ePlayerState.WallLanding);
                }
                else
                {
                    setPosition(Position + res.Overlap);
                    changePlayerState(ePlayerState.Idle);
                    _entityGround = res.Entity;
                }  
            }
        }

        /// <summary>
        /// Update the player when its state is IdleShoot
        /// </summary>
        private void updateStateIdleShoot()
        {
            //initialise everything
            if(_bPreState)
            {
                _bPreState = false;
                _bInputGameActionReleased[(int)GameAction.Attack] = false;
                _bShootAgain = false;

                Vector2 spawnPosition = Position;
                int Y = 12;
                int X = 30;
                if (_playerDirection == ePlayerDirection.eDirectionLeft)
                    spawnPosition += new Vector2(0, Y);
                else
                    spawnPosition += new Vector2(X, Y);
                shoot(spawnPosition, (int)_playerDirection);
            }

            //check if we have to shoot again
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                _bShootAgain = true;

            if ((_bInputGameActionPressed[(int)GameAction.Left]|| _bInputGameActionPressed[(int)GameAction.Right]) && _bShootAgain)
            {
                _structRunShoot._iFrameStart = 0;
                changePlayerState(ePlayerState.RunShoot);
            }

            //when the shoot animation is over, go to the next state.
            if (_bAnimationOver)
            {
                if (_bShootAgain)
                    changePlayerState(ePlayerState.IdleShoot);
                else
                    changePlayerState(ePlayerState.Idle);
            }

        }

        /// <summary>
        /// Update the player when its state is Idle
        /// </summary>
        private void updateStateIdle()
        {
            if (_bInputGameActionPressed[(int)GameAction.Left])//run left
            {
                changePlayerState(ePlayerState.Run);
            }
            //run right
            else if (_bInputGameActionPressed[(int)GameAction.Right])
            {
                changePlayerState(ePlayerState.Run);
            }
            else if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])//jump
            {
                changePlayerState(ePlayerState.Jump);
            }
            else if (_bInputGameActionPressed[(int)GameAction.Dash])//dash
            {
                for (int i = 0; i < 3; i++)
                    _v2DashPreviousFramePosition[i] = Position;
                changePlayerState(ePlayerState.StartDash);
            }
            else if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])//shoot
                changePlayerState(ePlayerState.IdleShoot);
            
            //press up, check if a ladder is close
            if (_bInputGameActionPressed[(int)GameAction.Up])
            {
                Physics.CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, (int)ePhysicGroup.ePhysicLadder);
                if (res != null)
                {
                    LadderEntity e = (LadderEntity)res.Entity;
                    float distMaxY = Math.Abs(e.HeightMax - Position.Y);
                    float distMinY = Math.Abs(e.HeightMin - Position.Y);
                    if (canClimb(e) && distMaxY < distMinY)
                    {
                        setPosition(new Vector2(e.PositionXMin, Position.Y));
                        _structClimb._entityLadder = e;
                        changePlayerState(ePlayerState.Climb);
                        return;
                    }
                }
            }

            //press down, check if a ladder is close
            if (_bInputGameActionPressed[(int)GameAction.Down])
            {
                Physics.CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, (int)ePhysicGroup.ePhysicLadder);
                if (res != null)
                {
                    LadderEntity e = (LadderEntity)res.Entity;
                    float distMaxY = Math.Abs(e.HeightMax - Position.Y);
                    float distMinY = Math.Abs(e.HeightMin - Position.Y);
                    if ( distMaxY > distMinY && canClimb(e))
                    {
                        setPosition(new Vector2(e.PositionXMin, Position.Y));
                        _structClimb._entityLadder = e;
                        changePlayerState(ePlayerState.Climb);
                        return;

                    }
                }
            }
 
        }

        /// <summary>
        /// Update the player when its state is Run
        /// </summary>
        private void updateStateRun()
        {
            //move left
            if (_bInputGameActionPressed[(int)GameAction.Left])//run left
            {
                setPosition(Position - _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionLeft;
            }
            //move right
            else if (_bInputGameActionPressed[(int)GameAction.Right])//run right
            {
                setPosition(Position + _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionRight;
            }
            else
                changePlayerState(ePlayerState.Idle); // no run, si idle

            if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])//jump 
            {
                changePlayerState(ePlayerState.Jump);
            }
            else if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack]) //shoot
            {
                _structRunShoot._iFrameStart = _iAnimationCurrentFrame;
                if (_structRunShoot._iFrameStart < 0) _structRunShoot._iFrameStart = 0;
                changePlayerState(ePlayerState.RunShoot);
            }
            else if (_bInputGameActionPressed[(int)GameAction.Dash])//dash
            {
                for (int i = 0; i < 3; i++)
                    _v2DashPreviousFramePosition[i] = Position;
                changePlayerState(ePlayerState.StartDash);
            }

            //collision test with every group except ladders
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }

        }

        private void updateStateClimb()
        {
            //check inputs to climb up or down
            Vector2 climbSpeed = new Vector2(0, 1);
            if (_bInputGameActionPressed[(int)GameAction.Up])
            {
                setPosition(Position - climbSpeed);
                _structClimb.setClimbUp();

                //check if the player is at the top of the ladder
                if (Position.Y < _structClimb._entityLadder.HeightMin)
                {
                    setPosition(Position + new Vector2(-8, 0));
                    changePlayerState(ePlayerState.Idle);
                }
                
            }
            else if (_bInputGameActionPressed[(int)GameAction.Down])
            {
                setPosition(Position + climbSpeed);
                _structClimb.setClimbDown();

                //check if the player is at the bottom of the ladder
                if (Position.Y > _structClimb._entityLadder.HeightMax)
                {
                    setPosition(Position + new Vector2(-8, 0));
                    changePlayerState(ePlayerState.Idle);
                }

            }
            else
                _structClimb.setClimbIdle();

            //When the player jump, he falls down
            if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])
            {
                changePlayerState(ePlayerState.Fall);
                _bInputGameActionReleased[(int)GameAction.Jump] = false;
            }
        }

        /// <summary>
        /// Update the player whent its state is RunShoot
        /// </summary>
        private void updateStateRunShoot()
        {

            if (_bPreState)
            {
                _bPreState = false;
                _bInputGameActionReleased[(int)GameAction.Attack] = false;
                _bShootAgain = false;

                Vector2 spawnPosition = Position;
                int Y = 12;
                int X = 30;
                if (_playerDirection == ePlayerDirection.eDirectionLeft)
                    spawnPosition += new Vector2(0, Y);
                else
                    spawnPosition += new Vector2(X, Y);
                shoot(spawnPosition, (int)_playerDirection);
            }

            //check if we have to shoot again
            if (_bInputGameActionPressed[(int)GameAction.Attack] && _bInputGameActionReleased[(int)GameAction.Attack])
                _bShootAgain = true;

            bool bIdle = false;
            //move left
            if (_bInputGameActionPressed[(int)GameAction.Left])
            {
                setPosition(Position - _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionLeft;
            }
            //move right
            else if (_bInputGameActionPressed[(int)GameAction.Right])
            {
                setPosition(Position + _v2RunningSpeed);
                _playerDirection = ePlayerDirection.eDirectionRight;
            }
            else
                bIdle = true;

            if (_bInputGameActionPressed[(int)GameAction.Jump] && _bInputGameActionReleased[(int)GameAction.Jump])
            {
                    changePlayerState(ePlayerState.Jump);
            }

            if (bIdle)
            {
                if (_bShootAgain)
                {
                    changePlayerState(ePlayerState.IdleShoot);
                }
                else
                    changePlayerState(ePlayerState.Idle);

            }
            else if (_bAnimationOver)
            {
                if (_bShootAgain)
                {
                    _structRunShoot._iFrameStart += 3;
                    _structRunShoot._iFrameStart = _structRunShoot._iFrameStart % 10;
                    changePlayerState(ePlayerState.RunShoot);
                }
                else
                    changePlayerState(ePlayerState.Run);
            }
    
            //collision test
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_dshPhysicShape, PHYSIC_GROUP_PLATFORM);
            if (res != null)
            {
                setPosition(Position + res.Overlap);
            }
        }

        /// <summary>
        /// Render the player
        /// </summary>
        public override void render()
        {
            int iIdDashTexture = -1;
            int iIdDashSprite = -1;
            Vector2 offset;

            //set the psrite effect to flip the graphics
            SpriteEffects flip = SpriteEffects.None;
            if (_playerDirection == ePlayerDirection.eDirectionLeft)
                flip = SpriteEffects.FlipHorizontally;

            //display an animation corresponding to the current state
            switch (_playerState)
            {
                case ePlayerState.Run:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDRunRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.RunShoot:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iRunShootAnimationID[_structRunShoot._iFrameStart], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.Idle:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDIdleRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.IdleShoot:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDIdleShootRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;
                
                case ePlayerState.Hurt:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDHurtRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.Jump:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDJumpRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.JumpShoot:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDJumpOrFallShootRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.Fall:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDFallRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.FallShoot:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDJumpOrFallShootRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip, _tintColor);
                    break;

                case ePlayerState.StopDash:
                    iIdDashTexture = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight]).indexTexture;
                    if (_iAnimationCurrentFrame != -1)
                    {
                        offset = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight]).getOffset(_iAnimationCurrentFrame);
                        iIdDashSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight]).getIndexSprite(_iAnimationCurrentFrame);
                    }
                    else
                    {
                        offset = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight]).getOffset(0);
                        iIdDashSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight]).idFirstSprite;
                    }
                    
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[2] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[1] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[0] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStopDashRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    
                    break;

                case ePlayerState.StartDash:
                    iIdDashTexture = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight]).indexTexture;
                    if (_iAnimationCurrentFrame != -1)
                    {
                        offset = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight]).getOffset(_iAnimationCurrentFrame);
                        iIdDashSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight]).getIndexSprite(_iAnimationCurrentFrame);
                    }
                    else
                    {
                        offset = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight]).getOffset(0);
                        iIdDashSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight]).idFirstSprite;
                    }
                  
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[2] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[1] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[0] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDStartDashRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    
                    break;

                case ePlayerState.Dash:
                    iIdDashTexture = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight]).indexTexture;
                    if (_iAnimationCurrentFrame != -1)
                    {
                        offset = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight]).getOffset(_iAnimationCurrentFrame);
                        iIdDashSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight]).getIndexSprite(_iAnimationCurrentFrame);
                    }
                    else
                    {
                        offset = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight]).getOffset(0);
                        iIdDashSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight]).idFirstSprite;
                    }
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[2] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[1] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    Visu.Instance.displaySprite(iIdDashTexture, iIdDashSprite, _v2DashPreviousFramePosition[0] - World.Instance.CameraPosition + offset, flip, Color.HotPink);
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDDashRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                   
                    break;

                case ePlayerState.WallLanding:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDWallLandRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    break;
                case ePlayerState.WallSliding:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDWallLoopRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    break;

                case ePlayerState.WallShoot:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDWallShootRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    break;

                case ePlayerState.WallJump:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDWallJumpRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    break;
                case ePlayerState.Climb:
                    if(_structClimb._bClimbUp)
                        _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDClimb], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime);
                    else if (_structClimb._bClimbDown)
                        _bAnimationOver = Visu.Instance.displayReverseAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDClimb], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, Microsoft.Xna.Framework.Graphics.SpriteEffects.None);
                    else
                    {
                        int idTexture = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDClimb]).indexTexture;
                        int idAnim = _iAnimationCurrentFrame;
                        if(idAnim <0) idAnim = 0;
                        int idSprite = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDClimb]).getIndexSprite(idAnim);
                        Vector2 offsetClimb = Visu.Instance.getAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIDClimb]).getOffset(idAnim);
                        Visu.Instance.displaySprite(idTexture, idSprite, ScreenPosition + offsetClimb);
                    }
                    break;

                case ePlayerState.StartMission:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIdMissionStart], _v2MissionAnimationPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime);
                    break;

                case ePlayerState.Teleport:
                    _bAnimationOver = Visu.Instance.displayAnimation(_iAnimationId[(int)eAnimationIndex.eAnimIdTeleportRight], ScreenPosition, ref _iAnimationCurrentFrame, ref _iAnimationCurrentTime, flip);
                    break;

                case ePlayerState.Dead:
                    Visu.Instance.displaySprite(_iIdTextureMissionFailed, _iIdSpriteMissionFailed, _v2MissionAnimationPosition);
                    break;
            }

#if DEBUG
            Vector2[] obb = _dshPhysicShape.getOrientedBoundingBox();
            for (int i = 0; i < 4; i++)
                obb[i] -= World.Instance.CameraPosition;

            Visu.Instance.displayPolygon(obb);      
#endif
        }

        /// <summary>
        /// Kill the player
        /// </summary>
        public override void die()
        {
            _dshPhysicShape._bCollisionEnable = false;
            Manager.ExplosionManager.Instance.activate(_iIdAnimationExplosion, Position + _v2AnimationExplosionOffset);
            changePlayerState(ePlayerState.Dead);
        }

       
        #region Tools

        /// <summary>
        /// Check if the player can climb the given ladder entity
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private bool canClimb(LadderEntity e)
        {
            int p = (int)_v2Position.X + 15;
            if (p > e.PositionXMin && p < e.PositionXMax)
                return true;

            return false;
        }

        /// <summary>
        /// Update the positions of the dash effect during dash state
        /// </summary>
        private void updateDashEffectPosition()
        {
            const int iDistance = 10;
            float fLength = (_v2DashPreviousFramePosition[0] - Position).Length();
            Vector2 _v2Direction = (_v2DashPreviousFramePosition[0] - Position);
            _v2Direction.Normalize();

            if (fLength > iDistance)
            {
                _v2DashPreviousFramePosition[0] = Position + _v2Direction * iDistance;
            }

            fLength = (_v2DashPreviousFramePosition[1] - Position).Length();
            if (fLength > iDistance*2)
                _v2DashPreviousFramePosition[1] = Position + _v2Direction * iDistance * 2;

            fLength = (_v2DashPreviousFramePosition[2] - Position).Length();
            if (fLength > iDistance*3)
                _v2DashPreviousFramePosition[2] = Position + _v2Direction * iDistance * 3;
        }

        /// <summary>
        /// Update the positions of the dash effect during stop dash state
        /// </summary>
        private void updateStopDashEffectPosition()
        {
            float fLength = _v2DashingSpeed.Length();

            if (Position != _v2DashPreviousFramePosition[0])
            {
                Vector2 _v2Direction = (_v2DashPreviousFramePosition[0] - Position);
                if (_v2Direction.Length() <= fLength)
                    _v2DashPreviousFramePosition[0] = Position;
                else
                {
                    _v2Direction.Normalize();
                    _v2DashPreviousFramePosition[0] = Position - _v2Direction * fLength;
                }
                return;
            }
            if (Position != _v2DashPreviousFramePosition[1])
            {
                Vector2 _v2Direction = (_v2DashPreviousFramePosition[1] - Position);
                if (_v2Direction.Length() <= fLength)
                    _v2DashPreviousFramePosition[1] = Position;
                else
                {
                    _v2Direction.Normalize();
                    _v2DashPreviousFramePosition[1] = Position - _v2Direction * fLength;
                }
                return;
            }
            if (Position != _v2DashPreviousFramePosition[2])
            {
                Vector2 _v2Direction = (_v2DashPreviousFramePosition[2] - Position);
                if (_v2Direction.Length() <= fLength)
                    _v2DashPreviousFramePosition[2] = Position;
                else
                {
                    _v2Direction.Normalize();
                    _v2DashPreviousFramePosition[2] = Position - _v2Direction * fLength;
                }
                return;
            }
        }

        #endregion

      
    }
}

