Я хочу создать эффект анимации снега в JavaScript. Мои знания действительно плохи в этом языке программирования. Однако мне удалось сделать это с одной снежинкой, а также с помощью петли.

Теперь я хочу создать более одной снежинки. Может кто-нибудь помочь мне понять, как генерировать больше снежинок?

let canvas = document.getElementById("wip"); let ctx = canvas.getContext("2d"); canvas.width = window.innerWidth-30; canvas.height = window.innerHeight-30; let xloc = Math.floor(Math.random() * canvas.width); let yloc = 0; ctx.strokeStyle="#" ((1{amp}lt;{amp}lt;24)*Math.random()|0).toString(16); function drawflake(){ ctx.beginPath(); //Top Right Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc-7,yloc-7); ctx.lineTo(xloc-11,yloc-7); ctx.moveTo(xloc-7,yloc-7); ctx.lineTo(xloc-7,yloc-11); ctx.moveTo(xloc-7,yloc-7); ctx.lineTo(xloc-14,yloc-14); ctx.lineTo(xloc-17,yloc-14); ctx.moveTo(xloc-14,yloc-14); ctx.lineTo(xloc-14,yloc-17); ctx.moveTo(xloc-14,yloc-14); ctx.lineTo(xloc-18,yloc-18); //Top Left Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc 7,yloc-7); ctx.lineTo(xloc 11,yloc-7); ctx.moveTo(xloc 7,yloc-7); ctx.lineTo(xloc 7,yloc-11); ctx.moveTo(xloc 7,yloc-7); ctx.lineTo(xloc 14,yloc-14); ctx.lineTo(xloc 17,yloc-14); ctx.moveTo(xloc 14,yloc-14); ctx.lineTo(xloc 14,yloc-17); ctx.moveTo(xloc 14,yloc-14); ctx.lineTo(xloc 18,yloc-18); //Bottom Left Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc 7,yloc 7); ctx.lineTo(xloc 7,yloc 11); ctx.moveTo(xloc 7,yloc 7); ctx.lineTo(xloc 11,yloc 7); ctx.moveTo(xloc 7,yloc 7); ctx.lineTo(xloc 14,yloc 14); ctx.lineTo(xloc 14,yloc 17); ctx.moveTo(xloc 14,yloc 14); ctx.lineTo(xloc 17,yloc 14); ctx.moveTo(xloc 14,yloc 14); ctx.lineTo(xloc 18,yloc 18); //Bottom Right Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc-7,yloc 7); ctx.lineTo(xloc-11,yloc 7); ctx.moveTo(xloc-7,yloc 7); ctx.lineTo(xloc-7,yloc 11); ctx.moveTo(xloc-7,yloc 7); ctx.lineTo(xloc-14,yloc 14); ctx.lineTo(xloc-17,yloc 14); ctx.moveTo(xloc-14,yloc 14); ctx.lineTo(xloc-14,yloc 17); ctx.moveTo(xloc-14,yloc 14); ctx.lineTo(xloc-18,yloc 18); //Left Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc-9.899,yloc); ctx.lineTo(xloc-12.899,yloc-3); ctx.moveTo(xloc-9.899,yloc); ctx.lineTo(xloc-12.899,yloc 3); ctx.moveTo(xloc-9.899,yloc); ctx.lineTo(xloc-19.799,yloc); ctx.lineTo(xloc-22.799,yloc-3); ctx.moveTo(xloc-19.799,yloc); ctx.lineTo(xloc-22.799,yloc 3); ctx.moveTo(xloc-19.799,yloc); ctx.lineTo(xloc-25.456,yloc); //Right Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc 9.899,yloc); ctx.lineTo(xloc 12.899,yloc-3); ctx.moveTo(xloc 9.899,yloc); ctx.lineTo(xloc 12.899,yloc 3); ctx.moveTo(xloc 9.899,yloc); ctx.lineTo(xloc 19.799,yloc); ctx.lineTo(xloc 22.799,yloc-3); ctx.moveTo(xloc 19.799,yloc); ctx.lineTo(xloc 22.799,yloc 3); ctx.moveTo(xloc 19.799,yloc); ctx.lineTo(xloc 25.456,yloc); ctx.lineWidth = 1; ctx.lineCap = 'round'; ctx.stroke(); yloc=yloc 1; if (yloc{amp}gt;canvas.height) { yloc=0; xloc = Math.floor(Math.random() * canvas.width); ctx.strokeStyle="#" ((1{amp}lt;{amp}lt;24)*Math.random()|0).toString(16); } } function clearCanvas() { ctx.clearRect(0,0, canvas.width, canvas.height); } function repeat() { clearCanvas(); drawflake(); setTimeout(repeat, 24); } repeat(); 
 {amp}lt;canvas id="wip"{amp}gt;{amp}lt;/canvas{amp}gt; 

Джордж

новый участник этого сайта. Будьте внимательны, спрашивая разъяснения, комментируя и отвечая. Проверьте наш

Правила поведения

,

Вы можете переместить весь специфичный для хлопьев код в class чтобы вы могли создать новую пластинку с new . Переменные, которые определяют свойства пластинки, должны быть определены как свойства экземпляра. В этом случае вам нужно сделать это изменение для переменных xloc , yloc и strokeStyle . Хотя последний является свойством ctx , это свойство необходимо менять каждый раз, когда отображается другая пластинка, поэтому пластинка должна сама знать, каков ее цвет. Так что это должна быть собственность.

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

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

Вот как ваш код может быть адаптирован к этому. Комментарии уточняют все сделанные мной изменения:

 let canvas = document.getElementById("wip"); let ctx = canvas.getContext("2d"); canvas.width = window.innerWidth-30; canvas.height = window.innerHeight-30; class SnowFlake { // each snowflake will be an instance of this class constructor() { // this is called when you do `new SnowFlake()` // the location is now saved in variables that belong to the instance: // Note the use of `this` in all three assignments: this.xloc = Math.floor(Math.random() * canvas.width); this.yloc = 0; this.strokeStyle="#" ((1{amp}lt;{amp}lt;24)*Math.random()|0).toString(16); } drawflake(){ // This function becomes a method // Get the stroke style that was saved during construction: ctx.strokeStyle=this.strokeStyle; // Get the location that was saved during construction let xloc = this.xloc; let yloc = this.yloc; // No change needed in the drawing part of this function... ctx.beginPath(); //Top Right Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc-7,yloc-7); ctx.lineTo(xloc-11,yloc-7); ctx.moveTo(xloc-7,yloc-7); ctx.lineTo(xloc-7,yloc-11); ctx.moveTo(xloc-7,yloc-7); ctx.lineTo(xloc-14,yloc-14); ctx.lineTo(xloc-17,yloc-14); ctx.moveTo(xloc-14,yloc-14); ctx.lineTo(xloc-14,yloc-17); ctx.moveTo(xloc-14,yloc-14); ctx.lineTo(xloc-18,yloc-18); //Top Left Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc 7,yloc-7); ctx.lineTo(xloc 11,yloc-7); ctx.moveTo(xloc 7,yloc-7); ctx.lineTo(xloc 7,yloc-11); ctx.moveTo(xloc 7,yloc-7); ctx.lineTo(xloc 14,yloc-14); ctx.lineTo(xloc 17,yloc-14); ctx.moveTo(xloc 14,yloc-14); ctx.lineTo(xloc 14,yloc-17); ctx.moveTo(xloc 14,yloc-14); ctx.lineTo(xloc 18,yloc-18); //Bottom Left Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc 7,yloc 7); ctx.lineTo(xloc 7,yloc 11); ctx.moveTo(xloc 7,yloc 7); ctx.lineTo(xloc 11,yloc 7); ctx.moveTo(xloc 7,yloc 7); ctx.lineTo(xloc 14,yloc 14); ctx.lineTo(xloc 14,yloc 17); ctx.moveTo(xloc 14,yloc 14); ctx.lineTo(xloc 17,yloc 14); ctx.moveTo(xloc 14,yloc 14); ctx.lineTo(xloc 18,yloc 18); //Bottom Right Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc-7,yloc 7); ctx.lineTo(xloc-11,yloc 7); ctx.moveTo(xloc-7,yloc 7); ctx.lineTo(xloc-7,yloc 11); ctx.moveTo(xloc-7,yloc 7); ctx.lineTo(xloc-14,yloc 14); ctx.lineTo(xloc-17,yloc 14); ctx.moveTo(xloc-14,yloc 14); ctx.lineTo(xloc-14,yloc 17); ctx.moveTo(xloc-14,yloc 14); ctx.lineTo(xloc-18,yloc 18); //Left Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc-9.899,yloc); ctx.lineTo(xloc-12.899,yloc-3); ctx.moveTo(xloc-9.899,yloc); ctx.lineTo(xloc-12.899,yloc 3); ctx.moveTo(xloc-9.899,yloc); ctx.lineTo(xloc-19.799,yloc); ctx.lineTo(xloc-22.799,yloc-3); ctx.moveTo(xloc-19.799,yloc); ctx.lineTo(xloc-22.799,yloc 3); ctx.moveTo(xloc-19.799,yloc); ctx.lineTo(xloc-25.456,yloc); //Right Brunch ctx.moveTo(xloc,yloc); ctx.lineTo(xloc 9.899,yloc); ctx.lineTo(xloc 12.899,yloc-3); ctx.moveTo(xloc 9.899,yloc); ctx.lineTo(xloc 12.899,yloc 3); ctx.moveTo(xloc 9.899,yloc); ctx.lineTo(xloc 19.799,yloc); ctx.lineTo(xloc 22.799,yloc-3); ctx.moveTo(xloc 19.799,yloc); ctx.lineTo(xloc 22.799,yloc 3); ctx.moveTo(xloc 19.799,yloc); ctx.lineTo(xloc 25.456,yloc); ctx.lineWidth = 1; ctx.lineCap = 'round'; ctx.stroke(); // Save the new location to the instance: this.yloc = yloc 1; // Don't deal here with the range check. Do that in `repeat` } } function clearCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); } // Collection that holds all of the active flakes let flakes = new Set; function repeat() { clearCanvas(); // Draw all flakes for (let flake of flakes) { flake.drawflake(); if (flake.yloc {amp}gt; canvas.height) { // flake reached the bottom? flakes.delete(flake); // remove the flake from the collection } } setTimeout(repeat, 24); } // new function to deal with the generation of new flakes function generate() { flakes.add(new SnowFlake()); // construct a new flake and add it to the collection // Make the time between two generations of a new flakes a bit random setTimeout(generate, 1000   Math.random() * 2000); } generate(); // also start the generations repeat(); 
 {amp}lt;canvas id="wip"{amp}gt;{amp}lt;/canvas{amp}gt; 

Вы можете влиять на скорость генерации чешуек и ее изменение, изменяя две константы, используемые в выражении 1000 Math.random() * 2000 .

Я хотел бы представить, что вы будете использовать классы для создания нескольких снежинок, которые имеют такое же поведение, но с уникальными свойствами. Поведение, как ваша функция drawflake которая рисует линию каждой чешуйки.

Создайте class который является основой для всех будущих SnowFlakes и он даст ему метод draw в который вы поместите свою логику рисования.

 const canvas = document.getElementById("wip"); const ctx = canvas.getContext("2d"); canvas.width = window.innerWidth-30; canvas.height = window.innerHeight-30; class SnowFlake { constructor(context) { this.ctx = context; } draw() { this.ctx.beginPath(); // other drawing functions... } } 

Теперь вы можете начать создавать экземпляры SnowFlake сколько угодно. Напишите функцию, которая будет создавать экземпляры вновь созданного class и позволять ему передавать amount экземпляров и context холста. Параметр amount будет указывать, сколько экземпляров вы хотите создать и вернуть, а context — это контекст элемента canvas который будет передан в объект, чтобы использовать его внутри него.

 function createSnowFlakes(amount, context) { const snowFlakes = []; for (let i = 0; i {amp}lt; amount; i  ) { const snowFlake = new SnowFlake(context); snowFlakes.push(snowFlake); } return snowFlakes; } 

Теперь создайте экземпляры, вызвав функцию createSnowFlakes с заданным параметром amount и context и сохраните результат в переменной.

 const amountOfSnowFlakes = 10; const snowFlakes = createSnowFlakes(amountOfSnowFlakes, ctx) 

Теперь вы создали несколько экземпляров SnowFlake и каждый из них может рисовать себя всегда и везде. Все, что вам нужно сделать, это вызвать метод .draw() каждого SnowFlake , который является вашей логикой рисования, которую вы добавите сами.

Создайте функцию, которая зацикливается на каждом SnowFlake и вызывает метод .draw() . С помощью этой функции вы можете контролировать, когда все снежные хлопья должны быть вытянуты и могут использоваться в вашей функции repeat .

 function drawSnowFlakes(snowFlakes) { snowFlakes.forEach(snowFlake ={amp}gt; snowFlake.draw()); } 

К настоящему времени у вас должен быть большой контроль над созданием группы снежных хлопьев, когда их нужно рисовать. Иди отсюда и посмотри, получится ли.

И не стесняйтесь задать вопрос.