Skip to content

Commit 6be9ae1

Browse files
update particle sample
1 parent c4edb49 commit 6be9ae1

File tree

1 file changed

+74
-58
lines changed

1 file changed

+74
-58
lines changed

Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/ParticleAnimations.kt

Lines changed: 74 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.smarttoolfactory.tutorial1_1basics
33
import android.graphics.Bitmap
44
import android.widget.Toast
55
import androidx.compose.animation.core.Animatable
6+
import androidx.compose.animation.core.LinearEasing
67
import androidx.compose.animation.core.tween
78
import androidx.compose.foundation.Canvas
89
import androidx.compose.foundation.Image
@@ -29,6 +30,7 @@ import androidx.compose.runtime.mutableStateListOf
2930
import androidx.compose.runtime.mutableStateOf
3031
import androidx.compose.runtime.remember
3132
import androidx.compose.runtime.setValue
33+
import androidx.compose.ui.Alignment
3234
import androidx.compose.ui.Modifier
3335
import androidx.compose.ui.composed
3436
import androidx.compose.ui.draw.drawWithCache
@@ -38,13 +40,15 @@ import androidx.compose.ui.graphics.Color
3840
import androidx.compose.ui.graphics.ImageBitmap
3941
import androidx.compose.ui.graphics.asAndroidBitmap
4042
import androidx.compose.ui.graphics.asImageBitmap
43+
import androidx.compose.ui.graphics.drawscope.clipRect
4144
import androidx.compose.ui.graphics.rememberGraphicsLayer
4245
import androidx.compose.ui.platform.LocalContext
4346
import androidx.compose.ui.platform.LocalDensity
4447
import androidx.compose.ui.res.painterResource
4548
import androidx.compose.ui.tooling.preview.Preview
4649
import androidx.compose.ui.unit.dp
4750
import androidx.compose.ui.unit.sp
51+
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
4852
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
4953
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.toPx
5054
import 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
353362
class 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

Comments
 (0)