Last active
December 5, 2024 22:24
-
-
Save bentrengrove/c2bdc85c7c4e2eca1905b0da2d5ff810 to your computer and use it in GitHub Desktop.
MatrixText.kt - A Composeable that displays text Matrix style down the screen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private const val MAX_SPEED = 25 | |
private const val MIN_SPEED = 7 | |
private const val MAX_FONT_SIZE = 64f | |
private const val MIN_FONT_SIZE = 24f | |
private val characters = listOf("ジ", "ェ", "ッ", "ト", "パ", "ッ", "ク", "構", "成") | |
private val colors = listOf(0xffcefbe4, 0xff81ec72, 0xff5cd646, 0xff54d13c, 0xff4ccc32, 0xff43c728) | |
@Composable | |
fun MatrixText( | |
stripCount: Int = 25, | |
lettersPerStrip: Int = 20, | |
modifier: Modifier = Modifier | |
) { | |
// Where each strip is in Y | |
// Drive composition with this state | |
val stripY = remember { mutableStateListOf<Int>() } | |
// Where each strip is in X | |
val stripX = remember { IntArray(stripCount).toMutableList() } | |
// The speed of each strip | |
val dY = remember { IntArray(stripCount).toMutableList() } | |
// The font size of each strip | |
val stripFontSize = remember { IntArray(stripCount).toMutableList() } | |
val paint = Paint().asFrameworkPaint().apply { | |
isAntiAlias = true | |
typeface = Typeface.SANS_SERIF | |
} | |
Canvas( | |
modifier | |
.fillMaxSize() | |
.background(Color.Black)) { | |
val width = size.width | |
val height = size.height | |
for (i in 0 until stripCount) { | |
var y = stripY.getOrNull(i) | |
paint.textSize = stripFontSize[i].toFloat() | |
if (y == null || (y > height + (lettersPerStrip * stripFontSize[i]))) { | |
if (y == null) { | |
stripY.add(0) | |
} | |
// Initialise a strip in a random location | |
stripX[i] = (Random.nextFloat() * width).toInt() | |
stripY[i] = -99 // Start off screen | |
dY[i] = ((Random.nextFloat() * MAX_SPEED.dp.value) + MIN_SPEED.dp.value).toInt() | |
stripFontSize[i] = ((Random.nextFloat() * MAX_FONT_SIZE) + MIN_FONT_SIZE).toInt() | |
} else { | |
val x = stripX[i] | |
(0 until lettersPerStrip).forEach { _ -> | |
val randChar = characters.random() | |
paint.color = colors.random().toInt() | |
drawIntoCanvas { | |
it.nativeCanvas.drawText(randChar, x.toFloat(), y.toFloat(), paint) | |
} | |
y -= stripFontSize[i] | |
} | |
} | |
} | |
} | |
LaunchedEffect(key1 = Unit) { | |
while(true) { | |
delay(60) | |
for (i in 0 until stripCount) { | |
// Increase the start position of each strip which will trigger a recomposition | |
stripY[i] = stripY[i] + dY[i] | |
} | |
} | |
} | |
} | |
private fun<T> SnapshotStateList<T>.getOrNull(index: Int): T? { | |
if (index < 0 || index >= size) return null | |
return get(index) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment