/// <summary> /// A teensy quadtree baby. /// </summary> private QuadTree(byte level, Rectangle bounds, List<PhysicalObject> objects) { byte level1 = level; Rectangle bounds1 = bounds; _center = bounds.Position + bounds.Size / 2f; Point childSize = bounds.Size / 2f; if (objects.Count > MaxObjects) { //decide in what childtree an object would fit and add it there List<PhysicalObject> childObjects0 = new List<PhysicalObject>(); List<PhysicalObject> childObjects1 = new List<PhysicalObject>(); List<PhysicalObject> childObjects2 = new List<PhysicalObject>(); List<PhysicalObject> childObjects3 = new List<PhysicalObject>(); foreach (PhysicalObject obj in objects) { bool[] fits = FitObject(obj); if (!fits[4]) { if (fits[0]) childObjects0.Add(obj); else if (fits[1]) childObjects1.Add(obj); else if (fits[2]) childObjects2.Add(obj); else childObjects3.Add(obj); } else _objects.Add(obj); } //create subtrees and add everything that fits inside of em _children[0] = new QuadTree((byte)(level1 + 1), new Rectangle(bounds1.Position, childSize), childObjects0); _children[1] = new QuadTree((byte)(level1 + 1), new Rectangle(new Point(_center.X, bounds1.Position.Y), childSize), childObjects1); _children[2] = new QuadTree((byte)(level1 + 1), new Rectangle(new Point(bounds1.Position.X, _center.Y), childSize), childObjects2); _children[3] = new QuadTree((byte)(level1 + 1), new Rectangle(_center, childSize), childObjects3); } else _objects = objects; }
private static void Step() { //push input state Input.PushState(); //process all SDL.SDL_events SDL.SDL_Event e; while (SDL.SDL_PollEvent(out e) == 1) { switch (e.type) { //let Input handle input related events case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: case SDL.SDL_EventType.SDL_MOUSEWHEEL: case SDL.SDL_EventType.SDL_MOUSEMOTION: case SDL.SDL_EventType.SDL_KEYDOWN: case SDL.SDL_EventType.SDL_KEYUP: case SDL.SDL_EventType.SDL_TEXTINPUT: case SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED: case SDL.SDL_EventType.SDL_CONTROLLERDEVICEREMOVED: case SDL.SDL_EventType.SDL_CONTROLLERBUTTONDOWN: case SDL.SDL_EventType.SDL_CONTROLLERBUTTONUP: case SDL.SDL_EventType.SDL_CONTROLLERAXISMOTION: Input.InputEvent(e); break; //let Window handle window related events case SDL.SDL_EventType.SDL_WINDOWEVENT: Window.WindowEvent(e); break; //global quit, not only the window's exit button case SDL.SDL_EventType.SDL_QUIT: Exit(); break; } } Input.UpdateMousePosition(); Input.ApplyButtonMaps(); foreach (GameObject obj in Resources.Objects) { if (!obj.Destroyed) obj.Step(); } //collision time! Profiler.Start("collision"); 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(); } } Profiler.Stop(); Resources.ObjectAdditionAndRemoval(); Resources.CleanupFontTextures(); }