Как рассчитать «плавный» угол поворота спрайта (2D)?

Собственно, сам угол поворота нахожу таким образом:
// поворот текущего юнита в сторону целевого юнита
void Unit::rotateToTarget(Unit *target, long elapsed)
{
    double delta = m_rotationSpeed * elapsed/1000.0f; // не используется
    // угол поворота за единицу времени

    QPointF targetCenterPos = target->centerPos();
    QPointF thisCenterPos = centerPos();
    QPointF diff = targetCenterPos - thisCenterPos;

    // угол поворота
    double angle = qAtan2(diff.y(), diff.x()) * 180/M_PI;

    // поворачиваем
    setRotation(angle);
}

/*
QPointF {
  double x;
  double y;

  operator - (QPointF p) {
    return QPointF(x - p.x, y - p.y)
  }
}
*/


Работает, но юнит поворачивается моментально. Не получается реализовать плавную модель поворота. Целевой юнит бегает в разных направлениях, рандомно. Написал вот такую ерундень:

// направление поворота
qint8 disp = 0;
if(angle > rotation()) {
    if(angle - rotation() > 180) disp = -1;
    else disp = 1;
else
    if(rotation() > angle)
        if(rotation() - angle > 180) disp = 1;
        else disp = -1;

// поворот за прошедшее время
double newRotation = rotation() + delta * disp;

// поворачиваем
setRotation(newRotation);

до какого-то момента юнит ведет себя адекватно, но потом он впадает в панику и начинает просто бесконечно крутиться в одну сторону :)
  • Вопрос задан
  • 432 просмотра
Решения вопроса 1
@wxmaper Автор вопроса
Вот что получилось:

bool QTDTower::rotateTo(QTDUnit *unit, qint64 time)
{
    // если обновление произошло слишком быстро, 
    // пропускаем ход
    qint64 elapsed = time - m_lastTime;
    if(!elapsed)
        return false;

    m_lastTime = time;

    QPointF unitCenterPos = unit->centerPos();
    QPointF thisCenterPos = centerPos();
    QPointF diff = unitCenterPos - thisCenterPos;

    // новый угол поворота
    qreal angle = qAtan2(diff.y(), diff.x()) * (180/M_PI);

    // скорость поворота
    qreal delta = m_rotationSpeed * elapsed/1000.0f;

    // выгодное направление поворота
    qint8 disp = 1;
    if(angle > rotation())
        if(angle - rotation() > 180) disp = -1;
        else disp = 1;
    else
        if(rotation() > angle)
            if(rotation() - angle > 180) disp = 1;
            else disp = -1;
    
    qreal newRotation = rotation() + delta * disp;

    // предотвращаем "переповорот" (сглаживание) 
    if((newRotation < 0 && newRotation < angle)
            || (newRotation > 0 && newRotation > angle))
        newRotation = angle;

    // фиксируем диапазон
    if(newRotation > 180) newRotation = (360 - newRotation) * -1;
    else if(newRotation < -180) newRotation = (360 + newRotation);

    // рассчитываем оставшийся угол поворота
    qreal adiff = newRotation - angle;
    if (adiff < 0) adiff += 360;
    if (adiff > 180) adiff = -(360 - adiff);
    
    // поворачиваем
    setRotation(newRotation);
    
    // если оставшийся угол удовлетворяет углу атаки 
    // (например от 0 до 20 градусов), то можно стрелять
    return qAbs(adiff) < m_attackAngle;
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
AtomKrieg
@AtomKrieg
Давай я поищу в Google за тебя
void Unit::rotateToTarget(Unit *target, long elapsed)
{
    QPointF targetCenterPos = target->centerPos();
    QPointF thisCenterPos = centerPos();
    QPointF diff = targetCenterPos - thisCenterPos;

    double angle = qAtan2(diff.y(), diff.x()) * 180/M_PI;
    double delta = m_rotationSpeed * elapsed/1000.0;

    setRotation(rotation() + (angle>0 ? 1:-1)*delta );
}


А еще вам надо посмотреть чтобы углы нормально рассчитывались. Если у вас все углы в диапазоне -180+180, то углы не считались в диапазон 0+360
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы