Столкновение мяча с мячом — при столкновении приобретает значительную скорость.
-
23-08-2019 - |
Вопрос
Я реализовал код из вопроса "Столкновение мяча с мячом – обнаружение и обработка" в Objective-C.Однако всякий раз, когда шары сталкиваются под углом, их скорость резко возрастает.Вся векторная математика выполняется с использованием cocos2d-iphone, с заголовком CGPointExtension.h.В чем причина этого нежелательного ускорения?
Ниже приведен пример увеличения скорости:
Вход:
масса == 12,56637
скорость.x == 1,73199439
скорость.y == -10,5695238
шар.масса == 12,56637
ball.velocity.x == 6.04341078
ball.velocity.y == 14.2686739
Выход:
масса == 12,56637
скорость.x == 110.004326
скорость.y == -10,5695238
шар.масса == 12,56637
ball.velocity.x == -102,22892
ball.velocity.y == -72.4030228
#import "CGPointExtension.h"
#define RESTITUTION_CONSTANT (0.75) //elasticity of the system
- (void) resolveCollision:(Ball*) ball
{
// get the mtd (minimum translation distance)
CGPoint delta = ccpSub(position, ball.position);
float d = ccpLength(delta);
// minimum translation distance to push balls apart after intersecting
CGPoint mtd = ccpMult(delta, (((radius + ball.radius)-d)/d));
// resolve intersection --
// inverse mass quantities
float im1 = 1 / [self mass];
float im2 = 1 / [ball mass];
// push-pull them apart based off their mass
position = ccpAdd(position, ccpMult(mtd, (im1 / (im1 + im2))));
ball.position = ccpSub(ball.position, ccpMult(mtd, (im2 / (im1 + im2))));
// impact speed
CGPoint v = ccpSub(velocity, ball.velocity);
float vn = ccpDot(v,ccpNormalize(mtd));
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / ([self mass] + [ball mass]);
CGPoint impulse = ccpMult(mtd, i);
// change in momentum
velocity = ccpAdd(velocity, ccpMult(impulse, im1));
ball.velocity = ccpSub(ball.velocity, ccpMult(impulse, im2));
}
Решение
Я тот, кто написал исходный код отскока мяча, на который вы ссылались.Если вы скачать и попробуйте этот код, вы увидите, что он работает нормально.
Следующий код правильный (тот, каким он был у вас изначально):
// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / (im1 + im2);
CGPoint impulse = ccpMult(mtd, i);
Это очень распространенный физический код, и вы можете увидеть его почти точную реализацию в следующих примерах:
- Найти реакцию столкновения двух объектов - GameDev
- Реакция на столкновение в 3D-понге
- Еще одно столкновение мяча с мячом, написанное на Java.
Это правильно, и это ~не~ создание CoR версии 1.0, как предлагали другие.Это расчет относительного вектора импульса на основе массы и коэффициента восстановления.
Если игнорировать трение, простой пример 1d выглядит следующим образом:
J = -Vr(1+e) / {1/m1 + 1/m2}
Где e — ваш CoR, Vr — ваша нормализованная скорость, а J — скалярное значение импульсной скорости.
Если вы планируете сделать что-то более сложное, я предлагаю вам использовать одну из многих уже существующих физических библиотек.Когда я использовал приведенный выше код, для нескольких шаров все было нормально, но когда я увеличил его до нескольких сотен, он начал захлебываться.Я использовал физический движок Box2D, и его решатель мог обрабатывать больше шаров и был гораздо точнее.
В любом случае, я просмотрел ваш код и на первый взгляд он выглядит нормально (это довольно точный перевод).Вероятно, это небольшая и незаметная ошибка, связанная с передачей неправильного значения, или проблема с векторной математикой.
Я ничего не знаю о разработке iPhone, но я бы предложил установить точку останова в верхней части этого метода и отслеживать результирующее значение каждого шага и определять, где находится взрыв.Убедитесь, что MTD рассчитан правильно, скорости удара и т. д. и т. п., пока не увидите, где происходит большое увеличение.
Сообщите нам значения каждого шага этого метода, и мы посмотрим, что у нас получится.
Другие советы
Просмотрев исходный код и комментарии автора оригинального текста, код кажется таким же, поэтому, если оригинал является правильной реализацией, я бы заподозрил плохую векторную библиотеку или какую-то неинициализированную переменную.
Зачем вы добавляете 1,0 к коэффициенту реституции?
От: http://en.wikipedia.org/wiki/Coefficient_of_restitution
COR обычно представляет собой число в диапазоне [0,1].Качественно 1 представляет собой совершенно упругое столкновение, а 0 — совершенно неупругое столкновение.Теоретически возможно значение COR больше единицы, что представляет собой столкновение, которое генерирует кинетическую энергию, например, когда наземные мины сбрасываются вместе и взрываются.
Другая проблема заключается в следующем:
/ (im1 + im2)
Вы делите на сумму обратных масс, чтобы получить импульс вдоль вектора контакта - вам, вероятно, следует делить на сумму самих масс.Это усиливает ваш импульс («она так сказала»).
В этой строке:
CGPoint impulse = ccpMult(mtd, i);
mtd необходимо нормализовать.Ошибка произошла потому, что в исходном коде mtd был нормализован в предыдущей строке, но не в вашем коде.Вы можете исправить это, выполнив что-то вроде этого:
CGPoint impulse = ccpMult(ccpNormalize(mtd), i);