“PK creative Spring Festival, I am participating in the” Spring Festival Creative submission contest “, please see: Spring Festival Creative Submission Contest”

This article teaches you how to achieve high performance fireworks particle effects in Canvas. By using Canvas + BitmapShader + GestureDetector technology stack, you can achieve interesting 2D Spring Festival fireworks special effects page. Velocity and acceleration are used to display the model speed changes and the simple animation effect of PVector 2D, etc. Every click on the screen will generate a firework, which will burst into 60~100 fragments when it flies to the top, and there may be thousands of particles updating its position continuously on the same screen. Hope to bring you some fun and interesting things!

demo

The code analysis

First look at the project structure

└─ Fireworks Colorfullview.java - Custom View Firework.java - Build model for firework.java - Particle PContext Pvector.java - Vector classCopy the code

XML code

<? The XML version = "1.0" encoding = "utf-8"? > <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" tools:context="com.example.MainActivity"> <RelativeLayout android:layout_width="200dp" android:layout_height="200dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <ImageView android:id="@+id/iv_text" android:layout_width="130dp" android:layout_height="130dp" android:layout_centerInParent="true" android:background="#EE4D1E" /> <TextView android:id="@+id/text" Android :layout_width="200dp" Android :layout_height="200dp" Android :gravity="center" Android :text=" f" android:textSize="120sp" /> </RelativeLayout> <com.example.ColorfullView android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>Copy the code

Java code

  • Custom ColorfullView uses GestureDetector to handle user input and create a firework at the current location with each click
mGesture = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { fireworks.add(new Firework(e.getX(), e.getY())); ViewCompat.postInvalidateOnAnimation(ColorfullView.this); return true; }});Copy the code
  • The FireWork class contains two attributes, which contain information about the “seeds” before the explosion and the particles emitted after the explosion. Since each particle after the explosion also has the corresponding position and velocity information, these particles can be classified as “seeds” in a FireWork beam. The Particle information is uniformly encapsulated into the Particle Bean class;
ArrayList<Particle> particles; // Particle firework; // The particle before the explosionCopy the code
  • The Particle class has random colors, sizes, and velocities that approximate reality. It also sets the initial position coordinates and radius of the firework seed, and the position of the particles emitted by each firework seed is determined according to the final explosive position of the seed
class Particle { PVector location; PVector velocity; PVector acceleration; float radius; // fireworks seed Particle(float x, float y, float hue) {this.hu = hue; acceleration = new PVector(0, 0); velocity = new PVector(0, PContext.random(-20, -10)); location = new PVector(x, y); seed = true; Life = PContext. Random (555.0 350.0 f, f); this.radius = PContext.random(10, 20); } // fireworks Particle(PVector loc, float hue) {this.hu = hue; acceleration = new PVector(0, 0); velocity = PVector.random2D(); velocity.mult(PContext.random(4, 8)); location = loc.get(); Life = PContext. Random (555.0 350.0 f, f); this.radius = PContext.random(10, 20); }Copy the code
  • Each frame will call FireWork’s Run method, which will constantly call the update and display methods of the current particle in the View onDraw callback; The update method is used to update the velocity, acceleration and position coordinates of each particle, and the display method is used to draw according to the position of the particle.
void run(Canvas canvas, Paint paint) { if (firework ! = null) {firework.applyForce(gravity); firework.update(); firework.display(canvas, paint); if (firework.explode()) { int fragments = (int) random(60, 100); For (int I = 0; i < fragments; i++) { particles.add(new Particle(firework.location, hu)); } firework = null; firstExplode = true; }} else {if (firstExplode) {// explode = false; Canvas. DrawColor (Color. HSVToColor (new float [] {hu, 0.6 f, 0.6 f})); } for (int i = particles.size() - 1; i >= 0; i--) { Particle p = particles.get(i); p.applyForce(gravity); p.update(); p.display(canvas, paint); if (p.isDead()) { particles.remove(i); }}}}Copy the code

Performance optimization

All that’s left is to draw each firework on the canvas, as we usually do

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        for (int i = fireworks.size() - 1; i >= 0; i--) {
            Firework f = fireworks.get(i);
            f.run(canvas, mParticlePaint);
            if (f.done()) {
                fireworks.remove(i);
            }
        }
        //canvas.drawBitmap(canvasBitmap,0, 0, mBitmapPaint);
        if (!fireworks.isEmpty()) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
Copy the code

However, you will find that the performance is terrible, and the frame count plummets to single digits as the number of particles increases, optimized as follows:

@Override protected void onDraw(Canvas canvas) { if (canvasBitmap == null || canvasBitmap.isRecycled()) { canvasBitmap =  Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); bitmapCanvas = new Canvas(canvasBitmap); mBitmapShader = new BitmapShader(canvasBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapPaint.setShader(mBitmapShader); mBitmapPaint.setDither(false); } bitmapCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); for (int i = fireworks.size() - 1; i >= 0; i--) { Firework f = fireworks.get(i); f.run(bitmapCanvas, mParticlePaint); if (f.done()) { fireworks.remove(i); } } canvas.drawPaint(mBitmapPaint); if (! fireworks.isEmpty()) { ViewCompat.postInvalidateOnAnimation(this); }}Copy the code

Write in the last

Here the whole fireworks dynamic effect is completed, due to the limited space, really can not explain every detail in detail, if you have any questions, welcome to the comment area or into the group to ask questions, here in advance to you New Year! I wish you all a smooth work, good health, the whole family hehemeimei and all the best!

❤️/ Thanks for your support /

That is all the content of this sharing. I hope it will help you

Don’t forget to share, like and bookmark your favorite things

Welcome to the public number programmer bus, from byte, shrimp, zhaoyin three brothers, share programming experience, technical dry goods and career planning, help you to avoid detours into the factory.