Как стать автором
Обновить

Processing 1.0 и почти закон всемирного тяготения

Время на прочтение5 мин
Количество просмотров2.7K
О Processing я слышал давно, но посмотреть что это из себя представляет никак не доходили руки. И вот у меня появилась идея сделать свой мирок с гравитацией и силами(есть точки и вокруг них летают частицы). В дальнейшем можно это как-то красиво обыграть и сделать крутой скринсейвер. Прототип решено было изготовить при помощи виновника торжества, а именно Processing 1.0.7.

Начнём с создания алгоритма описывающего физические взаимодействия между объектами. Точки обладающие гравитацией располагаются в пространстве случайно, а так как они ещё и не перемещаются(двигаются только частицы в гравитационном поле точек), то я решил заранее создать список векторов расположенных в пространстве с заданным шагом, и гордо назвать это «векторной сеткой» :) Вектора считаются как сумма векторов сил притяжения создаваемых каждой «гравитационной точкой» в точке приложения вектора.


Шаг сетки 20.


Шаг сетки 10.

class GravGrid
{
 int w = 0; /* Ширина сетки.*/
 int h = 0; /* Высота сетки.*/
 int step = 0; /* Размер стороны ячейки векторной сетки.
          Ну или просто шаг. */
 float G =0;  /* Гравитационная постоянная. От неё
          зависит как будет изменяться
          сила притяжения частиц к точкам с
          изменением расстояния между ними */
 /* Тут у нас будут жить гравитационные точки */
 public ArrayList points = new ArrayList();
 ArrayList vectors; /* А тут вектора составляющие
            векторную сетку */
 /* Конструктор класса. С w, h, step и G все уже знакомы */
 GravGrid(int w, int h, int step, float G)
 {
  this.w = w;
  this.h = h;
  this.step = step;
  this.G = G;
 }
 public void CreateGrid() /* Метод для построение сетки */
 {
  vectors = new ArrayList(); /* На случай если CreateGrid()
                 вызвана повторно очищаем
                 список */
  GravVector v; /* Вектор */
  GravPoint p; /* Точка */
  float xSum; /* Сумма проэкций сил на ось X */
  float ySum; /* Сумма проэкций сил на ось Y */
  float a = 0; /* Угол между точкой приложения вектора
          и гравитационной точкой*/
  for(int x = 0; x < w; x += step) /* Получаем точки
                    приложения векторов */
   for(int y = 0; y < h; y += step)
   {
    xSum = 0;
    ySum = 0;
    v = new GravVector(x, y); /* Создаем новый экземпляр
                   класса GravVector*/
    /* Проходимся по списку гравитационных точек */
    for(int i = 0; i < points.size(); i++)
    {
     /* Получаем i - ую точку */
     p = (GravPoint)points.get(i);
     a = atan2((p.x - x), (p.y - y)); /* Вычисляем угол */
     /* Вычисляем проекции на ось X и прибавляем к сумме.
       dist(x1, y1, x2, y2) - вычисляет расстояние между
       двумя точками */
     xSum += p.Grav(dist(x, y, p.x, p.y), G) * sin(a);
     /* Вычисляем проекции на ось Y и прибавляем к сумме.*/
     ySum += p.Grav(dist(x, y, p.x, p.y), G) * cos(a);
    }
    v.Set(xSum, ySum); /* Устанавливаем
               направление вектора */
    vectors.add(v);  /* и добавляем его в список */
   }
 }
 
 public void DrawGrid() /* Метод для рисования сетки */
 {
  float arrowsize = 4; /* Размер стрелочки */
  float len = 0; /* Длинна вектора */
  GravVector v;
  /* Проходимся по списку векторов */
  for(int i = 0; i < vectors.size(); i++)
  {
   /* Получаем i - ый вектор */
   v = (GravVector)vectors.get(i);
   /* Тут дальше идёт хитрый метод рисования вектора,
     который я подсмотрел из File -> Examples ->
     Topics -> Simulate -> SimpleParticleSystem
     могу сказать что pushMatrix() - это как бэ создание
     дополнительной системы координат.
     Если что, поправьте меня пожалуйста.*/
   pushMatrix();
   translate(v.x0, v.y0); /* Положение относительно
                основной системы координат
                v.x0, v.y0 - точки приложения
                вектора */
   stroke(255, 0, 0); /* Цвет линий */
   /* Поворачиваем дополнительную систему координат
     относительно основной v.Get() - возвращает PVector */
   rotate(atan2(v.Get().y, v.Get().x));
   len = v.Get().mag(); /* Получаем длину вектора */
   /* Дальше занимаемся рисованием */
   line(0,0,len,0);
   line(len,0,len-arrowsize,+arrowsize/2);
   line(len,0,len-arrowsize,-arrowsize/2);
   popMatrix();
  }
 }
 
 /* Возвращает вектор силы в заданной точке */
 public PVector GetVector(float x, float y)
 {
  GravVector v;
  for(int i = 0; i < vectors.size(); i++)
  {
   v = (GravVector)vectors.get(i);
   if((v.x0 <= x)
   && (x < (v.x0 + step))
   && (v.y0 <= y)
   && (y < (v.y0 + step)))
    return v.Get();
  }
  return new PVector(0, 0);
 }
}

class GravPoint /* Гравитационная точка */
{
 public int x = 0; /* Положение по X */
 public int y = 0; /* по Y */
 float mass = 0; /* Масса точка. Чем больше масса
           тем сильнее к точке будут
           притягиваться частицы */
 GravPoint(int x, int y, float mass) /* Конструктор */
 {
  this.x = x;
  this.y = y;
  this.mass = mass;
 }
 /* Тут вычисляем силу притяжения.
   Чем больше d(расстояние) тем меньше сила */
 public float Grav(float d, float G) {return mass * G / d; }
}

class GravVector /* Вектор */
{
 public int x0 = 0; /* Точка приложения по X */
 public int y0 = 0; /* по Y */
 public float x = 0; /* Точка приложения по X + проекция
             вектора на ось X */
 public float y = 0; /* тоже самое только Y */
 GravVector(int x0, int y0) /* Конструктор */
 {
  this.x0 = x0;
  this.y0 = y0;
 }
 /* Устанавливаем величину и направление вектора */
 public void Set(float x, float y)
 {
  this.x = x0 + x;
  this.y = y0 + y;
 }
 /* Возвращает PVector для экземпляра класса GravVector*/
 public PVector Get() {return new PVector(x - x0, y - y0); }
}


* This source code was highlighted with Source Code Highlighter.


Использование:

int w;
int h;
GravGrid gg;
Particle[] s;
void setup()
{
size(800, 600, JAVA2D); /* рендер P2D, по утверждению разработчиков
       работает быстрее чем JAVA2D,
       но почему - то у меня всё наоборот */
background(255);
w = width;
h = height;
s = new Particle[50]; /* Массив с частицами */
gg = new GravGrid(w, h, 20, 40); /* Создаём сетку */
for(int i = 0; i < s.length; i++)
 s[i] = new Particle();
gg.points = new ArrayList();
/* Добавляем точки */
for(int i = 0; i < 7; i++)
 gg.points.add(new GravPoint(
     (int)random(0, w), /* Положение точки по X */
     (int)random(0, h), /* Положение точки по Y */
     /* Из соображений зрелищности
      у нас будут точки даже с отрицательной
      гравитацией! :) */
     (int)random(-120, 120)));
gg.CreateGrid(); /* Создаём сетку */
}

GravPoint p;
void draw()
{
/* Закрашиваем всё белым цветом с прозрачностью 20
  для того что бы за частицами оставался крутой след :)
  Чем меньше alpha, тем соответственно длиннее шлейф */
fill(255, 20);
noStroke();
rect(0, 0, w, h);
for(int i = 0; i < s.length; i++)
{
 s[i].DrawParticle(gg); /* Рисуем i - ую частицу */
 /* Если вылетела за границы окна, то создаём новую */
 if(s[i].x > w
 || s[i].x < 0
 || s[i].y > h
 || s[i].y < 0)
 {
  s[i] = new Particle();
 }
 else
 {
  for(int t = 0; t < gg.points.size(); t++)
  {
  /* Получаем гравитационную точку */
  p = (GravPoint)gg.points.get(t);
  fill(255);
  stroke(0);
  /* рисуем её */
  ellipse(p.x, p.y, abs(p.mass), abs(p.mass));
  /* Если попала в точку, то создаём новую */
  if((((p.x - (p.mass / 4)) <= s[i].x)
   && (s[i].x < (p.x + (p.mass / 4)))
   && ((p.y - (p.mass / 4)) <= s[i].y)
   && (s[i].y < (p.y + (p.mass / 4)))))
  {
   s[i] = new Particle();
  }
  }
 }
}
if(keyPressed) if(key == '1') setup();
if(keyPressed) if(key == '2') gg.DrawGrid();
}

class Particle
{
float t = 0;
float m = random(3, 6);
float y = random(m, h);
float x = random(m, w);
float v0x = 0;
float v0y = 0;
public void DrawParticle(GravGrid gg)
{
 t += 0.005;
 x += v0x * t + (gg.GetVector(x, y).x / m) * pow(t, 2) / 2;
 y += v0y * t + (gg.GetVector(x, y).y / m) * pow(t, 2) / 2;
 fill(0, 0, 0, t * 300);
 noStroke();
 ellipse(x, y, m, m);
}

}


* This source code was highlighted with Source Code Highlighter.


Кстати если установить малый шаг сетки и поиграться с отображением векторов в DrawGrid(), то можно получить много клякс подобных этим:



Теги:
Хабы:
Всего голосов 55: ↑50 и ↓5+45
Комментарии19

Публикации

Ближайшие события