Beautiful cherry blossom dancing animation

Beautiful cherry blossom dancing animation

background

This matter should start from the big promotion...Every year 411 is the exclusive cherry blossom festival of Princess Pea. Since it is the cherry blossom festival, many activities and elements are around the cherry blossom exhibition. For example, the content to be shared this time needs to be a picture of cherry blossoms dancing. Of course, due to time issues, it may not be so cool. Here is mainly to share some ideas with you, and the specific effects. You can use your own imagination.

specific requirement

Here we only talk about the description of part of the requirements for the time being. The whole event is a lucky draw. After clicking the lucky draw button, there needs to be a transition animation of flying cherry blossoms. Animation requirements: Each petal can change from large to small, and can make a layered perspective effect. When all the cherry blossoms are reduced, they begin to fly out of the screen gradually.

Realization ideas

The action of the animation is mainly divided into several steps:

  • For petals to be able to transform from large to small, we can handle it with scale.
  • The change of petals from large to small requires a sense of hierarchy, that is to say, each petal needs to have the ability to delay drawing, that is, the delay method is required
  • The petals fly out of the screen accordingly. In this case, you can actually follow the logic of the delay above. As long as a petal delays the zooming action, then in theory the subsequent animation will be half a beat slower.

achieve

Each petal should have its own attributes

Each petal should have its own attributes
How should this sentence be understood? Everyone may wish to think this way, our set of animations of flying cherry blossoms can t be done with just one petal, but it would be too troublesome to deal with all the petals one by one, so we need a class to abstract the petals, then this What do the classes need? as follows:

  • Image information of petals: imgResource
  • The coordinates of the petals: x, y
  • The size of petals: width, height
  • Scale of petals: scale
  • The multiple of the final zoom: finalSizeScale
  • The degree of rotation of the petals: rotate
  • Transparency of petals: opacity
  • Coefficient of petal change (including transparency, size, moving speed): speed
  • Waiting time before changing petal size and transparency: delay
  • Waiting time before petal movement: shrinkDelay

The petals need to be placed randomly

code show as below

//Generate cherry blossoms; for ( let i = 0 ; i < 20 ; i++) { sakuraList[i] = []; for ( let j = 0 ; j <i; j++) { sakuraList[i].push( new Sakura( ctx, imgInfo, Math .random() * canvasCenterX * 4 -canvasCenterX * 2 , //x Math .random() * canvasCenterY * 4 -canvasCenterY * 2 , //y 1.8 , //scale ( Math .random() * 180 ) * Math .PI/180 , //rotate //The smaller the speed here, the faster the faster Math .floor( Math .random() * 3 + 3 )/100 , //speed 0 , //opacity canvas, //canvas Math .floor( Math .random() * 7 + 20 )/100 , //final i * 2 , //delay )); } } Copy code

Through the code above, it is not difficult to see that this is a process of initializing cherry blossom petals, and what we should focus on is the calculation of random positions .

One of the more important points here is how to distribute the petals relatively randomly and evenly . Perhaps the first reaction of many students is to use

random
And then through the canvas
width, height
To perform random distribution.
At first glance, this method feels that everything is normal, so let's implement it with code to see the distribution effect.

The Math .random () * canvas.width, //X the Math .random () * canvas.height, //Y copy the code

As shown in the figure, in fact, this distribution effect is not very ideal . The solution is also very simple. We can calculate through the center point of the canvas and implement it with code~

The Math .random () * * canvasCenterX . 4 - canvasCenterX * 2 , //X the Math .random () * * canvasCenterY . 4 - canvasCenterY * 2 , //Y copy the code

Looking at it this way, is it a lot more even?

The appearance of petals needs to change from large to small

In terms of demand, the appearance of our petals requires a change process from large to small, so the logic is relatively simple. Without considering other circumstances, we only need to define two values:

  • The size of the petals when they are initialized
  • The size of the petals after the petals are finally still

We have defined these two values when we initialized. The code snippet is:

class Sakura { /** * imgResource picture address * x * y * scale Image zoom * rotate * speed * opacity transparency * finalSizeScale * delay */ constructor ( imgResource, x = 0 , y = 0 , scale = 4 , rotate = 0 , speed = 1 , opacity = 0 , finalSizeScale = 0.2 , delay ) { this .imgResource = imgResource; this .width = imgResource.width; this .height = imgResource.height; this .x = x; this .y = y; this .scale = scale; //initialized size this .rotate Rotate =; the this .speed = Speed; the this .opacity = Opacity; the this .finalSizeScale = finalSizeScale; //ultimately scaled to the size of the this .delay = Delay; the this .shrinkDelay = . 7 ; } } Copy code

With these two values, we can calculate through the refresh mechanism, let's take a look at the effect first.

/** * Scaling method * sakura is the petal object we initialized before */ changeScale ( sakura ) { if (sakura.scale> sakura.finalSizeScale){ sakura.scale -= sakura.speed; } else { sakura.scale = sakura.finalSizeScale; } }, Copy code

Then the animation effect is realized, but the general feeling is a bit blunt, then we can add some easing operators to enter and make some optimizations.

/** * Scaling method * sakura is the petal object we initialized before */ changeScale ( sakura ) { if (sakura.scale> sakura.finalSizeScale){ sakura.scale -= ((sakura.scale-sakura.finalSizeScale) * sakura.speed); } else { sakura.scale = sakura.finalSizeScale; } }, Copy code

As in the above code, we have optimized the reduction method and replaced it with an easing formula

Current value + = (target value-current value) * coefficient

Of course, you can slowly adjust this coefficient to the feeling you want. I am a clown here.

The appearance of the petals requires a change in transparency

The change of transparency is actually the same idea as zooming, so the function can also be used directly

/** * Transparency transformation method * sakura is the petal object we initialized before */ changeOpacity ( sakura ) { if (sakura.opacity < 1 ) { //current value += (target value-current value) * coefficient sakura.opacity += (( 1 -sakura.opacity) * sakura.speed); } else { sakura.opacity = 1 ; } }, Copy code

The transparency transformation here is directly implemented using the previous easing formula, let s see the effect

It looks like there is no problem, but we have too many petals, which is not so obvious. However, comparing with the animation above, some visual changes have actually taken place.

The appearance of petals needs a sense of hierarchy

A sense of hierarchy is needed. To put it bluntly, it is necessary to have a delay setting for each petal to achieve a visual difference. In fact, we can set a

delay
Attribute, through the subtraction operation to achieve a
delayAnimation
Methods.

/** * Delay method * sakura is the petal object we initialized before */ delayAnimation ( sakura ) { sakura.delay> 0 && sakura.delay --; }, Copy code

After the delay method is designed, one more thing we need to consider is to intercept transparency and zoom, otherwise the delay has no meaning.

drawSakuraAnimation () { this .ctx.clearRect( 0 , 0 , this .canvas.width, this .canvas.height); for ( let item of sakuraList) { for ( let item2 of item) { this .ctx.globalAlpha = item2.opacity ; item2.delay <= 0 && this .changeScale(item2); item2.delay <= 0 && this .changeOpacity(item2); if (item2.opacity> 0 ) { this .ctx.save(); this .ctx.rotate(item2.rotate); item2.ctx.drawImage(item2.imgResource, item2.x, item2.y, item2.width*item2.scale, item2.height*item2.scale); this .ctx.restore(); } this .delayAnimation(item2); } } window .requestAnimationFrame( this .drawSakuraAnimation); }, Copy code

As above, you can see that drawing will only start after the delay is 0 , so let's take a look at the effect.

It can be seen that compared with the previous animation, there is indeed one more gradual effect. Of course, the time can be optimized by everyone.

The petals need to fly off the screen in turn

Analyze carefully, in fact, these are two actions:

  1. According to this
  2. Fly off the screen

In turn

At present, according to this, we have actually realized that each petal of us is performing the same set of actions , but because of the previous

delayAnimation
Method, it will cause the state of each petal to be different , but the overall movement curve remains unchanged . To put it bluntly, delay caused some petals to execute methods slowly.

Fly off the screen

If we fly out of the screen, we can use the easing method again~ But here is what we should pay attention to, because we can't fly at the beginning, it needs to wait for a certain value before the petals will fly. Therefore, a value is needed to make a judgment. Here I use transparency

drawSakuraAnimation () { this .ctx.clearRect( 0 , 0 , this .canvas.width, this .canvas.height); for ( let item of sakuraList) { for ( let item2 of item) { this .ctx.globalAlpha = item2.opacity ; item2.delay <= 0 && this .changeScale(item2); item2.delay <= 0 && this.changeOpacity(item2); if(item2.opacity > 0) { this.ctx.save(); this.ctx.rotate(item2.rotate); item2.ctx.drawImage(item2.imgResource, item2.x, item2.y, item2.width*item2.scale, item2.height*item2.scale); this.ctx.restore(); } // // += ( - )* if (item2.opacity >= 0.9) { item2.x += (-600-item2.x)*item2.speed; item2.y += (-600-item2.y)*item2.speed; item2.ctx.drawImage(item2.imgResource, item2.x, item2.y, item2.width*item2.scale, item2.height*item2.scale); } this.delayAnimation(item2); } } window .requestAnimationFrame( this .drawSakuraAnimation); }, Copy code

It is not difficult for everyone to see that when the transparency is greater than 0.9, the petals will move in one direction. Next we look at the effect.

Because the gif has omitted some key frames of the animation, it s a bit embarrassing, but please believe me, it s okay... But in fact, I think it might fly out of the screen too fast. I want to wait until the petals are almost on the ground before flying. Let me be lazy, I will use a simple subtraction operation.

Slightly optimize "in order"

Attentive classmates may have seen before, there is a property in the attribute I declared

shrinkDelay
It hasn't been used yet, so this one is actually used as a "sequential" delay. Come, come, show me the code!

drawSakuraAnimation () { this .ctx.clearRect( 0 , 0 , this .canvas.width, this .canvas.height); for ( let item of sakuraList) { for ( let item2 of item) { this .ctx.globalAlpha = item2.opacity ; item2.delay <= 0 && this.changeScale(item2); item2.delay <= 0 && this.changeOpacity(item2); if(item2.opacity > 0) { this.ctx.save(); this.ctx.rotate(item2.rotate); item2.ctx.drawImage(item2.imgResource, item2.x, item2.y, item2.width*item2.scale, item2.height*item2.scale); this.ctx.restore(); } if (item2.opacity >= 0.9) { item2.shrinkDelay -= 0.1; if (item2.shrinkDelay <= 0) { item2.x += (- 600 -item2.x)*item2.speed; item2.y += (- 600 -item2.y)*item2.speed; } item2.ctx.drawImage(item2.imgResource, item2.x, item2.y, item2.width*item2.scale, item2.height*item2.scale); } this .delayAnimation(item2); } } window .requestAnimationFrame( this .drawSakuraAnimation); }, Copy code

As you can see, I simply use

shrinkDelay
The self-decrement , to delay, don t be as lazy as me.....Let's take a look at the effect

how about it? From the current point of view, in fact, our needs are basically completed. Of course, everyone can do some optimizations on the machine ~ code !

summary

After clearing this animation, in fact, everyone will find that when we encounter a slightly more complicated animation, we can perform an action disassembly, of course, not including those who have their own graphics cards in their brains, 23333.

I summarized my dismantling:

  • Abstracting the attributes of petals is to find common ground
  • Random distribution of cherry blossoms and optimization
  • The zoom process of petal admission
  • Transparency transformation process of petal admission
  • Gradual perspective of petal admission
  • The petals fly out of the screen after landing, and optimize

Has been posted, it is my sharing this time, I don t know if there are any gains? If you want to gain something, you might as well like it, hehehe . At the same time, everyone is welcome to put forward all kinds of opinions and ideas.