/** * Returns 0 if intersections * Returns -1 if same m * Returns -2 if no intersections, circles out of range * Returns -3 if no intersection, circles includes another one */ int Trigonometric::intersectionsCircleCircle(BW_Point m1, float r1, BW_Point m2, float r2, BW_Point* i1, BW_Point* i2) { if (m1 == m2) return -1; // same point, no intersections float d, a, h, dx, dy; d = m1.distanceTo(m2); if (d > r1 + r2) return (-2); //no intersections dx = m2.x - m1.x; dy = m2.y - m1.y; a = (r1 * r1 - r2 * r2 + d * d) / (2 * d); h = sqrt(r1 * r1 - a * a); i1->x = m1.x + (a / d) * dx - (h / d) * dy; i1->y = m1.y + (a / d) * dy + (h / d) * dx; i2->x = m1.x + (a / d) * dx + (h / d) * dy; i2->y = m1.y + (a / d) * dy - (h / d) * dx; //Returns -3 if no intersection, circles includes another one if(isnan(i1->x) || isnan(i1->y) || isnan(i2->x) || isnan(i2->y)) return -3; return (0); }
void BW_Sprite::updateMovePosition(float dt) { if (_currentAnimation != MOVE) return; BW_Point currentPosition = getPositionBW(); float moveDistance = _speed * dt * 0.85; //multiply by 0.85 to achieve the same speed as the old move to version float maxDist = getPositionBW().distanceTo(_movingTo); BW_Point newPos; if (moveDistance >= maxDist) { newPos = _movingTo; spriteMoveFinished(_sprite); } else { float mult = moveDistance / maxDist; float x = _movingTo.x - currentPosition.x; float y = _movingTo.y - currentPosition.y; float xDelta = x * mult; float yDelta = y * mult; newPos = BW_Point(getPositionBW().x + xDelta, getPositionBW().y + yDelta); } if (!_isUnit) { //on projectiles there is no walk collition setPosition(newPos); return; } //we are a unit here, consider walk collition //get nearest unit to this point std::list<Unit*> allUnits = Model::getInstance()->getMyArmy(LEFT)->getUnits(); std::list<Unit*> rightUnits = Model::getInstance()->getMyArmy(RIGHT)->getUnits(); allUnits.insert(allUnits.end(), rightUnits.begin(), rightUnits.end()); //get nearest position of other units BW_Point nearest; float minDist = -1; for (std::list<Unit*>::iterator it = allUnits.begin(); it != allUnits.end(); ++it) { if ((*it) == this) continue; BW_Point currentPos = (*it)->getPositionBW(); float currentDist = newPos.distanceTo(currentPos); if (minDist == -1 || currentDist < minDist) { minDist = currentDist; nearest = currentPos; } } //check nearest position float minDistanceToOtherUnits = 50; if (minDist == -1 || minDist > minDistanceToOtherUnits) { //no problem setPosition(newPos); return; } //calculate intersections BW_Point i1, i2; int res = Trigonometric::intersectionsCircleCircle(getPositionBW(), moveDistance, nearest, minDistanceToOtherUnits, &i1, &i2); /** * Returns 0 if intersections * Returns -1 if same m * Returns -2 if no intersections */ if (res == 0) { //intersections found newPos = _movingTo.distanceTo(i1) < _movingTo.distanceTo(i2) ? i1 : i2; } else if (res == -3 || res == -1) { //circle includes another one, move away BW_Point directionPoint; if (res == -3) { directionPoint.x = currentPosition.x - (nearest.x - currentPosition.x); directionPoint.y = currentPosition.y - (nearest.y - currentPosition.y); } else { //same points, move away in random direction //to be easy, just move in run direction directionPoint.x = Tools::random(0, Model::getInstance()->getFieldWidth()); directionPoint.y = Tools::random(0, Model::getInstance()->getFieldHeigth()); } // now scale this to moveDistance float scale = moveDistance / directionPoint.distanceTo(currentPosition); float distX = currentPosition.x - directionPoint.x; float distY = currentPosition.y - directionPoint.y; newPos.x -= distX * scale; newPos.y -= distY * scale; } //if (res == -2) no problem setPosition(newPos); float dx = _movingTo.x - currentPosition.x; float dy = _movingTo.y - currentPosition.y; if (dx == 0 && dy == 0) { doIdle(); } }