Создание следа над уже сделанным холстом

1

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

Этот код выглядит следующим образом:

var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;


var mouse = {
    x : innerWidth/2,
    y : innerHeight/2
};

var colors = [
    '#3399CC',
    '#67B8DE',
    '#91C9E8',
    '#B4DCED',
    '#E8F8FF'
];



addEventListener('resize', function () {
    canvas.width = innerWidth;
    canvas.height = innerHeight;

    init();
});

var isClicked = false;
addEventListener('click', function () {
    mouse.x = event.clientX;
    mouse.y = event.clientY;
    isClicked = true;
});



function randomIntFromRange (min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
}

function randomColor (colors) {
    return colors[Math.floor(Math.random() * colors.length)];
}



function Stars (x, y, radius, dy, color) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.dy = dy;
    this.color = color;

    this.draw = function () {
        c.beginPath();
        c.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
        c.shadowColor = this.color;
        c.shadowBlur = 15;
        c.shadowOffsetX = 0;
        c.shadowOffsetY = 0;
        c.fillStyle = this.color;
        c.fill();
        c.closePath();
    }

    this.update = function () {
        if (this.y < -10) {
            this.y = canvas.height + 10;
            this.x = randomIntFromRange(this.radius, canvas.width);
        }
        this.y -= this.dy;

        this.draw();
    }
}

function ShootingStar (x, y, radius) {
    this.x = x;
    this.y = y;
    this.radius = radius;

    this.draw = function () {
        c.beginPath();
        c.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
        c.shadowColor = "red";
        c.shadowBlur = 15;
        c.shadowOffsetX = 0;
        c.shadowOffsetY = 0;
        c.fillStyle = "red";
        c.fill();
        c.closePath();
    }

    this.update = function () {
        this.x += 10;
        this.y += 10;

        this.draw();
    }
}



let stars = [];
let shooting_star = [];

function init () {
    stars = [];
    for (var i = 0; i < 300; i++) {
        var stars_radius = randomIntFromRange(2, 3);
        var stars_x = randomIntFromRange(stars_radius, canvas.width);
        var stars_y = randomIntFromRange(stars_radius, canvas.height);
        var stars_dy = Math.random() / 6;
        var color = randomColor(colors);
        stars.push(new Stars(stars_x, stars_y, stars_radius, stars_dy, color));
    }
}

function Explode () {
    shooting_star = [];
    var shooting_star_radius = 3;
    var shooting_star_x = mouse.x;
    var shooting_star_y = mouse.y;
    for (var i = 0; i < 50; i++) {
        shooting_star.push(new ShootingStar(shooting_star_x, shooting_star_y, shooting_star_radius));
        if (shooting_star_radius > 0.2) {
            shooting_star_radius -= .2;
        }
        var initiator = randomIntFromRange(-1, 1);
        console.log(initiator);
        shooting_star_x -= 3;
        shooting_star_y -= 3;
    }
}

function animate () {
    requestAnimationFrame(animate);
    c.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < stars.length; i++) 
        stars[i].update();
    for (var i = 0; i < shooting_star.length; i++) 
        shooting_star[i].update();

    if (isClicked == true) {
        Explode();
        isClicked = false;
    }
}

init();
animate();

Вот jsfiddle к нему https://jsfiddle.net/qjug4qdz/

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

  • 0
    Может быть, получить координаты нажатой точки, а затем получить случайные координаты от края холста. Затем выполните несколько простых векторных расчетов, чтобы получить траекторию для падающей звезды. Просто интересуюсь.
  • 0
    Да, я знаю об этом, но главная задача здесь - получить эффект следа.
Показать ещё 1 комментарий
Теги:
html5-canvas

1 ответ

0

Основные частицы

Для конкретного эффекта, который вы ищете, вы можете использовать базовую систему частиц.

По мере того, как стреляющая звезда движется, вы бросаете частицу, которая начинается со скоростью звезды, а затем замедляется и исчезает.

Частица

Сначала вы начинаете с частицы. Мне нравится использовать Object.assign при создании объектов, но вы можете использовать любой способ, который вам нравится, класс, новый, фабричный...

// This defines a particle and is copied to create new particles
const starDust = {
    x : 0,  // the current position
    y : 0, 
    dx : 0,  // delta x,y (velocity)
    dy : 0,
    drag : 0, // the rate that the particle slows down.
    life : 0, // count down till particle is removed
    age : 0, // the starting value of life
    draw(){ // function to update and draw the particle
        this.x += this.dx;   // move it
        this.y += this.dy;
        this.dx *= this.drag;  // slow it down
        this.dy *= this.drag;
        const unitLife = (this.life / this.age); // get the life left as a value 
                                                 // from 0 to 1 where 0 is end
        ctx.globalAlpha = unitLife;   // set the alpha
        ctx.beginPath();
        ctx.arc(this.x,this.y,4,0,Math.PI); // draw the particle


        this.life -= 1; // count down
        return this.life > 0; // return true if still alive
     }

Помните об этом.

Общей ошибкой при создании систем частиц является то, что люди забывают, что создание и уничтожение объектов добавит много работы в управление памятью javascripts. Хуже всего GC (Garbage Collection). GC является основным источником задержки, и если вы расточительны памяти, это повлияет на качество анимации. Для простых частиц это может быть не заметно, но вы можете захотеть, чтобы сотни сложных частиц порождали каждый кадр. Это когда GC действительно вредит анимации.

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

Таким образом, вы никогда не удаляете какие-либо частицы, значительно уменьшая нагрузку на GC и не позволяя анимации снимать кадры (если вы используете много частиц)

Частице требуется инициализатор

Но вам нужно предоставить способ повторной инициализации объекта. Таким образом, добавьте функцию init к частице, которая установит ее для повторного использования

    init(x,y,vx,vy){ // where x,y and velocity vx,vy of shooting star
        this.x = x;
        this.y = y;
        this.dx = vx;
        this.dy = vy;
        // give a random age
        this.age = (Math.random() * 100 + 60) | 0; // in frames and | 0 floors the value
        this.life = this.age; // and set the life countdown
        this.drag = Math.random() * 0.01 + 0.99; // the drag that slows the particle down
     }
}  // end of starDust object.

Массивы

Чтобы управлять всеми частицами, мы создаем объект с массивами и методами для добавления, создания и рендеринга частиц. В этом случае я буду называть это dust

const dust = {
     particles : [], // array of active particles
     pool : [], // array of unused particels
     createParticle(particleDesc){  // creates a new particle from particleDesc
         return Object.assign({},particleDesc);
     },
     add(x,y,vx,vy){ // where x,y and velocity vx,vy
         var dust; 
         if(this.pool.length){  // are there any particles in the pool
             dust = this.pool.pop(); // get one 
         }else{                 // else there are no spare particles so create a new one
             dust = this.createParticle(starDust);
         }
         dust.init(x,y,vx,vy); // init  the particle
         this.items.push(dust); // put it in the active particle array
         return dust;           // return it (sometimes you want to do something with it)
      },
      draw(){ // updates and draws all active particles
          var i = 0;
          while(i < this.items.length){ // iterate each particle in items
              if(this.items[i].draw() === false){ // is it dead??
                   this.pool.push(this.items.splice(i,1)[0]); // if dead put in the pool for later
              }else{ i ++ } // if not dead get index of next particle
          }
      }
   }//end of dust object

Использование системы частиц

Самый простой способ создания частицы - использовать случайное число и установить вероятность создания частицы в каждом кадре.

В вашем основном цикле

 // assuming that the falling star is called star and has an x,y and dx,dy (delta)
 if(star) {   // only if there is a start to spawn from
    // add a particle once every 10 frame (on average
    if(Math.random() < 0.1) { 
          dust.add(star.x, star.y, star.dx, star.dy); // add some dust at the shooting starts position and speed
    }
 }

 dust.draw(); // draw all particles

И это все.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню