Skip to content

Commit 6db2565

Browse files
update particle sample
1 parent 5b1d43a commit 6db2565

File tree

1 file changed

+89
-42
lines changed

1 file changed

+89
-42
lines changed

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

Lines changed: 89 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.compose.animation.core.Animatable
55
import androidx.compose.animation.core.tween
66
import androidx.compose.foundation.Canvas
77
import androidx.compose.foundation.Image
8+
import androidx.compose.foundation.border
89
import androidx.compose.foundation.clickable
910
import androidx.compose.foundation.gestures.detectTapGestures
1011
import androidx.compose.foundation.layout.Arrangement
@@ -59,21 +60,6 @@ enum class Direction {
5960
Top, TopStart, TopEnd, Bottom, BottomStart, BottomEnd
6061
}
6162

62-
class Particle(var x: Int, var y: Int, val width: Int, val height: Int, val color: Color) {
63-
64-
var alpha: Float = 1f
65-
66-
val center: Offset
67-
get() = Offset(x + width / 2f, y + height / 2f)
68-
69-
var radius: Float = width.coerceAtMost(height) / 2f
70-
71-
val rect: Rect
72-
get() = Rect(
73-
offset = Offset(x.toFloat(), y.toFloat()),
74-
size = Size(width.toFloat(), height.toFloat())
75-
)
76-
}
7763

7864
@Preview
7965
@Composable
@@ -156,6 +142,38 @@ fun GraphicsLayerToImageBitmapSample() {
156142
}
157143
}
158144

145+
data class Particle(
146+
val initialCenter: Offset,
147+
val initialSize: Size,
148+
val color: Color,
149+
val lifeSpan: Float = 1f,
150+
val scale: Float = 1f
151+
) {
152+
153+
val initialRadius: Float = initialSize.width.coerceAtMost(initialSize.height) / 2f
154+
var radius: Float = scale * initialRadius
155+
156+
var alpha: Float = 1f
157+
158+
159+
var center: Offset = initialCenter
160+
161+
val initialRect: Rect
162+
get() = Rect(
163+
offset = Offset(
164+
x = initialCenter.x - initialRadius,
165+
y = initialCenter.y - initialRadius
166+
),
167+
size = initialSize
168+
)
169+
170+
val rect: Rect
171+
get() = Rect(
172+
offset = Offset(center.x - radius, center.y - radius),
173+
size = Size(radius, radius)
174+
)
175+
}
176+
159177
@Preview
160178
@Composable
161179
fun GraphicsLayerToParticles() {
@@ -248,32 +266,42 @@ fun GraphicsLayerToParticles() {
248266
if (particleList.isEmpty().not()) {
249267
Canvas(
250268
modifier = Modifier
269+
.border(1.dp, Color.Blue)
251270
.clickable {
252271
coroutineScope.launch {
253-
animatable.snapTo(1f)
272+
animatable.snapTo(0f)
273+
var currentTime = System.currentTimeMillis()
254274
animatable.animateTo(
255-
targetValue = 0f,
275+
targetValue = 1f,
256276
animationSpec = tween(duration.toInt()),
257277
block = {
278+
258279
val progress = this.value
259-
particleList.forEachIndexed { index, particle ->
260-
particle.x =
261-
(particle.x + 5f * progress * Random.nextFloat()).toInt()
262280

263-
particle.y =
264-
(particle.y - 20f * progress * Random.nextFloat()).toInt()
281+
val timePassed = System.currentTimeMillis() - currentTime
282+
println("Time passed: $timePassed")
265283

284+
particleList.forEach { particle ->
266285

267-
if (animateSize) {
268-
val newRadius =
269-
(particle.radius - (1 - progress) * Random.nextInt(2))
270-
particle.radius = newRadius
286+
val oldCenter = particle.center
287+
val posX = oldCenter.x
288+
val posY = oldCenter.y
271289

272-
}
273-
if (animateAlpha) {
274-
particle.alpha -= (1 - progress) * Random.nextFloat()
275-
.coerceAtMost(.2f)
276-
}
290+
val newX = posX + 5f * progress * Random.nextFloat()
291+
val newY = posY - 5f * progress * Random.nextFloat()
292+
293+
particle.center = Offset(newX, newY)
294+
295+
// if (animateSize) {
296+
// val newRadius =
297+
// particle.radius * (particle.lifeSpan - progress)
298+
// .coerceAtLeast(0f)
299+
// }
300+
//
301+
// if (animateAlpha) {
302+
// particle.alpha -= (1 - progress) * Random.nextFloat()
303+
// .coerceAtMost(.2f)
304+
// }
277305
}
278306
}
279307
)
@@ -300,7 +328,7 @@ fun GraphicsLayerToParticles() {
300328
particleList.forEach { particle: Particle ->
301329

302330
// For debugging borders of particles
303-
// val rect = particle.rect
331+
// val rect = particle.initialRect
304332
// drawRect(
305333
// color = Color.Red,
306334
// topLeft = rect.topLeft,
@@ -310,7 +338,7 @@ fun GraphicsLayerToParticles() {
310338

311339
drawCircle(
312340
color = particle.color.copy(alpha = particle.alpha),
313-
radius = particle.radius * 1f,
341+
radius = particle.radius,
314342
center = particle.center,
315343
)
316344
}
@@ -323,7 +351,7 @@ fun GraphicsLayerToParticles() {
323351
onValueChange = {
324352
particleSize = it
325353
},
326-
valueRange = 2f..50f
354+
valueRange = 2f..100f
327355
)
328356

329357
Text("Duration: ${duration.toInt()}", fontSize = 22.sp)
@@ -370,22 +398,41 @@ fun createParticles(imageBitmap: ImageBitmap, particleSize: Int): List<Particle>
370398
"columnCount: $columnCount, rowCount: $rowCount"
371399
)
372400

401+
val particleRadius = particleSize / 2
402+
403+
// divide image into squares based on particle size
404+
// 110x100x image is divided into 10x10 squares
405+
373406
for (posX in 0 until width step particleSize) {
374407
for (posY in 0 until height step particleSize) {
375408

376-
val pixel: Int = bitmap.getPixel(posX, posY)
377-
val color = Color(pixel)
409+
// Get pixel at center of this pixel rectangle
410+
// If last pixel is out of image get it from end of the width or height
411+
// 🔥x must be < bitmap.width() and y must be < bitmap.height()
412+
val pixelCenterX = (posX + particleRadius).coerceAtMost(width - 1)
413+
val pixelCenterY = (posY + particleRadius).coerceAtMost(height - 1)
414+
415+
// println(
416+
// "posX: $posX, pixelCenterX: $pixelCenterX, " +
417+
// "posY: $posY, pixelCenterY: $pixelCenterY"
418+
// )
378419

379-
println("posX: $posX, posY: $posY, color: $color")
420+
val pixel: Int = bitmap.getPixel(pixelCenterX, pixelCenterY)
421+
val color = Color(pixel)
380422

381423
if (color != Color.Unspecified) {
424+
val size = particleSize * 1f
425+
382426
particleList.add(
383427
Particle(
384-
x = posX,
385-
y = posY,
386-
width = particleSize,
387-
height = particleSize,
388-
color = color
428+
initialCenter = Offset(
429+
x = pixelCenterX.toFloat(),
430+
y = pixelCenterY.toFloat()
431+
),
432+
initialSize = Size(size, size),
433+
color = color,
434+
scale = Random.nextInt(50, 150) / 100f,
435+
lifeSpan = Random.nextFloat().coerceAtLeast(.5f)
389436
)
390437
)
391438
} else {

0 commit comments

Comments
 (0)