-
Notifications
You must be signed in to change notification settings - Fork 35
/
FallObject.java
302 lines (265 loc) · 9.17 KB
/
FallObject.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
package com.anlia.fallingview;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import java.util.Random;
/**
* Created by anlia on 2017/11/20.
*/
public class FallObject {
private int initX;
private int initY;
private Random random;
private int parentWidth;//父容器宽度
private int parentHeight;//父容器高度
private float objectWidth;//下落物体宽度
private float objectHeight;//下落物体高度
public int initSpeed;//初始下降速度
public int initWindLevel;//初始风力等级
public float presentX;//当前位置X坐标
public float presentY;//当前位置Y坐标
public float presentSpeed;//当前下降速度
private float angle;//物体下落角度
private Bitmap bitmap;
public Builder builder;
private boolean isSpeedRandom;//物体初始下降速度比例是否随机
private boolean isSizeRandom;//物体初始大小比例是否随机
private boolean isWindRandom;//物体初始风向和风力大小比例是否随机
private boolean isWindChange;//物体下落过程中风向和风力是否产生随机变化
private static final int defaultSpeed = 10;//默认下降速度
private static final int defaultWindLevel = 0;//默认风力等级
private static final int defaultWindSpeed = 10;//默认单位风速
private static final float HALF_PI = (float) Math.PI / 2;//π/2
public FallObject(Builder builder, int parentWidth, int parentHeight){
random = new Random();
this.parentWidth = parentWidth;
this.parentHeight = parentHeight;
initX = random.nextInt(parentWidth);
initY = random.nextInt(parentHeight)- parentHeight;
presentX = initX;
presentY = initY;
this.builder = builder;
isSpeedRandom = builder.isSpeedRandom;
isSizeRandom = builder.isSizeRandom;
isWindRandom = builder.isWindRandom;
isWindChange = builder.isWindChange;
initSpeed = builder.initSpeed;
randomSpeed();
randomSize();
randomWind();
}
private FallObject(Builder builder) {
this.builder = builder;
initSpeed = builder.initSpeed;
bitmap = builder.bitmap;
isSpeedRandom = builder.isSpeedRandom;
isSizeRandom = builder.isSizeRandom;
isWindRandom = builder.isWindRandom;
isWindChange = builder.isWindChange;
}
public static final class Builder {
private int initSpeed;
private int initWindLevel;
private Bitmap bitmap;
private boolean isSpeedRandom;
private boolean isSizeRandom;
private boolean isWindRandom;
private boolean isWindChange;
public Builder(Bitmap bitmap) {
this.initSpeed = defaultSpeed;
this.initWindLevel = defaultWindLevel;
this.bitmap = bitmap;
this.isSpeedRandom = false;
this.isSizeRandom = false;
this.isWindRandom = false;
this.isWindChange = false;
}
public Builder(Drawable drawable) {
this.initSpeed = defaultSpeed;
this.initWindLevel = defaultWindLevel;
this.bitmap = drawableToBitmap(drawable);
this.isSpeedRandom = false;
this.isSizeRandom = false;
this.isWindRandom = false;
this.isWindChange = false;
}
/**
* 设置物体的初始下落速度
* @param speed
* @return
*/
public Builder setSpeed(int speed) {
this.initSpeed = speed;
return this;
}
/**
* 设置物体的初始下落速度
* @param speed
* @param isRandomSpeed 物体初始下降速度比例是否随机
* @return
*/
public Builder setSpeed(int speed,boolean isRandomSpeed) {
this.initSpeed = speed;
this.isSpeedRandom = isRandomSpeed;
return this;
}
/**
* 设置物体大小
* @param w
* @param h
* @return
*/
public Builder setSize(int w, int h){
this.bitmap = changeBitmapSize(this.bitmap,w,h);
return this;
}
/**
* 设置物体大小
* @param w
* @param h
* @param isRandomSize 物体初始大小比例是否随机
* @return
*/
public Builder setSize(int w, int h, boolean isRandomSize){
this.bitmap = changeBitmapSize(this.bitmap,w,h);
this.isSizeRandom = isRandomSize;
return this;
}
/**
* 设置风力等级、方向以及随机因素
* @param level 风力等级(绝对值为 5 时效果会比较好),为正时风从左向右吹(物体向X轴正方向偏移),为负时则相反
* @param isWindRandom 物体初始风向和风力大小比例是否随机
* @param isWindChange 在物体下落过程中风的风向和风力是否会产生随机变化
* @return
*/
public Builder setWind(int level,boolean isWindRandom,boolean isWindChange){
this.initWindLevel = level;
this.isWindRandom = isWindRandom;
this.isWindChange = isWindChange;
return this;
}
public FallObject build() {
return new FallObject(this);
}
}
/**
* 绘制物体对象
* @param canvas
*/
public void drawObject(Canvas canvas){
moveObject();
canvas.drawBitmap(bitmap,presentX,presentY,null);
}
/**
* 移动物体对象
*/
private void moveObject(){
moveX();
moveY();
if(presentY>parentHeight || presentX<-bitmap.getWidth() || presentX>parentWidth+bitmap.getWidth()){
reset();
}
}
/**
* X轴上的移动逻辑
*/
private void moveX(){
presentX += defaultWindSpeed * Math.sin(angle);
if(isWindChange){
angle += (float) (random.nextBoolean()?-1:1) * Math.random() * 0.0025;
}
}
/**
* Y轴上的移动逻辑
*/
private void moveY(){
presentY += presentSpeed;
}
/**
* 重置object位置
*/
private void reset(){
presentY = -objectHeight;
randomSpeed();//记得重置时速度也一起重置,这样效果会好很多
randomWind();//记得重置一下初始角度,不然雪花会越下越少(因为角度累加会让雪花越下越偏)
}
/**
* 随机物体初始下落速度
*/
private void randomSpeed(){
if(isSpeedRandom){
presentSpeed = (float)((random.nextInt(3)+1)*0.1+1)* initSpeed;//这些随机数大家可以按自己的需要进行调整
}else {
presentSpeed = initSpeed;
}
}
/**
* 随机物体初始大小比例
*/
private void randomSize(){
if(isSizeRandom){
float r = (random.nextInt(10)+1)*0.1f;
float rW = r * builder.bitmap.getWidth();
float rH = r * builder.bitmap.getHeight();
bitmap = changeBitmapSize(builder.bitmap,(int)rW,(int)rH);
}else {
bitmap = builder.bitmap;
}
objectWidth = bitmap.getWidth();
objectHeight = bitmap.getHeight();
}
/**
* 随机风的风向和风力大小比例,即随机物体初始下落角度
*/
private void randomWind(){
if(isWindRandom){
angle = (float) ((random.nextBoolean()?-1:1) * Math.random() * initWindLevel /50);
}else {
angle = (float) initWindLevel /50;
}
//限制angle的最大最小值
if(angle>HALF_PI){
angle = HALF_PI;
}else if(angle<-HALF_PI){
angle = -HALF_PI;
}
}
/**
* drawable图片资源转bitmap
* @param drawable
* @return
*/
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
/**
* 改变bitmap的大小
* @param bitmap 目标bitmap
* @param newW 目标宽度
* @param newH 目标高度
* @return
*/
public static Bitmap changeBitmapSize(Bitmap bitmap, int newW, int newH) {
int oldW = bitmap.getWidth();
int oldH = bitmap.getHeight();
// 计算缩放比例
float scaleWidth = ((float) newW) / oldW;
float scaleHeight = ((float) newH) / oldH;
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
bitmap = Bitmap.createBitmap(bitmap, 0, 0, oldW, oldH, matrix, true);
return bitmap;
}
}