public CollisionRule(PhysicalObject obj, CollisionAction action, Action <PhysicalObject> method = null) { Type = CollisionRuleType.Object; Target = obj; Action = action; Method = method; }
public List <PhysicalObject> GetCollisionCandidates(PhysicalObject obj) { List <PhysicalObject> targets = new List <PhysicalObject>(Objects); //check in the child trees this object overlaps with if (Children[0] != null) { bool[] fits = FitObject(obj); if (fits[0]) { targets.AddRange(Children[0].GetCollisionCandidates(obj)); } if (fits[1]) { targets.AddRange(Children[1].GetCollisionCandidates(obj)); } if (fits[2]) { targets.AddRange(Children[2].GetCollisionCandidates(obj)); } if (fits[3]) { targets.AddRange(Children[3].GetCollisionCandidates(obj)); } } targets.Remove(obj); return(targets); }
public CollisionRule(PhysicalObject obj, CollisionAction action, Action<PhysicalObject> method = null) { Type = CollisionRuleType.Object; Target = obj; Action = action; Method = method; }
/// <summary> /// Returns the childtrees the given object fits in. /// 0-3, left-to-right, top-to-bottom. /// 4 is true when the object doesn't fit in just one quadrant. /// </summary> private bool[] FitObject(PhysicalObject obj) { bool[] fits = new bool[5]; byte quadrants = 0; if (obj.CoverableArea.Position.X <= Center.X) { if (obj.CoverableArea.Position.Y <= Center.Y) { fits[0] = true; quadrants++; } if (obj.CoverableArea.Position2.Y >= Center.Y) { fits[2] = true; quadrants++; } } if (obj.CoverableArea.Position2.X >= Center.X) { if (obj.CoverableArea.Position.Y <= Center.Y) { fits[1] = true; quadrants++; } if (obj.CoverableArea.Position2.Y >= Center.Y) { fits[3] = true; quadrants++; } } if (quadrants > 1) { fits[4] = true; } return(fits); }
/// <summary> /// Performs the calculated collision. /// pair determines whether both object's involved (if they are) will be performed, second one will be called with false to prevent loopdeeloops. /// </summary> internal void PerformClosestCollision(bool pair = true) { //what do you mean perform? if (SpeedLeft == 0f) { return; } //if no collision was found move the remaining distance if (ClosestCollisionSpeedFraction == float.PositiveInfinity) { Position += Speed * SpeedLeft; SpeedLeft = 0f; return; } //move to touching point Position += Speed * ClosestCollisionSpeedFraction; SpeedLeft -= ClosestCollisionSpeedFraction; switch (ClosestCollisionRule.Action) { case CollisionAction.Block: Speed = 0f; SpeedLeft = 0f; break; case CollisionAction.Bounce: float speedDirection = SpeedDirection; float angleDifference = Misc.GetRelativeAngle(ClosestCollisionRelativeSpeed.GetAngleFromOrigin(), speedDirection); //prevent from bouncing if it is getting hit from around the side or back (another object just hit this one) if (angleDifference > -60f && angleDifference < 60f) { SpeedDirection = speedDirection - 180f + (ClosestCollisionTouchingAxis.GetAngleFromOrigin() - speedDirection - 90f) * 2; } break; } ClosestCollisionRule.CallMethod(ClosestCollisionMethodArg); if (ClosestCollisionRule.DeactivateAfterCollision) { ClosestCollisionRule.Active = false; } //make sure the other object (if any) performs his collision too before it gets rechecked if (pair && (ClosestCollisionRule.Type == CollisionRuleType.Object || ClosestCollisionRule.Type == CollisionRuleType.Objectmap || ClosestCollisionRule.Type == CollisionRuleType.ObjectType)) { //do not blindly assume the other object will collide against this one as well PhysicalObject otherObj = ((PhysicalObject)ClosestCollisionMethodArg); if (otherObj.ClosestCollisionRule != null && (otherObj.ClosestCollisionRule.Type == CollisionRuleType.Object || otherObj.ClosestCollisionRule.Type == CollisionRuleType.Objectmap || otherObj.ClosestCollisionRule.Type == CollisionRuleType.ObjectType) && otherObj.ClosestCollisionMethodArg == this) { otherObj.PerformClosestCollision(false); } } }
private static void Step() { //push input state Input.PushState(); //process all SDL events SDL.Event e; while (SDL.PollEvent(out e) == 1) { switch (e.type) { //let Input handle input related events case SDL.EventType.MOUSEBUTTONDOWN: case SDL.EventType.MOUSEBUTTONUP: case SDL.EventType.MOUSEWHEEL: case SDL.EventType.MOUSEMOTION: case SDL.EventType.KEYDOWN: case SDL.EventType.KEYUP: case SDL.EventType.TEXTINPUT: case SDL.EventType.CONTROLLERDEVICEADDED: case SDL.EventType.CONTROLLERDEVICEREMOVED: case SDL.EventType.CONTROLLERBUTTONDOWN: case SDL.EventType.CONTROLLERBUTTONUP: case SDL.EventType.CONTROLLERAXISMOTION: Input.InputEvent(e); break; //let Window handle window related events case SDL.EventType.WINDOWEVENT: Window.WindowEvent(e); break; //global quit, not only the window's exit button case SDL.EventType.QUIT: Exit(); break; } } Input.UpdateMousePosition(); Input.ApplyButtonMaps(); //update the weakreferences if they still exist Resources.UpdateManagedSprites(); foreach (LogicalObject obj in Resources.Objects) { if (!obj.Destroyed) { obj.Step(); } } //collision time! float minX = float.PositiveInfinity; float minY = float.PositiveInfinity; float maxX = float.NegativeInfinity; float maxY = float.NegativeInfinity; foreach (PhysicalObject obj in Resources.PhysicalObjects) { obj.UpdateCoverableArea(); if (obj.CoverableArea.Position.X < minX) { minX = obj.CoverableArea.Position.X; } if (obj.CoverableArea.Position2.X > maxX) { maxX = obj.CoverableArea.Position2.X; } if (obj.CoverableArea.Position.Y < minY) { minY = obj.CoverableArea.Position.Y; } if (obj.CoverableArea.Position2.Y > maxY) { maxY = obj.CoverableArea.Position2.Y; } //set before the actual collision check phase obj.SpeedLeft = 1f; obj.CollisionCandidates = null; } //create and fill quadtree for this step QuadTree = new QuadTree(new Rectangle(minX, minY, maxX - minX, maxY - minY)); //create list of objects to process and calculate all first collision speedfractions for those objects List <PhysicalObject> processingObjects = new List <PhysicalObject>(Resources.PhysicalObjects); foreach (PhysicalObject obj in Resources.PhysicalObjects) { if (obj.Speed == Point.Zero) { continue; } processingObjects.Add(obj); obj.CalculateClosestCollision(); } while (processingObjects.Count > 0) { //get closest collision, process it/the pair of objects PhysicalObject obj = processingObjects.MinBy(o => o.ClosestCollisionSpeedFraction + 1 - o.SpeedLeft); obj.PerformClosestCollision(); //remove/recalculate collisions if (obj.SpeedLeft == 0f) { processingObjects.Remove(obj); } else { obj.CalculateClosestCollision(); } //recalculate for all possibly influenced objects (if needed) if (obj.CollisionCandidates != null) { foreach (PhysicalObject influencedObj in obj.CollisionCandidates) { influencedObj.CalculateClosestCollision(); } } } Resources.ObjectAdditionAndRemoval(); Resources.CleanupFontTextures(); }
public List<PhysicalObject> GetCollisionCandidates(PhysicalObject obj) { List<PhysicalObject> targets = new List<PhysicalObject>(_objects); //check in the child trees this object overlaps with if (_children[0] != null) { bool[] fits = FitObject(obj); if (fits[0]) targets.AddRange(_children[0].GetCollisionCandidates(obj)); if (fits[1]) targets.AddRange(_children[1].GetCollisionCandidates(obj)); if (fits[2]) targets.AddRange(_children[2].GetCollisionCandidates(obj)); if (fits[3]) targets.AddRange(_children[3].GetCollisionCandidates(obj)); } targets.Remove(obj); return targets; }
/// <summary> /// Returns the childtrees the given object fits in. /// 0-3, left-to-right, top-to-bottom. /// 4 is true when the object doesn't fit in just one quadrant. /// </summary> private bool[] FitObject(PhysicalObject obj) { bool[] fits = new bool[5]; byte quadrants = 0; if (obj.CoverableArea.Position.X <= _center.X) { if (obj.CoverableArea.Position.Y <= _center.Y) { fits[0] = true; quadrants++; } if (obj.CoverableArea.Position2.Y >= _center.Y) { fits[2] = true; quadrants++; } } if (obj.CoverableArea.Position2.X >= _center.X) { if (obj.CoverableArea.Position.Y <= _center.Y) { fits[1] = true; quadrants++; } if (obj.CoverableArea.Position2.Y >= _center.Y) { fits[3] = true; quadrants++; } } if (quadrants > 1) fits[4] = true; return fits; }