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);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_game89_game);
|
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
|
// Get intent data
|
||||||
ArrayList<String> playerNames = getIntent().getStringArrayListExtra("PLAYERS");
|
ArrayList<String> playerNames = getIntent().getStringArrayListExtra("PLAYERS");
|
||||||
challengeTimerMinutes = getIntent().getIntExtra("CHALLENGE_TIMER_MINUTES", 1);
|
challengeTimerMinutes = getIntent().getIntExtra("CHALLENGE_TIMER_MINUTES", 1);
|
||||||
@@ -155,6 +158,9 @@ public class Game89GameActivity extends AppCompatActivity {
|
|||||||
challengeTitleTextView.setText(currentChallenge.getTitle());
|
challengeTitleTextView.setText(currentChallenge.getTitle());
|
||||||
challengeDescriptionTextView.setText(currentChallenge.getDescription());
|
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
|
// Vibrate to alert players
|
||||||
try {
|
try {
|
||||||
android.os.Vibrator vibrator = (android.os.Vibrator) getSystemService(android.content.Context.VIBRATOR_SERVICE);
|
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
|
int count = seekBar.getProgress() + 1; // 1-8
|
||||||
players.get(playerIndex).addGorgees(count);
|
players.get(playerIndex).addGorgees(count);
|
||||||
Toast.makeText(this,
|
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();
|
Toast.LENGTH_SHORT).show();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -288,10 +294,12 @@ public class Game89GameActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
StringBuilder stats = new StringBuilder();
|
StringBuilder stats = new StringBuilder();
|
||||||
for (Game89Player player : players) {
|
for (Game89Player player : players) {
|
||||||
|
int total = player.getTotalGorgees();
|
||||||
stats.append(player.getName())
|
stats.append(player.getName())
|
||||||
.append(": ")
|
.append(": ")
|
||||||
.append(player.getTotalGorgees())
|
.append(total)
|
||||||
.append(" gorgée(s)\n\n");
|
.append(total > 1 ? " gorgées" : " gorgée")
|
||||||
|
.append("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setMessage(stats.toString());
|
builder.setMessage(stats.toString());
|
||||||
|
|||||||
@@ -29,6 +29,6 @@ public class Game89Player {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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();
|
}).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
|
* Activer/Désactiver le son
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -64,6 +64,15 @@ public class SoundManager {
|
|||||||
soundGenerator.playFin();
|
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
|
* Active ou désactive le son
|
||||||
|
|||||||
Reference in New Issue
Block a user