#javascript #oop #p5.js
Вопрос:
До сих пор я создал класс, который генерирует круг. Я пытаюсь заставить этот круг постоянно двигаться/вибрировать, но я не уверен, что это лучший способ добавить функцию перемещения с помощью OOP. Кроме того, когда я создаю объект «лицо» в функции рисования, моя страница падает.
function setup() {
createCanvas(350, 350, WEBGL);
background('white')
let face = new Face();
}
class Face {
constructor() {
this.basicFace(100, random(10,30),0,0);
}
basicFace(radius, steps, centerX, centerY) {
var xValues = [];
var yValues = [];
for (var i = 0; i < steps; i ) {
let rad = radius random(-radius / 50, radius / 50)
xValues[i] = (centerX rad * cos(2 * PI * i / steps));
yValues[i] = (centerY rad * sin(2 * PI * i / steps));
}
beginShape();
strokeWeight(4)
for (let i = 0; i < xValues.length; i ) {
curveVertex(xValues[i], yValues[i]);
}
endShape(CLOSE);
}
}
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.js"></script>
Ответ №1:
Во-первых, одна из причин, по которой создание новых Face
экземпляров в вашей draw()
функции может привести к зависанию страницы, заключается в том, что draw()
функция выполняется много раз в секунду, а в JavaScript большое количество выделений (например, создание новых экземпляров класса) может негативно сказаться на производительности. Однако простое выделение одного экземпляра класса для каждого вызова draw()
обычно не вызывает проблем. С другой стороны, если вы добавляете эти экземпляры в структуру данных, такую как массив, это может привести к тому, что ваша страница будет использовать чрезмерный объем памяти и в конечном итоге зависнет. Не видя точного кода, который вызывает зависание, трудно сказать.
Если вы хотите реализовать приведенный выше эскиз объектно-ориентированным способом, вам следует выполнить следующие действия:
- Предоставьте своему классу некоторые параметры конструктора, которые определяют его свойства, такие как местоположение и размер, и сохраните их в качестве полей экземпляра.
- Отделите поведение вашего класса от конструктора (т. Е. Дайте ему метод, который вызывает его отображение.
- Создайте его один раз, а затем вызовите этот метод экземпляра
draw()
, чтобы он отображался в каждом кадре.
let face;
function setup() {
createCanvas(350, 350, WEBGL);
face = new Face(100, random(10, 30), 0, 0);
}
function draw() {
background('white');
face.show();
}
class Face {
constructor(radius, steps, centerX, centerY) {
this.radius = radius;
this.steps = steps;
this.centerX = centerX;
this.centerY = centerY;
}
show() {
var xValues = [];
var yValues = [];
for (var i = 0; i < this.steps; i ) {
let rad = this.radius random(-this.radius / 50, this.radius / 50)
xValues[i] = (this.centerX rad * cos(2 * PI * i / this.steps));
yValues[i] = (this.centerY rad * sin(2 * PI * i / this.steps));
}
strokeWeight(4);
beginShape();
for (let i = 0; i < xValues.length; i ) {
curveVertex(xValues[i], yValues[i]);
}
endShape(CLOSE);
}
}
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.js"></script>
Кроме того, при отображении кривой нет необходимости создавать массивы для значений x и y в одном цикле, а затем вызывать curveVertex()
отдельный цикл. Вместо этого вы можете объединить эти циклы и избежать ненужного выделения массива.
show() {
strokeWeight(4);
beginShape();
for (let i = 0; i < this.steps; i ) {
let rad = this.radius random(-this.radius / 50, this.radius / 50);
curveVertex(
this.centerX rad * cos(2 * PI * i / this.steps),
this.centerY rad * sin(2 * PI * i / this.steps)
);
}
endShape(CLOSE);
}
Комментарии:
1. Одна вещь, о которой следует помнить: при использовании
curveVertex
вам нужно учитывать, что для рисования правильного количества сегментов линии требуется 2 дополнительные вершины в начале и в конце вашей кривой. Когда вы начинаете кривую сcurveVertex
, эта первая вершина используется только для определения угла кривой, где она начинается со второй вершины в списке. Аналогично, последняя вершина определяет только угол кривой, когда она достигает предпоследней вершины.2. Спасибо вам за помощь. Последний вопрос, есть ли возможность сделать это без использования background() для замены старого рисунка? Например, когда я перемещаю(3) и использую show (), он создаст дубликат чертежа вместо перемещения исходного.
move(x){this.centerX = this.centerX x; }
3. Что ж, да, вы могли бы это сделать. Но это концептуально несовместимо с эффектом вибрации, вызванным добавлением случайного смещения к радиусу для каждой точки. Если вам нужно несколько анимированных экземпляров
Face
, то вам лучше создать отдельный экземпляр с новой позицией. Если бы вы изменили свою реализацию на статическую, а не анимированную, вы могли бы потенциально устранить необходимость в использованииbackground()
и просто выполнять аддитивный рисунок. Это обычно более подходит для эскиза, который вообще не используетсяdraw()
и вместо этого рисует графику в ответ на события.