feat(89++): écran allumé, carillon de fin de timer, accords gorgées
- FLAG_KEEP_SCREEN_ON pendant la partie - Fin du timer de défi: carillon convivial do-mi-sol (AudioTrack, synthèse PCM avec enveloppe de cloche) à la place des bips ToneGenerator télécoms - Accord singulier/pluriel: «1 gorgée» / «N gorgées» dans les toasts, les stats et Game89Player (fini les «gorgée(s)»)
This commit is contained in:
@@ -52,6 +52,9 @@ public class Game89GameActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game89_game);
|
||||
|
||||
// Garder l'écran allumé pendant la partie
|
||||
getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
// Get intent data
|
||||
ArrayList<String> playerNames = getIntent().getStringArrayListExtra("PLAYERS");
|
||||
challengeTimerMinutes = getIntent().getIntExtra("CHALLENGE_TIMER_MINUTES", 1);
|
||||
@@ -155,6 +158,9 @@ public class Game89GameActivity extends AppCompatActivity {
|
||||
challengeTitleTextView.setText(currentChallenge.getTitle());
|
||||
challengeDescriptionTextView.setText(currentChallenge.getDescription());
|
||||
|
||||
// Alerte sonore : le timer est terminé, un défi arrive
|
||||
com.example.boidelov3.utils.SoundManager.getInstance(this).playChallenge();
|
||||
|
||||
// Vibrate to alert players
|
||||
try {
|
||||
android.os.Vibrator vibrator = (android.os.Vibrator) getSystemService(android.content.Context.VIBRATOR_SERVICE);
|
||||
@@ -274,7 +280,7 @@ public class Game89GameActivity extends AppCompatActivity {
|
||||
int count = seekBar.getProgress() + 1; // 1-8
|
||||
players.get(playerIndex).addGorgees(count);
|
||||
Toast.makeText(this,
|
||||
players.get(playerIndex).getName() + " boit " + count + " gorgée(s)!",
|
||||
players.get(playerIndex).getName() + " boit " + count + " gorgée" + (count > 1 ? "s" : "") + " !",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
@@ -288,10 +294,12 @@ public class Game89GameActivity extends AppCompatActivity {
|
||||
|
||||
StringBuilder stats = new StringBuilder();
|
||||
for (Game89Player player : players) {
|
||||
int total = player.getTotalGorgees();
|
||||
stats.append(player.getName())
|
||||
.append(": ")
|
||||
.append(player.getTotalGorgees())
|
||||
.append(" gorgée(s)\n\n");
|
||||
.append(total)
|
||||
.append(total > 1 ? " gorgées" : " gorgée")
|
||||
.append("\n\n");
|
||||
}
|
||||
|
||||
builder.setMessage(stats.toString());
|
||||
|
||||
@@ -29,6 +29,6 @@ public class Game89Player {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (" + totalGorgees + " gorgées)";
|
||||
return name + " (" + totalGorgees + (totalGorgees > 1 ? " gorgées)" : " gorgée)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,68 @@ public class SoundGenerator {
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Carillon convivial - annonce la fin d'un timer (nouveau défi)
|
||||
* Notes sinusoïdales do-mi-sol avec décroissance douce, timbre de cloche
|
||||
*/
|
||||
public synchronized void playChallenge() {
|
||||
if (isMuted || toneGenerator == null) return;
|
||||
new Thread(() -> {
|
||||
android.media.AudioTrack track = null;
|
||||
try {
|
||||
final int sampleRate = 44100;
|
||||
final double[] frequencies = {523.25, 659.25, 783.99}; // Do5, Mi5, Sol5
|
||||
final double noteDuration = 0.45; // durée de résonance d'une note (s)
|
||||
final double noteSpacing = 0.15; // décalage entre les notes (s)
|
||||
int totalSamples = (int) ((noteSpacing * 2 + noteDuration) * sampleRate);
|
||||
|
||||
short[] pcm = new short[totalSamples];
|
||||
for (int n = 0; n < frequencies.length; n++) {
|
||||
double freq = frequencies[n];
|
||||
int start = (int) (noteSpacing * n * sampleRate);
|
||||
int length = (int) (noteDuration * sampleRate);
|
||||
for (int i = 0; i < length && start + i < totalSamples; i++) {
|
||||
double t = (double) i / sampleRate;
|
||||
// Attaque rapide + décroissance exponentielle = timbre de cloche
|
||||
double envelope = Math.min(1.0, t / 0.01) * Math.exp(-t * 5.5);
|
||||
// Légère harmonique pour enrichir le timbre
|
||||
double sample = 0.75 * Math.sin(2 * Math.PI * freq * t)
|
||||
+ 0.25 * Math.sin(2 * Math.PI * freq * 2.0 * t);
|
||||
double value = pcm[start + i] / 32768.0 + sample * envelope * 0.55;
|
||||
pcm[start + i] = (short) (Math.max(-1.0, Math.min(1.0, value)) * Short.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
track = new android.media.AudioTrack.Builder()
|
||||
.setAudioAttributes(new android.media.AudioAttributes.Builder()
|
||||
.setUsage(android.media.AudioAttributes.USAGE_MEDIA)
|
||||
.setContentType(android.media.AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.build())
|
||||
.setAudioFormat(new android.media.AudioFormat.Builder()
|
||||
.setEncoding(android.media.AudioFormat.ENCODING_PCM_16BIT)
|
||||
.setSampleRate(sampleRate)
|
||||
.setChannelMask(android.media.AudioFormat.CHANNEL_OUT_MONO)
|
||||
.build())
|
||||
.setTransferMode(android.media.AudioTrack.MODE_STREAM)
|
||||
.setBufferSizeInBytes(sampleRate)
|
||||
.build();
|
||||
track.play();
|
||||
track.write(pcm, 0, totalSamples);
|
||||
Thread.sleep((long) ((noteSpacing * 2 + noteDuration + 0.15) * 1000));
|
||||
} catch (Exception e) {
|
||||
Log.e("SoundGenerator", "Erreur lors de la lecture du carillon", e);
|
||||
} finally {
|
||||
if (track != null) {
|
||||
try {
|
||||
track.stop();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
track.release();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activer/Désactiver le son
|
||||
*/
|
||||
|
||||
@@ -64,6 +64,15 @@ public class SoundManager {
|
||||
soundGenerator.playFin();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Joue un carillon convivial (fin de timer / nouveau défi)
|
||||
*/
|
||||
public void playChallenge() {
|
||||
if (soundGenerator != null) {
|
||||
soundGenerator.playChallenge();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Active ou désactive le son
|
||||
|
||||
Reference in New Issue
Block a user