Cat hungry.png
Здравствуйте! Собираем деньги на перевод материалов по электронике(https://www.allaboutcircuits.com/education/). Реквизиты указаны здесь.

Processing:Примеры/Столкновение эллипсов

Материал из Онлайн справочника
Перейти к: навигация, поиск


Перевод: Максим Кузьмин (Cubewriter)
Перевел 2686 статей для сайта.

Контакты:

Проверка/Оформление/Редактирование: Мякишев Е.А.


Ambox content.png Черновик


Описание[1]

Этот скетч-пример основан на примере из книги «Основы анимации с помощью AutoScript: Двигай это!» Кита Питерса.

Пример

  1. Ball[] balls =  {
  2.   new Ball(100, 400, 20),
  3.   new Ball(700, 400, 80)
  4. };
  5.  
  6. void setup() {
  7.   size(640, 360);
  8. }
  9.  
  10. void draw() {
  11.   background(51);
  12.  
  13.   for (Ball b : balls) {
  14.     b.update();
  15.     b.display();
  16.     b.checkBoundaryCollision();
  17.   }
  18.  
  19.   balls[0].checkCollision(balls[1]);
  20. }
  21.  
  22. class Ball {
  23.   PVector position;
  24.   PVector velocity;
  25.  
  26.   float radius, m;
  27.  
  28.   Ball(float x, float y, float r_) {
  29.     position = new PVector(x, y);
  30.     velocity = PVector.random2D();
  31.     velocity.mult(3);
  32.     radius = r_;
  33.     m = radius*.1;
  34.   }
  35.  
  36.   void update() {
  37.     position.add(velocity);
  38.   }
  39.  
  40.   void checkBoundaryCollision() {
  41.     if (position.x > width-radius) {
  42.       position.x = width-radius;
  43.       velocity.x *= -1;
  44.     } else if (position.x < radius) {
  45.       position.x = radius;
  46.       velocity.x *= -1;
  47.     } else if (position.y > height-radius) {
  48.       position.y = height-radius;
  49.       velocity.y *= -1;
  50.     } else if (position.y < radius) {
  51.       position.y = radius;
  52.       velocity.y *= -1;
  53.     }
  54.   }
  55.  
  56.   void checkCollision(Ball other) {
  57.  
  58.     // считываем расстояние между эллипсами:
  59.     PVector distanceVect = PVector.sub(other.position, position);
  60.  
  61.     // рассчитываем длину вектора, разделяющего эллипсы:
  62.     float distanceVectMag = distanceVect.mag();
  63.  
  64.     // минимальное расстояние до столкновения эллипсов:
  65.     float minDistance = radius + other.radius;
  66.  
  67.     if (distanceVectMag < minDistance) {
  68.       float distanceCorrection = (minDistance-distanceVectMag)/2.0;
  69.       PVector d = distanceVect.copy();
  70.       PVector correctionVector = d.normalize().mult(distanceCorrection);
  71.       other.position.add(correctionVector);
  72.       position.sub(correctionVector);
  73.  
  74.       // считываем угол «distanceVect»:
  75.       float theta  = distanceVect.heading();
  76.       // заранее рассчитываем тригонометрические значения:
  77.       float sine = sin(theta);
  78.       float cosine = cos(theta);
  79.  
  80.       /* Массив «bTemp» будет хранить позиции вращающихся эллипсов.
  81.        Вас должна волновать лишь позиция bTemp[1] */
  82.       PVector[] bTemp = {
  83.         new PVector(), new PVector()
  84.       };
  85.  
  86.       /* Это позиция второго эллипса относительно позиции первого,
  87.          поэтому вы можете использовать вектор между ними (bVect)
  88.          в качестве ориентира для уравнений,
  89.          с помощью которых осуществляется расчет вращения.
  90.          «bTemp[0].position.x» и «bTemp[0].position.y»
  91.          будут автоматически инициализированы со значением «0.0»,
  92.          и это то как раз, что нужно, потому что эллипс b[1]
  93.          будет вращаться вокруг эллипса b[0]. */
  94.       bTemp[1].x  = cosine * distanceVect.x + sine * distanceVect.y;
  95.       bTemp[1].y  = cosine * distanceVect.y - sine * distanceVect.x;
  96.  
  97.       // меняем предварительные углы направления векторов:
  98.       PVector[] vTemp = {
  99.         new PVector(), new PVector()
  100.       };
  101.  
  102.       vTemp[0].x  = cosine * velocity.x + sine * velocity.y;
  103.       vTemp[0].y  = cosine * velocity.y - sine * velocity.x;
  104.       vTemp[1].x  = cosine * other.velocity.x + sine * other.velocity.y;
  105.       vTemp[1].y  = cosine * other.velocity.y - sine * other.velocity.x;
  106.  
  107.       /* Теперь, когда углы направления векторов изменены,
  108.        можно воспользоваться 1D-преобразованием уравнений импульса
  109.        для расчета финальных углов направления векторов по оси X. */
  110.       PVector[] vFinal = {  
  111.         new PVector(), new PVector()
  112.       };
  113.  
  114.       // финальный угол направления вектора для эллипса b[0]:
  115.       vFinal[0].x = ((m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (m + other.m);
  116.       vFinal[0].y = vTemp[0].y;
  117.  
  118.       // финальный угол направления вектора для эллипса b[1]:
  119.       vFinal[1].x = ((other.m - m) * vTemp[1].x + 2 * m * vTemp[0].x) / (m + other.m);
  120.       vFinal[1].y = vTemp[1].y;
  121.  
  122.       // небольшой трюк, чтобы избежать комкования:
  123.       bTemp[0].x += vFinal[0].x;
  124.       bTemp[1].x += vFinal[1].x;
  125.  
  126.       /* Инвертируем позиции эллипсов и углы направления векторов
  127.        при помощи тригонометрических уравнений. */
  128.       // вращаем эллипсы:
  129.       PVector[] bFinal = {
  130.         new PVector(), new PVector()
  131.       };
  132.  
  133.       bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
  134.       bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
  135.       bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
  136.       bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
  137.  
  138.       // обновляем позиции эллипсов на экране:
  139.       other.position.x = position.x + bFinal[1].x;
  140.       other.position.y = position.y + bFinal[1].y;
  141.  
  142.       position.add(bFinal[0]);
  143.  
  144.       // обновляем углы направления векторов:
  145.       velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
  146.       velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
  147.       other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
  148.       other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
  149.     }
  150.   }
  151.  
  152.   void display() {
  153.     noStroke();
  154.     fill(204);
  155.     ellipse(position.x, position.y, radius*2, radius*2);
  156.   }
  157. }

См.также

Внешние ссылки

  1. processing.org - Circle Collision with Swapping Velocities by Ira Greenberg