使用javascript创建闪烁效果

时间:2017-06-12 00:37:19

标签: javascript html5-canvas

var stars = function() {

this.x = Math.floor(Math.random()* 1000)   ;

this.y = Math.floor(Math.random()* 900)   ;

this.radius = 2  ;

this.starColour = "gold";





  }

   var starNum = 20;
   var starry = new Array(starNum);

 for(var s = 0 ; s < 100 ; s++){

 starry[s] = new stars()
}


var starDraw = function() {


var starCanvas = document.getElementById("stars");

var starCtx = starCanvas.getContext("2d");
starCtx.clearRect(0, 0, 1000, 900);

for(i = 0; i < 100 ; i++){
  var star = starry[i];



  starCtx.fillStyle= "white";

starCtx.shadowBlur = 5;

starCtx.shadowColor = "white";
  starCtx.beginPath();





  // draw it
  starCtx.arc(star.x, star.y, star.radius,  Math.PI * 2, false);
  starCtx.stroke();
  starCtx.fill();


   }


}






   function starLoop(){ 

starDraw(); 
requestAnimationFrame(starLoop); 
}

 requestAnimationFrame(starLoop);

所以我试图仅使用javascript为星星创造闪烁效果,我无法弄清楚如何做到这一点。 到目前为止,我一直在寻找并找不到真正的答案,所以如果我能在这里得到答案,我将不胜感激。我对编码很陌生,所以请你放轻松。

1 个答案:

答案 0 :(得分:1)

随机星空。有点夸张,但如果需要,很容易调低(或向上)。

重要的一点是避免直接随机值,因为大多数事物本质上不是随机的,而是倾向于接近固定点。这称为高斯分布。有几种方法可以生成这样的随机值。

// gRandom is far more likely to be near 0.5 than 1 or zero
var gRandom = (Math.random()+Math.random()+Math.random()+Math.random()) / 4;

// or
// gRandom is more likely to be near zero than near 1
var gRandom = Math.random() * Math.random();

我使用这些方法来设置恒星的大小(远小于大星星)并创建颜色和运动。

为了尝试获得更逼真的效果,我还将星星移动不到一个像素。这具有改变亮度但看起来不像移动的效果。

代码有很多评论

&#13;
&#13;
const ctx = canvas.getContext("2d");
// function calls a callback count times. Saves typing out for loops all the time 
const doFor = (count, callback) => {
  var i = 0;
  while (i < count) {
    callback(i++)
  }
};
// creates a random integer between min and max. If min only given the between 0 and the value 
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
// same as above but as floats.
const rand = (min, max = min + (min = 0)) => Math.random() * (max - min) + min;
// creates a 2d point at x,y. If only x is a point than set to that point
const point = (x = 0, y) => {
  if (x.x && y === undefined) {return { x: x.x,y: x.y} }
  return {x,y: y === undefined ? 0 : y }
};
function ease (time, amount = 2) { return Math.pow(time % 1,amount) };
const clamp = (v, min = 1,max = min + (min = 0)) => v < min ? min : v > max ? max : v;




// stuff for stars
const skyColour = [10,30,50];
const density = 1000; // number of star per every density pixels
const colourChangeRate = 16; // Time in frames to change a colour
const stars = [];
const star = { // define a star
  draw() {
    this.count += 1; // integer counter used to triger color change every 16 frames
    if (this.count % colourChangeRate === 0) { // change colour ?
      // colour is a gaussian distrabution (NOT random) centered at #888
      var c = (Math.random() + Math.random() + Math.random() + Math.random()) * 4;
      var str = "#";
      str += Math.floor(c * this.red).toString(16); // change color
      str += Math.floor(c * this.green).toString(16); // change color
      str += Math.floor(c * this.blue).toString(16); // change color
      

      this.col = str;
    }
    ctx.fillStyle = this.col;
    // move star around  a pixel. Again its not random
    // but a gaussian distrabution. The movement is sub pixel and will only
    // make the stars brightness vary not look like its moving
    var ox = (Math.random() + Math.random() + Math.random() + Math.random()) / 4;
    var oy = (Math.random() + Math.random() + Math.random() + Math.random()) / 4;
    ctx.fillRect(this.pos.x + ox, this.pos.y + oy, this.size, this.size);
  }
}
// create a random star
// the size is caculated to produce many more smaller stars than big
function createStar(pos) {
  stars.push(Object.assign({}, star, {
    pos,
    col: "#ccc",
    count: randI(colourChangeRate),
    size: rand(1) * rand(1) * 2 + 0.5,
    red: 1-(rand(1) * rand(1) *rand(1)),  // reduces colour channels
    green: 1-(rand(1) * rand(1) *rand(1)), // but only by a very small amount
    blue: 1-(rand(1) * rand(1) *rand(1)),  // most of the time but occasional 
                                           // star will have a distinct colour
  }));
}

var starCount;
var skyGrad;

// render the stars
function mainLoop(time) {
  // resize canva if page size changes
  if (canvas.width !== innerWidth || canvas.height !== innerHeight) {
    canvas.width = innerWidth;
    canvas.height = innerHeight;
    // create a new set of stars 
    stars.length = 0;
    // density is number of pixels one the canvas that has one star
    starCount = Math.floor((canvas.width * canvas.height) / density);
    // create the random stars;
    doFor(starCount, () => createStar(point(randI(canvas.width), randI(canvas.height))));
    skyGrad = ctx.createLinearGradient(0,0,0,canvas.height);
    skyGrad.addColorStop(0,"black");
    doFor(100,(i)=>{
        var pos  = clamp(i/100,0,1);
        var col = ease(pos);
        skyGrad.addColorStop(
            pos,
            "rgb(" + 
              Math.floor(skyColour[0] * col) + "," +
              Math.floor(skyColour[1] * col) + "," +
              Math.floor(skyColour[2] * col) + ")"
         );
     });
     // floating point error can cause problems if we dont set the top
     // at 1
     skyGrad.addColorStop(1,"rgb("+skyColour[0]+","+skyColour[1]+","+skyColour[2]+")");
    
  }
  ctx.fillStyle = skyGrad;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  doFor(starCount, (i) => stars[i].draw());

  requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
&#13;
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;