Результаты поиска
| |
QValidator | Дата: Пятница, 25 Декабря 2015, 08:54 | Сообщение # 1 | Тема: Движение объектов по ключевым точкам (waypoint) |
был не раз
Сейчас нет на сайте
| Цитата Daeloce ( ) то ли вы что-то не то сделали. Да, вы правы это я перепутал. В том алгоритме про который я рассказывал скорость перемещения за один тик напрямую зависела от длины маршрута, а с каждым тиком длина уменьшается, значит и скорость на каждом тике уменьшалась.
Доработал ваше предложение так, чтобы учитывался остаток от измененной deltams на следующий шаг, вроде работает. Спасибо :)
Код /* time - игровое время, мс с начала эпохи Unix * elapsed - прошедшее время между тиками, мс * residual - остаток предыдущего шага */ void Unit::moveByWayPoints(qint64 time, qint64 elapsed, qreal residual) { Q_UNUSED(time); // если движение не начиналось if(targetPointIndex == -1) { wayPoints = m_map->wayPoints(); wayPoints.takeFirst(); // remove start point targetPointIndex = wayPoints.takeFirst(); } // размер клетки игрового мира qreal cellSize = m_map->cellSize(); // получаем координаты центра клетки в которую движемся qreal deltac = cellSize/2 - width()/2; QVector2D target = QVector2D(m_map->cellAt(targetPointIndex)->col() * cellSize + deltac, m_map->cellAt(targetPointIndex)->row() * cellSize + deltac); // текущие координаты объекта QVector2D current = QVector2D(x(), y());
QVector2D diff = target - current; qreal distance = diff.length(); // если не приблизились к точке достаточно близко, то движемся в ее сторону if(distance > 1) { QVector2D direction = diff.normalized(); qreal deltams = elapsed/1000.0f * cellSize * m_moveSpeed + residual;
qreal newx = x(); qreal newy = y(); // если вектор смещения оказался по длине больше // чем вектор до конечной точки, пересчитываем дельту // и вызываем следующий шаг if((direction * deltams).length() > diff.length()) { qreal newdeltams = diff.length() / (direction * deltams).length(); qreal residual = deltams - newdeltams;
newx += direction.x() * newdeltams; newy += direction.y() * newdeltams; setPosition(QPointF(newx, newy));
if(!wayPoints.isEmpty()) { targetPointIndex = wayPoints.takeFirst(); moveByWayPoints(time, 0, residual); return; } }
newx += direction.x() * deltams; newy += direction.y() * deltams;
setPosition(QPointF(newx, newy)); } // иначе получаем индекс следующей клетки маршрута else { if(!wayPoints.isEmpty()) { targetPointIndex = wayPoints.takeFirst(); } } }
>=)
Сообщение отредактировал QValidator - Пятница, 25 Декабря 2015, 08:57 |
|
| |
QValidator | Дата: Пятница, 25 Декабря 2015, 07:47 | Сообщение # 2 | Тема: Движение объектов по ключевым точкам (waypoint) |
был не раз
Сейчас нет на сайте
| Первый вариант не подойдет, баловался с ним давно - замедление существенное, скорость движения стремится к нулю о-о-очень долго - это слишком критично движение должно быть равномерным (если не учитывать лаги, конечно).
Самым идеальным вариантом было бы сделать так же как в WarCraft III: если произошел лаг, то юниты двигаются не рывками, а просто ускоряется графика, как будто включили переметку вперед получаются, что юниты двигаются в ускоренном режиме, но не дергаются - сразу понятно что проблемы со скоростью передачи данных по сети, но это не сильно мешает воспринимать картинку. Реализация такой модели для меня остается загадкой.
Второй метод сейчас попробую впиндюрить, но сделаю привязку не ко времени, а к количеству допустимых шагов между клетками
>=)
Сообщение отредактировал QValidator - Пятница, 25 Декабря 2015, 07:48 |
|
| |
QValidator | Дата: Пятница, 25 Декабря 2015, 06:14 | Сообщение # 3 | Тема: Движение объектов по ключевым точкам (waypoint) |
был не раз
Сейчас нет на сайте
| Доброго времени суток. Помогите разобраться с проблемой Алгоритм движения по точкам реализован на основе этой статьи: MOVING 2D OBJECTS BETWEEN WAYPOINTS. Он довольно прост в понимании и реализации на других языках, плюс ко всему: работает прекрасно, но с одним "НО" =[ он работает прекрасно только для фиксированного шага, не зависящего от времени затраченного на прорисовку/расчет логики.
Сейчас объясню: допустим есть таймер, который срабатывает каждые 10мсек, при срабатывании таймера объект движется на фиксированное кол-во пикселей - тут все ок. Теперь другая ситуация: таймер отсутствует, вместо него обычный луп while (true) { move(elapsedTime); } - вот в этом случае представленный алгоритм работает крайне нестабильно, потому что если объект почти достиг очередной точки и в игре произошел лаг, то следующее местоположение объекта окажется за точкой, в которую он следовал, при этом сам индекс (currentIndex) точек не изменится: объект отрисуется в неправильной позиции (перескочит через точку) и на следующем шаге продолжит свое движение в обратном направлении, в сторону точки, в которую он должен следовать согласно индексу. Все еще хуже, когда игра начинает лагать интенсивно: объект просто прыгает из стороны в сторону из-за того что он никак не может попасть в точку =)
Моя реализация выглядит так:
Код void Unit::moveByWayPoints(qint64 time, qint64 elapsed) { Q_UNUSED(time);
// если движение не начиналось if(targetPointIndex == -1) { wayPoints = m_map->wayPoints(); // получаем маршрут (список индексов клеток игрового мира) wayPoints.takeFirst(); // удаляем стартовую точку (мы в ней) targetPointIndex = wayPoints.takeFirst(); // получаем индекс клетки в которую будем двигаться }
// размер клетки игрового мира qreal cellSize = m_map->cellSize();
// поучаем координаты центра клетки в которую движемся qreal deltac = cellSize/2 - width()/2; QVector2D target = QVector2D(m_map->cellAt(targetPointIndex)->col() * cellSize + deltac, m_map->cellAt(targetPointIndex)->row() * cellSize + deltac);
// текущие координаты объекта QVector2D current = QVector2D(x(), y());
QVector2D diff = target - current; qreal distance = diff.length();
// если не приблизились к точке достаточно близко, то движемся в ее сторону if(distance > 1.0f) { QVector2D direction = diff.normalized(); qreal deltams = elapsed/1000.0f * cellSize * m_moveSpeed;
qreal newx = x() + direction.x() * deltams; qreal newy = y() + direction.y() * deltams; /* QVector2D newPos(newx, newy); QVector2D newDirection = (target - newPos).normalized(); if(!qFuzzyCompare(direction, newDirection)) { if(!wayPoints.isEmpty()) { targetPointIndex = wayPoints.takeFirst(); } } */
setPosition(QPointF(newx, newy)); } // иначе получаем индекс следующей клетки маршрута else { if(!wayPoints.isEmpty()) { targetPointIndex = wayPoints.takeFirst(); } } }
закомментированный участок кода - это моя попытка исправить ситуацию, которая заключается в сравнении векторов направления движения: если вектор направления движения до смены позиции совпадает с вектором после смены позиции, то мы не достигли точки маршрута и не перескочили ее, иначе - переходим к следующему индексу, но все равно рисуем объект в новой позиции.
Алгоритм работает только в случае прямолинейного движения объекта, но как только объекту нужно сменить направление (скажем, свернуть вправо), все ломается к чертям оно и понятно: объект рисуется в неправильной позиции и продолжает движение в новом направлении по диагонали (хотя такое как бы не предусмотрено "правилами" игры) из-за чего вектора направления никогда не совпадут.
Кто что может сказать по этому поводу? может посоветуете другой подход/алгоритм? Если игру получится доделать, то она возможно будет сетевой, поэтому наличие возможных лагов обеспечено, пока я их симулирую задержками в игровом цикле.
>=)
|
|
| |
|