void UIColorPicker::Update() { if (!this->HasFocus() || (!this->pm_bIsBragging && !this->pm_bIsBraggingAlpha)) return; Vector2 mp = this->UIMan->LastMousePosition - this->GetAbsoluteLocation(); float mdist = mp.Distance(this->pm_vCenter); if (mdist >= this->W / 2 - BorderSize && mdist <= this->W / 2) { this->pm_fHue = (float)((int)(-atan2(mp.X - (float)this->W / 2, (float)this->H / 2 - mp.Y) * (float)(180.0 / M_PI) + 180) % 360); } else { if (mp.X >= this->BorderSize * 3 + +this->Padding && mp.Y >= this->BorderSize * 3 + this->Padding && mp.X <= this->W - this->BorderSize * 3 - this->Padding && mp.Y <= this->H - this->BorderSize * 3 - this->Padding) { Vector2 tmp = mp; tmp -= (float)this->BorderSize * 3 + this->Padding; this->pm_vsat.X = Utilities::Clamp(tmp.X / (float)(this->W - this->BorderSize * 6 - this->Padding * 2), 0.0f, 1.0f); this->pm_vsat.Y = Utilities::Clamp(1 - (tmp.Y / (float)(this->H - this->BorderSize * 6 - this->Padding * 2)), 0.0f, 1.0f); } } Color oldval = this->Value; this->Value = HSVtoRGB(this->pm_fHue, this->pm_vsat.X, this->pm_vsat.Y); if (this->Value != oldval) { if (this->OnValueChanged != nullptr) this->OnValueChanged(); this->MarkForFullRedraw(); } }
TID EntityController::GetClosestEnemyEntityInSight() { if (!IsControllingEntity() || !EntityExists()) return false; EntityList enemies; int closestDist = INT_MAX; TID closestId = INVALID_TID; Vector2 selfPos = Entity()->Position(); Vector2 otherPos = Vector2::Inf(); int los = Entity()->Type()->P(TP_LineOfSight); // For now, just select the closest entity in sight for (auto& entityR : g_Game->Enemy()->Entities()) { if (!Entity()->CanAttack(entityR.first)) continue; otherPos = entityR.second->Position(); int dist = selfPos.Distance(otherPos); if (dist < los && dist < closestDist) { closestId = entityR.first; closestDist = dist; } } return closestId; }
bool Eagle::DoesRobotHaveBall(RobotState robotState, Vector2 ballPos) { Vector2 robotPos = robotState.Position(); float angleThresh; float distanceThresh; if (robotState.HasBall()) { angleThresh = M_PI_2; distanceThresh = 70.0f; } else { angleThresh = M_PI_4; distanceThresh = 45.0f; } float angleToBall = fmod(robotPos.GetAngleTo(&ballPos), (2*M_PI)); float robotOrientation = fmod(robotState.Orientation(), (2*M_PI)); float distanceToBall = robotPos.Distance(&ballPos); float orientationDiff = fmod(fabs(robotOrientation - angleToBall), (2*M_PI)); bool withinOrientationThresh = (orientationDiff < angleThresh) || (2*M_PI - orientationDiff < angleThresh); bool withinProximityThresh = distanceToBall < distanceThresh; if(withinOrientationThresh && withinProximityThresh) { return true; } return false; }
//---------------------------------------------------------------------------------------------- MapArea StarCraftMap::GetSpecialBuildingPosition(EntityClassType p_buildingType) const { if (!m_isOnline) DEBUG_THROW(InvalidOperationException(XcptHere)); MapArea candidatePosition = MapArea::Null(); // Get the player base tile position MapArea colony = g_Game->Self()->GetColonyMapArea(); Vector2 colonyTile = colony.Pos(); // Get the unit type object UnitType type; TID unitTypeId; string typeName; unitTypeId = g_Database.EntityMapping.GetBySecond(p_buildingType); typeName = g_Database.EntityIdentMapping.GetByFirst(unitTypeId); type = BWAPI::UnitType::getType(typeName); if (type.isRefinery()) { int bestDistance = INT_MAX; Unitset geysers = Broodwar->getGeysers(); Unit currentGeyser; for (unsigned i = 0; i < geysers.size(); ++i) { currentGeyser = geysers[i]; Vector2 currentPosition = Vector2( UnitPositionFromTilePosition(currentGeyser->getTilePosition().x), UnitPositionFromTilePosition(currentGeyser->getTilePosition().y)); int currentDistance = colonyTile.Distance(currentPosition); if (currentDistance <= bestDistance) { bestDistance = currentDistance; candidatePosition = MapArea( currentPosition, type.tileWidth(), type.tileHeight()); } } _ASSERTE(CanBuildHere(candidatePosition.Pos(), p_buildingType)); } return candidatePosition; }
MapArea WorldMap::GetSpecialBuildingPosition(EntityClassType buildingType) const { if (!m_isOnline) DEBUG_THROW(InvalidOperationException(XcptHere)); // Add-ons are always built in place of its parent building, it has nothing to do with // place adaptation MapArea candidatePosition = MapArea::Null(); // Get the unit type object const IGameUnitType* pUnitType = g_GameImpl->GetUnitTypeByEngineId(buildingType); if (pUnitType->IsRefinery()) { // Get the player base tile position MapArea colony = g_Game->Self()->GetColonyMapArea(); Vector2 colonyTile = colony.Pos(); int bestDistance = INT_MAX; auto gasFields = g_GameImpl->MapGasFields(); TID currentGeyser; for (unsigned i = 0; i < gasFields->Size(); ++i) { currentGeyser = gasFields->At(i); Vector2 currentPosition = UnitPositionFromTilePosition(g_GameImpl->UnitTilePosition(currentGeyser)); if (CanBuildHere(currentPosition, pUnitType->EngineId())) { int currentDistance = colonyTile.Distance(currentPosition); if (currentDistance <= bestDistance) { bestDistance = currentDistance; candidatePosition = MapArea( currentPosition, pUnitType->TileWidth(), pUnitType->TileHeight()); } } } } return candidatePosition; }
void ArmyController::CalcEnemyData() { Vector2 selfPos = Center(); Vector2 otherPos = Vector2::Inf(); m_closestEnemy.clear(); m_enemyData.clear(); for (auto& entityR : g_Game->Enemy()->Entities()) { if (entityR.second->Exists() && entityR.second->P(OP_IsTargetable)) { otherPos = entityR.second->Position(); int dist = selfPos.Distance(otherPos); m_closestEnemy.insert(make_pair(dist, entityR.first)); auto& dat = m_enemyData[entityR.first]; dat.Id = entityR.first; dat.DistanceToCenter = dist; dat.TargetEntityId = entityR.second->TargetId(); } } // No enemy close to me if (m_closestEnemy.empty()) { m_targetEntityId = INVALID_TID; } // The closest enemy to me is in sight, and it is not my last chosen one else if (m_targetEntityId != m_closestEnemy.begin()->second) { m_targetEntityId = m_closestEnemy.begin()->second; LogInfo("%s chosen enemy target %s", ToString().c_str(), g_Game->Enemy()->GetEntity(m_targetEntityId)->ToString(true).c_str()); } }
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(); } } } }
/*! * Identify the target state that we wish the robot to be in. This will be the target which the A* algorithm plots towards. */ RobotState Eagle::IdentifyTarget(RobotState &ourRobotState, RobotState &enemyRobotState, Vector2 ballPos, bool doWeHaveBall, bool &isMovingToBall) { RobotState targetState; Vector2 ourRobotPos = ourRobotState.Position(); Vector2 enemyRobotPos = enemyRobotState.Position(); Vector2 ourGoalCentre = GoalCentrePosition(m_pitchSide); Vector2 enemyGoalCentre; if (m_pitchSide == eLeftSide) { enemyGoalCentre = GoalCentrePosition(eRightSide); } else { enemyGoalCentre = GoalCentrePosition(eLeftSide); } ballPos.Clamp(Vector2(0,0), Vector2(m_pitchSizeX-1, m_pitchSizeY-1)); isMovingToBall = false; // doWeHaveBall is a value which comes from the robot's rotational sensors. //ourRobotState.SetHasBall(doWeHaveBall); ourRobotState.SetHasBall(DoesRobotHaveBall(ourRobotState, ballPos)); enemyRobotState.SetHasBall(DoesRobotHaveBall(enemyRobotState, ballPos)); if (m_state == ePenaltyAttack) { m_isKickingPosSet = false; // When taking a penalty, we want to find a free position to kick to. // Position should stay the same - we only want to re-orientate. targetState.SetPosition(ourRobotPos); // We'll do this by checking for intersections between us and three positions on the goal line. Vector2 targetPositions[3]; targetPositions[0] = enemyGoalCentre; targetPositions[1] = enemyGoalCentre - Vector2(0,50); targetPositions[2] = enemyGoalCentre + Vector2(0,50); int arrayLength = sizeof(targetPositions)/sizeof(Vector2); Vector2 optimalShootingTarget; float bestDistanceFromEnemy = 0; // Iterate through the positions, finding the best one, based on if it's unblocked and how far it is from the enemy robot. for (int i=0; i < arrayLength; i++) { // Check if the target is unblocked. bool isBlocked = m_intersection.LineCircleIntersection(ourRobotPos, targetPositions[i], enemyRobotPos, ROBOT_RADIUS); if (isBlocked) { continue; } float distanceSqdToEnemy = enemyRobotPos.DistanceSquared(&targetPositions[i]); // Check if this beats our previous best distance. if (distanceSqdToEnemy > bestDistanceFromEnemy) { bestDistanceFromEnemy = distanceSqdToEnemy; optimalShootingTarget = targetPositions[i]; } // Check that we do actually have a target set. if (optimalShootingTarget.IsSet()) { float angleToTarget = ourRobotPos.GetAngleTo(&optimalShootingTarget); targetState.SetOrientation(angleToTarget); } else { targetState.SetOrientation(ourRobotState.Orientation()); } } } else if (m_state == ePenaltyDefend) { m_isKickingPosSet = false; // When defending, we're permitted to move up and down the goalline. // Orientation should stay the same. targetState.SetOrientation(ourRobotState.Orientation()); // X-axis position should be the same, y-axis should be a position extrapolated in the direction of the enemy robot. //float extrapolationGradient = tan(enemyRobotState.Orientation()); // I'm experimenting with extrapolating on a line between the robot and ball instead. float extrapolationGradient = enemyRobotPos.Gradient(&ballPos); int extrapolatedY = enemyRobotPos.Y() + ((ourRobotPos.X() - enemyRobotPos.X()) * extrapolationGradient); Vector2 proposedPosition(ourRobotPos.X(), extrapolatedY); proposedPosition.Clamp(Vector2(0,0), Vector2(m_pitchSizeX-1, m_pitchSizeY-1)); targetState.SetPosition(proposedPosition); } else { // If we're here, assume we're in open play. if (!ourRobotState.HasBall()) { m_isKickingPosSet = false; // Check if the enemy robot has the ball. if (enemyRobotState.HasBall()) { if (m_pitchSide == eLeftSide) { targetState.SetPosition(ourGoalCentre.X() + 50, ourGoalCentre.Y()); targetState.SetOrientation(0); } else { targetState.SetPosition(ourGoalCentre.X() - 50, ourGoalCentre.Y()); targetState.SetOrientation(M_PI); } } else { // If we don't have the ball, the aim should be to move to the ball. isMovingToBall = true; targetState.SetPosition(ballPos); if (m_pitchSide == eLeftSide) { targetState.SetOrientation(0); } else { targetState.SetOrientation(M_PI); } } } else { // Check if the previously calculated target pos is appropriate or if we need to recalc. if ((m_isKickingPosSet) && ((m_kickingPos.Distance(&ourRobotPos) < 30) || (m_kickingPos.Distance(&enemyRobotPos) < 40))) { m_isKickingPosSet = false; } if (!m_isKickingPosSet) { // If we have the ball, let's move to a more appropriate place. // This is done regardless of whether we're shooting or not. /* This should depend on: 1. The opposite half of the pitch to the enemy robot. 2. Within the kicking threshold. 3. Fairly central, but outside of the enemy robot's radius 4. Orientated towards the goal */ bool isEnemyOnBottomSide; // Determine which half of the pitch the enemy robot is on. if (enemyRobotState.Position().Y() < m_pitchSizeY/2) { isEnemyOnBottomSide = true; } else { isEnemyOnBottomSide = false; } // Determine where the kicking threshold is for this side of the pitch. float kickingPositionX; float kickingPositionY; if (m_pitchSide == eLeftSide) { kickingPositionX = m_pitchSizeX - ((KICKING_THRESHOLD/2)*m_pitchSizeX); } else { kickingPositionX = (KICKING_THRESHOLD/2)*m_pitchSizeX; } if (isEnemyOnBottomSide) { kickingPositionY = m_pitchSizeY/2 + 80; } else { kickingPositionY = m_pitchSizeY/2 - 80; } // Check if the position is within two robot radii of the enemy. Vector2 proposedPosition = Vector2(kickingPositionX,kickingPositionY); // Check if the proposed position is too close to the enemy robot to be used. if (proposedPosition.Distance(&enemyRobotPos) < 2*ROBOT_RADIUS) { float adjustedYPosition; if (isEnemyOnBottomSide) { adjustedYPosition = proposedPosition.Y() + 2*ROBOT_RADIUS; } else { adjustedYPosition = proposedPosition.Y() - 2*ROBOT_RADIUS; } proposedPosition = Vector2( proposedPosition.X(), adjustedYPosition); } proposedPosition.Clamp(Vector2(0,0), Vector2(m_pitchSizeX-1, m_pitchSizeY-1)); m_kickingPos = proposedPosition; m_isKickingPosSet = true; } targetState.SetPosition(m_kickingPos); // We'll do this by checking for intersections between us and three positions on the goal line. Vector2 targetPositions[3]; targetPositions[0] = enemyGoalCentre; targetPositions[1] = enemyGoalCentre - Vector2(0,50); targetPositions[2] = enemyGoalCentre + Vector2(0,50); int arrayLength = sizeof(targetPositions)/sizeof(Vector2); Vector2 optimalShootingTarget; float bestDistanceFromEnemy = 0; // Iterate through the positions, finding the best one, based on if it's unblocked and how far it is from the enemy robot. for (int i=0; i < arrayLength; i++) { // Check if the target is unblocked. bool isBlocked = m_intersection.LineCircleIntersection(m_kickingPos, targetPositions[i], enemyRobotPos, ROBOT_RADIUS); if (isBlocked) { continue; } float distanceSqdToEnemy = enemyRobotPos.DistanceSquared(&targetPositions[i]); // Check if this beats our previous best distance. if (distanceSqdToEnemy > bestDistanceFromEnemy) { bestDistanceFromEnemy = distanceSqdToEnemy; optimalShootingTarget = targetPositions[i]; } // Check that we do actually have a target set. if (optimalShootingTarget.IsSet()) { float angleToTarget = m_kickingPos.GetAngleTo(&optimalShootingTarget); targetState.SetOrientation(angleToTarget); } else { targetState.SetOrientation(ourRobotState.Orientation()); } } } targetState.SetPosition((int)targetState.Position().X(), (int)targetState.Position().Y()); } return targetState; }