Android 气泡自由移动和漩涡

原理:

1.气泡自由移动,就是随机的在气泡的四个方向上(上下左右)移动一个距离。

2.漩涡向内收缩,其实就是使用圆的极坐标方程x = R*cos(theta) + centerX; y = R*sin(theta) + centerY;让R和theta都成为变量。

废话不多说直接上代码:

</pre><pre name="code" class="java">package com.stevens.ui.view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Shader;import android.os.SystemClock;import android.util.AttributeSet;import android.util.Log;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import java.util.ArrayList;import java.util.Random;public class BubbleView extends View implements Runnable {private static final String TAG = "BubbleView";private static final int NORTH = 0;private static final int SOUTH = 1;private static final int EAST = 2;private static final int WEST = 3;private static final int NORTH_WEST = 4;private static final int NORTH_EAST = 5;private static final int SOUTH_WEST = 6;private static final int SOUTH_EAST = 7;private boolean isInitBubble = false;private static final int count = 10;private int height, width;private Rect viewRect;Shader mShasder;private Paint paint;private boolean isRunning = true;private Canvas canvas;private ArrayList<Circle> bubbles = new ArrayList<Circle>();private Random rand = new Random();private boolean isChangeRunning = false;private int frequency = 0;public BubbleView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}public BubbleView(Context context, AttributeSet attrs) {super(context, attrs);init();}public BubbleView(Context context) {super(context);init();}@Overridepublic void run() {while (isRunning) {SystemClock.sleep(10);this.postInvalidate();}}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {switch (keyCode) {case KeyEvent.KEYCODE_DPAD_CENTER:break;case KeyEvent.KEYCODE_BACK:isRunning = false;break;case KeyEvent.KEYCODE_HOME:isRunning = false;default:break;}return super.onKeyDown(keyCode, event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (!isChangeRunning) {isChangeRunning = true;} else {isChangeRunning = false;}break;default:break;}return super.onTouchEvent(event);}@Overrideprotected void onDraw(Canvas canvas) {if (!isInitBubble) {height = this.getHeight();width = this.getWidth();viewRect = new Rect(0, 0, width, height);mShasder = new LinearGradient(0, 0, 0, height, new int[] {Color.GREEN, Color.BLUE}, null, Shader.TileMode.CLAMP);isInitBubble = true;for (int i = 0; i < count; i++) {bubbles.add(new Circle(rand.nextInt(width), rand.nextInt(height),rand.nextInt(30) + 20, rand.nextInt(60) + 40));}}paint.reset();paint.setShader(mShasder);canvas.drawColor(Color.BLACK);canvas.drawRect(viewRect, paint);if (frequency % 5 == 0) {for (Circle c : bubbles) {if (isChangeRunning) {c.runBubble();} else {c.increase();}}}for (Circle c : bubbles) {c.draw(canvas, paint);}frequency++;super.onDraw(canvas);}private void init() {paint = new Paint();this.setFocusable(true);new Thread(this).start();}private class CircleCenterPoint {private float x;private float y;public CircleCenterPoint(float x, float y) {this.x = x;this.y = y;}public float getX() {return x;}public void setX(float x) {this.x = x;}public float getY() {return y;}public void setY(float y) {this.y = y;}public boolean isOutOfView(float r) {boolean isOutView = false;if (x > width – r || x < r || y > height – r || y <= r) {isOutView = true;}return isOutView;}public boolean isInCenterView(float r, float centerViewR) {boolean isOutView = false;if (x > width / 2 – centerViewR && x < width / 2 + centerViewR&& y > height / 2 – centerViewR && y <= height / 2 + centerViewR) {isOutView = true;}return isOutView;}}private class Circle {private CircleCenterPoint center;private float r;private int a;private int aMax;private double distance;private double minDistance;private int type = rand.nextInt(100);private int count = 0;private double delta = 0.1f;private double theta = 0;private boolean isInitDistance = false;private double delta2 = 0.1f;boolean isShouldDisapear = false;public Circle(float x, float y, float r, int a) {center = new CircleCenterPoint(x, y);this.r = r;this.a = a;minDistance = rand.nextInt(100);}public void runBubble() {if (!isInitDistance) {isInitDistance = true;float x = center.getX() – width / 2;float y = center.getY() – height / 2;distance = Math.sqrt((double) (x * x + y * y));if (x > 0) {theta = Math.atan(y / x);} else {theta = Math.atan(y / x) + Math.PI;}}theta = theta + 0.1;distance = getDistance(distance);center.setY((float) (distance * Math.sin(theta)) + height / 2);center.setX((float) (distance * Math.cos(theta)) + width / 2);}public void increase() {if (isInitDistance) {delta = 0.1f;isInitDistance = false;}changeCenterPoint(center, type);if (center.isOutOfView(r) || center.isInCenterView(r, 100f)) {isShouldDisapear = true;}}public void draw(Canvas canvas, Paint paint) {count++;if (count % ((type + 8) * 10) == 0) {type = rand.nextInt(100);}if (isShouldDisapear) {a–;if (a <= 0) {isShouldDisapear = false;center.setX(rand.nextInt(width));center.setY(rand.nextInt(height));r = rand.nextInt(30) + 20;aMax = rand.nextInt(60) + 40;}} else {if (a <= aMax) {a++;} else {aMax = 0;}}paint.reset();paint.setColor(Color.WHITE);paint.setAlpha(a);canvas.drawCircle(center.getX(), center.getY(), r, paint);}private double getDistance(double distance) {double result = distance;delta = delta + 0.1;result = result – delta * delta;if (result < minDistance) {result = minDistance;}return result;}}private void changeCenterPoint(CircleCenterPoint center, int type) {switch (type % 8) {case NORTH:center.setX(center.getX());center.setY(center.getY() – rand.nextInt(4));break;case SOUTH:center.setX(center.getX());center.setY(center.getY() + rand.nextInt(4));break;case EAST:center.setX(center.getX() + rand.nextInt(4));center.setY(center.getY());break;case WEST:center.setX(center.getX() – rand.nextInt(4));center.setY(center.getY());break;case NORTH_WEST:center.setX(center.getX() – rand.nextInt(4));center.setY(center.getY() – rand.nextInt(4));break;case NORTH_EAST:center.setX(center.getX() + rand.nextInt(4));center.setY(center.getY() – rand.nextInt(4));break;case SOUTH_WEST:center.setX(center.getX() + rand.nextInt(4));center.setY(center.getY() + rand.nextInt(4));break;case SOUTH_EAST:center.setX(center.getX() – rand.nextInt(4));center.setY(center.getY() + rand.nextInt(4));break;}}}

注意的问题:

1.这里的theta时候弧度,而非角度(高中的数学都还给数据老师了,很久以后才想明白^-^)。

2.由于直接使用随机值来计算气泡的下一个坐标,会发现气泡总是在一个位置停留很久,不是特别自然,这里让在跑随机在一个方向上多移动一会儿。

,那些曾经以为念念不忘的事情就在我们念念不忘的过程里,被我们遗忘了。

Android 气泡自由移动和漩涡

相关文章:

你感兴趣的文章:

标签云: