在已制作的画布上创建轨迹

时间:2017-09-08 04:49:26

标签: javascript html5 html5-canvas

因此,我试图在已经绘制的缓慢移动的恒星画布上实施一个射击星的概念。但我还没有找到办法。我尝试实现一个数组,使其看起来如此,但这条线索并不高效。

此代码如下:

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/

我基本上希望这颗流星可以从一个随机位置到达我点击鼠标的位置,但使用数组很难处理这条线。

1 个答案:

答案 0 :(得分: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(垃圾收集)。 GC是延迟的主要来源,如果你浪费了内存,它将影响动画的质量。对于简单的粒子,它可能不明显,但您可能需要数百个复杂的粒子产生每个帧。这是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

就是这样。