@@ -3,6 +3,7 @@ package com.smarttoolfactory.tutorial1_1basics
3
3
import android.graphics.Bitmap
4
4
import android.widget.Toast
5
5
import androidx.compose.animation.core.Animatable
6
+ import androidx.compose.animation.core.LinearEasing
6
7
import androidx.compose.animation.core.tween
7
8
import androidx.compose.foundation.Canvas
8
9
import androidx.compose.foundation.Image
@@ -29,6 +30,7 @@ import androidx.compose.runtime.mutableStateListOf
29
30
import androidx.compose.runtime.mutableStateOf
30
31
import androidx.compose.runtime.remember
31
32
import androidx.compose.runtime.setValue
33
+ import androidx.compose.ui.Alignment
32
34
import androidx.compose.ui.Modifier
33
35
import androidx.compose.ui.composed
34
36
import androidx.compose.ui.draw.drawWithCache
@@ -38,13 +40,15 @@ import androidx.compose.ui.graphics.Color
38
40
import androidx.compose.ui.graphics.ImageBitmap
39
41
import androidx.compose.ui.graphics.asAndroidBitmap
40
42
import androidx.compose.ui.graphics.asImageBitmap
43
+ import androidx.compose.ui.graphics.drawscope.clipRect
41
44
import androidx.compose.ui.graphics.rememberGraphicsLayer
42
45
import androidx.compose.ui.platform.LocalContext
43
46
import androidx.compose.ui.platform.LocalDensity
44
47
import androidx.compose.ui.res.painterResource
45
48
import androidx.compose.ui.tooling.preview.Preview
46
49
import androidx.compose.ui.unit.dp
47
50
import androidx.compose.ui.unit.sp
51
+ import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
48
52
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
49
53
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.toPx
50
54
import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
@@ -186,8 +190,9 @@ fun ParticleAnimationSample() {
186
190
modifier = Modifier
187
191
.fillMaxSize()
188
192
.verticalScroll(rememberScrollState())
189
- .padding(horizontal = 16 .dp, vertical = 32 .dp),
190
- verticalArrangement = Arrangement .spacedBy(8 .dp)
193
+ .padding(horizontal = 16 .dp, vertical = 100 .dp),
194
+ verticalArrangement = Arrangement .spacedBy(8 .dp),
195
+ horizontalAlignment = Alignment .CenterHorizontally
191
196
) {
192
197
193
198
val density = LocalDensity .current
@@ -244,8 +249,8 @@ data class Particle(
244
249
val endSize : Size ,
245
250
val color : Color ,
246
251
val trajectoryProgressRange : ClosedRange <Float > = 0f ..1f ,
247
- val velocity : Float = 4 * displacement.y,
248
- val acceleration : Float = -2 * velocity,
252
+ var velocity : Float = 4 * displacement.y,
253
+ var acceleration : Float = -2 * velocity,
249
254
val column : Int ,
250
255
val row : Int
251
256
) {
@@ -314,16 +319,14 @@ fun Modifier.explode(
314
319
315
320
if (animationStatus != AnimationStatus .Idle ) {
316
321
317
- // val progress = particleState.progress
322
+ val animatedProgress = particleState.progress
318
323
319
324
particleState.particleList.forEach { particle ->
320
325
321
- if (progress > 0 && progress <= 1f ) {
322
- particleState.updateParticle(progress, particle)
323
- }
326
+ particleState.updateParticle(animatedProgress, particle)
324
327
325
328
val color = particle.color
326
- val radius = particle.currentSize.width / 2f
329
+ val radius = particle.currentSize.width * . 7f
327
330
val position = particle.currentPosition
328
331
val alpha = particle.alpha
329
332
@@ -336,6 +339,12 @@ fun Modifier.explode(
336
339
// alpha = alpha
337
340
)
338
341
}
342
+
343
+ // clipRect(
344
+ // left = animatedProgress * size.width
345
+ // ) {
346
+ // this@onDrawWithContent.drawContent()
347
+ // }
339
348
}
340
349
}
341
350
}
@@ -352,7 +361,7 @@ fun rememberParticleState(): ParticleState {
352
361
@Stable
353
362
class ParticleState internal constructor() {
354
363
355
- var particleSize by mutableStateOf(200 .dp)
364
+ var particleSize by mutableStateOf(2 .dp)
356
365
357
366
val animatable = Animatable (0f )
358
367
val particleList = mutableStateListOf<Particle >()
@@ -397,31 +406,34 @@ class ParticleState internal constructor() {
397
406
val pixel: Int = bitmap.getPixel(pixelCenterX, pixelCenterY)
398
407
val color = Color (pixel)
399
408
400
- println (
401
- " Column: $column , " +
402
- " row: $row ," +
403
- " pixelCenterX: $pixelCenterX , " +
404
- " pixelCenterY: $pixelCenterY , color: $color "
405
- )
409
+ // println(
410
+ // "Column: $column, " +
411
+ // "row: $row," +
412
+ // " pixelCenterX: $pixelCenterX, " +
413
+ // "pixelCenterY: $pixelCenterY, color: $color"
414
+ // )
406
415
407
416
if (color != Color .Unspecified ) {
408
417
409
418
val initialCenter = Offset (pixelCenterX.toFloat(), pixelCenterY.toFloat())
410
- val horizontalDisplacement = width / 2f
411
- val verticalDisplacement = height / 2f
419
+ val horizontalDisplacement = randomInRange( - 50f , 50f )
420
+ val verticalDisplacement = randomInRange( - height * . 1f , height * . 2f )
412
421
413
- val velocity = 4 * verticalDisplacement
414
- val acceleration = - 2 * velocity
422
+ val velocity = verticalDisplacement
423
+ val acceleration = randomInRange(- 2f , 2f )
424
+ val progressStart = (initialCenter.x / width).coerceAtMost(.7f )
425
+ val progressEnd = progressStart + 0.3f
415
426
416
427
particleList.add(
417
428
Particle (
418
429
initialCenter = initialCenter,
419
430
displacement = Offset (horizontalDisplacement, verticalDisplacement),
420
431
initialSize = Size (particleSize.toFloat(), particleSize.toFloat()),
432
+ // trajectoryProgressRange = progressStart..progressEnd,
421
433
endSize = Size .Zero ,
422
434
color = color,
423
- column = column,
424
- row = row,
435
+ column = column/ particleSize ,
436
+ row = row/ particleRadius ,
425
437
velocity = velocity,
426
438
acceleration = acceleration
427
439
)
@@ -432,12 +444,9 @@ class ParticleState internal constructor() {
432
444
}
433
445
}
434
446
}
435
-
436
- println (" PARTICLE count: ${particleList.size} " )
437
-
438
447
}
439
448
440
- fun updateParticle (explosionProgress : Float , particle : Particle ) {
449
+ fun updateParticle (progress : Float , particle : Particle ) {
441
450
442
451
particle.run {
443
452
// Trajectory progress translates progress from 0f-1f to
@@ -449,58 +458,65 @@ class ParticleState internal constructor() {
449
458
// Each 0.1f change in trajectoryProgress 0.5f total range
450
459
// corresponds to 0.2f change of current time
451
460
452
- val trajectoryProgressStart = trajectoryProgressRange.start
453
- val trajectoryProgressEnd = trajectoryProgressRange.endInclusive
454
-
455
- val startXPosition = initialCenter.x
456
- val startYPosition = initialCenter.x
457
-
458
- val maxHorizontalDisplacement = displacement.x
459
-
460
- trajectoryProgress =
461
- if (explosionProgress < trajectoryProgressStart) {
462
- 0f
463
- } else if (explosionProgress > trajectoryProgressEnd) {
464
- 1f
465
- } else {
466
- scale(
467
- a1 = trajectoryProgressStart,
468
- b1 = trajectoryProgressEnd,
469
- x1 = explosionProgress,
470
- a2 = 0f ,
471
- b2 = 1f
472
- )
473
- }
461
+ setTrajectoryProgress(progress)
474
462
475
463
currentTime = trajectoryProgress
476
- // .mapInRange(0f, 1f, 0f, 1.4f)
464
+ // .mapInRange(0f, 1f, 0f, 1.4f)
465
+
466
+ // Set size
467
+ val width = initialSize.width + (endSize.width - initialSize.width) * currentTime
468
+ val height = initialSize.height + (endSize.height - initialSize.height) * currentTime
469
+ // currentSize = Size(width, height)
477
470
471
+ // Set alpha
478
472
// While trajectory progress is less than 70% have full alpha then slowly cre
479
- // alpha = if (trajectoryProgress < .7f) 1f else
480
- // scale(.7f, 1f, trajectoryProgress, 1f, 0f)
473
+ // alpha = if (trajectoryProgress == 0f) 0f
474
+ // else if (trajectoryProgress < .7f) 1f
475
+ // else scale(.7f, 1f, trajectoryProgress, 1f, 0f)
481
476
482
- val horizontalDisplacement = maxHorizontalDisplacement * trajectoryProgress
477
+ // Set position
478
+ // acceleration = randomInRange(-5f, 5f)
479
+ // velocity = 1f * Random.nextInt(10)
483
480
481
+ val maxHorizontalDisplacement = displacement.x
482
+ val horizontalDisplacement = maxHorizontalDisplacement * trajectoryProgress
484
483
val verticalDisplacement =
485
484
velocity * currentTime + 0.5f * acceleration * currentTime * currentTime
486
-
487
- println (" horizontalDisplacement: $horizontalDisplacement , verticalDisplacement: $verticalDisplacement " )
488
-
489
485
currentPosition = Offset (
490
- x = startXPosition + horizontalDisplacement,
491
- y = startYPosition - verticalDisplacement
486
+ x = initialCenter.x + horizontalDisplacement,
487
+ y = initialCenter.y - verticalDisplacement
492
488
)
493
489
}
494
490
}
495
491
492
+ private fun Particle.setTrajectoryProgress (progress : Float ) {
493
+ val trajectoryProgressStart = trajectoryProgressRange.start
494
+ val trajectoryProgressEnd = trajectoryProgressRange.endInclusive
495
+
496
+ trajectoryProgress =
497
+ if (progress < trajectoryProgressStart) {
498
+ 0f
499
+ } else if (progress > trajectoryProgressEnd) {
500
+ 1f
501
+ } else {
502
+ scale(
503
+ a1 = trajectoryProgressStart,
504
+ b1 = trajectoryProgressEnd,
505
+ x1 = progress,
506
+ a2 = 0f ,
507
+ b2 = 1f
508
+ )
509
+ }
510
+ }
511
+
496
512
fun startAnimation () {
497
513
animationStatus = AnimationStatus .Initializing
498
514
}
499
515
500
516
suspend fun animate () {
501
517
try {
502
518
animatable.snapTo(0f )
503
- animatable.animateTo(1f , tween(2000 ))
519
+ animatable.animateTo(1f , tween(durationMillis = 2000 , easing = LinearEasing ))
504
520
// animationStatus = AnimationStatus.Idle
505
521
} catch (e: CancellationException ) {
506
522
println (" FAILED: ${e.message} " )
0 commit comments