One, foreword

1. I’ve always wanted to write an article on sports, and now IT’s finally coming out.

2. This is a long, you see the fruit, drinks, peanuts, I believe will give you will eat very happy. 3. The source code of this project is shown in article 1 at the end of the document

Let’s take a look at some of the effects:
1.– Crazy split

2.– Smashed to pieces

3.– Brush overlap XOR

1. Pre-knowledge exposition:

1). What is motion: Visually, an object shows different physical positions on different timelines

2). Displacement = initial displacement + speed * time Velocity = initial velocity + acceleration * time Time, displacement, velocity and acceleration constitute the motion system of modern science

2. Simulation of kinematics using View

1. Time: Constant infinite execution of ValueAnimator —- simulates the time stream, each refresh interval, denoted as: 1U

2. Displacement: The position of the object in the screen pixels —- simulation world, each pixel distance is denoted as :1px 3. Speed (px/U), acceleration (px/U^2) : custom Note: The ideas in this section apply to any language that simulates time and displacement, but the syntax is different, right

3. Test object, encapsulation class:
public class Ball implements Cloneable { public float aX; Public float aY; Public float vX; // speed X public float vY; Public float x; Public float y; Public int color; Public float r; Public Ball clone() {Ball clone = null; try { clone = (Ball) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; }}Copy the code

Section 1: Uniform motion of a body in a straight line:

1. Build test View

It starts with a ball at 0,0, with velocity 10 in the x direction and velocity 0 in the y direction

public class RunBall extends View { private ValueAnimator mAnimator; // Private Ball mBall; // Private Paint mPaint; // Private Point mCoo; Private float defaultR = 20; Private int defaultColor = color.blue; Private float defaultVX = 10; Private float defaultVY = 0; private float defaultVY = 0; Public RunBall(Context Context) {this(Context, null); } public RunBall(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init() { mCoo = new Point(500, 500); MBall = new Ball(); mBall.color = defaultColor; mBall.r = defaultR; mBall.vX = defaultVX; mBall.vY = defaultVY; mBall.a = defaultA; MPaint = new Paint(Paint.ANTI_ALIAS_FLAG); ValueAnimator mAnimator = valueAnimator.offloat (0, 1); // Initialize the time stream. mAnimator.setRepeatCount(-1); mAnimator.setDuration(1000); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { updateBall(); Invalidate (); }}); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mCoo.x, mCoo.y); drawBall(canvas, mBall); canvas.restore(); } /** * draw the ball * @param canvas * @param ball */ private void drawBall(canvas canvas, Ball ball) { mPaint.setColor(ball.color); canvas.drawCircle(ball.x, ball.y, ball.r, mPaint); } /** * updateBall */ private void updateBall() {@override public Boolean onTouchEvent(MotionEvent) event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mAnimator.start(); // Start time stream break; case MotionEvent.ACTION_UP: mAnimator.pause(); // Pause the time stream break; } return true; }}Copy the code

2. Horizontal exercise:

Note: open screen + simulator comparison card, plus into GIF, looks like some cards, real machine running very smooth

RunBall#updateBall: just add (i.e. Displacement = initial displacement + velocity * time, where time is 1U)

private void updateBall() {
    mBall.x += mBall.vX;
}
Copy the code

3. Rebound effect :(x > 400 rebound) :

You just invert the vX velocity on the bounce, which is consistent with reality

private void updateBall() { mBall.x += mBall.vX; if (mBall.x > 400) { mBall.vX = -mBall.vX; }}Copy the code

4. Rebound color, infinite cycle:

/ / private void updateBall() {mball.x += mball.vx; if (mBall.x > 400) { mBall.vX = -mBall.vX; mBall.color = ColUtils.randomRGB(); } if (mball.x < -400) {mball.vx = -mball.vx; mBall.color = ColUtils.randomRGB(); // Change color}}Copy the code

5. Box bounce of the ball:

The translation of the X axis is basically the same as the translation of the Y axis, so I’m not going to talk about that, but let’s see if we change both X and Y, so the velocity is oblique

Let’s define the boundary values for reuse

private float defaultVY = 5; Private float mMaxX = 400; private float mMaxX = 400; Private float mMinX = -400; Private float mMaxY = 300; Private float mMinY = -100; private float mMinY = -100; / / Y minimum valueCopy the code

Now add a change in the Y direction to the updateBall method:

/ / private void updateBall() {mball.x += mball.vx; mBall.y += mBall.vY; if (mBall.x > mMaxX) { mBall.vX = -mBall.vX; mBall.color = ColUtils.randomRGB(); } if (mball.x < mMinX) {mball.vx = -mball.vx; mBall.color = ColUtils.randomRGB(); } if (mball. y > mMaxY) {mball. vY = -mball. vY; mBall.color = ColUtils.randomRGB(); } if (mball.y < mMinY) {mball.vy = -mball.vy; mBall.color = ColUtils.randomRGB(); // Change color}}Copy the code

Yeah, that’s it, that’s it, that’s it, that’s it, that’s it, that’s it, that’s it, that’s it, that’s it


Two, variable speed movement

1. Free fall

First, we simulate the most familiar free-falling body, the acceleration aY = 0.98f, the initial velocity of x and y is 0, and the initial height of y is set to -400

private float defaultR = 20; Private int defaultColor = color.blue; Private float defaultVX = 0; Private float defaultVY = 0; private float defaultVY = 0; Private float defaultAY = 0.98f; Private float mMaxY = 0; private float mMaxY = 0; / / Y maximumCopy the code

So in the updateBall, we dynamically change vY based on our vertical acceleration, aY, but we’re still following the laws of physics after the bounce

Note: You can multiply the rebound by a coefficient as the loss value to better simulate reality

private void updateBall() { mBall.x += mBall.vX; mBall.y += mBall.vY; mBall.vY += mBall.aY; if (mBall.y > mMaxY - mBall.r) { mBall.vY = -mBall.vY; mBall.color = ColUtils.randomRGB(); // Change color}}Copy the code

2. Flat throwing motion + simulated collision loss

A flat throw is a free fall with an initial velocity in the x direction

Modify initial horizontal velocity and collision loss coefficient

private float defaultVX = 15; Private float defaultF = 0.9f; private float defaultF = 0.9f; // Collision lossCopy the code
/ / private void updateBall() {mball.x += mball.vx; mBall.y += mBall.vY; mBall.vY += mBall.aY; if (mBall.x > mMaxX) { mBall.x = mMaxX; mBall.vX = -mBall.vX * defaultF; mBall.color = ColUtils.randomRGB(); } if (mball. x < mMinX) {mball. x = mMinX; mBall.vX = -mBall.vX * defaultF; mBall.color = ColUtils.randomRGB(); } if (mball. y > mMaxY) {mball. y = mMaxY; mBall.vY = -mBall.vY * defaultF; mBall.color = ColUtils.randomRGB(); } if (mball. y < mMinY) {mball. y = mMinY; mBall.vY = -mBall.vY * defaultF; mBall.color = ColUtils.randomRGB(); // Change color}}Copy the code

3. Oblique throwing motion: with initial horizontal and vertical velocity

Modify the initial vertical velocity

private float defaultVY = -12; // Default ball y direction speedCopy the code

5. Circular motion:

Unfortunately, I can’t do the kinematic simulation, but I have to keep the velocity and the acceleration out of the vertical, and the acceleration constant. Let’s see if we can do that in the future

Mark: ValueAnimator default Interpolator is not linear, it looks strange

ValueAnimator mAnimator = valueAnimator.offloat (0, 1); // Initialize the time stream. mAnimator.setRepeatCount(-1); mAnimator.setDuration(4000); mAnimator.setInterpolator(new LinearInterpolator()); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mDeg = (float) animation.getAnimatedValue() * 360; updateBall(); Invalidate (); }}); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mCoo.x, mCoo.y); canvas.rotate(mDeg+90); canvas.drawLine(0, 0, mBall.x, mBall.y, mPaint); drawBall(canvas, mBall); canvas.restore(); }Copy the code

6. The motion of the pendulum:

Also a non-kinematic pendulum, simulated by rotating the canvas:

ValueAnimator mAnimator = valueAnimator.offloat (0, 1); // Initialize the time stream. mAnimator.setRepeatCount(-1); mAnimator.setDuration(2000); mAnimator.setRepeatMode(ValueAnimator.REVERSE); mAnimator.setInterpolator(new LinearInterpolator()); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void OnAnimationUpdate ValueAnimator (animation) {mDeg = (float) animation. GetAnimatedValue () * 360 * 0.5 f; updateBall(); Invalidate (); }});Copy the code

7. The estimator implements the motion of the specified curve equation :(sin here is an example)

/** * Author: Zhang Feng Jiete: <br/> * Time: 2018/11/160016:7:42 <br/> * Email: [email protected]<br/> * Description: */ public class implements TypeEvaluator {@override public Object evaluate(float fraction, float fraction, float fraction) Object startValue, Object endValue) {// Ball startPos = (Ball) startValue; // Ball endPos = (Ball) endValue; Ball Clone = startPos.clone(); clone.x = startPos.x + fraction * (endPos.x - startPos.x); Y = (float) (math.sin (clone. X * math.pi / 180) * 100); // Return the updated point return clone; }}Copy the code
ValueAnimator Ball startBall = new Ball(); StartBall. Color = color.red; startBall.r = 20; Ball endBall = startBall.clone(); X = 1800; endBall.y = 300; = valueAnimator. ofObject(new SinEvaluator(), startBall, endBall); mAnimator.setRepeatCount(-1); mAnimator.setDuration(8000); mAnimator.setRepeatMode(ValueAnimator.REVERSE); mAnimator.setInterpolator(new LinearInterpolator()); mAnimator.addUpdateListener(animation -> { mBall = (Ball) animation.getAnimatedValue(); // Update the ball invalidate(); });Copy the code

Third, effect realization

1. The effect of collision splitting is realized

From drawing a small ball to drawing a collection of small balls, each time the collision adds a reverse ball to the collection

And you can just halve the radius of both of them, which makes sense.

/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2018/11/150015:8:10 <br/> * Email: [email protected]<br/> * Description: Public class RunBall extends View {private ValueAnimator mAnimator; Private List<Ball> mBalls; // Private Paint mPaint; Private Paint mHelpPaint; // Private Point mCoo; Private float defaultR = 80; Private int defaultColor = color.blue; Private float defaultVX = 10; Private float defaultF = 0.95f; Private float defaultVY = 0; Private float defaultAY = 0.5f; private float defaultAY = 0.5f; Private float mMaxX = 600; Private float mMinX = -200; Private float mMaxY = 300; Private float mMinY = -100; private float mMinY = -100; Public RunBall(Context Context) {this(Context, null); } public RunBall(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init() { mCoo = new Point(500, 500); MPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBalls = new ArrayList<>(); Ball ball = initBall(); mBalls.add(ball); mHelpPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mHelpPaint.setColor(Color.BLACK); mHelpPaint.setStyle(Paint.Style.FILL); mHelpPaint.setStrokeWidth(3); ValueAnimator mAnimator = valueAnimator.offloat (0, 1); // Initialize the time stream. mAnimator.setRepeatCount(-1); mAnimator.setDuration(2000); mAnimator.setRepeatMode(ValueAnimator.REVERSE); mAnimator.setInterpolator(new LinearInterpolator()); mAnimator.addUpdateListener(animation -> { updateBall(); Invalidate (); }); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mCoo.x, mCoo.y); drawBalls(canvas, mBalls); canvas.restore(); } /** * Draw ball set ** @param canvas * @param Balls */ private void drawBalls(canvas canvas, List<Ball> balls) { for (Ball ball : balls) { mPaint.setColor(ball.color); canvas.drawCircle(ball.x, ball.y, ball.r, mPaint); }} /** * updateBall */ private void updateBall() {for (int I = 0; i < mBalls.size(); i++) { Ball ball = mBalls.get(i); If (ball.r < 1) {// remove mballs.remove (I); } ball.x += ball.vX; ball.y += ball.vY; ball.vY += ball.aY; ball.vX += ball.aX; if (ball.x > mMaxX) { Ball newBall = ball.clone(); // create a newBall with the same information as the ball newball. r = newball. r / 2; newBall.vX = -newBall.vX; newBall.vY = -newBall.vY; mBalls.add(newBall); ball.x = mMaxX; ball.vX = -ball.vX * defaultF; ball.color = ColUtils.randomRGB(); // Change the color ball.r = ball.r / 2; } if (ball.x < mMinX) { Ball newBall = ball.clone(); newBall.r = newBall.r / 2; newBall.vX = -newBall.vX; newBall.vY = -newBall.vY; mBalls.add(newBall); ball.x = mMinX; ball.vX = -ball.vX * defaultF; ball.color = ColUtils.randomRGB(); ball.r = ball.r / 2; } if (ball.y > mMaxY) { ball.y = mMaxY; ball.vY = -ball.vY * defaultF; ball.color = ColUtils.randomRGB(); } if (ball.y < mMinY) { ball.y = mMinY; ball.vY = -ball.vY * defaultF; ball.color = ColUtils.randomRGB(); } } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mAnimator.start(); break; case MotionEvent.ACTION_UP: // mAnimator.pause(); break; } return true; } private Ball initBall() { Ball mBall = new Ball(); mBall.color = defaultColor; mBall.r = defaultR; mBall.vX = defaultVX; mBall.vY = defaultVY; mBall.aY = defaultAY; mBall.x = 0; mBall.y = 0; return mBall; }}Copy the code

2. Brush overlap XOR test:

Private void initBalls() {for (int I = 0; i < 28; i++) { Ball mBall = new Ball(); mBall.color = ColUtils.randomRGB(); mBall.r = rangeInt(80, 120); mBall.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); mBall.vY = rangeInt(-15, 35); MBall. AY = 0.98 f; mBall.x = 0; mBall.y = 0; mBalls.add(mBall); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Int sc = 0; // Create a layer and show the blending effect on it. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { sc = canvas.saveLayer(new RectF(0, 0, 2500, 2500), null); } mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); Canvas. Translate (McOo.x, McOo.y); drawBalls(canvas, mBalls); canvas.restoreToCount(sc); }Copy the code

3. The collision and rebound of the two balls

Private void initBalls() {for (int I = 0; i < 2; i++) { Ball mBall = new Ball(); mBall.color = Color.RED; mBall.r = 80; mBall.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); mBall.vY = rangeInt(-15, 35); MBall. AY = 0.98 f; mBalls.add(mBall); } mBalls.get(1).x = 300; mBalls.get(1).y = 300; mBalls.get(1).color = Color.BLUE; } distance function between two points / * * * * / public static float disPos2d (float float x1, y1, float x2, float y2) { return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } /** * updateBall */ private void updateBall() {Ball redBall = mballs.get (0); Ball blueBall = mBalls.get(1); X, blueball. x, blueball. y) < 80 * 2) {redball-vx = -redball-vx; redBall.vY = -redBall.vY; blueBall.vX = -blueBall.vX; blueBall.vY = -blueBall.vY; } for (int i = 0; i < mBalls.size(); i++) { Ball ball = mBalls.get(i); ball.x += ball.vX; ball.y += ball.vY; ball.vY += ball.aY; ball.vX += ball.aX; if (ball.x > mMaxX) { ball.x = mMaxX; ball.vX = -ball.vX * defaultF; } if (ball.x < mMinX) { ball.x = mMinX; ball.vX = -ball.vX * defaultF; } if (ball.y > mMaxY) { ball.y = mMaxY; ball.vY = -ball.vY * defaultF; } if (ball.y < mMinY) { ball.y = mMinY; ball.vY = -ball.vY * defaultF; }}}Copy the code

Okay, that’s it. There’s a lot of variation in the motion of the View, and those interested can explore some of it


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1 – making 2018-11-15 Android Native Drawing lets you understand the movement of the View
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books My CSDN Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support