Строительство автономных объектов

Часть 1 и Часть 2

Весь код и библиотеки для этих руководств можно найти здесь: https://github.com/GeorgeGally/creative_coding

Мы делали довольно простые вещи, так что давайте поднимем их на ступеньку выше.

В предыдущих статьях я показал вам, как заставить мяч прыгать по экрану. Что, если нам нужно много мячей?

Но прежде чем мы дойдем до этого, всегда полезно немного очистить код и разделить рисование и вычислительную часть на отдельные функции. Что привело бы нас к чему-то вроде этого:

var ctx = createCanvas("canvas1");
var ball_size = 20;
var ball_x = width/2;
var ball_y = height/2;
var speed_x = randomInt(-15, 15);
var speed_y = randomInt(-15, 15);
ctx.fillStyle = rgb(randomInt(255),randomInt(255),0);

function draw(){
  //ctx.background(255, 0.2);
  moveBall();
  drawBall();
}

function moveBall(){
  ball_x = ball_x + speed_x;
  ball_y = ball_y + speed_y;
  if (bounce(ball_x, 0, w, ball_size)) {
    speed_x *=-1;
    ctx.fillStyle = rgb(randomInt(255),randomInt(255),0);
  }
  if (bounce(ball_y, 0 ,h, ball_size)) {
    speed_y *=-1;
    ctx.fillStyle = rgb(0, randomInt(255),randomInt(255));
  }
}

function drawBall(){
  ctx.fillEllipse(ball_x, ball_y, ball_size, ball_size);
}

И давайте выделим наш код больше, превратив мяч в объект. Это позволяет нам получить доступ к переменным мячей через точечный синтаксис. Создаем такой объект:

var ball = {
  x:  width/2,
  y: height/2,
  speed_x: random(-5, 5),
  speed_y: random(-5, 5),
  size: 20,
  colour: rgb(0)
}

Теперь мы можем получить доступ к следующим свойствам мяча:

ball.x = ball.x + ball.speed_x;

Полный отредактированный код теперь выглядит примерно так:

var ctx = createCanvas("canvas1");
var ball = {
  x: width/2,
  y: height/2,
  speed_x: random(-5, 5),
  speed_y: random(-5, 5),
  size: 20,
  colour: rgb(0)
}
function draw(){
  //ctx.background(255, 0.2);
  moveBall();
  drawBall();
}
function moveBall(){
 // bounce() is a function I created, essentially the same as going 
 // if (ball.x < ball.size/2 || ball.x > w - ball.size/2)
 if (bounce(ball.x, 0, w, ball.size)) {
    ball.speed_x *=-1;
    ctx.fillStyle = rgb(randomInt(255),randomInt(255),0);
  }
  if (bounce(ball.y, 0 ,h, ball.size)) {
    ball.speed_y *=-1;
    ctx.fillStyle = rgb(0, randomInt(255),randomInt(255));
  }
  ball.x += ball.speed_x;
  ball.y += ball.speed_y;
}
function drawBall(){
  ctx.fillEllipse(ball.x, ball.y, ball.size, ball.size);
}

Пора поговорить о массивах. Я пойду быстро, потому что в Интернете есть много материалов, посвященных этому вопросу. По сути, массивы - это просто контейнеры, которые могут содержать объекты, переменные и строки, разделенные запятыми. Вот так:

var my_array = [ 1, 2, 3 ]; 

К первому значению массива обращается my_array [0], а ко второму - my_array [1] и т. Д. И мы можем получить длину массива, сказав my_array.length. Так…

var balls = []; // declare a variable with an empty array
var colours = ['red', 'green', 'blue', 'indigo', 'violet'];

console.log(colours.length); //outputs 5
console.log(colours[0]); //outputs red
console.log(colours[4]); //outputs violet

И если мы хотим добавить что-то в конец массива, мы можем использовать push:

var colours = ['red'];
console.log(colours); //outputs red
colours.push('green'); //add to the front of the array
console.log(colours); //outputs red, green

Еще один лучший друг для программирования - цикл for, который выглядит так:

// this will loop 10 times
for (var i = 0; i < 10; i++) {
  // do something
}

Цикл for повторяется до тех пор, пока не будет выполнено определенное условие. В этом случае мы увеличиваем нашу временную переменную i с 0 на единицу до тех пор, пока она не перестанет соответствовать условию «меньше 10».

Подробнее о цикле for можно прочитать здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration

Наша система частиц - это просто массив шаров. И мы создаем это, создавая объект-мяч, а затем помещая его в массив:

var number_of_balls = 10;
var balls = [];
// push a ball and it's values into the array
for (var i = 0; i < number_of_balls; i++) {
  var ball = {
   x:  200,
   y: height/2,
   speed_x: random(-5, 5),
   speed_y: random(-5, 5),
   size: 20,
   colour: rgb(0)
  }
  balls.push(ball);
}

Чтобы получить доступ к свойствам нашего шара, теперь мы можем:

console.log(ball[2].x); //outputs 200

И мы можем перебрать все наши шары так:

for (var i = 0; i < balls.length; i++) {
 balls[i].x += balls[i].speed_x;
 balls[i].y += balls[i].speed_y;
}

Но при манипулировании нашими частицами и их рисовании набирать шары [i] утомительно и часто, поэтому мы можем вместо этого назначить временную переменную для представления шаров [i], например:

for (var i = 0; i < balls.length; i++) {
 var b = balls[i];
 b.x = b.x + b.speed_x;
 b.y = b.y + b.speed_y;
}

Любые изменения, которые мы вносим в эту временную переменную, также изменят фактические значения частиц.

Собирая все вместе, мы получаем:

var ctx = createCanvas("canvas1");
var number_of_balls = 10;
var balls = [];
// push a ball and it's values into the array
for (var i = 0; i < number_of_balls; i++) {
  var ball = {
    x:  width/2,
    y: height/2,
    speed_x: random(-5, 5),
    speed_y: random(-5, 5),
    size: 20,
    colour: rgb(0)
  }
  balls.push(ball);
}
function draw(){
  //ctx.background(255, 0.2);
  moveBall();
  drawBall();
}
function moveBall(){
for (var i = 0; i < balls.length; i++) {
    var b = balls[i];
    b.x = b.x + b.speed_x;
    b.y = b.y + b.speed_y;
if (bounce(b.x, 0, w, b.size)) {
      b.speed_x *=-1;
      b.colour = rgb(randomInt(55),randomInt(255),0);
    }
if (bounce(b.y, 0 ,h, b.size)) {
      b.speed_y *=-1;
      b.colour = rgb(0, randomInt(255),randomInt(55));
    }
}
}
function drawBall(){
  for (var i = 0; i < balls.length; i++) {
    var b = balls[i];
    ctx.fillStyle = b.colour;
    ctx.fillEllipse(b.x, b.y, b.size, b.size);
  }
}

И бум, у нас есть система частиц:

Раскомментируйте ctx.background, чтобы увидеть отдельные шарики, и давайте увеличим количество шариков до 100:

Давайте добавим шарики, когда будем двигать мышью. Давайте создадим функцию addBall (), которая устанавливает новое положение шара в положение мыши:

function addBall(){
  var ball = {
    x: mouseX,
    y: mouseY,
    speed_x: random(-5, 5),
    speed_y: random(-5, 5),
    size: 20,
    colour: rgb(0)
  }
  balls.push(ball);
}

Чтобы проверить, переместили ли мы мышь, чтобы избавить нас от лишних хлопот, я добавил в свою библиотеку прослушиватель и глобальную переменную под названием mouseMoved:

// check if mouse has moved and add if so, add a new ball
if (mouseMoved) {
  addBall();
}

Переменная mouseMoved в моей библиотеке создается с помощью eventListener:

var mouseMoved = false;
window.addEventListener('mousemove', function(e) {
  mouseMoved = true;
});

А затем в моем цикле requestAnimationFrame () я просто сбрасываю его на false.

Если мы продолжаем перемещать мышь, в конечном итоге шаров будет так много, что наш компьютер будет замедляться и в конечном итоге зависнет, поэтому нам нужен способ удаления шаров, желательно самого старого шара, и это довольно просто, добавив проверку для максимальной длины шаров до конца нашей функции addBall ():

// syntax: splice(start, length)
if (balls.length > 1000) balls.splice(0,1);

Splice просто вырезает массив из определенной точки на определенную величину, в нашем случае из позиции 0 нашего массива шаров (и самого старого из наших шаров) на 1.

Если мы уменьшим число до 20, мы начнем получать некоторые интересные эффекты следа:

var ctx = createCanvas("canvas1");
var max_balls = 10;
var balls = [];
// push a ball and it's values into the array
function addBall(){
  var ball = {
    x: mouseX,
    y: mouseY,
    speed_x: random(-5, 5),
    speed_y: random(-5, 5),
    size: 20,
    colour: rgb(randomInt(55),randomInt(255),0)
  }
  balls.push(ball);
  if (balls.length > max_balls) balls.splice(0,1);
}
function draw(){
ctx.background(255, 0.2);
  if (mouseMoved) {
    addBall();
  }
  moveBall();
  drawBall();
}
function moveBall(){
for (var i = 0; i < balls.length; i++) {
    var b = balls[i];
    b.x = b.x + b.speed_x;
    b.y = b.y + b.speed_y;
if (bounce(b.x, 0, w, b.size)) {
      b.speed_x *=-1;
      b.colour = rgb(randomInt(55),randomInt(255),0);
    }
if (bounce(b.y, 0 ,h, b.size)) {
      b.speed_y *=-1;
      b.colour = rgb(0, randomInt(255),randomInt(55));
    }
}
}
function drawBall(){
  for (var i = 0; i < balls.length; i++) {
    var b = balls[i];
    ctx.fillStyle = b.colour;
    ctx.fillEllipse(b.x, b.y, b.size, b.size);
  }
}

Итак, это все для части 3. Поэкспериментируйте, уменьшив размер шариков по мере того, как они становятся старше, и удаляйте их, когда они становятся слишком маленькими. Поиграйте с цветами, прозрачностью фона и всем остальным, что делает вас счастливым. До следующего раза, удачного кодирования…

Подпишитесь на меня в Instagram здесь: https://www.instagram.com/radarboy3000/

И поставьте лайк на моей странице в Facebook: https://www.facebook.com/radarboy3000

Введение в творческое кодирование, часть 1: https://medium.com/@radarboy3000/creative-coding-basics-4d623af1c647#.hn9zzliob

Введение в творческое кодирование, часть 2: https://medium.com/@radarboy3000/introduction-to-creative-coding-part-2-d869832d9ffb#.fzxcom541

Весь код и библиотеки для этих руководств можно найти здесь: https://github.com/GeorgeGally/creative_coding

Хакерский полдень - это то, с чего хакеры начинают свои дни. Мы часть семьи @AMI. Сейчас мы принимаем заявки и рады обсуждать рекламные и спонсорские возможности.

Если вам понравился этот рассказ, мы рекомендуем прочитать наши Последние технические истории и Современные технические истории. До следующего раза не воспринимайте реалии мира как должное!