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)); }