我找到了一个很棒的脚本来制作五彩纸屑:http://jsfiddle.net/hcxabsgh/
注意粒子如何具有这种扭曲/转弯/倾斜效果,以使其感觉更自然。

我一直在尝试使粒子变圆,这也很好用:http://jsfiddle.net/rqr9hb7x/2/

但是我无法像矩形示例中那样使粒子绕其轴扭曲/旋转/倾斜。

我认为它应该可以与ctx.setTransform()一起使用,因为它可以处理偏斜参数,但是它似乎偏斜了整个画布而不是单个粒子。任何人都知道如何正确处理此问题?

this.draw = function () {
    ctx.beginPath();
    ctx.save();
    //ctx.setTransform(1, 0, 0, 1, 0, 0); // straigt
    ctx.setTransform(1, .3, 0, .7, 0, 0); // skewed - to make dynamic
    ctx.arc(this.x + this.tilt, this.y + this.tilt + (this.r / 4), (this.r / 2), 0, Math.PI * 2, false);
    ctx.restore();
    ctx.fillStyle = this.color;
    return ctx.fill();
}

最佳答案

使用setTransform倾斜

您想随着时间旋转粒子局部x轴。 x轴是setTransform的前两个参数。要随时间旋转该轴,请使用cos(angle)sin(angle)设置x轴的x和y分量。

如果您希望该粒子位于粒子局部,则还需要设置粒子原点(旋转点),然后将粒子绘制为0,0。原点是setTransform的最后两个参数

您想要的绘图功能是

draw() {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.setTransform(
        Math.cos(this.tiltAngle),  // set the x axis to the tilt angle
        Math.sin(this.tiltAngle),
        0, 1,
        this.x, this.y    // set the origin
    );
    ctx.arc(0, 0, (this.r / 2), 0, Math.PI * 2, false); // draw at origin (0,0)
    ctx.fill();
}




看看给出的小提琴的代码,我无法弄清他们正在尝试做什么,因为它已经很复杂了,所以我重新编写了整个程序,现在只需要三分之三的代码,而没有jQuery。

为您想要的FX运行演示...

也许????



(function () {
    requestAnimationFrame(mainLoop);
    const ctx = canvas.getContext("2d");
    var W,H;
    var confetti = new Particles();
    var droppedCount = 0;
    var particlesPerFrame = 1.5;
    var wind = 0;
    var windSpeed = 1;
    const windSpeedMax = 1;
    const windChange = 0.01;
    const windPosCoef = 0.002;
    const maxParticlesPerFrame = 2; //max particles dropped per frame
    var id = 0;
    stopButton.addEventListener("click",() => particlesPerFrame = 0 );
    startButton.addEventListener("click",() => particlesPerFrame = maxParticlesPerFrame);
		const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
		const rand  = (min = 1, max = min + (min = 0)) => Math.random() * (max - min) + min;
    const colors = {
        options: "DodgerBlue,OliveDrab,Gold,pink,SlateBlue,lightblue,Violet,PaleGreen,SteelBlue,SandyBrown,Chocolate,Crimson".split(","),
        index: 0,
        step: 10,
        get color() { return colors.options[((colors.index++) / colors.step | 0) % colors.options.length] }
    }
    function Confetti() { this.setup() }
    Confetti.prototype = {
        setup(){
            this.x = rand(-35,W + 35);
            this.y = rand(-30,-35);
            this.r = rand(10, 30);
            this.d = rand(150) + 10; //density;
            this.color = colors.color;
            this.tilt = randI(10);
            this.tiltAngleIncremental = (rand(0.08) + 0.04) * (rand() < 0.5 ? -1 : 1);
            this.tiltAngle = 0;
            this.angle = rand(Math.PI * 2);
            this.id = id++;
            return this;
        },
        update() {
            this.tiltAngle += this.tiltAngleIncremental * (Math.cos(wind + (this.d + this.x + this.y) * windPosCoef) * 0.2 + 1);
            this.y += (Math.cos(this.angle + this.d) + 3 + this.r / 2) / 2;
            this.x += Math.sin(this.angle);
            this.x += Math.cos(wind + (this.d + this.x + this.y) * windPosCoef) * windSpeedMax;
            this.y += Math.sin(wind + (this.d + this.x + this.y) * windPosCoef) * windSpeedMax;
            this.tilt = (Math.sin(this.tiltAngle - (this.id / 3))) * 15;
            return this.y > H;  // returns true if particle is past bottom
        },
        draw() {
            ctx.fillStyle = this.color;
            ctx.beginPath();
            ctx.setTransform(
                Math.cos(this.tiltAngle),  // set the x axis to the tilt angle
                Math.sin(this.tiltAngle),
                0, 1,
                this.x, this.y    // set the origin
            );
            ctx.arc(0, 0, (this.r / 2), 0, Math.PI * 2, false);
            ctx.fill();
        }
    }
    function Particles() {
        const items = [];
        const pool = [];
        this.update = function() {
            for (var i = 0; i < items.length; i++) {
                if(items[i].update() === true){ pool.push(items.splice(i--,1)[0]) }
            }
        }
        this.draw = function() { for (var i = 0; i < items.length; i++) { items[i].draw()  } }
        this.add = function() {
            if (pool.length > 0) { items.push(pool.pop().setup()) }
            else { items.push(new Confetti()) }
        }
    }
    function mainLoop(time) {
        if (W !== innerWidth || H !== innerHeight) {
            W = canvas.width = innerWidth;
            H = canvas.height = innerHeight;
        } else {
            ctx.setTransform(1,0,0,1,0,0);
            ctx.clearRect(0, 0, W, H);
        }
        windSpeed = Math.sin(time / 8000) * windSpeedMax;
        wind += windChange;
        while(droppedCount < particlesPerFrame){
           droppedCount += 1;
           confetti.add();
        }
        droppedCount -= particlesPerFrame;
        confetti.update();
        confetti.draw();
        requestAnimationFrame(mainLoop);
    }
})();

* {
  margin: 0;
  padding: 0;
}

body {
  /*You can use any kind of background here.*/
  background: transparent;
}

canvas {
  display: block;
  position: relative;
  zindex: 1;
  pointer-events: none;
}

#content {
  text-align: center;
  width: 500px;
  height: 300px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -250px;
  margin-top: -150px;
  color: silver;
  font-family: verdana;
  font-size: 45px;
  font-weight: bold;
}

.buttonContainer {
  display: inline-block;
}

button {
  padding: 5px 10px;
  font-size: 20px;
}

<div id="content">
  Confetti World
  <br /> I 💙 confetti!
  <br />
  <div class="buttonContainer">
    <button id="stopButton">Stop Confetti</button>
    <button id="startButton">Drop Confetti</button>
  </div>
</div>
<canvas id="canvas"></canvas>





注意某些代码和内容已从this fiddle复制而来。

07-24 17:57