Exemple #1
0
        /// <summary>
        /// Tests the tile for a collision. Returns via out the position in world space where the collision occured.
        /// </summary>
        /// <returns>The tile collision.</returns>
        /// <param name="tile">Tile.</param>
        /// <param name="edgeToTest">the opposite side of movement, the side the leading edge will collide with</param>
        /// <param name="perpindicularPosition">Perpindicular position.</param>
        /// <param name="leadingPosition">Leading position.</param>
        /// <param name="shouldTestSlopes">Should test slopes.</param>
        /// <param name="collisionResponse">Collision response.</param>
        bool testTileCollision(TiledTile tile, Edge edgeToTest, int perpindicularPosition, int leadingPosition, bool shouldTestSlopes, out int collisionResponse)
        {
            collisionResponse = leadingPosition;

            // one way platforms are only collideable from the top when the player is already above them
            if (tile.isOneWayPlatform())
            {
                // only the top edge of one way platforms are checked for collisions
                if (edgeToTest != Edge.Top)
                {
                    return(false);
                }

                // our response should be the top of the platform
                collisionResponse = tiledMap.tileToWorldPositionX(tile.y);
                return(_boxColliderBounds.Bottom <= collisionResponse);
            }

            var forceSlopedTileCheckAsWall = false;

            // when moving horizontally the only time a slope is considered for collision testing is when its closest side is the tallest side
            // and we were not intesecting the tile before moving.
            // this prevents clipping through a tile when hitting its edge: -> |\
            if (edgeToTest.isHorizontal() && tile.isSlope() && tile.getNearestEdge(leadingPosition) == tile.getHighestSlopeEdge())
            {
                var moveDir = edgeToTest.oppositeEdge();
                var leadingPositionPreMovement = _boxColliderBounds.getSide(moveDir);

                // we need the tile x position that is on the opposite side of our move direction. Moving right we want the left edge
                var tileX = moveDir == Edge.Right ? tiledMap.tileToWorldPositionX(tile.x) : tiledMap.tileToWorldPositionX(tile.x + 1);

                // using the edge before movement, we see if we were colliding before moving.
                var wasCollidingBeforeMove = moveDir == Edge.Right ? leadingPositionPreMovement > tileX : leadingPositionPreMovement < tileX;

                // if we were not colliding before moving we need to consider this tile for a collision check as if it were a wall tile
                forceSlopedTileCheckAsWall = !wasCollidingBeforeMove;
            }


            if (forceSlopedTileCheckAsWall || !tile.isSlope())
            {
                switch (edgeToTest)
                {
                case Edge.Top:
                    collisionResponse = tiledMap.tileToWorldPositionY(tile.y);
                    break;

                case Edge.Bottom:
                    collisionResponse = tiledMap.tileToWorldPositionY(tile.y + 1);
                    break;

                case Edge.Left:
                    collisionResponse = tiledMap.tileToWorldPositionX(tile.x);
                    break;

                case Edge.Right:
                    collisionResponse = tiledMap.tileToWorldPositionX(tile.x + 1);
                    break;
                }

                return(true);
            }

            if (shouldTestSlopes)
            {
                var tileWorldX = tiledMap.tileToWorldPositionX(tile.x);
                var tileWorldY = tiledMap.tileToWorldPositionX(tile.y);
                var slope      = tile.getSlope();
                var offset     = tile.getSlopeOffset();

                // calculate the point on the slope at perpindicularPosition
                collisionResponse = (int)(edgeToTest.isVertical() ? slope * (perpindicularPosition - tileWorldX) + offset + tileWorldY : (perpindicularPosition - tileWorldY - offset) / slope + tileWorldX);
                var isColliding = edgeToTest.isMax() ? leadingPosition <= collisionResponse : leadingPosition >= collisionResponse;

                // this code ensures that we dont consider collisions on a slope while jumping up that dont intersect our collider.
                // It also makes sure when testing the bottom edge that the leadingPosition is actually above the collisionResponse.
                // HACK: It isn't totally perfect but it does the job
                if (isColliding && edgeToTest == Edge.Bottom && leadingPosition <= collisionResponse)
                {
                    isColliding = false;
                }

                return(isColliding);
            }

            return(false);
        }
Exemple #2
0
		/// <summary>
		/// Tests the tile for a collision. Returns via out the position in world space where the collision occured.
		/// </summary>
		/// <returns>The tile collision.</returns>
		/// <param name="tile">Tile.</param>
		/// <param name="edgeToTest">the opposite side of movement, the side the leading edge will collide with</param>
		/// <param name="perpindicularPosition">Perpindicular position.</param>
		/// <param name="leadingPosition">Leading position.</param>
		/// <param name="shouldTestSlopes">Should test slopes.</param>
		/// <param name="collisionResponse">Collision response.</param>
		bool testTileCollision( TiledTile tile, Edge edgeToTest, int perpindicularPosition, int leadingPosition, bool shouldTestSlopes, out int collisionResponse )
		{
			collisionResponse = leadingPosition;

			// one way platforms are only collideable from the top when the player is already above them
			if( tile.isOneWayPlatform() )
			{
				// only the top edge of one way platforms are checked for collisions
				if( edgeToTest != Edge.Top )
					return false;

				// our response should be the top of the platform
				collisionResponse = tiledMap.tileToWorldPositionX( tile.y );
				return _boxColliderBounds.Bottom <= collisionResponse;
			}

			var forceSlopedTileCheckAsWall = false;

			// when moving horizontally the only time a slope is considered for collision testing is when its closest side is the tallest side
			// and we were not intesecting the tile before moving.
			// this prevents clipping through a tile when hitting its edge: -> |\
			if( edgeToTest.isHorizontal() && tile.isSlope() && tile.getNearestEdge( leadingPosition ) == tile.getHighestSlopeEdge() )
			{
				var moveDir = edgeToTest.oppositeEdge();
				var leadingPositionPreMovement = _boxColliderBounds.getSide( moveDir );

				// we need the tile x position that is on the opposite side of our move direction. Moving right we want the left edge
				var tileX = moveDir == Edge.Right ? tiledMap.tileToWorldPositionX( tile.x ) : tiledMap.tileToWorldPositionX( tile.x + 1 );

				// using the edge before movement, we see if we were colliding before moving.
				var wasCollidingBeforeMove = moveDir == Edge.Right ? leadingPositionPreMovement > tileX : leadingPositionPreMovement < tileX;

				// if we were not colliding before moving we need to consider this tile for a collision check as if it were a wall tile
				forceSlopedTileCheckAsWall = !wasCollidingBeforeMove;
			}


			if( forceSlopedTileCheckAsWall || !tile.isSlope() )
			{				
				switch( edgeToTest )
				{
					case Edge.Top:
						collisionResponse = tiledMap.tileToWorldPositionY( tile.y );
						break;
					case Edge.Bottom:
						collisionResponse = tiledMap.tileToWorldPositionY( tile.y + 1 );
						break;
					case Edge.Left:
						collisionResponse = tiledMap.tileToWorldPositionX( tile.x );
						break;
					case Edge.Right:
						collisionResponse = tiledMap.tileToWorldPositionX( tile.x + 1 );
						break;
				}

				return true;
			}

			if( shouldTestSlopes )
			{
				var tileWorldX = tiledMap.tileToWorldPositionX( tile.x );
				var tileWorldY = tiledMap.tileToWorldPositionX( tile.y );
				var slope = tile.getSlope();
				var offset = tile.getSlopeOffset();

				// calculate the point on the slope at perpindicularPosition
				collisionResponse = (int)( edgeToTest.isVertical() ? slope * ( perpindicularPosition - tileWorldX ) + offset + tileWorldY : ( perpindicularPosition - tileWorldY - offset ) / slope + tileWorldX );
				var isColliding = edgeToTest.isMax() ? leadingPosition <= collisionResponse : leadingPosition >= collisionResponse;

				// this code ensures that we dont consider collisions on a slope while jumping up that dont intersect our collider.
				// It also makes sure when testing the bottom edge that the leadingPosition is actually above the collisionResponse.
				// HACK: It isn't totally perfect but it does the job
				if( isColliding && edgeToTest == Edge.Bottom && leadingPosition <= collisionResponse )
					isColliding = false;
				
				return isColliding;
			}

			return false;
		}