2009-05-11 4 views
3

Я в настоящее время занят написанием маленького физического движка шарика для моего курса программирования в API Win32 и C++. Я закончил визуализатор буферов GDI и весь графический интерфейс (пару дополнительных действий для настройки), но я очень близок к завершению. Единственными серьезными препятствиями, которые в последнее время являются шары на столкновение с мячом (но я могу это исправить самостоятельно), но самая большая проблема из них - это отскок шаров. Что происходит, так это то, что я бросаю мяч, и он действительно падает, но как только он отскакивает, он будет подпрыгивать выше, чем точка, я выпустил его ??? самое смешное, это происходит только при определенной высоте. Эта часть кода физики: (Если вам нужно больше кода или объяснение, пожалуйста, спросить, но я бы очень признательны, если вы, ребята могли бы посмотреть на мой код.)Отскок мяча не соответствует правилу сохранения энергии

#void RunPhysics(OPTIONS &o, vector<BALL*> &b) 
{ 
    UINT simspeed = o.iSimSpeed; 
    DOUBLE DT; //Delta T 
    BOOL bounce; //for playing sound 

    DT= 1/o.REFRESH; 

    for(UINT i=0; i<b.size(); i++) 
    { 
     for(UINT k=0; k<simspeed; k++) 
     {   
      bounce=false; 

      //handle the X bounce 
      if(b.at(i)->rBall.left <= 0 && b.at(i)->dVelocityX < 0) //ball bounces against the left wall 
      { 
       b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof; 
       bounce=true; 
      } 
      else if(b.at(i)->rBall.right >= SCREEN_WIDTH && b.at(i)->dVelocityX > 0) //ball bounces against the right wall 
      {   
       b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof; 
       bounce=true; 
      } 
      //handle the Y bounce 
      if(b.at(i)->rBall.bottom >= SCREEN_HEIGHT && b.at(i)->dVelocityY > 0) //ball bounces against the left wall 
      { 
       //damping of the ball 
       if(b.at(i)->dVelocityY < 2+o.dGravity/o.REFRESH) 
       { 
        b.at(i)->dVelocityY = 0; 
       } 

       //decrease the Velocity of the ball according to the bouncecof 
       b.at(i)->dVelocityY = b.at(i)->dVelocityY * -1*b.at(i)->dBounceCof; 
       b.at(i)->dVelocityX = b.at(i)->dVelocityX * b.at(i)->dBounceCof; 

       bounce=true; 
      } 


      //gravity 
      b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH; 
      b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER; 
      //METER IS DEFINED GLOBALLY AS 100 which is the amount of pixels in a meter 

      b.at(i)->pOrigin.x += b.at(i)->dVelocityX/o.REFRESH*METER; 

      b.at(i)->UpdateRect(); 
     } 
    } 
    return; 
} 
+0

DT установлен в 1/o.REFRESH, а затем используется в o.REFRESH * DT, поэтому я предполагаю, что в нем есть какая-то логическая ошибка или вы можете просто удалить его. – schnaader

ответ

1

Хорошо, несколько здесь.

У вас есть разные кодовые дорожки для отскока к левой стене и к правой стене, но код тот же. Объедините эти коды кода, так как код тот же.

Что касается вашей основной проблемы: я подозреваю, что ваша проблема связана с тем, что вы применяете гравитацию после применения каких-либо сил демпфирования/отскоков.

0

Если ваш dBounceCof равен> 1, тогда ваш мяч будет отскакивать выше. У нас нет всех значений, чтобы отвечать на ваш вопрос.

4

Вы используете метод интеграции Эйлера. Возможно, ваш временной шаг (DT) слишком велик. Кроме того, кажется, ошибка в строке, которая обновляет Y координаты:

b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER; 

Вы уже добавили тяжести к скорости, так что вам не нужно, чтобы добавить его в положение, и вы не умножая скорость по DT. Это должно быть так:

b.at(i)->pOrigin.y += b.at(i)->dVelocityY * DT; 

Кроме того, как представляется, некоторая путаница относительно единиц (способ METER используется).

+0

Никогда не используйте метод Эйлера с ударом столкновения. При обнаружении столкновения немедленно пересчитайте скорость с сохранением импульса и нового положения. – Joshua

+0

Если я использую ваш метод, мяч не перемещается в направлении y вообще, спасибо в любом случае – 2009-05-11 19:25:00

+0

@Joshua: Я лично использовал (с большим успехом) переменную сегментацию времени. Пока вы не сталкиваетесь с вычислительными ограничениями, это работает как шарм. –

1

Когда вы звоните в RunPhysics? В таймерном цикле? Этот код является просто приближением и точным вычислением. В коротком интервале дельта t мяч уже изменил свое положение и скорость на бит, который не учитывается в вашем алгоритме и не производит небольших ошибок. Вам нужно будет вычислить время, пока мяч не ударит по земле и не предскажет изменения.

И тяжесть уже включена в скорости, так что не добавить ее дважды:

b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;

Кстати: Сохранить b.at (я) во временной переменной, так что вы не нужно пересчитывать его в каждой строке.

Ball* CurrentBall = b.at(i); 
0

Я не думаю, что ваше уравнение для позиции справа:

b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH; 

Это v=v0+gt - что кажется хорошо, хотя я бы написал dGravity*DT вместо dGravity/REFRESH_FREQ.

b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER; 

Но это, кажется, от: Это eqivalent к p = p0+v + 1/2gt^2.

  • Вы должны умножить скорость * время, чтобы получить единицы права
  • Вы масштабирование термина гравитации пикселей/метром, но не термин скорости. Так что следует умножить на METER также
  • Вы уже учитывали влияние силы тяжести при обновленной скорости, поэтому вам не нужно снова добавлять термин гравитации.
0

Спасибо за быстрые ответы! Извините, я должен был быть более понятным, RunPhysics запускается после PeekMessage. Я также добавил ограничитель кадров, который гарантирует, что больше не выполняется вычислений в секунду, чем частота обновления монитора. Таким образом, моя длина равна 1 секунде, уменьшенной частотой обновления. Может быть, мой DT на самом деле слишком мал, чтобы рассчитать, хотя это двойное значение ??? Мой коп реституции регулируется, но начинается с 0,9

+0

dt должен работать, если он находится между 50 мс и 2 мкс. Попробуйте опустить его, чтобы сделать вашу симуляцию более точной, но более тяжелой для циклов процессора. Если вы используете Euler так же, как и вы, вы можете использовать dt 2-10 мс. – Macke

0

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

I.e. разрешить точный момент времени, когда произошел отскок, и рассчитать новую скорость/позицию на основе изменения направления (частично в «кадр» вычисления), чтобы убедиться, что ваш мяч не перемещается «за» стены, все больше и больше каждый отскок.

W.r.t. вы можете проверить my answer here.

+0

Мой таймер точно такой: P в зависимости от обновления монитора изменяет временной интервал. И я не против, чтобы он подпрыгивал за стеной так, как за такой короткий промежуток времени, и это не должно повлиять на отскок задницы, если бы он отскакивал (за стеной), то должен был компенсироваться с понижением скорости снова – 2009-05-11 19:50:39

+0

Do у вас есть верхняя граница на вашем dt? Как max 0,05s? Вы пытались запустить цикл вычислений несколько раз за кадр? (Как 10 или 50) – Macke

0

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

Вы комбинируете эти два шага (интегрируя силы и разрешая столкновения). Для простой симуляции, как вы показали, достаточно, чтобы пропустить бит тяжести на любой итерации, где вы обработали вертикальный отскок.

В более продвинутом моделировании вы разделили бы любой интервал (dt), который содержит столкновение в фактическом экземпляре столкновения. Интегрируйте до столкновения, затем разрешите столкновение (путем регулировки скорости), а затем интегрируйте для остальной части интервала. Но это выглядит излишним для вашей ситуации.

+0

Спасибо, причина, по которой я хочу иметь гравитацию, потому что моя цель - держать все под контролем, я не возражаю, если это приближение, пока эффект показывается. Не могли бы вы показать пример того, как вы будете вычислять траекторию? – 2009-05-11 20:14:03

1

ANSWER !! ANSWER !! ANSWER !! но я забыл свою другую учетную запись, поэтому я не могу ее отметить :-(

Спасибо за все замечательные ответы, это действительно помогло мне! Ответы, которые вы дали, были действительно правильными, несколько моих формул были неправильными, некоторая оптимизация кода могла бы быть выполнена, но ни один из них не был действительно решением проблемы. Поэтому я просто сел с листом бумаги и начал вычислять каждое значение, которое я получил от своей программы вручную, взял меня, как два часа: O Но я сделал найти решение моей проблемы: Проблема в том, что при обновлении моей скорости (с исправленным кодом) я получаю десятичное значение, без проблем. Позже я увеличиваю положение в Y, добавляя скорость, умноженную на Delta T, которая Это небольшое значение, которое нужно добавить. Проблема заключается в том, что если вы нарисуете Elipse() в Win32, точка будет LONG, и поэтому все десятичные значения будут потеряны. Это означает, что только после долгого периода, когда скорость значений начинает выходить из десятичных значений, что-то происходит, и что наряду с этим, чем выше вы бросаете мяч, тем лучше результаты (один из моих симптомов). Решение эта проблема была очень простой, добавьте дополнительное значение DOUBLE для моего класса Ball, в котором содержится истинное положение (включая десятичные числа) моего шара.Во время RenderFrame() вы просто берете слово или потолок двойника, чтобы нарисовать elipse, но для всех вычислений вы используете двойное значение. Еще раз спасибо за все ваши ответы, STACKOVERFLOW PEOPLE ROCK !!!

Смежные вопросы