Esempio n. 1
0
        public override Node Render(SpriteBatch batch)
        {
            //Draw.FillRectangleCentered(batch, AbsXY, new Vector2(24,32), Color.CadetBlue, 0f);
            //Draw.FillRectangleCentered(batch, AbsXY + new Vector2(0,14), new Vector2(18,12), Color.CadetBlue, 0f);

            //Draw.Polygon(batch, _hotPoints.Values.ToArray(), Color.RoyalBlue, 2f, XY + _parent.AbsXY);
            Draw.FillRectangle(batch, AbsRect, Color.CadetBlue);
            //Draw.Circle(batch, AbsXY, 8, 6, Color.Yellow, 2f);
            Draw.Rectangle(batch, AbsRect, Color.Gray, 2f);

            bool flipX = _direction < 0 ? true : false;

            //_sprite.Render(batch, AbsX, AbsY + _rect.Height / 2, Color.White, 1f, 1f, 0, 0, 0, flipX ? SpriteEffects.FlipHorizontally : SpriteEffects.None, flipX);

            //batch.Draw(Game1._text_Hero, AbsXY - new Vector2(Game1._text_Hero.Width / 2, Game1._text_Hero.Height/2 + 14), Color.White);

            //Draw.Line(batch, AbsXY, AbsXY + new Vector2(0, _tileMapLayer._map2D._tileH), Color.Red, 3);



            // Debug : Draw _collideP
            if (_showContactPoint)
            {
                for (int i = 0; i < _cPoints.Length; ++i)
                {
                    if (null != _cPoints[i])
                    {
                        //if (i==(int)HotPoints.RU || i==(int)HotPoints.RD)
                        //    Draw.Line(batch, XY + _parent.AbsXY, _parent.AbsXY + _contactPoints[i]._pointContact, Color.LightSlateGray, 2f);

                        Color color = Color.GreenYellow;

                        // Raycast line
                        //Vector2 raycast = _finalVector * 2f;
                        //Draw.Line(batch, _contactPoints[i]._pos - raycast + _parent.AbsXY, _contactPoints[i]._pos + raycast + _parent.AbsXY, Color.MediumVioletRed, 1f);
                        Draw.Line(batch, _cPoints[i]._pos - _cPoints[i]._raycast + _parent.AbsXY, _cPoints[i]._pos + _cPoints[i]._raycast + _parent.AbsXY, Color.MediumVioletRed, 1f);

                        if (_cPoints[i]._isContact)
                        {
                            color = Color.Red;

                            // Polygon of contact point
                            Draw.PolyLine(batch, _cPoints[i]._polygon, Color.White, 1f, _parent.AbsXY + _cPoints[i]._offset);

                            Line line = _cPoints[i]._lineContact;

                            // Line of contact point
                            Draw.Line(batch, line.A + _parent.AbsXY, line.B + _parent.AbsXY, Color.Aqua, 3f);

                            // Point of intersect raycast line & line Contact
                            Draw.Point(batch, _cPoints[i]._pointContact + _parent.AbsXY, 3f, Color.ForestGreen);

                            // Name of the point contact
                        }

                        if (i == (int)HSpots.EL)
                        {
                            Draw.Line(batch, _cPoints[i]._firstline.A + _parent.AbsXY, _cPoints[i]._firstline.B + _parent.AbsXY, Color.Magenta, 2f);
                            Draw.TopCenterString(batch, Game1._fontMain, _cPoints[i]._pos.Y.ToString("0") + "," + _cPoints[i]._pos.Y.ToString("0"), _cPoints[i]._pos.X + _parent.AbsX, _cPoints[i]._pos.Y + _parent.AbsY, Color.White);
                        }

                        // Contact point
                        Draw.Point(batch, _cPoints[i]._pos + _parent.AbsXY, 1, color);
                    }


                    //Draw.Point(batch, new Vector2(_mapPosX * _tileW + _tileW/2, _mapPosY * _tileW +_tileH/2) + _parent.AbsXY, 4, Color.Gold);
                    //Draw.LeftTopString(batch, Game1._fontMain, TILE_AT_L.ToString(), _mapPosX * _tileW + _tileW/ 2 + _parent.AbsX, _mapPosY * _tileW +_tileH/2 + _parent.AbsY, Color.Goldenrod);
                }

                //Draw.TopCenterString(batch, Game1._fontMain, "oldStatus = " + _oldStatus, AbsX, AbsY + 48, Color.Gray);
                //Draw.TopCenterString(batch, Game1._fontMain, CAN_CLIMB_L + "<EDGE>" + CAN_CLIMB_R, AbsX, AbsY + 64, Color.GreenYellow);
                Draw.TopCenterString(batch, Game1._fontMain, "PUSH " + _isPush, AbsX, AbsY + 48, Color.Violet);

                if (_status == Status.IS_JUMP)
                {
                    Draw.TopCenterString(batch, Game1._fontMain, "JUMP", AbsX, AbsY - 48, Color.Yellow);
                }
                if (_status == Status.IS_FALL)
                {
                    Draw.TopCenterString(batch, Game1._fontMain, "FALL", AbsX, AbsY - 48, Color.Red);
                }
                if (_status == Status.IS_LAND)
                {
                    Draw.TopCenterString(batch, Game1._fontMain, "LAND", AbsX, AbsY - 48, Color.Orange);
                }
                if (_status == Status.IS_GRAB)
                {
                    Draw.TopCenterString(batch, Game1._fontMain, "GRAB " + _ticGrab, AbsX, AbsY - 48, Color.Honeydew);
                }
                if (_status == Status.IS_CLIMB)
                {
                    Draw.TopCenterString(batch, Game1._fontMain, "CLIMB" + _ticAutoMove, AbsX, AbsY - 48, Color.Honeydew);
                }

                Draw.Line(batch, _landLineA + _parent.AbsXY, _landLineB + _parent.AbsXY, Color.Green, 2f);
                Draw.Point(batch, _pointLandCollision + _parent.AbsXY, 4f, Color.RoyalBlue);

                Draw.Line(batch, AbsXY, AbsXY - Geo.GetVector(_landRadian) * 40, Color.LimeGreen, 1f);
                Draw.Line(batch, AbsXY, AbsXY + Geo.GetVector(_landRadian) * 40, Color.LimeGreen, 1f);

                Draw.Line(batch, AbsXY, AbsXY + Geo.GetVector(_angleMove.X) * _velocity.X * 40, Color.MediumVioletRed, 2f);
                Draw.Line(batch, AbsXY, AbsXY + Geo.GetVector(_angleMove.Y) * _velocity.Y * 40, Color.DarkOliveGreen, 2f);

                Draw.TopCenterString(batch, Game1._fontMain, $"[{_x.ToString("0")} , { _y.ToString("0")}]", AbsX, AbsY - 64, Color.Yellow);

                Draw.TopCenterString(batch, Game1._fontMain, $"{ _sumVector.X.ToString("0.0")}|{ _sumVector.Y.ToString("0.0")}", AbsX, AbsY + 64, Color.Yellow);
                Draw.TopCenterString(batch, Game1._fontMain, $"{ _velocity.X.ToString("0.0")}|{ _velocity.Y.ToString("0.0")}", AbsX, AbsY + 80, Color.MonoGameOrange);



                // Ddebug Raycast !
                Draw.Rectangle(batch, new RectangleF(_mapPosX * _tileW + _parent.AbsX, _mapPosY * _tileH + _parent.AbsY, _tileW, _tileH), Color.Yellow);
                Level.DrawLine(batch, (int)_x, (int)_y, _mouse.AbsX, _mouse.AbsY, _tileW, _tileH, Color.OrangeRed, new Point(_parent.AbsX, _parent.AbsY));
            }

            if (_status == Status.IS_GRAB)
            {
                Draw.Point(batch, _ledgeGrip + _parent.AbsXY, 4f, Color.MonoGameOrange);
            }

            //Draw.CenterStringXY(batch, Game1._fontMain, $"{_pointLandCollision_L.Y.ToString("0")}:{_pointLandCollision_R.Y.ToString("0")}", AbsX, AbsY + 32, Color.Ivory);


            return(base.Render(batch));
        }
Esempio n. 2
0
        public override Node Update(GameTime gameTime)
        {
            CAN_MOVE_UP    = true;
            CAN_MOVE_DOWN  = true;
            CAN_MOVE_LEFT  = true;
            CAN_MOVE_RIGHT = true;

            CAN_GRAB_L = false;
            CAN_GRAB_R = false;

            //CAN_WALL_JUMP = false;

            _deltaX = _x - _oldX;
            _deltaY = _y - _oldY;

            UpdateRect();

            if (!_isMove)
            {
                if (_status == Status.IS_LAND)
                {
                    DecelerateX(2f);
                }
                else
                {
                    DecelerateX(2f);
                }
            }

            // Lateral Move State
            _isPush = false;
            _isMove = false;
            _onMove = false;

            // Jump Move State
            //_onJump = false;
            //_onFall = false;



            //_sumVector.X = Geo.GetVector(_angleMove.X).X;
            //_sumVector.Y = Geo.GetVector(_angleMove.Y).Y;

            _sumVector = Geo.GetVector(_angleMove.X) * _velocity.X + Geo.GetVector(_angleMove.Y) * _velocity.Y;

            if (MOVE_LEFT && MOVE_RIGHT)
            {
                _sumVector.X = 0f;
            }

            //_finalVector.X = _sumVector.X * _velocity.X;
            //_finalVector.Y = _sumVector.Y * _velocity.Y;

            _finalVector = _sumVector;

            //_finalVector.X = Geo.GetVector(_angleMove.X).X * _velocity.X;
            //_finalVector.Y = Geo.GetVector(_angleMove.Y).Y * _velocity.Y;

            #region Collisions Test

            if (_hSpots.Count > 0)
            {
                // Reset all collide point to false !
                for (int i = 0; i < _hSpots.Count; i++)
                {
                    _cPoints[i]._isContact = false;

                    _cPoints[i]._hotPoint = _hSpots[i];

                    _cPoints[i]._pos = XY + _hSpots[i] + _finalVector;

                    _cPoints[i]._mapX = (int)(_cPoints[i]._pos.X / _tileW);
                    _cPoints[i]._mapY = (int)(_cPoints[i]._pos.Y / _tileH);

                    _cPoints[i]._offset = new Vector2(_cPoints[i]._mapX * _tileW, _cPoints[i]._mapY * _tileH);

                    _cPoints[i]._tile = _map2D.Get(_cPoints[i]._mapX, _cPoints[i]._mapY);

                    //_CollidePointInPolygon = false;

                    if (null != _cPoints[i]._tile)
                    {
                        // check the tileset if collide in polygon
                        if (_tileMapLayer._tileSets.ContainsKey(_cPoints[i]._tile._id))
                        {
                            TileSet tileset = _tileMapLayer._tileSets[_cPoints[i]._tile._id];

                            _cPoints[i]._polygon = tileset._polygonCollision;

                            if (_cPoints[i]._polygon != null)
                            {
                                // get polygon[] in the tile where is the contactPoint of the global Tileset
                                _cPoints[i].GetLineContact(_cPoints[i]._offset, _cPoints[i]._polygon);

                                _cPoints[i]._isContact =
                                    Collision2D.PointInPolygon(_cPoints[i]._pos, _cPoints[i]._polygon, _cPoints[i]._polygon.Length, _cPoints[i]._offset) &&
                                    _cPoints[i]._tile._isCollidable &&
                                    _cPoints[i]._tile._passLevel > PASS_LEVEL; // && _contactPoints[i]._successRaycast;
                            }
                        }
                    }
                }

                // Point Test

                // Up Top
                #region Contact : UP / TOP
                if (_cPoints[(int)HSpots.UL]._isContact && _status == Status.IS_JUMP)
                {
                    CAN_MOVE_UP = false;
                    //_topY = _topY_L = _contactPoints[(int)HotPoints.UL]._mapY * _tileH + _tileH + _rect.Height / 2 + 2;
                    _topY = _topY_L = _cPoints[(int)HSpots.UL]._pointContact.Y + _rect.Height / 2 + 2;
                }
                if (_cPoints[(int)HSpots.UR]._isContact && _status == Status.IS_JUMP)
                {
                    CAN_MOVE_UP = false;
                    //_topY = _topY_R = _contactPoints[(int)HotPoints.UR]._mapY * _tileH + _tileH + _rect.Height / 2 + 2;
                    _topY = _topY_R = _cPoints[(int)HSpots.UR]._pointContact.Y + _rect.Height / 2 + 2;
                }

                if (_cPoints[(int)HSpots.UL]._isContact && _cPoints[(int)HSpots.UR]._isContact && _status == Status.IS_JUMP)
                {
                    if (_topY_L > _topY_R)
                    {
                        _topY = _topY_L;
                    }
                    else
                    {
                        _topY = _topY_R;
                    }
                }
                #endregion

                #region Contact : DOWN / BOTTOM
                if (_cPoints[(int)HSpots.DL]._isContact)
                {
                    CAN_MOVE_DOWN = false;

                    _landLineA = _landLineA_L = _cPoints[(int)HSpots.DL]._polygon[0] + _cPoints[(int)HSpots.DL]._offset;
                    _landLineB = _landLineB_L = _cPoints[(int)HSpots.DL]._polygon[1] + _cPoints[(int)HSpots.DL]._offset;

                    _landRadian = _landRadian_L = Geo.GetRadian(_landLineA, _landLineB);

                    //_pointLandCollision = _pointLandCollision_L = Collision2D.LineLineIntersection(_landLineA, _landLineB, _contactPoints[(int)HotPoints.DL]._pos, _contactPoints[(int)HotPoints.DL]._pos + _contactPoints[(int)HotPoints.DL]._raycast);
                    _pointLandCollision = _pointLandCollision_L = _cPoints[(int)HSpots.DL]._pointContact;

                    _landY = _landY_L = _pointLandCollision_L.Y - _rect.Height / 2 - 2;
                }


                if (_cPoints[(int)HSpots.DR]._isContact)
                {
                    CAN_MOVE_DOWN = false;

                    _landLineA = _landLineA_R = _cPoints[(int)HSpots.DR]._polygon[0] + _cPoints[(int)HSpots.DR]._offset;
                    _landLineB = _landLineB_R = _cPoints[(int)HSpots.DR]._polygon[1] + _cPoints[(int)HSpots.DR]._offset;

                    _landRadian = _landRadian_R = Geo.GetRadian(_landLineA, _landLineB);

                    //_pointLandCollision = _pointLandCollision_R = Collision2D.LineLineIntersection(_landLineA, _landLineB, _contactPoints[(int)HotPoints.DR]._pos, _contactPoints[(int)HotPoints.DR]._pos + _contactPoints[(int)HotPoints.DR]._raycast);
                    _pointLandCollision = _pointLandCollision_R = _cPoints[(int)HSpots.DR]._pointContact;

                    _landY = _landY_R = _pointLandCollision_R.Y - _rect.Height / 2 - 2;
                }
                #endregion

                #region Contact : LEFT & RIGHT
                // Limit Side Move
                // LEFT
                if (_cPoints[(int)HSpots.LU]._isContact && MOVE_LEFT)
                {
                    CAN_MOVE_LEFT = false;
                    //_sideL = _contactPoints[(int)HotPoints.LU]._mapX * _tileW + _tileW + _rect.Width / 2 + 2;
                    _sideL = _cPoints[(int)HSpots.LU]._pointContact.X + _rect.Width / 2 + 2;
                }
                if (_cPoints[(int)HSpots.LD]._isContact && MOVE_LEFT)
                {
                    CAN_MOVE_LEFT = false;
                    //_sideL = _contactPoints[(int)HotPoints.LD]._mapX * _tileW + _tileW + _rect.Width / 2 + 2;
                    _sideL = _cPoints[(int)HSpots.LD]._pointContact.X + _rect.Width / 2 + 2;
                }
                // RIGHT
                if (_cPoints[(int)HSpots.RU]._isContact && MOVE_RIGHT)
                {
                    CAN_MOVE_RIGHT = false;
                    //_sideR = _contactPoints[(int)HotPoints.RU]._mapX * _tileW - _rect.Width / 2 - 2;
                    _sideR = _cPoints[(int)HSpots.RU]._pointContact.X - _rect.Width / 2 - 2;
                }
                if (_cPoints[(int)HSpots.RD]._isContact && MOVE_RIGHT)
                {
                    CAN_MOVE_RIGHT = false;
                    //_sideR = _contactPoints[(int)HotPoints.RD]._mapX * _tileW - _rect.Width / 2 - 2;
                    _sideR = _cPoints[(int)HSpots.RD]._pointContact.X - _rect.Width / 2 - 2;
                }

                // Type Slope = 3
                if (_cPoints[(int)HSpots.LU]._tile != null)
                {
                    if (!_cPoints[(int)HSpots.LU]._isContact && _cPoints[(int)HSpots.LU]._tile._type == 3 && MOVE_LEFT) // && _contactPoints[(int)CPoint.DL]._isContact
                    {
                        //CAN_MOVE_DOWN = false;

                        _landLineA = _landLineA_L = _cPoints[(int)HSpots.LU]._polygon[0] + _cPoints[(int)HSpots.LU]._offset;
                        _landLineB = _landLineB_L = _cPoints[(int)HSpots.LU]._polygon[1] + _cPoints[(int)HSpots.LU]._offset;

                        _landRadian = _landRadian_L = Geo.GetRadian(_landLineA, _landLineB);

                        if (_cPoints[(int)HSpots.DL]._isContact)
                        {
                            CAN_MOVE_DOWN = false;

                            _pointLandCollision = _pointLandCollision_L = Collision2D.LineLineIntersection(_landLineA, _landLineB, _cPoints[(int)HSpots.DL]._pos, _cPoints[(int)HSpots.DL]._pos + _cPoints[(int)HSpots.DL]._raycast);
                            //_pointLandCollision = _pointLandCollision_L = _cPoints[(int)HSpots.DL]._pointContact;
                            _landY = _landY_L = _pointLandCollision_L.Y - _rect.Height / 2 - 2;
                        }
                    }
                }

                if (_cPoints[(int)HSpots.RU]._tile != null)
                {
                    if (!_cPoints[(int)HSpots.RU]._isContact && _cPoints[(int)HSpots.RU]._tile._type == 3 && MOVE_RIGHT) // && _contactPoints[(int)CPoint.DL]._isContact
                    {
                        //CAN_MOVE_DOWN = false;

                        _landLineA = _landLineA_R = _cPoints[(int)HSpots.RU]._polygon[0] + _cPoints[(int)HSpots.RU]._offset;
                        _landLineB = _landLineB_R = _cPoints[(int)HSpots.RU]._polygon[1] + _cPoints[(int)HSpots.RU]._offset;

                        _landRadian = _landRadian_R = Geo.GetRadian(_landLineA, _landLineB);

                        if (_cPoints[(int)HSpots.DR]._isContact)
                        {
                            CAN_MOVE_DOWN = false;

                            _pointLandCollision = _pointLandCollision_R = Collision2D.LineLineIntersection(_landLineA, _landLineB, _cPoints[(int)HSpots.DR]._pos, _cPoints[(int)HSpots.DR]._pos + _cPoints[(int)HSpots.DR]._raycast);
                            //_pointLandCollision = _pointLandCollision_R = _cPoints[(int)HSpots.DR]._pointContact;
                            _landY = _landY_R = _pointLandCollision_R.Y - _rect.Height / 2 - 2;
                        }
                    }
                }

                // Choose best LandY Left or Right
                //if (MOVE_LEFT && _contactPoints[(int)CPoint.DL]._isContact)
                if (_cPoints[(int)HSpots.DL]._isContact && _cPoints[(int)HSpots.DR]._isContact)
                {
                    //Console.Write("< BOTH LAND L & R >");

                    if (_pointLandCollision_L.Y < _pointLandCollision_R.Y)
                    //if (_landY_L < _landY_R)
                    {
                        _pointLandCollision = _pointLandCollision_L;

                        _landLineA  = _landLineA_L;
                        _landLineB  = _landLineB_L;
                        _landRadian = _landRadian_L;
                        //_landY_R = _landY = _landY_L;
                        _landY = _landY_L;

                        _contactPointDown = _cPoints[(int)HSpots.DL];
                    }
                    else //if (MOVE_RIGHT && _contactPoints[(int)CPoint.DR]._isContact)
                    if (_pointLandCollision_L.Y > _pointLandCollision_R.Y)
                    {
                        _pointLandCollision = _pointLandCollision_R;

                        _landLineA  = _landLineA_R;
                        _landLineB  = _landLineB_R;
                        _landRadian = _landRadian_R;
                        //_landY_L = _landY = _landY_R;
                        _landY = _landY_R;

                        _contactPointDown = _cPoints[(int)HSpots.DR];
                    }
                }

                #endregion

                #region Contact : GRAB LEDGE

                if (CAN_MOVE_UP && CAN_MOVE_DOWN && !CAN_MOVE_LEFT &&
                    _cPoints[(int)HSpots.EL]._isContact &&
                    Math.Abs(_cPoints[(int)HSpots.EL]._pos.Y - _cPoints[(int)HSpots.EL]._firstline.B.Y) <= 8)
                {
                    TileMap tileU = _map2D.Get(_cPoints[(int)HSpots.EL]._mapX, _cPoints[(int)HSpots.EL]._mapY - 1);

                    bool climbable = false;

                    if (tileU == null)
                    {
                        climbable = true;
                    }
                    else if (tileU._id != Const.NoIndex) // test is tile at up is empty or not, if not then test is climbable on Left
                    {
                        if (tileU._tileSet._properties.ContainsKey("ClimbR"))
                        {
                            climbable = true;
                        }
                    }
                    else
                    {
                        climbable = true;
                    }

                    if (climbable && !CAN_GRAB_L)
                    {
                        CAN_GRAB_L = true;

                        _grabY = _cPoints[(int)HSpots.EL]._firstline.B.Y - _hSpots[(int)HSpots.EL].Y;

                        _ledgeGrip.X = _cPoints[(int)HSpots.EL]._firstline.B.X;
                        _ledgeGrip.Y = _cPoints[(int)HSpots.EL]._firstline.B.Y;
                    }
                }

                if (CAN_MOVE_UP && CAN_MOVE_DOWN && !CAN_MOVE_RIGHT &&
                    _cPoints[(int)HSpots.ER]._isContact &&
                    Math.Abs(_cPoints[(int)HSpots.ER]._pos.Y - _cPoints[(int)HSpots.ER]._firstline.A.Y) <= 8)
                {
                    TileMap tileU = _map2D.Get(_cPoints[(int)HSpots.ER]._mapX, _cPoints[(int)HSpots.ER]._mapY - 1);

                    bool climbable = false;

                    if (tileU == null)
                    {
                        climbable = true;
                    }
                    else if (tileU._id != Const.NoIndex) // test is tile at up is empty or not, if not then test is climbable on Left
                    {
                        if (tileU._tileSet._properties.ContainsKey("ClimbL"))
                        {
                            climbable = true;
                        }
                    }
                    else
                    {
                        climbable = true;
                    }

                    if (climbable && !CAN_GRAB_R)
                    {
                        CAN_GRAB_R = true;

                        _grabY = _cPoints[(int)HSpots.ER]._firstline.A.Y - _hSpots[(int)HSpots.ER].Y;

                        _ledgeGrip.X = _cPoints[(int)HSpots.ER]._firstline.A.X;
                        _ledgeGrip.Y = _cPoints[(int)HSpots.ER]._firstline.A.Y;
                    }
                }
                #endregion
            }

            #endregion

            #region CAN MOVE TEST & Pre Collision Raycast

            if (!CAN_MOVE_DOWN)
            {
                if (_status != Status.IS_LAND)
                {
                    _preCollisionRayCastY = (_y + _finalVector.Y) - _landY;
                    _finalVector.Y       -= _preCollisionRayCastY;

                    //_y = _landY ;
                    //_finalVector.Y = 0;

                    Land();
                }
            }
            if (!CAN_MOVE_UP)
            {
                Console.WriteLine("!! Touch Top !!");
                _preCollisionRayCastY = (_y + _finalVector.Y) - _topY;
                _finalVector.Y       -= _preCollisionRayCastY;
            }

            if (!CAN_MOVE_LEFT)
            //if (_contactPoints[(int)HotPoints.LU]._isContact || _contactPoints[(int)HotPoints.LD]._isContact)
            {
                _preCollisionRayCastX = (_x + _finalVector.X) - _sideL;
                _finalVector.X       -= _preCollisionRayCastX;

                if (MOVE_LEFT)
                {
                    _isPush = true;

                    if (!CAN_WALL_JUMP_R && _status == Status.IS_FALL && CAN_MOVE_UP && _cPoints[(int)HSpots.EL]._isContact)
                    {
                        Console.WriteLine("CAN WALL JUMP R");

                        _onCanWallJump  = true;
                        CAN_WALL_JUMP_R = true;
                    }
                }
            }
            if (!CAN_MOVE_RIGHT)
            //if (_contactPoints[(int)HotPoints.RU]._isContact || _contactPoints[(int)HotPoints.RD]._isContact)
            {
                _preCollisionRayCastX = (_x + _finalVector.X) - _sideR;
                _finalVector.X       -= _preCollisionRayCastX;

                if (MOVE_RIGHT)
                {
                    _isPush = true;

                    if (!CAN_WALL_JUMP_L && _status == Status.IS_FALL && CAN_MOVE_UP && _cPoints[(int)HSpots.ER]._isContact)
                    {
                        Console.WriteLine("CAN WALL JUMP L");

                        _onCanWallJump  = true;
                        CAN_WALL_JUMP_L = true;
                    }
                }
            }


            if (((CAN_GRAB_L && !CAN_MOVE_LEFT) || (CAN_GRAB_R && !CAN_MOVE_RIGHT)) && _isPush && _status == Status.IS_FALL)
            {
                _preCollisionRayCastY = (_y + _finalVector.Y) - _grabY;
                _finalVector.Y       -= _preCollisionRayCastY;

                //Console.WriteLine($"---------------------> _grabY = {_grabY} _preCollisionRayCastY = {_preCollisionRayCastY}");
                if (CAN_GRAB_L)
                {
                    Grab(ref IS_GRAB_L);
                }
                if (CAN_GRAB_R)
                {
                    Grab(ref IS_GRAB_R);
                }
            }


            #endregion

            #region Status

            if (_status == Status.IS_FALL)
            {
                float factor = 1f;

                if (((CAN_WALL_JUMP_L && _cPoints[(int)HSpots.ER]._isContact) || (CAN_WALL_JUMP_R && _cPoints[(int)HSpots.EL]._isContact)) && _isPush && CAN_MOVE_UP)
                {
                    factor = .05f; // Slow down when grip wall
                }

                _velocity.Y += _acceleration.Y * factor;

                if (_velocity.Y >= _speedMax.Y)
                {
                    _velocity.Y = _speedMax.Y;
                }
            }

            if (_status == Status.IS_LAND && _velocity.Y == 0)
            {
                if (CAN_MOVE_DOWN)
                {
                    Fall();
                }

                //_contactX = _x - _contactDown._mapX * _tileW; _contactY = _contactDown._mapY * _tileH;

                //_contactY = -((_contactY - _landLineA.Y) + (_landLineB.Y - _landLineA.Y) / (_landLineA.X - _landLineB.X) * _contactX) ;

                //_contactY = _contactY + _contactDown._mapY * _tileH;

                //Console.WriteLine($"_contactX = {_contactX} : {_contactY}");

                //if (_contactDown._isContact)
                //    _y = _contactY - _rect.Height / 2 - 2;
            }

            if (_status == Status.IS_GRAB)
            {
                ++_ticGrab;

                if (_ticGrab >= _tempoGrab)
                {
                    _ticGrab = _tempoGrab;

                    if (CAN_GRAB_L)
                    {
                        CAN_GRAB_L = false; CAN_CLIMB_L = true;
                    }
                    if (CAN_GRAB_R)
                    {
                        CAN_GRAB_R = false; CAN_CLIMB_R = true;
                    }


                    if (!_isPush) // When release button push then readyToClimb !
                    {
                        _readyToClimb = true;

                        if (MOVE_UP)
                        {
                            Console.WriteLine($"Climb < {IS_GRAB_L} - {IS_GRAB_R} > : MOVE_UP");

                            if (IS_GRAB_L)
                            {
                                Climb(-1);
                            }
                            if (IS_GRAB_R)
                            {
                                Climb(1);
                            }
                        }

                        if (MOVE_DOWN)
                        {
                            Fall();
                        }
                    }
                    else if (MOVE_JUMP)
                    {
                        Console.WriteLine($"Climb < {IS_GRAB_L} - {IS_GRAB_R} > : MOVE_JUMP");

                        _readyToClimb = true;

                        if (IS_GRAB_L)
                        {
                            Climb(-1);
                        }
                        if (IS_GRAB_R)
                        {
                            Climb(1);
                        }
                    }
                }
            }

            if (_status == Status.IS_CLIMB)
            {
                if (AUTO_UP)
                {
                    _y += -4f;

                    ++_ticAutoUp;
                    if (_ticAutoUp > _rect.Height / 4)
                    {
                        _ticAutoUp   = 0;
                        _ticAutoMove = 0;
                        AUTO_UP      = false;
                        AUTO_MOVE    = true;
                    }
                }
                if (AUTO_MOVE)
                {
                    _y += -.5f;

                    ++_ticAutoMove;
                    if (_ticAutoMove > _rect.Width / 4)
                    {
                        AUTO_MOVE          = false;
                        _directionAutoMove = 0;

                        //Fall();
                        SetStatus(Status.IS_LAND);
                    }

                    if (_directionAutoMove < 0)
                    {
                        _landRadian = Geo.GetRadian(_cPoints[(int)HSpots.EL]._firstline.B, _cPoints[(int)HSpots.EL]._firstline.A);
                        MoveL();
                    }
                    if (_directionAutoMove > 0)
                    {
                        _landRadian = Geo.GetRadian(_cPoints[(int)HSpots.ER]._firstline.A, _cPoints[(int)HSpots.ER]._firstline.B);
                        MoveR();
                    }
                }
            }

            if (_status == Status.IS_JUMP)
            {
                _velocity.Y += -_deceleration.Y;

                if (_velocity.Y <= 0 || !CAN_MOVE_UP)
                {
                    Fall();
                }
            }

            #endregion

            #region Jump Helper when left Land or Grab

            if (_onFall && _status == Status.IS_FALL && (_oldStatus == Status.IS_LAND || (_status == Status.IS_GRAB && !_isPush)))
            {
                _isJustFall  = true;
                _ticJustFall = 0;
                //Console.Write("<Just Fall from land >");
            }

            if (_isJustFall)
            {
                //if (!CAN_MOVE_UP)
                //{
                //    _isJustFall = false;
                //    SetStatus(Status.IS_FALL); Fall();
                //}

                if (MOVE_JUMP && !_onJump) // second chance to jump
                {
                    Console.WriteLine("Helper Jump !");

                    SetStatus(Status.IS_LAND);
                    Jump(_speedMax.Y);
                }

                ++_ticJustFall;
                if (_ticJustFall > _maxTicJustFall)
                {
                    //Console.Write("< Stop jump helper >");
                    _isJustFall  = false;
                    _ticJustFall = 0;
                }
            }


            if (_onCanWallJump)
            {
                Console.WriteLine("ON Can Wall Jump !");
                _onCanWallJump = false;

                _velocity.Y = 0f;
            }


            #endregion

            #region Trigger

            if (_onLand)
            {
                _onLand = false;

                _velocity.Y = 0;
                _velocity.X = 0;
            }

            if (_onFall)
            {
                _onFall      = false;
                _angleMove.Y = Geo.RAD_D;

                _velocity.X = 0;
                _velocity.Y = 0;
            }

            if (_onJump)
            {
                _onJump = false;
            }

            if (_onGrab)
            {
                _onGrab = false;
                //_isJustGrab = true;
                _velocity.Y = 0;
            }

            if (_onClimb)
            {
                _onClimb = false;
                //System.Console.Write("< ON_CLIMB >");
            }

            #endregion

            _oldX = _x;
            _oldY = _y;

            _x += _finalVector.X; //* (float)gameTime.ElapsedGameTime.TotalSeconds * 100;
            _y += _finalVector.Y; //* (float)gameTime.ElapsedGameTime.TotalSeconds * 100;

            MOVE_UP    = false;
            MOVE_DOWN  = false;
            MOVE_LEFT  = false;
            MOVE_RIGHT = false;

            MOVE_JUMP = false;
            MOVE_FALL = false;

            return(base.Update(gameTime));
        }