// This is the function that tries to make a step, it can recurse once. public void attemptStep(myVector v, bool recurse) { // Optimistic no collision double t = 1.0; myVector newV = null; // Check for team derp collisions double derpT; myVector derpV = null; int colID = manager.CheckDerpCollision(this, v, out derpT, enemyDetected); // note: this returns -1 if either there is no collision, or if we are colliding with the other team isColliding = (colID != -1); // We have collided with another derp // Tell the other to move out of the way, and have us try to move perpendicular to them if (isColliding && !recurse) { Derp slowDerp = manager.SetToMoveOutOfWay(colID, this); if (slowDerp != null) { // Get the Unit Vector towards the slow Derp myVector u = new myVector(slowDerp.x - x, slowDerp.y - y); u.toUnit(); // Make sure that the slow derp is actually in front of where you want to go if (u.dot(v) > 0.0) { // Get a perpendicular unit vector to follow myVector uPerp = new myVector(-u.y, u.x); // Make sure it is the correct way double dir = uPerp.dot(v); // Wrong way if (dir < -1e-3) { uPerp.x *= -1; uPerp.y *= -1; } // Special Zero case, pick a random direction // this should... almost never happen // I'm concerned this could mess up random synch in multiplayer. Just pick a constant direction. else if (dir < 1e-3) { /* * if (MyRandom.Next(team, 2) % 2 == 0) * { * uPerp.x *= -1; * uPerp.y *= -1; * } */ } // Try moving along the new path double remainingT = (1.0 - derpT); derpV = new myVector(uPerp.x * remainingT * v.mag(), uPerp.y * remainingT * v.mag()); } } } // Check for field collisions double fieldT; myVector fieldV = null; myLineSegment collisionVect; if (Field.field.CheckFieldCollision(this, v, out fieldT, out collisionVect) && !recurse) { // try to move parallel to the wall with the extra t collisionVect.v.toUnit(); // make sure this unit vector is in the right direction double dir = collisionVect.v.dot(v); // Wrong way if (dir < -1e-3) { collisionVect.v.x *= -1; collisionVect.v.y *= -1; } // ignore zero case if (Math.Abs(dir) > 1e-3) { // Try moving along the new path double remainingT = (1.0 - fieldT); fieldV = new myVector(collisionVect.v.x * remainingT * v.mag(), collisionVect.v.y * remainingT * v.mag()); } } // See if we have a collision // If either of the recalculated V values are not null, we hit something along the way if (derpT < 1.0 - 1e-6 || fieldT < 1.0 - 1e-6) { if (fieldT < derpT) { t = fieldT; newV = fieldV; } else { t = derpT; newV = derpV; } } // Only step as far as we can x += v.x * t; y += v.y * t; if (newV != null) { attemptStep(newV, true); } }
public void Update() { // CHECK FOR ATTACKS // use the derp radar to search for visible enemies in range Derp enemy = manager.SearchForEnemy(this, 100.0); enemyDetected = (enemy != null); // see if we can attack this enemy myVector toEnemy = null; if (enemyDetected) { toEnemy = new myVector(enemy.x - x, enemy.y - y); isAttacking = (toEnemy.mag() < stats.radius + enemy.stats.radius + stats.rng); debugDist = toEnemy.mag(); if (isAttacking && (DateTime.Now.Subtract(lastAttack).TotalMilliseconds > (2000 - 15 * stats.aspd))) { lastAttack = DateTime.Now; enemy.takeHit(stats.atk); manager.AddAttack(this, enemy); } } else { isAttacking = false; } // FOLLOW THE TRAIL // Find the vector between the derp and its current node destination double dx = path[pathID].x - x; double dy = path[pathID].y - y; double mag = Math.Sqrt(dx * dx + dy * dy); double t = 1.0; myLineSegment throwaway; int nextPathID = pathID + (team == TEAM.HOME ? 1 : -1); // Check if we can move to the next path node if (mag < (stats.spd * SPEED_CONST)) { pathID = nextPathID; // Recalculate for the next node dx = path[pathID].x - x; dy = path[pathID].y - y; mag = Math.Sqrt(dx * dx + dy * dy); } // Sometimes we can abort the current node for the next-next node else if (nextPathID >= 0 && nextPathID < path.Count) { // if the next node is behind us (meaning we passed it accidentily) then just keep going // we use a manual dot product for this double ndx = path[nextPathID].x - x; double ndy = path[nextPathID].y - y; if (dx * ndx + dy * ndy < 0.0 && !Field.field.CheckFieldCollision(this, new myVector(path[nextPathID].x - x, path[nextPathID].y - y), out t, out throwaway)) { pathID = nextPathID; // Recalculate for the next node dx = path[pathID].x - x; dy = path[pathID].y - y; mag = Math.Sqrt(dx * dx + dy * dy); } // we can give a more liberal option to move forward to the next node // if we are colliding or seeking an enemy derp, and we can see the next node else if (isColliding && mag < GENERIOUS_THRESHHOLD && !Field.field.CheckFieldCollision(this, new myVector(path[nextPathID].x - x, path[nextPathID].y - y), out t, out throwaway)) { pathID = nextPathID; // Recalculate for the next node dx = path[pathID].x - x; dy = path[pathID].y - y; mag = Math.Sqrt(dx * dx + dy * dy); } } // DETERMINE MOVE if (!isAttacking) { // Calculate velocity and try to make the step double velocity = stats.spd * SPEED_CONST; myVector v; if (enemyDetected && toEnemy != null) { toEnemy.toUnit(); v = new myVector(toEnemy.x * velocity, toEnemy.y * velocity); } else if (moveOutOfWay) { // Move out of the way! v = new myVector(moveOutOfWayVector.x * velocity, moveOutOfWayVector.y * velocity); } else { // Move Towards next Node v = new myVector((dx / mag) * velocity, (dy / mag) * velocity); } // DEBUG: error catching double oldx = x; double oldy = y; if (isStuck) { isStuck = false; } // Try to Step attemptStep(v, false); // DEBUG: error catching if (Math.Abs(x - oldx) < 1e-3) { isStuck = true; } // Update our current instantaneous velocity vel.x = x - oldx; vel.y = y - oldy; // WE SHOULD NEVER MOVE THIS FAST. FIND MATH ERRORS. if (Math.Abs(vel.x) > 50 || Math.Abs(vel.y) > 50) { x = oldx; y = oldy; } } // Reset our MoveOUtOfWay variable, it will be set again next round if we need to keep moving out of the way moveOutOfWay = false; // This will be the game end condition eventually if ((team == TEAM.HOME && x > (Field.field.Width - 1) * Field.BLOCK_WIDTH) || (team == TEAM.AWAY && x < Field.BLOCK_WIDTH) || stats.hp <= 0) { Kill(); } }