//private static Vector2 ExitVector(Box collision, Box collisionWith) //{ // Box intersection = Box.Intersect(collision, collisionWith); // Vector2 intersectionVector = new Vector2(intersection.Width, intersection.Height); // Vector2 directionVector = collision.Center - collisionWith.Center; // // if (directionVector == Vector2.Zero) // { // directionVector.X = -1; // } // // Vector2 exitVector = intersectionVector * (directionVector / directionVector.Length()); // // if ((exitVector.Y != 0) && (Math.Abs(exitVector.X) > Math.Abs(exitVector.Y))) // { // exitVector.X = 0; // } // else if ((exitVector.X != 0) && (Math.Abs(exitVector.Y) > Math.Abs(exitVector.X))) // { // exitVector.Y = 0; // } // // return exitVector; //} public static void MovementCollision(KineticBox box, SpatialGrid spatialGrid) { //S'il y a vraiment collision if (Intersect(box, spatialGrid.GetProbableSolidCollisions(box))) { Vector2 exitVector = box.OldLocation - box.Location; KineticBox copy = ResolveMovementCollision(box, exitVector, spatialGrid); Vector2 finalMovement = box.Location - copy.Location; IEnumerable <Box> solids = spatialGrid.GetProbableSolidCollisions(copy); if (((finalMovement.X < 0) && (LeftCollision(copy, solids))) || ((finalMovement.X > 0) && ((RightCollision(copy, solids))))) { finalMovement.X = 0; } if (((finalMovement.Y < 0) && (TopCollision(copy, solids))) || ((finalMovement.Y > 0) && (BottomCollision(copy, solids)))) { finalMovement.Y = 0; } if (finalMovement != Vector2.Zero) { copy.Offset(finalMovement); MovementCollision(copy, spatialGrid); } else { box.Speed = Vector2.Zero; } box.Location = copy.Location; } }
//C'est sacré public static void StopSpeed(KineticBox box, SpatialGrid spatialGrid) { //Restore l'ancienne vitesse en vérifiant quels côtés ont fait la collision IEnumerable <Box> solids = spatialGrid.GetProbableSolidCollisions(box); if (((box.Speed.X <= 0) && (LeftCollision(box, solids))) || ((box.Speed.X >= 0) && ((RightCollision(box, solids))))) { box.Speed.X = 0; } if (((box.Speed.Y <= 0) && (TopCollision(box, solids))) || ((box.Speed.Y >= 0) && (BottomCollision(box, solids)))) { box.Speed.Y = 0; } }
public static void ExpulseCollision(Box sender, SpatialGrid spatialGrid) { if (sender.Solid) { foreach (Box aabb in spatialGrid.GetProbableCollisions(sender)) { if (aabb is KineticBox) { KineticBox box = aabb as KineticBox; if ((box.InteractWithSolid) && (box.Intersects(sender))) { ClassicCollision(box, spatialGrid); } } } } }
public override void Update(GameTime gameTime) { foreach (Box aabb in boxes.Values) { if (aabb is KineticBox) { KineticBox box = aabb as KineticBox; box.UpdateSpeed(gameTime); box.Update(gameTime); box.UpdateLocation(gameTime); CollisionHelper.StopSpeed(box, SpatialGrid); } else { aabb.Update(gameTime); } } }
public override void Draw(GameTime gameTime) { SpriteBatch spriteBatch = Game.Services.GetService <SpriteBatch>(); foreach (Box aabb in SpatialGrid.GetProbableCollisions(new Box(null, 0, 0, Width, Height))) { if (aabb.CollisionSide.HasFlag(Box.CollisionDirection.Inside)) { DrawHelper.DrawRectangle(spriteBatch, aabb.Rectangle, new Color(Color.Green, 0.1f)); } DrawHelper.DrawOutline(spriteBatch, aabb.Rectangle, Color.Black); if (aabb.CollisionSide.HasFlag(Box.CollisionDirection.Top)) { DrawHelper.DrawRectangle(spriteBatch, new Rectangle(aabb.Rectangle.Left, aabb.Rectangle.Top, aabb.Rectangle.Width, 1), Color.Green); } if (aabb.CollisionSide.HasFlag(Box.CollisionDirection.Left)) { DrawHelper.DrawRectangle(spriteBatch, new Rectangle(aabb.Rectangle.Left, aabb.Rectangle.Top, 1, aabb.Rectangle.Height), Color.Green); } if (aabb.CollisionSide.HasFlag(Box.CollisionDirection.Right)) { DrawHelper.DrawRectangle(spriteBatch, new Rectangle(aabb.Rectangle.Right - 1, aabb.Rectangle.Top, 1, aabb.Rectangle.Height), Color.Green); } if (aabb.CollisionSide.HasFlag(Box.CollisionDirection.Bottom)) { DrawHelper.DrawRectangle(spriteBatch, new Rectangle(aabb.Rectangle.Left, aabb.Rectangle.Bottom - 1, aabb.Rectangle.Width, 1), Color.Green); } if (aabb is KineticBox) { KineticBox box = aabb as KineticBox; Vector2 end = box.Acceleration; end *= (float)gameTime.ElapsedGameTime.TotalSeconds; DrawHelper.DrawLine(spriteBatch, box.Rectangle.Center, box.Rectangle.Center + end.ToPoint(), Color.Red); end = box.Speed; end *= (float)gameTime.ElapsedGameTime.TotalSeconds; DrawHelper.DrawLine(spriteBatch, box.Rectangle.Center, box.Rectangle.Center + end.ToPoint(), Color.Blue); } } SpatialGrid.Draw(gameTime); }
//Use with caution public static void ClassicCollision(KineticBox sender, SpatialGrid spatialGrid) { if (sender.InteractWithSolid) { Vector2 exitVector = Vector2.Zero; int total = 1; foreach (Box collision in spatialGrid.GetProbableSolidCollisions(sender)) { if (collision.Intersects(sender)) { exitVector += sender.ExitVector(collision); total++; } } if (exitVector != Vector2.Zero) { exitVector /= total; sender.Offset(exitVector); } } }
private static KineticBox ResolveMovementCollision(KineticBox box, Vector2 exitVector, SpatialGrid spatialGrid) { KineticBox copy = new KineticBox(box); //Tant que la collision n'est pas résolue while (copy.Location != copy.OldLocation) //Pourrait être optimisé contre une perte de précision? { if (Intersect(copy, spatialGrid.GetProbableSolidCollisions(copy))) { //Défait le mouvement qui créer la collion copy.Offset(exitVector); } else { //Avance plus lentement vers la collion exitVector /= 2; copy.Offset(-exitVector); } } return(copy); }
private void aabb_PropertyChanged(Box sender, PropertyChangedEventArgs e) { SpatialGrid.Add(sender); if (sender is KineticBox) { KineticBox box = sender as KineticBox; if (box.SpeedUpdate) { CollisionHelper.MovementCollision(box, SpatialGrid); } else { CollisionHelper.ClassicCollision(box, SpatialGrid); } } else { CollisionHelper.ExpulseCollision(sender, SpatialGrid); } CollisionHelper.SetCollisionNotification(sender, SpatialGrid); }
public KineticBox(KineticBox box) : this(box.Game, box.X, box.Y, box.Width, box.Height, box.Solid, box.InteractWithSolid, box.MovementIncrement) { }