public void HandleCollision(GameObject obj1, GameObject obj2, CollisionResult collisionResult) { //if (!(obj2 is Player) && collisionResult.CollisionTime > 1e-10) if (obj2 is BasicGroundEnemy && collisionResult.collisionTime > 1e-10) { direction *= -1; obj1.Velocity.X *= -1; } }
public void HandleCollision(GameObject obj, BoundingPolygon p, Vector collisionNormal, CollisionResult collisionResult) { if (collisionNormal.X > 0.8) { direction = 1; } else if (collisionNormal.X < -0.8) { direction = -1; } else if (obj.Velocity.X > 0) { direction = 1; } else if (obj.Velocity.X < 0) { direction = -1; } }
//Handle collisions against edges public override void Collide(BoundingPolygon p, Vector collisionNormal, CollisionResult collisionResult) { //if (collisionResult.isIntersecting) return; base.Collide(p, collisionNormal, collisionResult); // If intersecting, push back if (collisionResult.isIntersecting) { Position += collisionResult.minimumTranslationVector; } else { remainingFrameTime -= collisionResult.collisionTime; if (collisionResult.hasIntersected) Position -= (1-collisionResult.collisionTime + 1e-6) * Velocity * frameTime; else Position -= collisionResult.minimumTranslationVector; Velocity = Velocity - ((1.0+objectPhysics.Elasticity)*Velocity.DotProduct(collisionNormal))*collisionNormal; Position += remainingFrameTime * Velocity * frameTime; /* * Run the event handlers */ if (Math.Abs(collisionNormal.X) > 0.8) OnCollidedWithWall(); if (collisionNormal.Y > 0.5) { if (!OnGround) { OnLanded(); OnGround = true; } inAirTimer.Restart(); } } // } }
public override void Collide(ICollidable o, Vector edgeNormal, CollisionResult collisionResult) { if (currentState == dieState) return; if (o is Coin) { PlayerState.Coins++; if (PlayerState.Coins >= 100) { PlayerState.Lives += PlayerState.Coins / 100; PlayerState.Coins = PlayerState.Coins % 100; } ((Coin)o).Delete = true; game.Audio.PlaySound("coin"); } else if (o is Mushroom && ((Mushroom)o).MushroomType == Mushroom.ItemType.RedMushroom) { Grow(); ((Mushroom)o).Delete = true; } else if (o is BasicGroundEnemy) { BasicGroundEnemy e = (BasicGroundEnemy)o; if (BoundingBox.Bottom >= o.BoundingBox.Top && e.Stompable && !e.Dying) { if (collisionResult.hasIntersected) { Velocity.Y = 200; e.Kill(); game.Audio.PlaySound("stomp"); } } else if (!e.Dying) { Shrink(); } } }
public override void Collide(BoundingPolygon p, Vector collisionNormal, CollisionResult collisionResult) { if (currentState == dieState) return; base.Collide (p, collisionNormal, collisionResult); if (collisionResult.hitNormal.X > 0.8 && sliding) { sliding = false; objectPhysics.Friction = oldFriction; } }
public void HandleCollision(GameObject obj1, GameObject obj2, CollisionResult collisionResult) { }
public void HandleCollision(GameObject obj, BoundingPolygon p, Vector collisionNormal, CollisionResult collisionResult) { }
public CollisionEvent(ICollidable obj1, ICollidable obj2, Vector normal, CollisionResult collisionResult) { collisionType = Type.OBJECT_OBJECT; object1 = obj1; object2 = obj2; this.collisionNormal = normal; this.collisionResult = collisionResult; }
/// <summary> /// Test collision against a series of polygons. /// </summary> public static void TestCollision(ICollidable o, List<BoundingPolygon> polygons, double frameTime) { if (polygons.Count == 0) return; //Applying Separating Axis theorem //First find all the axis. They are the union of the object's edge normals, and the polygon's edge normals. //The polygon's edge normals will be retrieved for each polygon that is checked. List<Vector>[] edges = {o.BoundingBox.EdgeNormals, null}; double remainingFrameTime = 1; int loopCount = 0; #if DEBUG_COLLISION_OBJECT_POLYGON int collCount = 0; Log.Write("Testing collision object vs polygon, polygon count: " + polygons.Count, Log.DEBUG); #endif //As long as we may get another collision in this frame while (o.Velocity.DotProduct(o.Velocity) > 0 && remainingFrameTime > 0/* && loopCount < 4*/) { BoundingPolygon oldBoundingBox = (BoundingPolygon)o.BoundingBox.Clone(); oldBoundingBox.Translate(-o.Velocity.X*frameTime*remainingFrameTime, -o.Velocity.Y*frameTime*remainingFrameTime); loopCount++; //This is the reference to the first edge we're colliding with. If null at the end, we didn't collide. BoundingPolygon firstCollisionPolygon = null; //The current minimum time until collision double minimumCollisionTime = double.PositiveInfinity; //Final collision results CollisionResult finalResult = new CollisionResult(); //How far have we actually moved this frame? Vector velocity = o.Velocity * frameTime; //Set the minimum translation vector to the longest vector possible during a frame finalResult.minimumTranslationVector = o.Velocity * frameTime; finalResult.frameTime = frameTime; int finalNormalOwner = -1; //Check each edge foreach (BoundingPolygon p in polygons) { /*if (p.Vertices.Count == 2 && p.EdgeNormals[0].DotProduct(o.Velocity) > 0) { #if DEBUG_COLLISION_OBJECT_POLYGON Log.Write("Polygon has only one edge, which faces the same way as the movement direction. Ignoring.", Log.DEBUG); #endif continue; }*/ #if DEBUG_COLLISION_OBJECT_POLYGON Log.Write("Object bounding polygon: " + o.BoundingBox, Log.DEBUG); Log.Write("Testing polygon " + p, Log.DEBUG); #endif //Collision results for the current polygon CollisionResult result = new CollisionResult(); edges[1] = p.EdgeNormals; bool separating = false; int normalOwner = -1; for (int i = 0; i < edges.Length; i++) { var poly = edges[i]; foreach (Vector axis in poly) { // Do the collision test on the polygons testAxis(ProjectPolygon(oldBoundingBox, axis), ProjectPolygon(p, axis), velocity, axis, result, remainingFrameTime, i); if (object.ReferenceEquals(axis, result.hitNormal)) normalOwner = i; if (!result.hasIntersected && !result.isIntersecting) { separating = true; break; } if (result.isIntersecting && double.IsNegativeInfinity(result.distance)) result.isIntersecting = false; } if (separating) break; } //Already intersecting if (result.isIntersecting) { finalResult = result; finalNormalOwner = normalOwner; minimumCollisionTime = 0; firstCollisionPolygon = p; } //Will intersect with p in the future. //If we're not already overlapping with another polygon, go ahead and update the current minimum collision time. else if (result.hasIntersected) { //If the collision time is the smallest so far, if (result.collisionTime < minimumCollisionTime) { minimumCollisionTime = result.collisionTime; finalResult = result; finalNormalOwner = normalOwner; firstCollisionPolygon = p; } } } //If we have a first collision, call the collision handler if (firstCollisionPolygon != null) { if (finalResult.isIntersecting) finalResult.minimumTranslationVector = (finalNormalOwner == 0 ? 1 : -1) * Math.Abs(finalResult.distance) * finalResult.hitNormal; //o.Velocity * finalResult.distance * frameTime; remainingFrameTime -= minimumCollisionTime; //Subtract a small amount to behave correctly when we have small rounding errors. finalResult.collisionTime = minimumCollisionTime; // - 1e-6;//Constants.MinDouble; o.Collide(firstCollisionPolygon, finalNormalOwner == 1 ? finalResult.hitNormal : -finalResult.hitNormal, finalResult); #if DEBUG_COLLISION_OBJECT_POLYGON Log.Write("COLLISION." + " Time: " + finalResult.collisionTime + " Normal: " + finalResult.hitNormal + " Remaining: " + remainingFrameTime + " Collision polygon: " + firstCollisionPolygon + " Velocity: " + o.Velocity + " Translation vector: " + finalResult.minimumTranslationVector, Log.DEBUG); collCount++; #endif } else { remainingFrameTime = 0; #if DEBUG_COLLISION_OBJECT_POLYGON Log.Write("NO COLLISION.", Log.DEBUG); #endif } } #if DEBUG_COLLISION_OBJECT_POLYGON Log.Write("Collision count: " + collCount + "\n", Log.DEBUG); #endif }
public CollisionEvent(ICollidable obj, BoundingPolygon p, Vector normal, CollisionResult collisionResult) { collisionType = Type.OBJECT_POLYGON; object1 = obj; polygon = p; collisionNormal = normal; this.collisionResult = collisionResult; }
/// <summary> /// Test one axis with SAT. /// Updates result if there is a "better" hit /// </summary> private static void testAxis(Projection prj1, Projection prj2, Vector relativeVelocity, Vector axis, CollisionResult result, double remainingFrameFraction, int axisOwner) { bool isIntersecting = false, willIntersect = false; double t = 0; //Collision time //Positive distance means we don't have an overlap. Negative means we have an overlap. double distance = prj1.GetDistance(prj2); #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT Log.Write("\tTesting axis " + axis + ", relative vel: " + relativeVelocity, Log.DEBUG); Log.Write("\tProjection 1: " + prj1 + " Projection 2: " + prj2, Log.DEBUG); Log.Write("\tDistance " + distance, Log.DEBUG); #endif //Already intersecting? if (distance < 0) { isIntersecting = true; #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT Log.Write("\tIntersecting.", Log.DEBUG); #endif } else { //Calculate velocity component in direction of axis double velAxis = axis.DotProduct(relativeVelocity); //if (velAxis < Constants.MinDouble) velAxis = 0; #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT Log.Write("\tNot intersecting. Velocity along axis: " + velAxis, Log.DEBUG); #endif //If projection of polygon 2 is to the right of polygon 1, AND we have a positive velocity along the axis //OR projection of polygon 1 is to the left of polygon 2 AND we have a negative velocity along axis //then we might have a collision in the future. If not, the objects are either moving in separate directions //or they are staying still. if ((velAxis > 0 && prj2.Min >= prj1.Max) || (velAxis < 0 && prj1.Min >= prj2.Max)) { //If the axis belongs to object 1, and it's facing the opposite direction of the velocity, //then ignore it because it can't collide. Also, if the axis belongs to object 2, //and the axis faces the same direction as the velocity, also ignore it. #if DEBUG_COLLISION_OBJECT_POLYGON Log.Write("\tAxis dot Velocity: " + axis.DotProduct(relativeVelocity) * (axisOwner == 0 ? -1 : 1) + " Axis: " + axis, Log.DEBUG); #endif //Ignore this test if the axis faces the wrong way if (axis.DotProduct(relativeVelocity) * (axisOwner == 0 ? -1 : 1) > Constants.MinDouble) { #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT Log.Write("\tIgnoring test because the edge faces the wrong way. Dot: " + axis.DotProduct(relativeVelocity) * (axisOwner == 0 ? -1 : 1) + "Owner: " + axisOwner); #endif distance = double.NegativeInfinity; isIntersecting = true; } else { t = distance / Math.Abs(velAxis); if (t < remainingFrameFraction) willIntersect = true; #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT Log.Write("\tCollision time: " + t, Log.DEBUG); #endif } } #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT else { Log.Write("\tMoving the wrong way. No collision.", Log.DEBUG); } #endif } //Find the "best" guess of HOW the objects collides. //That is, what direction, and what normal was intersected first. if ((!result.isIntersecting && !result.hasIntersected) || //If the result intersection flags are both false, this is the first test. (result.isIntersecting && (willIntersect || (isIntersecting && result.distance < distance))) || //Previous result was an overlapping one, while the latest result indicate o1 and o2 will collide in the future instead, (result.hasIntersected && willIntersect && t > result.collisionTime)) //Previous result was that o1 and o2 collides in the future, but this result indicates that they collide later. { result.isIntersecting = isIntersecting; result.hasIntersected = willIntersect; result.collisionTime = t; result.distance = distance; result.hitNormal = axis; #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT Log.Write("\tNew best axis", Log.DEBUG); #endif } //No intersection now or in the future. else if (!isIntersecting && !willIntersect) { result.hasIntersected = false; result.isIntersecting = false; } }
/// <summary> /// Test collision between two objects. /// </summary> public static void TestCollision(ICollidable o1, ICollidable o2, double frameTime) { #if DEBUG_COLLISION_OBJECT_OBJECT Log.Write("Begin collision test object vs object", Log.DEBUG); Log.Write("Bounding box 1: " + o1.BoundingBox.ToString(), Log.DEBUG); Log.Write("Bounding box 2: " + o2.BoundingBox.ToString(), Log.DEBUG); #endif //Calculate relative velocity between o1 and o2, as seen from o1 Vector relativeVelocity = (o1.Velocity - o2.Velocity)*frameTime; #if DEBUG_COLLISION_OBJECT_OBJECT Log.Write("Velocity 1 " + o1.Velocity + " Velocity 2 " + o2.Velocity, Log.DEBUG); #endif CollisionResult result = new CollisionResult(); result.frameTime = frameTime; bool separating = false; int normalOwner = -1; List<Vector>[] polygons = {o1.BoundingBox.EdgeNormals, o2.BoundingBox.EdgeNormals}; // Find each edge normal in the bounding polygons, which is used as axes. //foreach (var poly in polygons) for (int i = 0; i < polygons.Length; i++) { var poly = polygons[i]; // If the result is ever null, we have a separating axis, and we can cancel the search. foreach (var axis in poly) { //Test for collision on one axis testAxis(ProjectPolygon(o1.BoundingBox, axis), ProjectPolygon(o2.BoundingBox, axis), relativeVelocity, axis, result, 1, i); if (object.ReferenceEquals(axis, result.hitNormal)) normalOwner = i; //No intersection (now or in the future) if (!result.isIntersecting && !result.hasIntersected) { separating = true; break; } } if (separating) break; } if (!separating) { #if DEBUG_COLLISION_OBJECT_OBJECT Log.Write("COLLISION. Normal: " + result.hitNormal + " Time: " + result.collisionTime, Log.DEBUG); #endif if (result.isIntersecting) result.minimumTranslationVector = result.hitNormal * result.distance * frameTime; result.frameTime = frameTime; collisionEvents.Add(new CollisionEvent(o1, o2, normalOwner == 1 ? result.hitNormal : -result.hitNormal, result)); collisionEvents.Add(new CollisionEvent(o2, o1, normalOwner == 0 ? result.hitNormal : -result.hitNormal, result)); } #if DEBUG_COLLISION_OBJECT_OBJECT else { Log.Write("NO COLLISION", Log.DEBUG); } Log.Write(""); #endif }
public virtual void Collide(ICollidable o, Vector edgeNormal, CollisionResult collisionResult) { if (controller != null) controller.HandleCollision(this, (GameObject)o, collisionResult); }
public virtual void Collide(BoundingPolygon p, Vector collisionNormal, CollisionResult collisionResult) { if (controller != null) controller.HandleCollision(this, p, collisionNormal, collisionResult); }