Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Нютоновская физика в моем клоне agario. (2 стр)

Нютоновская физика в моем клоне agario. (2 стр)

Поделиться

Страницы: 1 2 3 Следующая

SuslikМодераторwww15 июля 201615:44#15
sba
> Как это сделать не зная шага интегрирования? Ведь в месте применения импульса
> мы не знаем этого. Понятно что на самом деле шаг интегрирования фиксированный и
> известный, но не передавать же его в Cell::applayImpulse или хранить в объекте
> или еще что велосипедить.
да, это — известная архитектурная проблема position-based. я её решаю так:
struct PhysicalParticle
{
  vec pos, deltaPosition, acceleration;
};

struct ParticleSystem
{
  void ApplyImpulse(int particleIndex, vec impulse)
  {
    particles[particleIndex].deltaVelocity += impulse / particles[particleIndex].mass * dt;
  }
  std::vector<PhysicalParticle> particles;
  float dt;
};

struct ParticleHandle
{
  void ApplyImpulse(vec impulse)
  {
    owner->ApplyImpulse(this->particleIndex, impulse);
  }
  ParticleSystem *owner;
  int particleIndex;
};

на самом деле такая схема используется в первую очередь для абстрагирования от пользователя внутреннего устройства PhysicalParticle, позволяя их хранить в памяти полностью произвольным образом, например, так

struct PhysicalParticlesSoA
{
  std::vector<vec> positions;
  std::vector<vec> deltaPositions;
  std::vector<vec> masses;
}
struct ParticleSystem
{
  PhysicalParticlesSoA particles;
}
это позволяет в существенных пределах варьировать memory layout, позволяя реализовывать сильные векторные оптимизации, а во-вторых, что важно архитектурно, идеологически связывает сущность каждой частицы с системой частиц, в которой она находится, так как они по сути независимыми сущностями и не являются. важное преимущество подхода — в самих физических частицах не хранится никаких лишних полей, для них оверхеда при расчётах нет. оверхед небольшой будет при обращении по ParticleHandle, но это будет делать пользователь и не так часто, как сам ParticleSystem

Правка: 15 июля 2016 15:45

sbaПользовательwww17 июля 201611:06#16
Suslik
Я запилил классическую упруго-вязкую модель из #1. Чтобы не залазить в дебри - пока еще в velocity-based реализации.
void Player::simulate(float dt)
{
  const auto& config = m_room.getConfig();
  auto dstPos = m_position + m_pointer;
  for (PlayerCell* cell : m_cells) {
    geometry::Vec2D force = ((dstPos - cell->position) * config.playerVelocityRatio - cell->velocity) * config.playerForceRatio;
    force -= cell->velocity.direction() * (cell->mass * config.frictionRatio + cell->radius * cell->radius * config.resistanceRatio). 
    cell->applayForce(force);
    cell->simulate(dt);
  }
  calcParams(); // расчет центра масс игрока - m_position 
}

Играюсь с коефициентами - и ничего не получается. Тело не двигается так как надо. Пока вообще не понимаю как оно двигается, сложно даже описать этот процесс. У меня несколько вопросов.
1. В этой формуле не учитывается масса тела. Для общего случая (для тел с разными массами) разве не надо как-то учитывать массу?
2. В текущей архитектуре тело никогда не может достигнуть dstPos. Это не проблема?
В целях оптимизации я сделал так - так как на клиенте экран центрируется по центру масс игрока, соответственно при смене позиции мыши клиент шлет на сервер смещение относительно центра экрана - m_pointer. На сервере игрок постоянно двигается к точке m_position (центр масс игрока) + m_pointer. Естественно что в эту точку игрок никогда не попадет.
3. Какова должна быть сила противодействия?
В текущем варианте это -velocity.direction() * (mass * config.frictionRatio + radius * radius * config.resistanceRatio).

Если отключить силу противодействия, то тело более-менее резво реагирует на смену dstPos, но все равно есть значительная инерция для тела с массой 100 и playerVelocityRatio = 5000000, playerForceRatio = 2500000. Я предполагаю что чем больше эти коефициенты тем резвее тело, но всеравно не то. Инерция есть и она очень заметна на глаз.

SuslikМодераторwww18 июля 20168:16#17
sba
> Играюсь с коефициентами - и ничего не получается. Тело не двигается так как
> надо. Пока вообще не понимаю как оно двигается, сложно даже описать этот
> процесс.
ну так сделай видео.

1. можешь вычислять не силу, а напрямую ускорение, как бы сокращая массу. тогда тела любой массы будут ускоряться одинаково.
2. нет, оно должно по асимптоте приближаться к dstPos. однако, оно настолко близко будет приближаться к этой точке, что разница не будет заметна глазом.
3. неправильно. сила сопротивления от массы никак не зависит, она зависит только от размеров тела.

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

sbaПользовательwww18 июля 20169:42#18
Suslik
Ура! Начинает получаться. Огромнейшее спасибо.

>ну так сделай видео.
Подойдет если я подниму на beta.cellwar.xyz тестовый вариант? А то сейчас еще разбираться как видео делать....

>1. можешь вычислять не силу, а напрямую ускорение
Работает великолепно.

>2. оно должно по асимптоте приближаться к dstPos
Совсем непонятно. В системе где dstPos задан один раз - так оно и будет. У меня же на каждом шаге моделирования меняется dstPos = m_position + m_pointer. Получается на сколько сдвигается тело, на столько же каждый раз сдвигается dstPos. С этим надо что-то решать? Я могу более подробно описать почему так сделано.

>3. сила сопротивления
Давай подытожим. Для моделирования движения тел будем использовать только 2 силы.
Сила из #1 (классическая упруго-вязкая модель):

Vector2f dstVelocity = (dstPos - body->pos) * velocityCoef;
Vector2f dstForce = (dstVelocity - body->velocity) * forceCoef;
и противодействующая сила (сила сопротивления):
Vector2f resForce = -body.velocity.direction() * (body.radius * body.radius * resistanceCoef);

В текущем варианте задача резвости тела решена на отлично. То есть тела ускоряются и меняют направление движения так как я хотел.
Остается еще вопрос с равномерностью движения и скоростью. Скорость должна зависить от радиуса тела (может я и неправ). Так как радиус ограничен снизу и сверху, получаем максимальную и минимальную скорости тела. После смены скорости (то есть после смены направления движения) тело должно выходить на заданную скорость и держать ее. Может стоит использовать проекцию dstPos на круг ограничивающий тело? Это 100% скорости. Прямо уже сейчас имеем эффект снижения скорости если dstPos внутри тела игрока (и это очень даже хорошо).

Правка: 18 июля 2016 19:18

sbaПользовательwww18 июля 201622:52#19
Suslik
Не дожидаясь ответа на #18 выложил что есть (http://cellwar.xyz/).
Почему-то сломался импульс.
Согласно #17 я вычисляю напрямую ускоренее. Чтобы не ломать интерфейс, работаю с силой.
geometry::Vec2D force = ((dstPos - cell->position) * config.playerVelocityRatio - cell->velocity) * (cell->mass * config.playerForceRatio);
cell->applayForce(force);
cell->simulate(dt);

Без этой силы импульс при разделении тела работает ожидаемо, 100% точности не проверял, но визуально работает как надо. Если применять эту силу при разделении тела творится не пойми что.
Код разделения весьма прост.
bool Room::split(PlayerCell& cell, const geometry::Vec2D& point)
{
  if (cell.mass < m_config.playerMinMassSplit) {
    return false;
  }
  auto& obj = createPlayerCell();
  float mass = 0.5 * cell.mass;
  modifyMass(obj, mass);
  modifyMass(cell, -mass);
  auto direction = (point - cell.position).direction();
  obj.position = cell.position;
  obj.applayImpulse(direction * (obj.mass * m_config.playerSplitImpulse));
}
SuslikМодераторwww19 июля 20166:59#20
sba
> Совсем непонятно. В системе где dstPos задан один раз - так оно и будет. У меня
> же на каждом шаге моделирования меняется dstPos = m_position + m_pointer.
> Получается на сколько сдвигается тело, на столько же каждый раз сдвигается
> dstPos. С этим надо что-то решать? Я могу более подробно описать почему так
> сделано.
это нормально

sba
> Давай подытожим. Для моделирования движения тел будем использовать только 2
> силы.
> Сила из #1 (классическая упруго-вязкая модель):
>
> Vector2f dstVelocity = (dstPos - body->pos) * velocityCoef;
> Vector2f dstForce = (dstVelocity - body->velocity) * forceCoef;
> и противодействующая сила (сила сопротивления):
> Vector2f resForce = -body.velocity.direction() * (body.radius * body.radius *
> resistanceCoef);
силу сопротивления можно вообще опустить на самом деле, так как она по сути уже входит в разность dstVelocity - body->velocity

> Скорость должна зависить от радиуса тела (может я и неправ).
что значит "должна"? есть аспекты, определяемые физикой, а есть — игровым дизайном. зависимость скорости от размера определяется исключительно игровым дизайном, как ты сделаешь, так и будет. максимальная скорость определяется параметром velocityCoef. если ты хочешь её в явно виде ограничить некоторым значением, сделай так:
if(dstVelocity.GetLength() > maxVelocity) dstVelocity = dstVelocity.GetNorm() * maxVelocity;
но подобные дополнительные константы нужно всегда подбирать уже в последний момент. ты, грубо говоря, определяешь максимальное расстояние, дальше которого мышь отодвигать от тела смысла нет. должна ли эта величина зависеть от размера тела? да тебе решать, это тоже вопрос геймдизайна, а не физики.

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

sbaПользовательwww19 июля 201614:39#21
Suslik
Я не знаю есть ли у тебя время и желание помогать мне, поэтому задаю прямо вопрос - можно ли продолжать наше общение в таком же формате. Не хочу долго стопориться на неочевидных для меня вещах, поэтому задаю кучу тупых вопросов. Благодарен за любые физические смыслы типа
максимальная скорость определяется параметром velocityCoef
Такая информация отметает кучу вопросов, расставляя многое на свои места. Да и вообще у тебя весьма понятные ответы. Спасибо.

> силу сопротивления можно вообще опустить
От силы сопротивления не хочу отказываться, ведь есть и другие тела, которые получают импульс и должны как то замедляться и останавливаться. Значит пускай и игрок по тем же законам двигается.

>да тебе решать, это тоже вопрос геймдизайна, а не физики.
Спасибо, спасибо и еще раз спасибо. Именно в таком ответе нуждаюсь. Четко и ясно, все стало на свои места.

>как я могу узнать, что именно тебя не устраивает?
Без силы из #1 (притяжения к указателю мыши или как ее назвать) импульс работает правильно. Игрок разделяется на 2 части. Основная часть остается на месте, отсреленная с замедлением проходит нужную дистанцию. Если применить силу из #1 то понятно что главная часть игрока не стоит, а двигается в указанном направлении, но при разделении его на 2 части нету никакого отстреливания, отсреленная часть остается почти там же где и главная, так как будто ее чтото сильно тормозит. Это все прямо сейчас можно наблюдать на сайте.

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

SuslikМодераторwww19 июля 201615:19#22
sba
> можно ли продолжать наше общение в таком же формате
слушай, ты со мной отношения пытаешься строить или как? я отвечаю, если есть время и желание. со временем я ничего особо не могу поделать, но желание отвечать обычно больше, если вижу, что советы имеют какой-то эффект. плюс у тебя код нормально оформлен, я это уважаю.

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

> Без силы из #1 (притяжения к указателю мыши или как ее назвать) импульс
> работает правильно. Игрок разделяется на 2 части. Основная часть остается на
> месте, отсреленная с замедлением проходит нужную дистанцию. Если применить силу
> из #1 то понятно что главная часть игрока не стоит, а двигается в указанном
> направлении, но при разделении его на 2 части нету никакого отстреливания,
> отсреленная часть остается почти там же где и главная, так как будто ее чтото
> сильно тормозит. Это все прямо сейчас можно наблюдать на сайте.
а, я понял. это потому что при большом значении коэффициента forceCoef, тело быстро приобретает ту скорость, какую ты от него хочешь, то есть dstVelocity, поэтому даже если ты его с некоторой скоростью запулишь, эта скорость быстро выровняется на dstVelocity. выход — либо запуливать с бОльшей скоростью(думаю, в agar.io примерно так и делалось), либо на время разлёта использовать меньшее значение forceCoef, либо просто использовать меньшее значение этого параметра, но тогда они будут менее резко останавливаться и разгоняться по жизни.

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

Правка: 19 июля 2016 15:22

sbaПользовательwww19 июля 201619:48#23
Suslik
Опять вопрос из разряда тонкой грани между физикой и игровым дизайном.
Сила сопротивления зависит от размеров тела. Что есть размер круглого тела в 2D? body->radius * body->radius. У меня получилось так:
force = -velocity.direction() * (radius * radius * config.resistanceRatio);
В общем случае есть зависимость радиуса от массы. Согласно игрового дизайна я хочу ограничить минимальный радиус. Получается есть некоторый диапазон значений радиуса при которых радиус физически какбы не соответствует массе. Из-за этого я столкнулся с неприятным эффектом - тела с маленькой массой слишком медленно двигаются, так как их давит слишком большая сила сопротивления. После того как тело наберет массу, которая соответсвует радиусу - получаем правильную скорость. Как принято поступать в такой ситуации? В похожей ситуации на клиенте - там я анимирую изменения радиуса, я поступил просто - ввел дополнительный радиус для визуализации, а в расчетах используется серверный радиус который меняется мгновенно.  Казалось бы что сложного? На сервере можно поступить аналогично. Просто меня смущает тот факт (именно на сервере), что от радиуса зависит просчет взаимодействия между телами. И одно дело клиент, где анимация ни на что не влияет, другое дело сервер. Или я усложняю?

Правка: 19 июля 2016 19:55

ReviriПостоялецwww19 июля 201622:40#24
Если разговор идет о силе сопротивления среды, то в 2D среда контактирует с телом не по его площади pi*r*r , а по периметру 2*pi*r.
Поэтому сила сопротивления будет пропорциональна не квадрату радиуса тела, а просто радиусу.
SuperInoyПостоялецwww20 июля 20162:53#25
sba
Как ты предлагаешь в игре есть крупных противников, если скорость движения ~=0
SuslikМодераторwww20 июля 201612:58#26
sba
> Согласно игрового дизайна я хочу ограничить минимальный радиус
ну так ограничивай вместе с ним и минимальную массу, в чём проблема?

sba
> Сила сопротивления зависит от размеров тела.
на самом деле сила сопротивления зависит от размера сложным нелинейным образом, определяемым из решения уравнения навье-стокса, которое, к слову, аналитического решения в общем случае не имеет. предположение, что сила сопротивления зависит от радиуса в такой-то степени — это по сути аппроксимация. обычно предполагается, что на средних скоростях сила лобового сопротивления зависит от лобовой площади объекта в первой степени в трёхмерном пространстве. трёхмерный аналог 2д окружности — это бесконечный цилиндр, лобовая площадь которого равна [cht]2rh[/cht], то есть пропорциональна радиусу в первой степени.

sbaПользовательwww20 июля 201616:23#27
Reviri
>сила сопротивления будет пропорциональна не квадрату радиуса тела, а просто радиусу.
Тупанул. Не зря привожу кучу деталей - знающие люди поправят. Результат выглядел вполне реалистично, поэтому меня вовсе не смутила квадратичная зависимость. Мне даже нравилась излишняя жесткость. С линейной зависимостью все стало заметно плавнее. Пока подбираю коэфициенты.

SuperInoy
Скорость движения крупных шаров или скорость шара после разделения? Для первого еще подбираю коэфициенты. Второе вообще еще не завершено. Более крупный игрок никогда не догонит более мелкого. По геймдизайну противника надо поедать именно путем разделения себя. Ну или загонять в угол, тут скорость не критична. Или ты имеешь в виду что бывает у большого шара скорость стремится к нулю? Этот баг я еще не проработал. Пока не понял из-за чего так. Позже сформулирую вопрос.

Suslik
>ну так ограничивай вместе с ним и минимальную массу, в чём проблема?
Это физическое решение. Все логино :). Получается для визуально красивого старта нужно ограничить минимальную массу примерно 40 единицами. Ранее (при геометрическом подходе) я без последствий провернул такое - стартуем с массой 10, минимальная масса ограничена 1, радиус - 20. Искуственное ограничение значения радиуса никак не влияло на механику движения - скорость зависела только от радиуса. В физической же интерпретации имеем зависимость и от радиуса и от массы, поэтому нельзя искуственно ограничивать только что-то одно. Физически я понимаю данный процесс так - если у тела слишком большой радиус для его массы, то сила сопротивления неестественно давит скорость. Но это не суть. Просто думал может есть какая-то хитрость для удовлетворения подобных хотелок.

У меня еще странный вопрос о скорости шара игрока. Возможно мои требования из разряда взаимоисключающих. Без ограничений на максимальную скорость я подобрал такие коэфициенты при которых меня устраивает резвость тел. Но получилась слишком большая конечная скорость. Понятное дело я ограничил скорость сверху (скорость зависит от радиуса тела). Получил желаемую конечную скорость (когда движение стабилизировалось), но от этого очень снизилась резвость. Как это решать? Получается нужна большая скорость во время смены направления, пока скорость не выровняется и тело не начет двигаться равномерно?

Правка: 20 июля 2016 17:27

ReviriПостоялецwww20 июля 201618:08#28
Мне кажется, что ты слишком заморочился с тем, что хочешь сделать такую хитрую физику, что бы на ее основе тела двигались интересно.
С моей точки зрения в игре проще сразу делать, чтобы тела двигались интересно, а физику выкинуть.
Я бы для простоты рассчитывал скорость по обратной линейной зависимости от массы тела, а ее вектор доводил бы как скользящее среднее до направления на курсор, если игрок зажал кнопку мыши, или до нуля, если игрок отпустил.
Визуально выглядело бы все очень резво с заносами и разгонами, но физики там было бы ноль. 

Правка: 20 июля 2016 18:10

sbaПользовательwww20 июля 201619:13#29
Reviri
До недавнего времени я и не собирался влезать в физику. Запилил обратную линейную зависимость скорости от радиуса тела, равномерное движение в направлении курсора и равноускоренное движение при разделении и взрывах. Но когда дошло до расталкивания тел начал задумываться что одной геометрией не решить такие задачи.

Страницы: 1 2 3 Следующая

/ Форум / Программирование игр / Физика

2001—2017 © GameDev.ru — Разработка игр