A
A
Alexander2015-12-05 21:43:30
C++ / C#
Alexander, 2015-12-05 21:43:30

How to calculate the "smooth" rotation angle of a sprite (2D)?

Actually, I find the angle of rotation in this way:

// поворот текущего юнита в сторону целевого юнита
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)
  }
}
*/

Works, but the unit turns instantly. It is not possible to implement a smooth rotation model. The target unit runs in different directions, randomly. Wrote this nonsense:
// направление поворота
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);

up to a certain point, the unit behaves adequately, but then it panics and starts spinning endlessly in one direction :)

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Alexander, 2015-12-07
@wxmaper

Here's what happened:

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;
}

A
AtomKrieg, 2015-12-06
@AtomKrieg

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 );
}

And you also need to see that the angles are normally calculated. If you have all the angles in the range -180+180, then the angles were not considered in the range 0+360

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question