Использование значения эпсилон, чтобы определить, не движется ли мяч в игре?

У меня есть мячи, которые подпрыгивают, и каждый раз, когда они сталкиваются, их вектор скорости уменьшается на коэффициент восстановления.

Прямо сейчас мои шары CoR для моих шаров 0,80. Итак, после многих отскоков мои мячи «перестали» катиться, потому что их скорость стала до смешного малой.

На каком этапе уместно проверить, достаточно ли мало значение скорости, чтобы просто назвать его нулем (чтобы у меня не было сумасшедшего дрожания шариков, реагирующих на их микроскорости). Раньше я читал на некоторых форумах, что люди иногда используют константу эпсилон, какое-то небольшое число и проверяют его.

Должен ли я определить константу эпсилон и сделать что-то вроде:

if Math.abs(velocity.x) < epsilon then velocity.x = 0

Каждый раз, когда я обновляю скорость и положение шаров? Это то, что обычно делается? Было бы разумно разместить это в моих установщиках классов Vector для x и y? Или я должен делать это вне моего векторного класса, когда я вычисляю скорости.

Кроме того, что было бы разумным значением эпсилон, если бы я использовал поплавки для моего вектора скорости?


person mmcdole    schedule 10.12.2008    source источник


Ответы (4)


Разумное значение эпсилон будет зависеть от ограничений вашей системы. Если вы представляете мяч графически, то ваш эпсилон может соответствовать, скажем, скорости 0,1 пикселя в секунду (гарантируя, что ваше представление об остановке соответствует восприятию пользователем остановки экранных объектов). Если вы выполняете физическое моделирование, вам нужно настроить его на точность, с которой вы пытаетесь измерить свою систему.

Что касается того, как часто вы проверяете - это тоже зависит. Если вы моделируете что-то в реальном времени, дополнительная проверка может быть дорогостоящей, и вам нужно будет проверять каждые 10 обновлений или раз в секунду или что-то в этом роде. Или производительность может не быть проблемой, и вы можете проверять ее с каждым обновлением.

person bradheintz    schedule 10.12.2008

Вместо эпсилон для функции IsStillMoving, возможно, вы могли бы использовать функцию UpdatePosition, запланированную для каждого объекта на основе его скорости.

Я бы сделал что-то вроде этого (в моем собственном псевдокоде make-it-up-as-you-go):

void UpdatePosition(Ball b) {

   TimeStamp now = Clock.GetTime();
   float secondsSinceLastUpdate = now.TimeSince(b.LastUpdate).InSeconds;

   Point3D oldPosition = b.Position;
   Point3D newPosition = CalculatePosition(b.Position, b.Velocity, interval);
   b.MoveTo(newPosition);

   float epsilonOfAccuracy = 0.5; // Accurate to one half-pixel
   float pixelDistance = Camera.PixelDistance(oldPosition, newPosition);
   float fps = System.CurrentFramesPerSecond;
   float secondsToMoveOnePixel = (pixelDistance * secondsSinceLastUpdate) / fps;
   float nextUpdateInterval = secondsToMoveOnePixel / epsilonOfAccuracy;

   b.SetNextUpdateAt(now + nextUpdateInterval);
}

Мячи, движущиеся очень быстро, будут обновляться в каждом кадре. Мячи, движущиеся медленнее, могут обновляться каждые пять или десять кадров. А шары, которые остановились (или почти остановились), будут обновляться очень-очень редко.

person benjismith    schedule 10.12.2008

ИМО, ваш эпсилон-подход в порядке. Я бы просто поэкспериментировал, чтобы увидеть, что выглядит естественным для анимации в игре.

person grepsedawk    schedule 10.12.2008

Эпсилон по своей природе является наименьшим возможным приращением. К сожалению, компьютеры имеют разные собственные «минимальные» приращения в зависимости от представления с плавающей запятой. Я был бы очень осторожен (и мог бы даже превысить то, что я рассчитал только для безопасности), экспериментируя с этим, особенно если я хочу, чтобы код был переносимым.

Вы можете написать функцию, которая вычисляет минимальное приращение ваших чисел с плавающей запятой, а не использовать магическое значение.

person Uri    schedule 10.12.2008