forked from george/snake-compose
Этап 4: звук при поедании еды
Короткий звуковой эффект при съедании еды через SoundPool. - res/raw/eat.wav — короткий синтезированный «блип» (PCM 16-bit моно) - SoundPool с AudioAttributes USAGE_GAME, загрузка сэмпла один раз - воспроизведение в step() при поедании еды - освобождение SoundPool в DisposableEffect при уходе с экрана Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d8efaa53a6
commit
05d65eab14
@ -79,4 +79,9 @@ app/src/main/
|
||||
диск не блокирует UI. Смотри `LaunchedEffect` для загрузки рекорда и
|
||||
`scope.launch { ScoreStore.saveBest(...) }` при новом рекорде.
|
||||
|
||||
Идеи для следующих этапов: экранные кнопки-стрелки, анимации, звук, паузу.
|
||||
- **`snake-stage-4`** — звук при поедании еды через **SoundPool**: короткий
|
||||
WAV в `res/raw/eat.wav` грузится один раз, играется при каждом съедании
|
||||
(низкая задержка). Смотри настройку `SoundPool` и `soundPool.play(...)`
|
||||
в `step()`; освобождение ресурса — в `DisposableEffect`.
|
||||
|
||||
Идеи для следующих этапов: анимации поедания, пауза, выбор размера поля.
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.example.snake
|
||||
|
||||
import android.media.AudioAttributes
|
||||
import android.media.SoundPool
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
@ -9,6 +11,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
@ -86,6 +89,24 @@ fun SnakeGame() {
|
||||
best = ScoreStore.bestFlow(context).first()
|
||||
}
|
||||
|
||||
// Этап 4: звук поедания еды через SoundPool (короткий эффект, низкая задержка).
|
||||
// Пул и загруженный сэмпл создаём один раз и освобождаем при уходе с экрана.
|
||||
val soundPool = remember {
|
||||
SoundPool.Builder()
|
||||
.setMaxStreams(4)
|
||||
.setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_GAME)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
val eatSoundId = remember { soundPool.load(context, R.raw.eat, 1) }
|
||||
DisposableEffect(Unit) {
|
||||
onDispose { soundPool.release() }
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
snake = startSnake
|
||||
dir = Cell(0, -1)
|
||||
@ -112,6 +133,8 @@ fun SnakeGame() {
|
||||
snake = if (grew) listOf(nh) + snake else listOf(nh) + snake.dropLast(1)
|
||||
if (grew) {
|
||||
score++
|
||||
// звук поедания (left=1f, right=1f, prio=1, без зацикливания, обычная скорость)
|
||||
soundPool.play(eatSoundId, 1f, 1f, 1, 0, 1f)
|
||||
if (score > best) {
|
||||
best = score
|
||||
// новый рекорд — сохраняем на диск (асинхронно, UI не блокируется)
|
||||
|
||||
BIN
app/src/main/res/raw/eat.wav
Normal file
BIN
app/src/main/res/raw/eat.wav
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user