mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-09-25 10:48:59 +00:00
Processed last feedback on minigame.
This commit is contained in:
parent
08e98b089c
commit
8b53e9e5e3
1 changed files with 53 additions and 39 deletions
|
@ -20,13 +20,8 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
) : View(context, attrs) {
|
) : View(context, attrs) {
|
||||||
private val primaryColor = "#2D63ED".toColorInt()
|
private val primaryColor = "#2D63ED".toColorInt()
|
||||||
private val inactiveGlobalAlpha = 110
|
private val inactiveGlobalAlpha = 110
|
||||||
private val streakAccelerationStep = .3f
|
|
||||||
private val minSpawnDelay = 200L
|
|
||||||
private val idleSpeedMultiplier = .015f
|
private val idleSpeedMultiplier = .015f
|
||||||
private val baseDeterministicDelay = 700L
|
private val overshootInterpolator = OvershootInterpolator(1.5f)
|
||||||
private val baseIndeterminateDelay = 1400L
|
|
||||||
private val overshootInterpolator = OvershootInterpolator(2f)
|
|
||||||
private val initialSpawnFactor = 2f
|
|
||||||
private val floatAccel = .03f
|
private val floatAccel = .03f
|
||||||
private val idleMaxSpeed = .35f
|
private val idleMaxSpeed = .35f
|
||||||
private val idleInitialTargets = 10
|
private val idleInitialTargets = 10
|
||||||
|
@ -39,7 +34,6 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
private var forceIndeterminate= false
|
private var forceIndeterminate= false
|
||||||
private var lastFrameTime = System.currentTimeMillis()
|
private var lastFrameTime = System.currentTimeMillis()
|
||||||
|
|
||||||
private var streak = 0
|
|
||||||
private var score = 0
|
private var score = 0
|
||||||
private var isPlaying = false
|
private var isPlaying = false
|
||||||
|
|
||||||
|
@ -53,6 +47,11 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
setShadowLayer(4f, 0f, 0f, Color.BLACK)
|
setShadowLayer(4f, 0f, 0f, Color.BLACK)
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
typeface = Typeface.DEFAULT_BOLD
|
||||||
}
|
}
|
||||||
|
private val idleHintPaint = Paint(textPaint).apply {
|
||||||
|
textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12f, resources.displayMetrics)
|
||||||
|
typeface = Typeface.DEFAULT
|
||||||
|
setShadowLayer(2f, 0f, 0f, Color.BLACK)
|
||||||
|
}
|
||||||
private val progressBarPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = primaryColor }
|
private val progressBarPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = primaryColor }
|
||||||
private val spinnerPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
private val spinnerPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||||
color = primaryColor; strokeWidth = 12f
|
color = primaryColor; strokeWidth = 12f
|
||||||
|
@ -67,10 +66,11 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
private val backgroundPaint = Paint()
|
private val backgroundPaint = Paint()
|
||||||
private var spinnerShader: SweepGradient? = null
|
private var spinnerShader: SweepGradient? = null
|
||||||
private var spinnerAngle = 0f
|
private var spinnerAngle = 0f
|
||||||
private var lastSpawnDelayMs: Long = baseDeterministicDelay
|
private val MIN_SPAWN_RATE = 1f
|
||||||
private var currentSpawnDelayMs = baseDeterministicDelay.toFloat()
|
private val MAX_SPAWN_RATE = 20.0f
|
||||||
private val DELAY_SMOOTHING = 0.7f
|
private val HIT_RATE_INCREMENT = 0.15f
|
||||||
private val MISS_PENALTY = 1
|
private val MISS_RATE_DECREMENT = 0.09f
|
||||||
|
private var spawnRate = MIN_SPAWN_RATE
|
||||||
|
|
||||||
private val frameRunnable = object : Runnable {
|
private val frameRunnable = object : Runnable {
|
||||||
override fun run() { invalidate(); if (!loaderFinished) postDelayed(this, 16L) }
|
override fun run() { invalidate(); if (!loaderFinished) postDelayed(this, 16L) }
|
||||||
|
@ -91,8 +91,8 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
loaderFinished = false
|
loaderFinished = false
|
||||||
isPlaying = false
|
isPlaying = false
|
||||||
score = 0
|
score = 0
|
||||||
streak = 0
|
|
||||||
particles.clear()
|
particles.clear()
|
||||||
|
spawnRate = MIN_SPAWN_RATE
|
||||||
|
|
||||||
post { if (targets.isEmpty()) prepopulateIdleTargets() }
|
post { if (targets.isEmpty()) prepopulateIdleTargets() }
|
||||||
|
|
||||||
|
@ -122,6 +122,7 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
if (score > 0) {
|
if (score > 0) {
|
||||||
val elapsed = (System.currentTimeMillis() - (if (playStartTime > 0) playStartTime else loadStartTime)) / 1000.0
|
val elapsed = (System.currentTimeMillis() - (if (playStartTime > 0) playStartTime else loadStartTime)) / 1000.0
|
||||||
UIDialogs.toast("Nice! score $score | ${"%.1f".format(score / elapsed)} / s")
|
UIDialogs.toast("Nice! score $score | ${"%.1f".format(score / elapsed)} / s")
|
||||||
|
score = 0
|
||||||
}
|
}
|
||||||
loaderFinished = true
|
loaderFinished = true
|
||||||
isPlaying = false
|
isPlaying = false
|
||||||
|
@ -139,7 +140,7 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
val t = targets[idx]
|
val t = targets[idx]
|
||||||
t.hit = true; t.hitTime = System.currentTimeMillis()
|
t.hit = true; t.hitTime = System.currentTimeMillis()
|
||||||
streak++
|
accelerateSpawnRate()
|
||||||
score += if (!isIndeterminate) 10 else 5
|
score += if (!isIndeterminate) 10 else 5
|
||||||
spawnParticles(t.x, t.y, t.radius)
|
spawnParticles(t.x, t.y, t.radius)
|
||||||
|
|
||||||
|
@ -147,21 +148,29 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
playStartTime = System.currentTimeMillis()
|
playStartTime = System.currentTimeMillis()
|
||||||
score = 0
|
score = 0
|
||||||
streak = 0
|
spawnRate = MIN_SPAWN_RATE
|
||||||
targets.retainAll { it === t }
|
targets.retainAll { it === t }
|
||||||
spawnTarget()
|
spawnTarget()
|
||||||
}
|
}
|
||||||
} else if (isPlaying) applyMissPenalty()
|
} else if (isPlaying) decelerateSpawnRate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyMissPenalty() { streak = max(0, streak - MISS_PENALTY) }
|
private inline fun accelerateSpawnRate() {
|
||||||
|
spawnRate = (spawnRate + HIT_RATE_INCREMENT).coerceAtMost(MAX_SPAWN_RATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun decelerateSpawnRate() {
|
||||||
|
spawnRate = (spawnRate - MISS_RATE_DECREMENT).coerceAtLeast(MIN_SPAWN_RATE)
|
||||||
|
}
|
||||||
|
|
||||||
private fun spawnTarget() {
|
private fun spawnTarget() {
|
||||||
if (loaderFinished || width == 0 || height == 0) {
|
if (loaderFinished || width == 0 || height == 0) {
|
||||||
postDelayed({ spawnTarget() }, 200L); return
|
postDelayed({ spawnTarget() }, 200L); return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isPlaying) { postDelayed({ spawnTarget() }, 500L); return }
|
if (!isPlaying) {
|
||||||
|
postDelayed({ spawnTarget() }, 500L); return
|
||||||
|
}
|
||||||
|
|
||||||
val radius = Random.nextInt(40, 80).toFloat()
|
val radius = Random.nextInt(40, 80).toFloat()
|
||||||
val x = Random.nextFloat() * (width - 2 * radius) + radius
|
val x = Random.nextFloat() * (width - 2 * radius) + radius
|
||||||
|
@ -175,14 +184,8 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
val alpha = Random.nextInt(150, 255)
|
val alpha = Random.nextInt(150, 255)
|
||||||
|
|
||||||
targets += Target(x, y, radius, System.currentTimeMillis(), baseAlpha = alpha, vx = vx, vy = vy)
|
targets += Target(x, y, radius, System.currentTimeMillis(), baseAlpha = alpha, vx = vx, vy = vy)
|
||||||
val delayBase = if (isIndeterminate) baseIndeterminateDelay else baseDeterministicDelay
|
|
||||||
val streakBoost = 1f + streak * streakAccelerationStep
|
|
||||||
val baseFactor = if (streak == 0) initialSpawnFactor else 1f
|
|
||||||
val targetDelay = max(minSpawnDelay.toFloat(), delayBase * baseFactor / streakBoost)
|
|
||||||
|
|
||||||
currentSpawnDelayMs = currentSpawnDelayMs * DELAY_SMOOTHING + targetDelay * (1 - DELAY_SMOOTHING)
|
val delay = (1000f / spawnRate).roundToLong()
|
||||||
val delay = currentSpawnDelayMs.roundToLong()
|
|
||||||
lastSpawnDelayMs = delay
|
|
||||||
postDelayed({ spawnTarget() }, delay)
|
postDelayed({ spawnTarget() }, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,8 +237,7 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
val margin = 24f
|
val margin = 24f
|
||||||
val scoreTxt = "Score $score"
|
val scoreTxt = "Score $score"
|
||||||
val speed = 1000f / lastSpawnDelayMs
|
val speedTxt = "Speed ${"%.2f".format(spawnRate)}/s"
|
||||||
val speedTxt = "Speed ${"%.2f".format(speed)}/s"
|
|
||||||
val maxWidth = width - margin
|
val maxWidth = width - margin
|
||||||
val needRight = max(textPaint.measureText(scoreTxt), textPaint.measureText(speedTxt)) > maxWidth
|
val needRight = max(textPaint.measureText(scoreTxt), textPaint.measureText(speedTxt)) > maxWidth
|
||||||
|
|
||||||
|
@ -249,17 +251,29 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
else if (loaderFinished)
|
else if (loaderFinished)
|
||||||
canvas.drawText("Loading Complete!", width/2f, height/2f, textPaint.apply { textAlign = Paint.Align.CENTER })
|
canvas.drawText("Loading Complete!", width/2f, height/2f, textPaint.apply { textAlign = Paint.Align.CENTER })
|
||||||
else {
|
else {
|
||||||
textPaint.textAlign = Paint.Align.CENTER
|
idleHintPaint.textAlign = Paint.Align.CENTER
|
||||||
canvas.drawText(idleHintText, width / 2f, height - 48f, textPaint)
|
canvas.drawText(idleHintText, width / 2f, height - 48f, idleHintPaint)
|
||||||
textPaint.textAlign = Paint.Align.LEFT
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawBackground(canvas: Canvas) {
|
private fun drawBackground(canvas: Canvas) {
|
||||||
|
val colors = intArrayOf(
|
||||||
|
Color.rgb(20, 20, 40),
|
||||||
|
Color.rgb(15, 15, 30),
|
||||||
|
Color.rgb(10, 10, 20),
|
||||||
|
Color.rgb( 5, 5, 10),
|
||||||
|
Color.BLACK
|
||||||
|
)
|
||||||
|
val pos = floatArrayOf(0f, 0.25f, 0.5f, 0.75f, 1f)
|
||||||
|
|
||||||
|
if (backgroundPaint.shader == null) {
|
||||||
backgroundPaint.shader = LinearGradient(
|
backgroundPaint.shader = LinearGradient(
|
||||||
0f, 0f, 0f, height.toFloat(),
|
0f, 0f, 0f, height.toFloat(),
|
||||||
Color.rgb(20, 20, 40), Color.BLACK, Shader.TileMode.CLAMP
|
colors, pos,
|
||||||
|
Shader.TileMode.CLAMP
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), backgroundPaint)
|
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), backgroundPaint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +284,7 @@ class TargetTapLoaderView @JvmOverloads constructor(
|
||||||
val t = it.next()
|
val t = it.next()
|
||||||
if (t.hit && now - t.hitTime > 300L) { it.remove(); continue }
|
if (t.hit && now - t.hitTime > 300L) { it.remove(); continue }
|
||||||
if (isPlaying && !t.hit && now - t.spawnTime > expireMsActive) {
|
if (isPlaying && !t.hit && now - t.spawnTime > expireMsActive) {
|
||||||
it.remove(); applyMissPenalty(); continue
|
it.remove(); decelerateSpawnRate(); continue
|
||||||
}
|
}
|
||||||
t.x += t.vx; t.y += t.vy
|
t.x += t.vx; t.y += t.vy
|
||||||
t.vx += (Random.nextFloat() - .5f) * floatAccel
|
t.vx += (Random.nextFloat() - .5f) * floatAccel
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue