private bool TestMapCollision(Rectangle kollitionsRect, Edge riktning, KollitionsStatusTiled KollitionsStatus, out int KollitsionResponse) { KollitsionResponse = 0; Edge side = riktning.OppositeEdge(); int perpindicularPosition = side.IsVertical() ? kollitionsRect.Center.X : kollitionsRect.Center.Y; int leadingPosition = kollitionsRect.GetSide(riktning); bool shouldTestSlopes = side.IsVertical(); PopulateCollidingTiles(kollitionsRect, riktning); for (int i = 0; i < KolliderandeTiles.Count; i++) { if (KolliderandeTiles[i] == null) { continue; } // disregard horizontal collisions with tiles on the same row as a slope if the last tile we were grounded on was a slope. // the y collision response will push us up on the slope. if (riktning.IsHorizontal() && KollitionsStatus.SitaGrundadeTile != null && KollitionsStatus.SitaGrundadeTile.IsSlope() && IsSlopeCollisionRow(KolliderandeTiles[i].Y)) { continue; } if (TestTileCollision(KolliderandeTiles[i], side, perpindicularPosition, leadingPosition, shouldTestSlopes, out KollitsionResponse)) { // store off our last ground tile if we collided below if (riktning == Edge.Bottom) { KollitionsStatus.SitaGrundadeTile = KolliderandeTiles[i]; KollitionsStatus.GrundadPåEnkelriktadPlatform = KollitionsStatus.SitaGrundadeTile.IsOneWayPlatform(); } return(true); } // special case for sloped ground tiles if (KollitionsStatus.SitaGrundadeTile != null && riktning == Edge.Bottom) { // if grounded on a slope and intersecting a slope or if grounded on a wall and intersecting a tall slope we go sticky. // tall slope here means one where the the slopeTopLeft/Right is 0, i.e. it connects to a wall var isHighSlopeNearest = KolliderandeTiles[i].IsSlope() && KolliderandeTiles[i].GetNearestEdge(perpindicularPosition) == KolliderandeTiles[i].GetHighestSlopeEdge(); if ((KollitionsStatus.SitaGrundadeTile.IsSlope() && KolliderandeTiles[i].IsSlope()) || (!KollitionsStatus.SitaGrundadeTile.IsSlope() && isHighSlopeNearest)) { // store off our last ground tile if we collided below KollitionsStatus.SitaGrundadeTile = KolliderandeTiles[i]; return(true); } } } return(false); }
/// <summary> /// moves the Entity taking into account the tiled map /// </summary> /// <param name="rörelse">Motion.</param> /// <param name="boxCollider">Box collider.</param> public void Move(Vector2 rörelse, BoxCollider boxCollider, KollitionsStatusTiled KollitionsStatus) { if (Karta == null) { return; } // test for collisions then move the Entity TestCollisions(ref rörelse, boxCollider.Bounds, KollitionsStatus); boxCollider.UnregisterColliderWithPhysicsSystem(); boxCollider.Entity.Transform.Position += rörelse; boxCollider.RegisterColliderWithPhysicsSystem(); }
public void TestCollisions(ref Vector2 rörelse, Rectangle boxColliderGränser, KollitionsStatusTiled KollitionsStatus) { BoxColliderGränser = boxColliderGränser; // save off our current grounded state which we will use for wasGroundedLastFrame and becameGroundedThisFrame KollitionsStatus.VarGrundadFöraFramen = KollitionsStatus.Under; // reset our collisions state KollitionsStatus.Återställ(ref rörelse); // reset rounded motion for us while dealing with subpixel movement so fetch the rounded values to use for our actual detection int motionX = (int)rörelse.X; int motionY = (int)rörelse.Y; // first, check movement in the horizontal dir if (motionX != 0) { Edge direction = motionX > 0 ? Edge.Right : Edge.Left; Rectangle sweptBounds = CollisionRectForSide(direction, motionX); int collisionResponse; if (TestMapCollision(sweptBounds, direction, KollitionsStatus, out collisionResponse)) { // react to collision. get the distance between our leading edge and what we collided with rörelse.X = collisionResponse - boxColliderGränser.GetSide(direction); KollitionsStatus.Vänster = direction == Edge.Left; KollitionsStatus.Höger = direction == Edge.Right; KollitionsStatus.RörelsePåminareX.Reset(); } else { KollitionsStatus.Vänster = false; KollitionsStatus.Höger = false; } } // next, check movement in the vertical dir { Edge riktning = motionY >= 0 ? Edge.Bottom : Edge.Top; Rectangle sweptGränser = CollisionRectForSide(riktning, motionY); sweptGränser.X += (int)rörelse.X; int KollitsionResponse; if (TestMapCollision(sweptGränser, riktning, KollitionsStatus, out KollitsionResponse)) { // react to collision. get the distance between our leading edge and what we collided with rörelse.Y = KollitsionResponse - boxColliderGränser.GetSide(riktning); KollitionsStatus.Ovanför = riktning == Edge.Top; KollitionsStatus.Under = riktning == Edge.Bottom; KollitionsStatus.RörelsePåminareY.Reset(); if (KollitionsStatus.Under && KollitionsStatus.SitaGrundadeTile?.IsSlope() == true) { KollitionsStatus.SlopeVinkel = MathHelper.ToDegrees((float)Math.Atan(KollitionsStatus.SitaGrundadeTile.GetSlope())); } } else { KollitionsStatus.Ovanför = false; KollitionsStatus.Under = false; KollitionsStatus.SitaGrundadeTile = null; } // when moving down we also check for collisions in the opposite direction. this needs to be done so that ledge bumps work when // a jump is made but misses by the colliderVerticalInset if (riktning == Edge.Bottom) { riktning = riktning.OppositeEdge(); sweptGränser = CollisionRectForSide(riktning, 0); sweptGränser.X += (int)rörelse.X; sweptGränser.Y += (int)rörelse.Y; if (TestMapCollision(sweptGränser, riktning, KollitionsStatus, out KollitsionResponse)) { // react to collision. get the distance between our leading edge and what we collided with rörelse.Y = KollitsionResponse - boxColliderGränser.GetSide(riktning); // if we collide here this is an overlap of a slope above us. this small bump down will prevent hitches when hitting // our head on a slope that connects to a solid tile. It puts us below the slope when the normal response would put us // above it rörelse.Y += 2; KollitionsStatus.Ovanför = true; } } } // set our becameGrounded state based on the previous and current collision state if (!KollitionsStatus.VarGrundadFöraFramen && KollitionsStatus.Under) { KollitionsStatus.BlevGrundadDennaFrame = true; } }