void Game::HandleAI(float msecs) { // Run AI for computer planes for (int i = activePlayers_; i < TotalPlayers(); i ++) { // Bail if it's dying or stalled. We're not allowing sniping while stalling, the // bots are just too good a shot Plane *current = &players_[i]; if (current->IsDying() || current->IsStalled()) continue; // Find the closets enemy plane Plane *target = NULL; float currentRange = 9999; for (int j = 0; j < TotalPlayers(); j ++) { if (j == i) // Can't target self continue; // We're currently ignoring respawning players. May remove this later to make // the AI more aggressive if (currentRange > current->GetPosition().Distance(players_[j].GetPosition()) && !players_[j].IsDying() && !players_[j].IsStalled() && !players_[j].IsInvincible()) { target = &players_[j]; currentRange = current->GetPosition().Distance(target->GetPosition()); } } if (target == NULL) // Level off if we don't have a target { float targetAngle = 0; if (targetAngle > current->GetRotation()) current->TurnLeft(msecs); else current->TurnRight(msecs); } else { // Plot an intercept course! Vector2 currentPosition = current->GetPosition(); Vector2 targetPosition = target->GetPosition(); Vector2 interceptPoint = Vector2::CollisionPoint(currentPosition, current->GetVelocity(), targetPosition, target->GetVelocity()); // If the target is running parallel to us, go for them //if (interceptPoint.x == 0 && interceptPoint.y == 0) // interceptPoint = targetPosition; // If the target is in front of us, try and lead it // Calculate time for bullet to reach intercept point Vector2 bulletStartPos = currentPosition + current->GetVelocity().Normalise() * (20 + MAX_SPEED + 0.5f); float bulletTravelTime = (bulletStartPos - interceptPoint).Length() / BULLET_SPEED; // Calculate target position at that time Vector2 projectedTargetPos = targetPosition + (target->GetVelocity() * bulletTravelTime); // Decide if it's worth a shot if (interceptPoint.Distance(projectedTargetPos) < 20) { Bullet *bullet = current->Fire(); if (bullet != NULL) bullets_.push_back(bullet); } // Don't play chicken // TODO: Turn away from collisions // Don't derp // TODO: Don't run into the ground // Attempt to maneuver for a better shot Vector2 currentVelocity = current->GetVelocity().Normalise(); Vector2 targetVelocity = (currentPosition - projectedTargetPos).Normalise(); float diffAngle = currentVelocity.Cross(targetVelocity); if (diffAngle < 0) current->TurnLeft(msecs); else current->TurnRight(msecs); if (DEBUG_RENDERER) { glBegin(GL_QUADS); glColor3f(0, 0, 0); glVertex2f(interceptPoint.x - 2, interceptPoint.y - 2); glVertex2f(interceptPoint.x + 2, interceptPoint.y - 2); glVertex2f(interceptPoint.x + 2, interceptPoint.y + 2); glVertex2f(interceptPoint.x - 2, interceptPoint.y + 2); glEnd(); glBegin(GL_QUADS); glColor3f(1, 0, 1); glVertex2f(projectedTargetPos.x - 15, projectedTargetPos.y - 15); glVertex2f(projectedTargetPos.x + 15, projectedTargetPos.y - 15); glVertex2f(projectedTargetPos.x + 15, projectedTargetPos.y + 15); glVertex2f(projectedTargetPos.x - 15, projectedTargetPos.y + 15); glEnd(); } } } }
//---------------------------------------------------------------------------- bool Mgc::SeparatePointSets2D (int iQuantity0, const Vector2* akVertex0, int iQuantity1, const Vector2* akVertex1, Line2& rkSeprLine) { // construct convex hull of point set 0 ConvexHull2D kHull0(iQuantity0,akVertex0); kHull0.ByDivideAndConquer(); int iEdgeQuantity0 = kHull0.GetQuantity(); const int* aiEdge0 = kHull0.GetIndices(); // construct convex hull of point set 1 ConvexHull2D kHull1(iQuantity1,akVertex1); kHull1.ByDivideAndConquer(); int iEdgeQuantity1 = kHull1.GetQuantity(); const int* aiEdge1 = kHull1.GetIndices(); // test edges of hull 0 for possible separation of points int j0, j1, iI0, iI1, iSide0, iSide1; Vector2 kDiff; for (j1 = 0, j0 = iEdgeQuantity0-1; j1 < iEdgeQuantity0; j0 = j1++) { // lookup edge (assert: iI0 != iI1 ) iI0 = aiEdge0[j0]; iI1 = aiEdge0[j1]; // compute potential separating line (assert: (xNor,yNor) != (0,0)) kDiff = akVertex0[iI1] - akVertex0[iI0]; rkSeprLine.Normal() = kDiff.Cross(); rkSeprLine.Constant() = rkSeprLine.Normal().Dot(akVertex0[iI0]); // determine if hull 1 is on same side of line iSide1 = OnSameSide(rkSeprLine,iEdgeQuantity1,aiEdge1,akVertex1); if ( iSide1 ) { // determine which side of line hull 0 lies iSide0 = WhichSide(rkSeprLine,iEdgeQuantity0,aiEdge0,akVertex0); if ( iSide0*iSide1 <= 0 ) // line separates hulls return true; } } // test edges of hull 1 for possible separation of points for (j1 = 0, j0 = iEdgeQuantity1-1; j1 < iEdgeQuantity1; j0 = j1++) { // lookup edge (assert: iI0 != iI1 ) iI0 = aiEdge1[j0]; iI1 = aiEdge1[j1]; // compute perpendicular to edge (assert: (xNor,yNor) != (0,0)) kDiff = akVertex1[iI1] - akVertex1[iI0]; rkSeprLine.Normal() = kDiff.Cross(); rkSeprLine.Constant() = rkSeprLine.Normal().Dot(akVertex1[iI0]); // determine if hull 0 is on same side of line iSide0 = OnSameSide(rkSeprLine,iEdgeQuantity0,aiEdge0,akVertex0); if ( iSide0 ) { // determine which side of line hull 1 lies iSide1 = WhichSide(rkSeprLine,iEdgeQuantity1,aiEdge1,akVertex1); if ( iSide0*iSide1 <= 0 ) // line separates hulls return true; } } return false; }