Processing:Примеры/Неперпендикулярное отражение 1

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

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


Описание[1]

Этот скетч-пример основан на уравнении R = 2N(N*L)-L, где R – это вектор отражения, N – это нормаль, а L – это вектор столкновения.

Пример

// позиция левого края «земли»:
PVector base1;
// позиция правого края «земли»:
PVector base2;
// длина «земли»:
float baseLength;

// массив с точками (координатами) вдоль линии «земли»:
PVector[] coords;

// переменные для двигающегося шара:
PVector position;
PVector velocity;
float r = 6;
float speed = 3.5;

void setup() {
  size(640, 360);

  fill(128);
  base1 = new PVector(0, height-150);
  base2 = new PVector(width, height);
  createGround();

  // начальная позиция шара – вверху посередине экрана:
  position = new PVector(width/2, 0);

  // рассчитываем начальную случайную скорость:
  velocity = PVector.random2D();
  velocity.mult(speed);
}

void draw() {
  // рисуем фон:
  fill(0, 12);
  noStroke();
  rect(0, 0, width, height);

  // рисуем «землю»:
  fill(200);
  quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height);

  // рассчитываем нормаль:
  PVector baseDelta = PVector.sub(base2, base1);
  baseDelta.normalize();
  PVector normal = new PVector(-baseDelta.y, baseDelta.x);

  // рисуем шар:
  noStroke();
  fill(255);
  ellipse(position.x, position.y, r*2, r*2);

  // двигаем шар:
  position.add(velocity);

  // делаем вектор столкновения единичным:
  PVector incidence = PVector.mult(velocity, -1);
  incidence.normalize();

  // определяем и обрабатываем столкновение:
  for (int i=0; i<coords.length; i++) {
    // проверяем расстояние между шаром и координатами «земли»:
    if (PVector.dist(position, coords[i]) < r) {

      // рассчитываем скалярное произведение
      // вектора столкновения и нормали: 
      float dot = incidence.dot(normal);

      // рассчитываем вектор отражения,
      // присваиваем вектор отражения направлению движения шара:
      velocity.set(2*normal.x*dot - incidence.x, 2*normal.y*dot - incidence.y, 0);
      velocity.mult(speed);

      // рисуем линию нормали в точке столкновения:
      stroke(255, 128, 0);
      line(position.x, position.y, position.x-normal.x*100, position.y-normal.y*100);
    }
  }

  // задаем границы экрана...
  // правая сторона:
  if (position.x > width-r) {
    position.x = width-r;
    velocity.x *= -1;
  }
  // левая сторона: 
  if (position.x < r) {
    position.x = r;
    velocity.x *= -1;
  }
  // верхняя сторона:
  if (position.y < r) {
    position.y = r;
    velocity.y *= -1;
    // рандомизируем «землю»:
    base1.y = random(height-100, height);
    base2.y = random(height-100, height);
    createGround();
  }
}


// рассчитываем переменные для «земли»:
void createGround() {
  // рассчитываем длину «земли»:
  baseLength = PVector.dist(base1, base2);

  // заполняем массив с координатами для «земли»:
  coords = new PVector[ceil(baseLength)];
  for (int i=0; i<coords.length; i++) {
    coords[i] = new PVector();
    coords[i].x = base1.x + ((base2.x-base1.x)/baseLength)*i;
    coords[i].y = base1.y + ((base2.y-base1.y)/baseLength)*i;
  }
}

См.также

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