Колебания постоянной скорости в SpriteKit

Я применяю постоянную скорость к одному из моих узлов, как это в функции обновления:

// Set a constant velocity to the right:
node.physicsBody?.velocity.dx = 300

Когда я печатаю скорость в функции didSimulatePhysics, она выводит около 290. Хорошо, я теряю некоторую скорость из-за linearDamping, это имеет смысл. Но это не остается постоянным.

Каждые 10-15 секунд будет происходить необъяснимое дрожание скорости (из печати didSimulatePhysics). Для 6 или 7 кадров скорость будет колебаться в пределах 285-295. Медленнее, потом быстрее. Так что я возьму 287, потом 294, потом 286, потом 294. Никогда два медленных или два быстрых подряд.

Это мой главный персонаж, за которым следит моя камера, и небольшое изменение скорости заставляет камеру дрожать всякий раз, когда это происходит.

Я далек от каких-либо коллизий, но обратите внимание, что я игнорирую коллизии на этом узле, а реституция установлена ​​​​на 0:

node.physicsBody?.collisionBitMask = 0
node.physicsBody?.restitution = 0

Моделирование физики отстает, а затем пытается компенсировать это на следующем кадре (FPS привязан к 60)? Или, возможно, столкнулись с проблемами округления?

Есть ли способ получить точно постоянную скорость в одном направлении в каждом кадре?

Добавляем пример фактического изменения node.position.x за кадр при движении прямо по воздуху без столкновений, устанавливая speed.dx на 300 при каждом обновлении:

3.82861328125 // this is the norm - thousands of these before this blip)
3.82861328125
3.82861328125
5.740478515625 // blip begins
1.9150390625
3.82861328125
5.740478515625
1.9150390625
5.740478515625
1.9150390625
5.740478515625
1.9150390625
5.740478515625
3.82861328125 // blip ends
3.82861328125
3.82861328125

person Stephen    schedule 16.06.2015    source источник
comment
Что касается дрожания камеры, в большинстве игр камера плавно перемещается, так что камера перемещается в нужное положение с течением времени, а не мгновенно, поэтому сценарии, подобные описанному вами, кажутся плавными. Теперь, что касается вашей реальной проблемы, если вы устанавливаете скорость в методе обновления (то есть непрерывно), скорость должна оставаться постоянной. Однако набор спрайтов реализует переменный временной шаг, поэтому дрожание может появиться в положении, когда частота кадров падает. Вы работаете на симуляторе или устройстве. А вы уверены, что нет внешних сил, таких как гравитация, трение?   -  person Epic Byte    schedule 16.06.2015
comment
Хорошие мысли - на самом деле я дергаюсь в новое положение, но изменение все еще (едва) заметно, потому что в остальном камера такая устойчивая. Это на устройстве iPhone 6. Счетчик FPS остается привязанным к 60 с процессором около 5%, но это, безусловно, похоже на небольшое отставание. Определенно никакого трения. Гравитация включена (именно из-за гравитации я использую узел физики), но повлияет ли она на горизонтальную скорость? И только раз в 10-15 секунд, но всего несколько кадров. Возможно, ARC что-то подчищает и вызывает очень небольшую задержку частоты кадров? Инструменты не показывают всплески процессора. Спасибо за ответ.   -  person Stephen    schedule 16.06.2015
comment
Очень странно. Если вы хотите немного отладить эту проблему, вы можете начать с того, что посмотрите, действительно ли это частота кадров, отслеживая собственное дельта-время, которое набор спрайтов дает вам в функции обновления. Это потому, что вы не всегда можете руководствоваться тем, что показывает SKView FPS, потому что это просто среднее значение. Если вы рассчитаете свое собственное дельта-время, вы сможете увидеть, что происходит в момент нервозности. Если дельта-время постоянно показывает 1/60, значит, дрожащее движение должно быть вызвано чем-то другим. Также может быть полезно воспроизвести эту проблему в примере проекта.   -  person Epic Byte    schedule 16.06.2015
comment
Вы также можете попробовать запустить свой проект в режиме выпуска, чтобы удалить большую часть накладных расходов на отладку. И, наконец (и это может показаться странным), вы можете попробовать удалить приложение и очистить папку сборки. Очень редко во время моей игры с набором спрайтов сборка зависала, и это всегда решало проблему. Опять же, это может быть совершенно другой проблемой, чем та, с которой вы столкнулись, я просто пытаюсь дать вам как можно больше информации.   -  person Epic Byte    schedule 16.06.2015
comment
Интересно (5,740478515625 + 1,9150390625)/2 = 3,8277... Похоже, что закончилась съемка, а затем исправление следующего кадра. Я подозреваю, что если вы зарегистрируете время на кадр, вы также увидите всплеск. 60 кадров в секунду — это среднее значение, и, поскольку это всего несколько кадров в общей схеме, вы, вероятно, не увидите падения частоты кадров или, скорее, он не сообщит об этом. Что касается того, почему это происходит каждые 10-15 минут, я не уверен. Я бы предположил, что 10-15 - это оценка. Я бы на самом деле замерил его, чтобы увидеть, есть ли какие-либо постоянства со временем, которое требуется для пропуска.   -  person Skyler Lauren    schedule 16.06.2015


Ответы (1)


Проблема с физикой SpriteKit заключается в том, что она использует переменный временной шаг, который плохо работает, особенно при постоянном движении. Это означает, что SpriteKit обновляет вашу физику в каждом кадре с помощью deltaTime, прошедшего с последнего кадра. Это время никогда не бывает одинаковым, даже если вы поддерживаете постоянные 60 кадров в секунду. Для решения этой проблемы может быть хорошей идеей использовать постоянный шаг по времени для физического моделирования. К сожалению, в SpriteKit нет возможности контролировать временной шаг для моделирования физики, и он всегда привязан к частоте кадров. Если бы вы использовали движок, который позволяет обновлять физику вручную, вы могли бы реализовать постоянный шаг по времени для симуляции физики, например, следующим образом:

-(void)update:(double)dt
{
  double fixedDt = 1.0/60.0; // or you can put for example 1.0/300.0 to have more physics updates per frame

  self.difference += MIN(dt, 0.1); // prevent too big dt changes

  while (self.difference > fixedDt)
  {
      [self updatePhysics:fixedDt];
      self.difference -= fixedDt;
  }
}

К сожалению, в SpriteKit вы не можете контролировать это, и именно по этой причине вы всегда будете видеть небольшие дрожания даже при 60 кадрах в секунду в постоянном движении. У вас есть несколько решений:

  • игнорировать это и просто жить с этим
  • попробуйте использовать другой физический движок, например Chipmunk или Box2D
  • вообще не использовать физический движок

Вы также можете найти больше информации о переменном/постоянном временном шаге для физики здесь: https://gamedev.stackexchange.com/questions/1589/when-should-i-use-a-fixed-or-variable-time-step

person Leszek Szary    schedule 06.08.2019