public void Update(GameTime gameTime) { // Update all Derps // Use the kill stack to clean up dead derps Stack <Derp> killingStack = new Stack <Derp>(); foreach (KeyValuePair <SortKey, Derp> keyVal in derpsSpeed) { Derp d = keyVal.Value; // Update each if (d.alive) { d.Update(); } else { killingStack.Push(d); } } // Cleaning up while (killingStack.Count > 0) { RemoveDerp(killingStack.Pop()); } }
public int CheckDerpCollision(Derp casting, myVector v, out double t, bool checkBothTeams) { // t is initialized optimistically to the full distance t = 1.0; // the id of the derp is -1 if there is no collision int ret = -1; // For collision we are checking only against our teammates (because we will always attack (and stop moving) before we collide with enemies) <- at least that's the plan List <Derp> checkingList; if (casting.team == TEAM.HOME) { checkingList = homeDerps; } else { checkingList = awayDerps; } // I'm making the optimistic assumption that these lists will be sorted because they are sorted every Draw Step int myID = checkingList.IndexOf(casting); // check derps above me for (int i = myID - 1; i >= 0; --i) { // only check derps near me on the y axis if (casting.y - checkingList[i].y > distThreshholdY) { break; } double check_t = Geometry.DerpCircleCast(casting, checkingList[i], v); if (check_t < t) { t = check_t; ret = i; } } // check derps below me for (int i = myID + 1; i < checkingList.Count; ++i) { // only check derps near me on the y axis if (casting.y - checkingList[i].y > distThreshholdY) { break; } double check_t = Geometry.DerpCircleCast(casting, checkingList[i], v); if (check_t < t) { t = check_t; ret = i; } } // If we need to check the enemy team, then we can't do it quite as fast, but just check against them all if (checkBothTeams) { checkingList = (casting.team == TEAM.HOME ? awayDerps : homeDerps); foreach (Derp o in checkingList) { double check_t = Geometry.DerpCircleCast(casting, o, v); if (check_t < t) { t = check_t; ret = -1; } } } // the id of the colliding derp return(ret); }
// Check for a Derp's Circle-Cast across the field // This will work like a BFS, starting from the initial position // then check all 4 corners around the position to build on the bfs public bool CheckFieldCollision(Derp d, myVector v, out double t, out myLineSegment col) { // initial optimistic setup that there will not be a collision bool ret = false; t = 1.0; col = null; // calculate starting point int startX = (int)(d.x / BLOCK_WIDTH); int startY = (int)(d.y / BLOCK_HEIGHT); // Unit Vector in desired direction myVector vUnit = new myVector(v.x, v.y); vUnit.toUnit(); // set up the bfs Queue<SimpleNode> q = new Queue<SimpleNode>(); bool[,] vis = new bool[height+1, width+1]; q.Enqueue(new SimpleNode(startX, startY, 0)); vis[startY, startX] = true; // Create the 4 line segments so we don't have to do quiiite as much object creation in this loop myLineSegment[] segs = new myLineSegment[4]; for (int i = 0; i < 4; ++i) segs[i] = new myLineSegment(null, null); // BFS int[] dx = { 0, 1, 0, -1 }; int[] dy = { -1, 0, 1, 0 }; int cur_step = 0; while (q.Count > 0) { SimpleNode cur = q.Dequeue(); // end early if we had a hit already in a previous step if (ret && cur_step != cur.step) break; // checking 4 nodes around us myPoint p1 = new myPoint(cur.x * BLOCK_WIDTH, cur.y * BLOCK_HEIGHT); myPoint p2 = new myPoint((cur.x + 1) * BLOCK_WIDTH, cur.y * BLOCK_HEIGHT); myPoint p3 = new myPoint((cur.x + 1) * BLOCK_WIDTH, (cur.y + 1) * BLOCK_HEIGHT); myPoint p4 = new myPoint(cur.x * BLOCK_WIDTH, (cur.y + 1) * BLOCK_HEIGHT); segs[0].Update(p1, p2); segs[1].Update(p2, p3); segs[2].Update(p4, p3); segs[3].Update(p1, p4); for (int i = 0; i < 4; ++i) { int nx = cur.x + dx[i]; int ny = cur.y + dy[i]; if (nx < 0 || nx > width || ny < 0 || ny >= height || vis[ny, nx]) continue; double possible_t; if (Geometry.DerpLineSegmentCast(d, v, segs[i], out possible_t)) { // We have a hit! If the next zone is safe to move in, then continue the bfs if (gameGrid[ny, nx] != '0') { q.Enqueue(new SimpleNode(nx, ny, cur.step + 1)); vis[ny, nx] = true; } // We hit an unnavigable space. Stop the BFS, this is as far as we go else { ret = true; if (Math.Abs(possible_t - t) < 1e-5 && col != null) { // break ties by taking the furthest behind the direction we wish to go // Calculate the center point on the wall, and get the dot product of the vector to that point. // The most negative value is the furthest behind myPoint segMidPoint1 = new myPoint((segs[i].p1.x + segs[i].p2.x) / 2.0, (segs[i].p1.y + segs[i].p2.y) / 2.0); myVector toMidPoint1 = new myVector(segMidPoint1.x - d.x, segMidPoint1.y - d.y); myPoint segMidPoint2 = new myPoint((col.p1.x + col.p2.x) / 2.0, (col.p1.y + col.p2.y) / 2.0); myVector toMidPoint2 = new myVector(segMidPoint2.x - d.x, segMidPoint2.y - d.y); if (vUnit.dot(toMidPoint1) < vUnit.dot(toMidPoint2)) { t = possible_t; col = new myLineSegment(segs[i].p1.x, segs[i].p1.y, segs[i].p2.x, segs[i].p2.y); // careful... memory bugs } } else if (possible_t < t) { t = possible_t; col = new myLineSegment(segs[i].p1.x, segs[i].p1.y, segs[i].p2.x, segs[i].p2.y); // careful... memory bugs } } } } // if we are a special diagonal case, then check the cross hit as well myLineSegment diag = null; char c = gameGrid[cur.y, cur.x]; if (c == '1' || c == '3') diag = new myLineSegment(p2, p4); if (c == '2' || c == '4') diag = new myLineSegment(p1, p3); if (diag != null) { double possible_t; if (Geometry.DerpLineSegmentCast(d, v, diag, out possible_t)) { ret = true; if (Math.Abs(possible_t - t) < 1e-5 && col != null) { // break ties by taking the furthest behind the direction we wish to go // Calculate the center point on the wall, and get the dot product of the vector to that point. // The most negative value is the furthest behind myPoint segMidPoint1 = new myPoint((diag.p1.x + diag.p2.x) / 2.0, (diag.p1.y + diag.p2.y) / 2.0); myVector toMidPoint1 = new myVector(segMidPoint1.x - d.x, segMidPoint1.y - d.y); myPoint segMidPoint2 = new myPoint((col.p1.x + col.p2.x) / 2.0, (col.p1.y + col.p2.y) / 2.0); myVector toMidPoint2 = new myVector(segMidPoint2.x - d.x, segMidPoint2.y - d.y); if (vUnit.dot(toMidPoint1) < vUnit.dot(toMidPoint2)) { t = possible_t; col = new myLineSegment(diag.p1.x, diag.p1.y, diag.p2.x, diag.p2.y); // careful... memory bugs } } else if (possible_t < t) { t = possible_t; col = new myLineSegment(diag.p1.x,diag.p1.y, diag.p2.x, diag.p2.y); // careful... memory bugs } } } cur_step = cur.step; } return ret; }