Javascript: частицы конфетти падают на холст

1

Я нашел этот отличный сценарий, чтобы сделать его дождевой конфетти: 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();
}
  • 0
    от всей моей головы - вам нужно вставить ctx.setTransform(1, .3, 0, .7, 0, 0); x и y в ctx.setTransform(1, .3, 0, .7, 0, 0);
  • 0
    но могут быть и лучшие решения, конечно
Теги:
canvas
transform

1 ответ

2
Лучший ответ

setTransform с использованием setTransform

Вы хотите вращать локальную ось x частиц с течением времени. Ось x - это первые два аргумента setTransform. Чтобы повернуть эту ось с течением времени, вы используете cos(angle) и sin(angle) для установки x и y-составляющей оси x.

Поскольку вы хотите, чтобы это было локально для частицы, вам нужно также установить начало частицы (точку вращения), а затем нарисуйте частицу на 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();
}

пример

Глядя на код на скрипке, я не мог понять, что они пытались сделать, поскольку это было слишком сложно, поэтому я переписал все, что теперь занимает 3-й код и не 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>

Примечание. Некоторые из этого кода и содержимого были скопированы из этого скрипта.

  • 0
    Потрясающие! Спасибо :)

Ещё вопросы

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