diff --git a/LeonidsExamples/build.gradle b/LeonidsExamples/build.gradle index b10def4..2a56175 100644 --- a/LeonidsExamples/build.gradle +++ b/LeonidsExamples/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 30 + buildToolsVersion "30.0.3" defaultConfig { applicationId "com.plattysoft.leonids.examples" minSdkVersion 11 - targetSdkVersion 25 + targetSdkVersion 30 } buildTypes { @@ -19,7 +19,7 @@ android { } dependencies { - compile project(':LeonidsLib') + implementation project(':LeonidsLib') // compile files('libs/LeonidsLib.jar') // compile 'com.plattysoft.leonids:LeonidsLib:1.3.1' } diff --git a/LeonidsLib/build.gradle b/LeonidsLib/build.gradle index 989d24a..0cece9e 100644 --- a/LeonidsLib/build.gradle +++ b/LeonidsLib/build.gradle @@ -5,12 +5,12 @@ apply plugin: 'com.jfrog.bintray' def versionName = '1.3.2' android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 30 + buildToolsVersion "30.0.3" defaultConfig { minSdkVersion 11 - targetSdkVersion 25 + targetSdkVersion 30 } buildTypes { diff --git a/LeonidsLib/src/main/AndroidManifest.xml b/LeonidsLib/src/main/AndroidManifest.xml index c73d740..683a7e9 100644 --- a/LeonidsLib/src/main/AndroidManifest.xml +++ b/LeonidsLib/src/main/AndroidManifest.xml @@ -4,10 +4,6 @@ android:versionCode="1" android:versionName="1.0" > - - diff --git a/LeonidsLib/src/main/java/com/plattysoft/leonids/ParticleSystem.java b/LeonidsLib/src/main/java/com/plattysoft/leonids/ParticleSystem.java index 2be0442..0bc3269 100644 --- a/LeonidsLib/src/main/java/com/plattysoft/leonids/ParticleSystem.java +++ b/LeonidsLib/src/main/java/com/plattysoft/leonids/ParticleSystem.java @@ -8,9 +8,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -22,8 +20,8 @@ import com.plattysoft.leonids.initializers.RotationInitializer; import com.plattysoft.leonids.initializers.RotationSpeedInitializer; import com.plattysoft.leonids.initializers.ScaleInitializer; -import com.plattysoft.leonids.initializers.SpeeddByComponentsInitializer; import com.plattysoft.leonids.initializers.SpeedModuleAndRangeInitializer; +import com.plattysoft.leonids.initializers.SpeeddByComponentsInitializer; import com.plattysoft.leonids.modifiers.AlphaModifier; import com.plattysoft.leonids.modifiers.ParticleModifier; @@ -36,35 +34,35 @@ public class ParticleSystem { - private static long TIMER_TASK_INTERVAL = 33; // Default 30fps - private ViewGroup mParentView; - private int mMaxParticles; - private Random mRandom; + private static long TIMER_TASK_INTERVAL = 33; // Default 30fps + private ViewGroup mParentView; + private int mMaxParticles; + private Random mRandom; - private ParticleField mDrawingView; + private ParticleField mDrawingView; - private ArrayList mParticles; - private final ArrayList mActiveParticles = new ArrayList<>(); - private long mTimeToLive; - private long mCurrentTime = 0; + private ArrayList mParticles; + private final ArrayList mActiveParticles = new ArrayList<>(); + private long mTimeToLive; + private long mCurrentTime = 0; - private float mParticlesPerMillisecond; - private int mActivatedParticles; - private long mEmittingTime; + private float mParticlesPerMillisecond; + private int mActivatedParticles; + private long mEmittingTime; - private List mModifiers; - private List mInitializers; - private ValueAnimator mAnimator; - private Timer mTimer; + private List mModifiers; + private List mInitializers; + private ValueAnimator mAnimator; + private Timer mTimer; private final ParticleTimerTask mTimerTask = new ParticleTimerTask(this); - private float mDpToPxScale; - private int[] mParentLocation; + private float mDpToPxScale; + private int[] mParentLocation; - private int mEmitterXMin; - private int mEmitterXMax; - private int mEmitterYMin; - private int mEmitterYMax; + private int mEmitterXMin; + private int mEmitterXMax; + private int mEmitterYMin; + private int mEmitterYMax; private static class ParticleTimerTask extends TimerTask { @@ -76,7 +74,7 @@ public ParticleTimerTask(ParticleSystem ps) { @Override public void run() { - if(mPs.get() != null) { + if (mPs.get() != null) { ParticleSystem ps = mPs.get(); ps.onUpdate(ps.mCurrentTime); ps.mCurrentTime += TIMER_TASK_INTERVAL; @@ -84,80 +82,76 @@ public void run() { } } - private ParticleSystem(ViewGroup parentView, int maxParticles, long timeToLive) { - mRandom = new Random(); - mParentLocation = new int[2]; - - setParentViewGroup(parentView); - - mModifiers = new ArrayList<>(); - mInitializers = new ArrayList<>(); - - mMaxParticles = maxParticles; - // Create the particles - - mParticles = new ArrayList<>(); - mTimeToLive = timeToLive; - - DisplayMetrics displayMetrics = parentView.getContext().getResources().getDisplayMetrics(); - mDpToPxScale = (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT); - } - - /** - * Creates a particle system with the given parameters - * - * @param parentView The parent view group - * @param drawable The drawable to use as a particle - * @param maxParticles The maximum number of particles - * @param timeToLive The time to live for the particles - */ - public ParticleSystem(ViewGroup parentView, int maxParticles, Drawable drawable, long timeToLive) { - this(parentView, maxParticles, timeToLive); - - if (drawable instanceof AnimationDrawable) { - AnimationDrawable animation = (AnimationDrawable) drawable; - for (int i=0; i(); + mInitializers = new ArrayList<>(); + + mMaxParticles = maxParticles; + // Create the particles + + mParticles = new ArrayList<>(); + mTimeToLive = timeToLive; + + mDpToPxScale = parentView.getResources().getDisplayMetrics().density; + } /** * Creates a particle system with the given parameters * - * @param a The parent activity + * @param parentView The parent view group + * @param drawable The drawable to use as a particle * @param maxParticles The maximum number of particles + * @param timeToLive The time to live for the particles + */ + public ParticleSystem(ViewGroup parentView, int maxParticles, Drawable drawable, long timeToLive, int dpWidth, int dpHeight) { + this(parentView, maxParticles, timeToLive); + + if (drawable instanceof AnimationDrawable) { + AnimationDrawable animation = (AnimationDrawable) drawable; + for (int i = 0; i < mMaxParticles; i++) { + mParticles.add(new AnimatedParticle(animation)); + } + } else { + Bitmap bitmap = null; +// if (drawable instanceof BitmapDrawable) { +// bitmap = ((BitmapDrawable) drawable).getBitmap(); +// } else { + bitmap = Bitmap.createBitmap((int) dpToPx(dpWidth), (int) dpToPx(dpHeight), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); +// } + for (int i = 0; i < mMaxParticles; i++) { + mParticles.add(new Particle(bitmap)); + } + } + } + + /** + * Creates a particle system with the given parameters + * + * @param a The parent activity + * @param maxParticles The maximum number of particles * @param drawableRedId The drawable resource to use as particle (supports Bitmaps and Animations) - * @param timeToLive The time to live for the particles - * @param parentViewId The view Id for the parent of the particle system + * @param timeToLive The time to live for the particles + */ + public ParticleSystem(Activity a, int maxParticles, int drawableRedId, long timeToLive) { + this(a, maxParticles, a.getResources().getDrawable(drawableRedId), timeToLive, android.R.id.content); + } + + /** + * Creates a particle system with the given parameters + * + * @param a The parent activity + * @param maxParticles The maximum number of particles + * @param drawableRedId The drawable resource to use as particle (supports Bitmaps and Animations) + * @param timeToLive The time to live for the particles + * @param parentViewId The view Id for the parent of the particle system */ public ParticleSystem(Activity a, int maxParticles, int drawableRedId, long timeToLive, int parentViewId) { this(a, maxParticles, a.getResources().getDrawable(drawableRedId), timeToLive, parentViewId); @@ -166,587 +160,615 @@ public ParticleSystem(Activity a, int maxParticles, int drawableRedId, long time /** * Utility constructor that receives a Drawable * - * @param a The parent activity + * @param a The parent activity * @param maxParticles The maximum number of particles - * @param drawable The drawable to use as particle (supports Bitmaps and Animations) - * @param timeToLive The time to live for the particles + * @param drawable The drawable to use as particle (supports Bitmaps and Animations) + * @param timeToLive The time to live for the particles */ public ParticleSystem(Activity a, int maxParticles, Drawable drawable, long timeToLive) { this(a, maxParticles, drawable, timeToLive, android.R.id.content); } - /** - * Utility constructor that receives a Drawable - * - * @param a The parent activity - * @param maxParticles The maximum number of particles - * @param drawable The drawable to use as particle (supports Bitmaps and Animations) - * @param timeToLive The time to live for the particles + + /** + * Utility constructor that receives a Drawable + * + * @param a The parent activity + * @param maxParticles The maximum number of particles + * @param drawable The drawable to use as particle (supports Bitmaps and Animations) + * @param timeToLive The time to live for the particles * @param parentViewId The view Id for the parent of the particle system - */ - public ParticleSystem(Activity a, int maxParticles, Drawable drawable, long timeToLive, int parentViewId) { - this((ViewGroup) a.findViewById(parentViewId), maxParticles, drawable, timeToLive); - } + */ + public ParticleSystem(Activity a, int maxParticles, Drawable drawable, long timeToLive, int parentViewId) { + this((ViewGroup) a.findViewById(parentViewId), maxParticles, drawable, timeToLive, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + } - public float dpToPx(float dp) { - return dp * mDpToPxScale; - } + public float dpToPx(float dp) { + return dp * mDpToPxScale; + } /** * Utility constructor that receives a Bitmap * - * @param a The parent activity + * @param a The parent activity * @param maxParticles The maximum number of particles - * @param bitmap The bitmap to use as particle - * @param timeToLive The time to live for the particles + * @param bitmap The bitmap to use as particle + * @param timeToLive The time to live for the particles */ public ParticleSystem(Activity a, int maxParticles, Bitmap bitmap, long timeToLive) { this(a, maxParticles, bitmap, timeToLive, android.R.id.content); } - /** - * Utility constructor that receives a Bitmap - * - * @param a The parent activity - * @param maxParticles The maximum number of particles - * @param bitmap The bitmap to use as particle - * @param timeToLive The time to live for the particles + + /** + * Utility constructor that receives a Bitmap + * + * @param a The parent activity + * @param maxParticles The maximum number of particles + * @param bitmap The bitmap to use as particle + * @param timeToLive The time to live for the particles * @param parentViewId The view Id for the parent of the particle system - */ - public ParticleSystem(Activity a, int maxParticles, Bitmap bitmap, long timeToLive, int parentViewId) { - this((ViewGroup) a.findViewById(parentViewId), maxParticles, timeToLive); - for (int i=0; iALL ParticleSystems - * - * @param fps the desired frames per second - */ - public static void setFPS(double fps) { - TIMER_TASK_INTERVAL = Math.round(1000 / fps); - } - - /** - * Adds a modifier to the Particle system, it will be executed on each update. - * - * @param modifier modifier to be added to the ParticleSystem - */ - public ParticleSystem addModifier(ParticleModifier modifier) { - mModifiers.add(modifier); - return this; - } - - public ParticleSystem setSpeedRange(float speedMin, float speedMax) { - mInitializers.add(new SpeedModuleAndRangeInitializer(dpToPx(speedMin), dpToPx(speedMax), 0, 360)); - return this; - } + */ + public ParticleSystem(Activity a, int maxParticles, AnimationDrawable animation, long timeToLive, int parentViewId) { + this((ViewGroup) a.findViewById(parentViewId), maxParticles, timeToLive); + // Create the particles + for (int i = 0; i < mMaxParticles; i++) { + mParticles.add(new AnimatedParticle(animation)); + } + } + + /** + * Sets the frames per second of ALL ParticleSystems + * + * @param fps the desired frames per second + */ + public static void setFPS(double fps) { + TIMER_TASK_INTERVAL = Math.round(1000 / fps); + } + + /** + * Adds a modifier to the Particle system, it will be executed on each update. + * + * @param modifier modifier to be added to the ParticleSystem + */ + public ParticleSystem addModifier(ParticleModifier modifier) { + mModifiers.add(modifier); + return this; + } + + public ParticleSystem setSpeedRange(float speedMin, float speedMax) { + mInitializers.add(new SpeedModuleAndRangeInitializer(dpToPx(speedMin), dpToPx(speedMax), 0, 360)); + return this; + } /** * Initializes the speed range and angle range of emitted particles. Angles are in degrees * and non negative: * 0 meaning to the right, 90 to the bottom,... in clockwise orientation. Speed is non - * negative and is described in pixels per millisecond. + * negative and is described in pixels per millisecond. + * * @param speedMin The minimum speed to emit particles. * @param speedMax The maximum speed to emit particles. * @param minAngle The minimum angle to emit particles in degrees. * @param maxAngle The maximum angle to emit particles in degrees. * @return This. */ - public ParticleSystem setSpeedModuleAndAngleRange(float speedMin, float speedMax, int minAngle, int maxAngle) { + public ParticleSystem setSpeedModuleAndAngleRange(float speedMin, float speedMax, int minAngle, int maxAngle) { // else emitting from top (270°) to bottom (90°) range would not be possible if someone // entered minAngle = 270 and maxAngle=90 since the module would swap the values while (maxAngle < minAngle) { maxAngle += 360; } - mInitializers.add(new SpeedModuleAndRangeInitializer(dpToPx(speedMin), dpToPx(speedMax), minAngle, maxAngle)); - return this; - } + mInitializers.add(new SpeedModuleAndRangeInitializer(dpToPx(speedMin), dpToPx(speedMax), minAngle, maxAngle)); + return this; + } /** * Initializes the speed components ranges that particles will be emitted. Speeds are * measured in density pixels per millisecond. + * * @param speedMinX The minimum speed in x direction. * @param speedMaxX The maximum speed in x direction. * @param speedMinY The minimum speed in y direction. * @param speedMaxY The maximum speed in y direction. * @return This. */ - public ParticleSystem setSpeedByComponentsRange(float speedMinX, float speedMaxX, float speedMinY, float speedMaxY) { + public ParticleSystem setSpeedByComponentsRange(float speedMinX, float speedMaxX, float speedMinY, float speedMaxY) { mInitializers.add(new SpeeddByComponentsInitializer(dpToPx(speedMinX), dpToPx(speedMaxX), - dpToPx(speedMinY), dpToPx(speedMaxY))); - return this; - } + dpToPx(speedMinY), dpToPx(speedMaxY))); + return this; + } /** * Initializes the initial rotation range of emitted particles. The rotation angle is * measured in degrees with 0° being no rotation at all and 90° tilting the image to the right. + * * @param minAngle The minimum tilt angle. * @param maxAngle The maximum tilt angle. * @return This. */ - public ParticleSystem setInitialRotationRange(int minAngle, int maxAngle) { - mInitializers.add(new RotationInitializer(minAngle, maxAngle)); - return this; - } + public ParticleSystem setInitialRotationRange(int minAngle, int maxAngle) { + mInitializers.add(new RotationInitializer(minAngle, maxAngle)); + return this; + } /** * Initializes the scale range of emitted particles. Will scale the images around their * center multiplied with the given scaling factor. + * * @param minScale The minimum scaling factor * @param maxScale The maximum scaling factor. * @return This. */ - public ParticleSystem setScaleRange(float minScale, float maxScale) { - mInitializers.add(new ScaleInitializer(minScale, maxScale)); - return this; - } + public ParticleSystem setScaleRange(float minScale, float maxScale) { + mInitializers.add(new ScaleInitializer(minScale, maxScale)); + return this; + } /** * Initializes the rotation speed of emitted particles. Rotation speed is measured in degrees * per second. + * * @param rotationSpeed The rotation speed. * @return This. */ - public ParticleSystem setRotationSpeed(float rotationSpeed) { + public ParticleSystem setRotationSpeed(float rotationSpeed) { mInitializers.add(new RotationSpeedInitializer(rotationSpeed, rotationSpeed)); - return this; - } + return this; + } /** * Initializes the rotation speed range for emitted particles. The rotation speed is measured * in degrees per second and can be positive or negative. + * * @param minRotationSpeed The minimum rotation speed. * @param maxRotationSpeed The maximum rotation speed. * @return This. */ - public ParticleSystem setRotationSpeedRange(float minRotationSpeed, float maxRotationSpeed) { + public ParticleSystem setRotationSpeedRange(float minRotationSpeed, float maxRotationSpeed) { mInitializers.add(new RotationSpeedInitializer(minRotationSpeed, maxRotationSpeed)); - return this; - } + return this; + } /** * Initializes the acceleration range and angle range of emitted particles. The acceleration * components in x and y direction are controlled by the acceleration angle. The acceleration * is measured in density pixels per square millisecond. The angle is measured in degrees * with 0° pointing to the right and going clockwise. + * * @param minAcceleration * @param maxAcceleration * @param minAngle * @param maxAngle * @return */ - public ParticleSystem setAccelerationModuleAndAndAngleRange(float minAcceleration, float maxAcceleration, int minAngle, int maxAngle) { + public ParticleSystem setAccelerationModuleAndAndAngleRange(float minAcceleration, float maxAcceleration, int minAngle, int maxAngle) { mInitializers.add(new AccelerationInitializer(dpToPx(minAcceleration), dpToPx(maxAcceleration), - minAngle, maxAngle)); - return this; - } - - /** - * Adds a custom initializer for emitted particles. The most common use case is the ability to - * update the initializer in real-time instead of adding new ones ontop of the existing one. - * @param initializer The non-null initializer to add. - * @return This. - */ - public ParticleSystem addInitializer(ParticleInitializer initializer) { - if (initializer != null) { - mInitializers.add(initializer); - } - return this; - } + minAngle, maxAngle)); + return this; + } + + /** + * Adds a custom initializer for emitted particles. The most common use case is the ability to + * update the initializer in real-time instead of adding new ones ontop of the existing one. + * + * @param initializer The non-null initializer to add. + * @return This. + */ + public ParticleSystem addInitializer(ParticleInitializer initializer) { + if (initializer != null) { + mInitializers.add(initializer); + } + return this; + } /** * Initializes the acceleration for emitted particles with the given angle. Acceleration is * measured in pixels per square millisecond. The angle is measured in degrees with 0° * meaning to the right and orientation being clockwise. The angle controls the acceleration * direction. + * * @param acceleration The acceleration. - * @param angle The acceleration direction. + * @param angle The acceleration direction. * @return This. */ - public ParticleSystem setAcceleration(float acceleration, int angle) { + public ParticleSystem setAcceleration(float acceleration, int angle) { mInitializers.add(new AccelerationInitializer(acceleration, acceleration, angle, angle)); - return this; - } + return this; + } /** * Initializes the parent view group. This needs to be done before any other configuration or * emitting is done. Drawing will be done to a child that is added to this view. So this view * needs to allow displaying an arbitrary sized view on top of its other content. + * * @param viewGroup The view group to use. * @return This. */ - public ParticleSystem setParentViewGroup(ViewGroup viewGroup) { - mParentView = viewGroup; + public ParticleSystem setParentViewGroup(ViewGroup viewGroup) { + mParentView = viewGroup; if (mParentView != null) { mParentView.getLocationInWindow(mParentLocation); } - return this; - } - - public ParticleSystem setStartTime(long time) { - mCurrentTime = time; - return this; - } - - /** - * Configures a fade out for the particles when they disappear - * - * @param milisecondsBeforeEnd fade out duration in milliseconds - * @param interpolator the interpolator for the fade out (default is linear) - */ - public ParticleSystem setFadeOut(long milisecondsBeforeEnd, Interpolator interpolator) { - mModifiers.add(new AlphaModifier(255, 0, mTimeToLive-milisecondsBeforeEnd, mTimeToLive, interpolator)); - return this; - } - - /** - * Configures a fade out for the particles when they disappear - * - * @param duration fade out duration in milliseconds - */ - public ParticleSystem setFadeOut(long duration) { - return setFadeOut(duration, new LinearInterpolator()); - } - - /** - * Starts emitting particles from a specific view. If at some point the number goes over the amount of particles availabe on create - * no new particles will be created - * - * @param emitter View from which center the particles will be emited - * @param gravity Which position among the view the emission takes place - * @param particlesPerSecond Number of particles per second that will be emited (evenly distributed) - * @param emittingTime time the emitter will be emitting particles - */ - public void emitWithGravity (View emitter, int gravity, int particlesPerSecond, int emittingTime) { - // Setup emitter - configureEmitter(emitter, gravity); - startEmitting(particlesPerSecond, emittingTime); - } - - /** - * Starts emitting particles from a specific view. If at some point the number goes over the amount of particles availabe on create - * no new particles will be created - * - * @param emitter View from which center the particles will be emited - * @param particlesPerSecond Number of particles per second that will be emited (evenly distributed) - * @param emittingTime time the emitter will be emitting particles - */ - public void emit (View emitter, int particlesPerSecond, int emittingTime) { - emitWithGravity(emitter, Gravity.CENTER, particlesPerSecond, emittingTime); - } - - /** - * Starts emitting particles from a specific view. If at some point the number goes over the amount of particles availabe on create - * no new particles will be created - * - * @param emitter View from which center the particles will be emited - * @param particlesPerSecond Number of particles per second that will be emited (evenly distributed) - */ - public void emit (View emitter, int particlesPerSecond) { - // Setup emitter - emitWithGravity(emitter, Gravity.CENTER, particlesPerSecond); - } - - /** - * Starts emitting particles from a specific view. If at some point the number goes over the amount of particles availabe on create - * no new particles will be created - * - * @param emitter View from which center the particles will be emited - * @param gravity Which position among the view the emission takes place - * @param particlesPerSecond Number of particles per second that will be emited (evenly distributed) - */ - public void emitWithGravity (View emitter, int gravity, int particlesPerSecond) { - // Setup emitter - configureEmitter(emitter, gravity); - startEmitting(particlesPerSecond); - } - - private void startEmitting(int particlesPerSecond) { - mActivatedParticles = 0; - mParticlesPerMillisecond = particlesPerSecond/1000f; - // Add a full size view to the parent view - mDrawingView = new ParticleField(mParentView.getContext()); - mParentView.addView(mDrawingView); - mEmittingTime = -1; // Meaning infinite - mDrawingView.setParticles (mActiveParticles); - updateParticlesBeforeStartTime(particlesPerSecond); - mTimer = new Timer(); - mTimer.schedule(mTimerTask, 0, TIMER_TASK_INTERVAL); - } - - public void emit(int emitterX, int emitterY, int particlesPerSecond, int emittingTime) { - configureEmitter(emitterX, emitterY); - startEmitting(particlesPerSecond, emittingTime); - } - - private void configureEmitter(int emitterX, int emitterY) { - // We configure the emitter based on the window location to fix the offset of action bar if present - mEmitterXMin = emitterX - mParentLocation[0]; - mEmitterXMax = mEmitterXMin; - mEmitterYMin = emitterY - mParentLocation[1]; - mEmitterYMax = mEmitterYMin; - } - - private void startEmitting(int particlesPerSecond, int emittingTime) { - mActivatedParticles = 0; - mParticlesPerMillisecond = particlesPerSecond/1000f; - // Add a full size view to the parent view - mDrawingView = new ParticleField(mParentView.getContext()); - mParentView.addView(mDrawingView); - - mDrawingView.setParticles (mActiveParticles); - updateParticlesBeforeStartTime(particlesPerSecond); - mEmittingTime = emittingTime; - startAnimator(new LinearInterpolator(), emittingTime + mTimeToLive); - } - - public void emit (int emitterX, int emitterY, int particlesPerSecond) { - configureEmitter(emitterX, emitterY); - startEmitting(particlesPerSecond); - } - - - public void updateEmitPoint (int emitterX, int emitterY) { - configureEmitter(emitterX, emitterY); - } - - public void updateEmitPoint (View emitter, int gravity) { - configureEmitter(emitter, gravity); - } - - /** - * Launches particles in one Shot - * - * @param emitter View from which center the particles will be emited - * @param numParticles number of particles launched on the one shot - */ - public void oneShot(View emitter, int numParticles) { - oneShot(emitter, numParticles, new LinearInterpolator()); - } - - /** - * Launches particles in one Shot using a special Interpolator - * - * @param emitter View from which center the particles will be emited - * @param numParticles number of particles launched on the one shot - * @param interpolator the interpolator for the time - */ - public void oneShot(View emitter, int numParticles, Interpolator interpolator) { - configureEmitter(emitter, Gravity.CENTER); - mActivatedParticles = 0; - mEmittingTime = mTimeToLive; - // We create particles based in the parameters - for (int i=0; i 0 && miliseconds < mEmittingTime)|| mEmittingTime == -1) && // This point should emit - !mParticles.isEmpty() && // We have particles in the pool - mActivatedParticles < mParticlesPerMillisecond *miliseconds) { // and we are under the number of particles that should be launched - // Activate a new particle - activateParticle(miliseconds); - } - synchronized(mActiveParticles) { - for (int i = 0; i < mActiveParticles.size(); i++) { - boolean active = mActiveParticles.get(i).update(miliseconds); - if (!active) { - Particle p = mActiveParticles.remove(i); - i--; // Needed to keep the index at the right position - mParticles.add(p); - } - } - } - mDrawingView.postInvalidate(); - } - - private void cleanupAnimation() { - mParentView.removeView(mDrawingView); - mDrawingView = null; - mParentView.postInvalidate(); - mParticles.addAll(mActiveParticles); - } - - /** - * Stops emitting new particles, but will draw the existing ones until their timeToLive expire - * For an cancellation and stop drawing of the particles, use cancel instead. - */ - public void stopEmitting () { - // The time to be emitting is the current time (as if it was a time-limited emitter - mEmittingTime = mCurrentTime; - } - - /** - * Cancels the particle system and all the animations. - * To stop emitting but animate until the end, use stopEmitting instead. - */ - public void cancel() { - if (mAnimator != null && mAnimator.isRunning()) { - mAnimator.cancel(); - } - if (mTimer != null) { - mTimer.cancel(); - mTimer.purge(); - cleanupAnimation(); - } - } - - private void updateParticlesBeforeStartTime(int particlesPerSecond) { - if (particlesPerSecond == 0) { - return; - } - long currentTimeInMs = mCurrentTime / 1000; - long framesCount = currentTimeInMs / particlesPerSecond; - if (framesCount == 0) { - return; - } - long frameTimeInMs = mCurrentTime / framesCount; - for (int i = 1; i <= framesCount; i++) { - onUpdate(frameTimeInMs * i + 1); - } - } + mAnimator.setInterpolator(interpolator); + mAnimator.start(); + } + + private void configureEmitter(View emitter, int gravity) { + // It works with an emision range + int[] location = new int[2]; + emitter.getLocationInWindow(location); + + // Check horizontal gravity and set range + if (hasGravity(gravity, Gravity.LEFT)) { + mEmitterXMin = location[0] - mParentLocation[0]; + mEmitterXMax = mEmitterXMin; + } else if (hasGravity(gravity, Gravity.RIGHT)) { + mEmitterXMin = location[0] + emitter.getWidth() - mParentLocation[0]; + mEmitterXMax = mEmitterXMin; + } else if (hasGravity(gravity, Gravity.CENTER_HORIZONTAL)) { + mEmitterXMin = location[0] + emitter.getWidth() / 2 - mParentLocation[0]; + mEmitterXMax = mEmitterXMin; + } else { + // All the range + mEmitterXMin = location[0] - mParentLocation[0]; + mEmitterXMax = location[0] + emitter.getWidth() - mParentLocation[0]; + } + + // Now, vertical gravity and range + if (hasGravity(gravity, Gravity.TOP)) { + mEmitterYMin = location[1] - mParentLocation[1]; + mEmitterYMax = mEmitterYMin; + } else if (hasGravity(gravity, Gravity.BOTTOM)) { + mEmitterYMin = location[1] + emitter.getHeight() - mParentLocation[1]; + mEmitterYMax = mEmitterYMin; + } else if (hasGravity(gravity, Gravity.CENTER_VERTICAL)) { + mEmitterYMin = location[1] + emitter.getHeight() / 2 - mParentLocation[1]; + mEmitterYMax = mEmitterYMin; + } else { + // All the range + mEmitterYMin = location[1] - mParentLocation[1]; + mEmitterYMax = location[1] + emitter.getHeight() - mParentLocation[1]; + } + } + + private boolean hasGravity(int gravity, int gravityToCheck) { + return (gravity & gravityToCheck) == gravityToCheck; + } + + private void activateParticle(long delay) { + Particle p = mParticles.remove(0); + p.init(); + // Initialization goes before configuration, scale is required before can be configured properly + for (int i = 0; i < mInitializers.size(); i++) { + mInitializers.get(i).initParticle(p, mRandom); + } + int particleX = getFromRange(mEmitterXMin, mEmitterXMax); + int particleY = getFromRange(mEmitterYMin, mEmitterYMax); + p.configure(mTimeToLive, particleX, particleY); + p.activate(delay, mModifiers); + mActiveParticles.add(p); + mActivatedParticles++; + } + + private int getFromRange(int minValue, int maxValue) { + if (minValue == maxValue) { + return minValue; + } + if (minValue < maxValue) { + return mRandom.nextInt(maxValue - minValue) + minValue; + } else { + return mRandom.nextInt(minValue - maxValue) + maxValue; + } + } + + private void onUpdate(long miliseconds) { + while (((mEmittingTime > 0 && miliseconds < mEmittingTime) || mEmittingTime == -1) && // This point should emit + !mParticles.isEmpty() && // We have particles in the pool + mActivatedParticles < mParticlesPerMillisecond * miliseconds) { // and we are under the number of particles that should be launched + // Activate a new particle + activateParticle(miliseconds); + } + synchronized (mActiveParticles) { + for (int i = 0; i < mActiveParticles.size(); i++) { + boolean active = mActiveParticles.get(i).update(miliseconds); + if (!active) { + Particle p = mActiveParticles.remove(i); + i--; // Needed to keep the index at the right position + mParticles.add(p); + } + } + } + mDrawingView.postInvalidate(); + } + + private void cleanupAnimation() { + mParentView.removeView(mDrawingView); + mDrawingView = null; + mParentView.postInvalidate(); + mParticles.addAll(mActiveParticles); + } + + /** + * Stops emitting new particles, but will draw the existing ones until their timeToLive expire + * For an cancellation and stop drawing of the particles, use cancel instead. + */ + public void stopEmitting() { + // The time to be emitting is the current time (as if it was a time-limited emitter + mEmittingTime = mCurrentTime; + } + + /** + * Cancels the particle system and all the animations. + * To stop emitting but animate until the end, use stopEmitting instead. + */ + public void cancel() { + if (mAnimator != null && mAnimator.isRunning()) { + mAnimator.cancel(); + } + if (mTimer != null) { + mTimer.cancel(); + mTimer.purge(); + cleanupAnimation(); + } + } + + private void updateParticlesBeforeStartTime(int particlesPerSecond) { + if (particlesPerSecond == 0) { + return; + } + long currentTimeInMs = mCurrentTime / 1000; + long framesCount = currentTimeInMs / particlesPerSecond; + if (framesCount == 0) { + return; + } + long frameTimeInMs = mCurrentTime / framesCount; + for (int i = 1; i <= framesCount; i++) { + onUpdate(frameTimeInMs * i + 1); + } + } } diff --git a/build.gradle b/build.gradle index 64e7c43..27da725 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,11 @@ buildscript { repositories { jcenter() - mavenCentral() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1' + classpath 'com.android.tools.build:gradle:4.1.2' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1+' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' } } @@ -14,5 +14,6 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1ecd73e..4b277b5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Sep 19 13:36:06 IST 2016 +#Wed Feb 24 09:44:53 EET 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip