@@ -3,6 +3,7 @@ package com.smarttoolfactory.tutorial1_1basics
33import android.graphics.Bitmap
44import android.widget.Toast
55import androidx.compose.animation.core.Animatable
6+ import androidx.compose.animation.core.LinearEasing
67import androidx.compose.animation.core.tween
78import androidx.compose.foundation.Canvas
89import androidx.compose.foundation.Image
@@ -29,6 +30,7 @@ import androidx.compose.runtime.mutableStateListOf
2930import androidx.compose.runtime.mutableStateOf
3031import androidx.compose.runtime.remember
3132import androidx.compose.runtime.setValue
33+ import androidx.compose.ui.Alignment
3234import androidx.compose.ui.Modifier
3335import androidx.compose.ui.composed
3436import androidx.compose.ui.draw.drawWithCache
@@ -38,13 +40,15 @@ import androidx.compose.ui.graphics.Color
3840import androidx.compose.ui.graphics.ImageBitmap
3941import androidx.compose.ui.graphics.asAndroidBitmap
4042import androidx.compose.ui.graphics.asImageBitmap
43+ import androidx.compose.ui.graphics.drawscope.clipRect
4144import androidx.compose.ui.graphics.rememberGraphicsLayer
4245import androidx.compose.ui.platform.LocalContext
4346import androidx.compose.ui.platform.LocalDensity
4447import androidx.compose.ui.res.painterResource
4548import androidx.compose.ui.tooling.preview.Preview
4649import androidx.compose.ui.unit.dp
4750import androidx.compose.ui.unit.sp
51+ import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
4852import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
4953import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.toPx
5054import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
@@ -186,8 +190,9 @@ fun ParticleAnimationSample() {
186190 modifier = Modifier
187191 .fillMaxSize()
188192 .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
191196 ) {
192197
193198 val density = LocalDensity .current
@@ -244,8 +249,8 @@ data class Particle(
244249 val endSize : Size ,
245250 val color : Color ,
246251 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,
249254 val column : Int ,
250255 val row : Int
251256) {
@@ -314,16 +319,14 @@ fun Modifier.explode(
314319
315320 if (animationStatus != AnimationStatus .Idle ) {
316321
317- // val progress = particleState.progress
322+ val animatedProgress = particleState.progress
318323
319324 particleState.particleList.forEach { particle ->
320325
321- if (progress > 0 && progress <= 1f ) {
322- particleState.updateParticle(progress, particle)
323- }
326+ particleState.updateParticle(animatedProgress, particle)
324327
325328 val color = particle.color
326- val radius = particle.currentSize.width / 2f
329+ val radius = particle.currentSize.width * . 7f
327330 val position = particle.currentPosition
328331 val alpha = particle.alpha
329332
@@ -336,6 +339,12 @@ fun Modifier.explode(
336339// alpha = alpha
337340 )
338341 }
342+
343+ // clipRect(
344+ // left = animatedProgress * size.width
345+ // ) {
346+ // this@onDrawWithContent.drawContent()
347+ // }
339348 }
340349 }
341350 }
@@ -352,7 +361,7 @@ fun rememberParticleState(): ParticleState {
352361@Stable
353362class ParticleState internal constructor() {
354363
355- var particleSize by mutableStateOf(200 .dp)
364+ var particleSize by mutableStateOf(2 .dp)
356365
357366 val animatable = Animatable (0f )
358367 val particleList = mutableStateListOf<Particle >()
@@ -397,31 +406,34 @@ class ParticleState internal constructor() {
397406 val pixel: Int = bitmap.getPixel(pixelCenterX, pixelCenterY)
398407 val color = Color (pixel)
399408
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+ // )
406415
407416 if (color != Color .Unspecified ) {
408417
409418 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 )
412421
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
415426
416427 particleList.add(
417428 Particle (
418429 initialCenter = initialCenter,
419430 displacement = Offset (horizontalDisplacement, verticalDisplacement),
420431 initialSize = Size (particleSize.toFloat(), particleSize.toFloat()),
432+ // trajectoryProgressRange = progressStart..progressEnd,
421433 endSize = Size .Zero ,
422434 color = color,
423- column = column,
424- row = row,
435+ column = column / particleSize ,
436+ row = row / particleRadius ,
425437 velocity = velocity,
426438 acceleration = acceleration
427439 )
@@ -432,12 +444,9 @@ class ParticleState internal constructor() {
432444 }
433445 }
434446 }
435-
436- println (" PARTICLE count: ${particleList.size} " )
437-
438447 }
439448
440- fun updateParticle (explosionProgress : Float , particle : Particle ) {
449+ fun updateParticle (progress : Float , particle : Particle ) {
441450
442451 particle.run {
443452 // Trajectory progress translates progress from 0f-1f to
@@ -449,58 +458,65 @@ class ParticleState internal constructor() {
449458 // Each 0.1f change in trajectoryProgress 0.5f total range
450459 // corresponds to 0.2f change of current time
451460
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)
474462
475463 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)
477470
471+ // Set alpha
478472 // 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)
481476
482- val horizontalDisplacement = maxHorizontalDisplacement * trajectoryProgress
477+ // Set position
478+ // acceleration = randomInRange(-5f, 5f)
479+ // velocity = 1f * Random.nextInt(10)
483480
481+ val maxHorizontalDisplacement = displacement.x
482+ val horizontalDisplacement = maxHorizontalDisplacement * trajectoryProgress
484483 val verticalDisplacement =
485484 velocity * currentTime + 0.5f * acceleration * currentTime * currentTime
486-
487- println (" horizontalDisplacement: $horizontalDisplacement , verticalDisplacement: $verticalDisplacement " )
488-
489485 currentPosition = Offset (
490- x = startXPosition + horizontalDisplacement,
491- y = startYPosition - verticalDisplacement
486+ x = initialCenter.x + horizontalDisplacement,
487+ y = initialCenter.y - verticalDisplacement
492488 )
493489 }
494490 }
495491
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+
496512 fun startAnimation () {
497513 animationStatus = AnimationStatus .Initializing
498514 }
499515
500516 suspend fun animate () {
501517 try {
502518 animatable.snapTo(0f )
503- animatable.animateTo(1f , tween(2000 ))
519+ animatable.animateTo(1f , tween(durationMillis = 2000 , easing = LinearEasing ))
504520// animationStatus = AnimationStatus.Idle
505521 } catch (e: CancellationException ) {
506522 println (" FAILED: ${e.message} " )
0 commit comments