Class_generator/js/games/temp-games.js

736 lines
23 KiB
JavaScript

// === MODULE JEUX TEMPORAIRES ===
class TempGamesModule {
constructor(options) {
this.container = options.container;
this.content = options.content;
this.onScoreUpdate = options.onScoreUpdate || (() => {});
this.onGameEnd = options.onGameEnd || (() => {});
this.currentGame = null;
this.availableGames = [
{
id: 'word-match',
name: 'Word Match',
icon: '🎯',
description: 'Associe les mots anglais avec leur traduction',
difficulty: 'easy'
},
{
id: 'quick-translation',
name: 'Quick Translation',
icon: '⚡',
description: 'Traduis le mot le plus rapidement possible',
difficulty: 'medium'
},
{
id: 'word-builder',
name: 'Word Builder',
icon: '🔤',
description: 'Reconstitue le mot lettre par lettre',
difficulty: 'medium'
}
];
this.init();
}
init() {
this.showGameSelector();
}
showGameSelector() {
this.container.innerHTML = `
<div class="temp-games-wrapper">
<div class="game-selector-header">
<h3>🎯 Mini-Jeux Temporaires</h3>
<p>Sélectionne un mini-jeu pour t'amuser avec le vocabulaire !</p>
</div>
<div class="mini-games-grid">
${this.availableGames.map(game => this.createGameCard(game)).join('')}
</div>
<div class="temp-games-info">
<p><em>Ces jeux sont en développement et seront bientôt des modules complets !</em></p>
</div>
</div>
`;
this.setupGameSelector();
}
createGameCard(game) {
const difficultyColor = {
easy: '#10B981',
medium: '#F59E0B',
hard: '#EF4444'
}[game.difficulty];
return `
<div class="mini-game-card" data-game="${game.id}">
<div class="mini-game-icon">${game.icon}</div>
<h4 class="mini-game-title">${game.name}</h4>
<p class="mini-game-description">${game.description}</p>
<div class="mini-game-difficulty" style="color: ${difficultyColor}">
${game.difficulty.toUpperCase()}
</div>
<button class="play-mini-game-btn">Jouer</button>
</div>
`;
}
setupGameSelector() {
document.querySelectorAll('.mini-game-card').forEach(card => {
card.addEventListener('click', () => {
const gameId = card.dataset.game;
this.startMiniGame(gameId);
});
});
}
startMiniGame(gameId) {
const game = this.availableGames.find(g => g.id === gameId);
if (!game) return;
switch(gameId) {
case 'word-match':
this.startWordMatch();
break;
case 'quick-translation':
this.startQuickTranslation();
break;
case 'word-builder':
this.startWordBuilder();
break;
}
}
// === WORD MATCH GAME ===
startWordMatch() {
this.container.innerHTML = `
<div class="mini-game word-match-game">
<div class="mini-game-header">
<button class="back-to-selector">← Retour</button>
<h3>🎯 Word Match</h3>
<div class="mini-score">Score: <span id="match-score">0</span></div>
</div>
<div class="word-match-board">
<div class="english-words" id="english-words">
<!-- Mots anglais -->
</div>
<div class="french-words" id="french-words">
<!-- Mots français -->
</div>
</div>
<div class="match-feedback" id="match-feedback">
Clique sur un mot anglais, puis sur sa traduction française !
</div>
</div>
`;
this.setupWordMatch();
}
setupWordMatch() {
document.querySelector('.back-to-selector').addEventListener('click', () => {
this.showGameSelector();
});
const words = this.content.vocabulary.slice(0, 6).map(w => ({
english: w.english,
french: w.french
}));
const shuffledFrench = [...words].sort(() => Math.random() - 0.5);
const englishContainer = document.getElementById('english-words');
const frenchContainer = document.getElementById('french-words');
let selectedEnglish = null;
let matchedPairs = 0;
let score = 0;
words.forEach((word, index) => {
const englishBtn = document.createElement('button');
englishBtn.className = 'word-btn english-btn';
englishBtn.textContent = word.english;
englishBtn.dataset.word = word.english;
englishContainer.appendChild(englishBtn);
englishBtn.addEventListener('click', () => {
document.querySelectorAll('.english-btn').forEach(btn =>
btn.classList.remove('selected'));
englishBtn.classList.add('selected');
selectedEnglish = word.english;
});
});
shuffledFrench.forEach(word => {
const frenchBtn = document.createElement('button');
frenchBtn.className = 'word-btn french-btn';
frenchBtn.textContent = word.french;
frenchBtn.dataset.word = word.french;
frenchContainer.appendChild(frenchBtn);
frenchBtn.addEventListener('click', () => {
if (!selectedEnglish) {
document.getElementById('match-feedback').textContent =
'Sélectionne d\'abord un mot anglais !';
return;
}
const correctWord = words.find(w => w.english === selectedEnglish);
if (correctWord && correctWord.french === word.french) {
// Correct match
score += 10;
matchedPairs++;
document.querySelector(`[data-word="${selectedEnglish}"]`).classList.add('matched');
frenchBtn.classList.add('matched');
document.getElementById('match-feedback').textContent = 'Parfait ! 🎉';
if (matchedPairs === words.length) {
setTimeout(() => {
alert(`Félicitations ! Score final: ${score}`);
this.onGameEnd(score);
}, 1000);
}
} else {
// Wrong match
score = Math.max(0, score - 2);
document.getElementById('match-feedback').textContent =
`Non, "${selectedEnglish}" ne correspond pas à "${word.french}"`;
}
document.getElementById('match-score').textContent = score;
this.onScoreUpdate(score);
selectedEnglish = null;
document.querySelectorAll('.english-btn').forEach(btn =>
btn.classList.remove('selected'));
});
});
}
// === QUICK TRANSLATION GAME ===
startQuickTranslation() {
this.container.innerHTML = `
<div class="mini-game quick-translation-game">
<div class="mini-game-header">
<button class="back-to-selector">← Retour</button>
<h3>⚡ Quick Translation</h3>
<div class="game-stats">
<span>Score: <span id="quick-score">0</span></span>
<span>Temps: <span id="quick-time">30</span>s</span>
</div>
</div>
<div class="quick-translation-board">
<div class="word-to-translate">
<h2 id="current-word">---</h2>
<p>Traduction en français :</p>
</div>
<div class="translation-options" id="translation-options">
<!-- Options de traduction -->
</div>
</div>
<button id="start-quick-game" class="start-btn">🎮 Commencer</button>
</div>
`;
this.setupQuickTranslation();
}
setupQuickTranslation() {
document.querySelector('.back-to-selector').addEventListener('click', () => {
this.showGameSelector();
});
let currentWordIndex = 0;
let score = 0;
let timeLeft = 30;
let gameTimer = null;
let isPlaying = false;
const words = this.shuffleArray([...this.content.vocabulary]).slice(0, 10);
document.getElementById('start-quick-game').addEventListener('click', () => {
if (isPlaying) return;
isPlaying = true;
currentWordIndex = 0;
score = 0;
timeLeft = 30;
document.getElementById('start-quick-game').style.display = 'none';
gameTimer = setInterval(() => {
timeLeft--;
document.getElementById('quick-time').textContent = timeLeft;
if (timeLeft <= 0) {
clearInterval(gameTimer);
alert(`Temps écoulé ! Score final: ${score}`);
this.onGameEnd(score);
}
}, 1000);
this.showQuickWord();
});
const showQuickWord = () => {
if (currentWordIndex >= words.length) {
clearInterval(gameTimer);
alert(`Bravo ! Score final: ${score}`);
this.onGameEnd(score);
return;
}
const currentWord = words[currentWordIndex];
document.getElementById('current-word').textContent = currentWord.english;
// Créer 4 options (1 correcte + 3 fausses)
const options = [currentWord.french];
const otherWords = words.filter(w => w.french !== currentWord.french);
for (let i = 0; i < 3; i++) {
if (otherWords[i]) {
options.push(otherWords[i].french);
}
}
const shuffledOptions = this.shuffleArray(options);
const optionsContainer = document.getElementById('translation-options');
optionsContainer.innerHTML = '';
shuffledOptions.forEach(option => {
const btn = document.createElement('button');
btn.className = 'option-btn';
btn.textContent = option;
btn.addEventListener('click', () => {
if (option === currentWord.french) {
score += 5;
btn.classList.add('correct');
setTimeout(() => {
currentWordIndex++;
this.showQuickWord();
}, 500);
} else {
score = Math.max(0, score - 1);
btn.classList.add('wrong');
document.querySelector(`button:contains("${currentWord.french}")`);
}
document.getElementById('quick-score').textContent = score;
this.onScoreUpdate(score);
// Désactiver tous les boutons
document.querySelectorAll('.option-btn').forEach(b => b.disabled = true);
});
optionsContainer.appendChild(btn);
});
};
this.showQuickWord = showQuickWord;
}
// === WORD BUILDER GAME ===
startWordBuilder() {
this.container.innerHTML = `
<div class="mini-game word-builder-game">
<div class="mini-game-header">
<button class="back-to-selector">← Retour</button>
<h3>🔤 Word Builder</h3>
<div class="mini-score">Score: <span id="builder-score">0</span></div>
</div>
<div class="word-builder-board">
<div class="french-word">
<p>Traduction : <strong id="french-hint">---</strong></p>
</div>
<div class="word-construction">
<div class="word-spaces" id="word-spaces">
<!-- Espaces pour les lettres -->
</div>
<div class="available-letters" id="available-letters">
<!-- Lettres disponibles -->
</div>
</div>
<div class="builder-controls">
<button id="next-word-btn" style="display:none;">Mot suivant</button>
<button id="give-up-btn">Passer</button>
</div>
</div>
</div>
`;
this.setupWordBuilder();
}
setupWordBuilder() {
document.querySelector('.back-to-selector').addEventListener('click', () => {
this.showGameSelector();
});
let currentWordIndex = 0;
let score = 0;
const words = this.shuffleArray([...this.content.vocabulary]).slice(0, 8);
const showBuilderWord = () => {
if (currentWordIndex >= words.length) {
alert(`Félicitations ! Score final: ${score}`);
this.onGameEnd(score);
return;
}
const currentWord = words[currentWordIndex];
const wordSpaces = document.getElementById('word-spaces');
const availableLetters = document.getElementById('available-letters');
document.getElementById('french-hint').textContent = currentWord.french;
// Créer les espaces
wordSpaces.innerHTML = '';
currentWord.english.split('').forEach((letter, index) => {
const space = document.createElement('div');
space.className = 'letter-space';
space.dataset.index = index;
space.dataset.letter = letter.toLowerCase();
wordSpaces.appendChild(space);
});
// Créer les lettres mélangées + quelques lettres supplémentaires
const wordLetters = currentWord.english.toLowerCase().split('');
const extraLetters = 'abcdefghijklmnopqrstuvwxyz'.split('')
.filter(l => !wordLetters.includes(l))
.slice(0, 3);
const allLetters = this.shuffleArray([...wordLetters, ...extraLetters]);
availableLetters.innerHTML = '';
allLetters.forEach(letter => {
const letterBtn = document.createElement('button');
letterBtn.className = 'letter-btn';
letterBtn.textContent = letter.toUpperCase();
letterBtn.dataset.letter = letter;
letterBtn.addEventListener('click', () => {
this.placeLetter(letter, letterBtn);
});
availableLetters.appendChild(letterBtn);
});
document.getElementById('next-word-btn').style.display = 'none';
document.getElementById('give-up-btn').style.display = 'inline-block';
};
const placeLetter = (letter, btn) => {
const emptySpace = document.querySelector(
`.letter-space[data-letter="${letter}"]:not(.filled)`
);
if (emptySpace) {
emptySpace.textContent = letter.toUpperCase();
emptySpace.classList.add('filled');
btn.disabled = true;
// Vérifier si le mot est complet
const allSpaces = document.querySelectorAll('.letter-space');
const filledSpaces = document.querySelectorAll('.letter-space.filled');
if (allSpaces.length === filledSpaces.length) {
score += 15;
document.getElementById('builder-score').textContent = score;
this.onScoreUpdate(score);
document.getElementById('next-word-btn').style.display = 'inline-block';
document.getElementById('give-up-btn').style.display = 'none';
// Désactiver toutes les lettres
document.querySelectorAll('.letter-btn').forEach(b => b.disabled = true);
}
} else {
// Mauvaise lettre
btn.classList.add('wrong-letter');
setTimeout(() => btn.classList.remove('wrong-letter'), 1000);
}
};
document.getElementById('next-word-btn').addEventListener('click', () => {
currentWordIndex++;
showBuilderWord();
});
document.getElementById('give-up-btn').addEventListener('click', () => {
currentWordIndex++;
showBuilderWord();
});
this.placeLetter = placeLetter;
showBuilderWord();
}
shuffleArray(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
start() {
// Interface commune - montrer le sélecteur
this.showGameSelector();
}
destroy() {
this.container.innerHTML = '';
}
}
// CSS supplémentaire pour les mini-jeux
const tempGamesStyles = `
<style>
.temp-games-wrapper {
text-align: center;
}
.mini-games-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 30px 0;
}
.mini-game-card {
background: white;
border: 2px solid #e5e7eb;
border-radius: 12px;
padding: 20px;
cursor: pointer;
transition: all 0.3s ease;
}
.mini-game-card:hover {
border-color: var(--primary-color);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.mini-game-icon {
font-size: 2.5rem;
margin-bottom: 10px;
}
.mini-game-title {
color: var(--primary-color);
margin-bottom: 8px;
}
.mini-game-description {
color: var(--text-secondary);
font-size: 0.9rem;
margin-bottom: 10px;
}
.mini-game-difficulty {
font-weight: bold;
font-size: 0.8rem;
margin-bottom: 15px;
}
.play-mini-game-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px 16px;
border-radius: 20px;
font-size: 0.9rem;
cursor: pointer;
}
.mini-game {
max-width: 800px;
margin: 0 auto;
}
.mini-game-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.word-match-board {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 20px;
}
.word-btn {
display: block;
width: 100%;
padding: 12px;
margin-bottom: 10px;
border: 2px solid #e5e7eb;
border-radius: 8px;
background: white;
cursor: pointer;
transition: all 0.3s ease;
}
.word-btn:hover {
border-color: var(--primary-color);
}
.word-btn.selected {
background: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.word-btn.matched {
background: var(--secondary-color);
color: white;
border-color: var(--secondary-color);
cursor: default;
}
.translation-options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-top: 20px;
}
.option-btn {
padding: 15px;
border: 2px solid #e5e7eb;
border-radius: 8px;
background: white;
cursor: pointer;
font-size: 1rem;
transition: all 0.3s ease;
}
.option-btn:hover {
border-color: var(--primary-color);
}
.option-btn.correct {
background: var(--secondary-color);
color: white;
border-color: var(--secondary-color);
}
.option-btn.wrong {
background: var(--error-color);
color: white;
border-color: var(--error-color);
}
.word-construction {
margin: 30px 0;
}
.word-spaces {
display: flex;
justify-content: center;
gap: 8px;
margin-bottom: 30px;
}
.letter-space {
width: 40px;
height: 40px;
border: 2px solid #e5e7eb;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
font-weight: bold;
background: white;
}
.letter-space.filled {
background: var(--secondary-color);
color: white;
border-color: var(--secondary-color);
}
.available-letters {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 8px;
}
.letter-btn {
width: 35px;
height: 35px;
border: 2px solid #e5e7eb;
border-radius: 8px;
background: white;
cursor: pointer;
font-size: 1rem;
font-weight: bold;
transition: all 0.3s ease;
}
.letter-btn:hover {
border-color: var(--primary-color);
}
.letter-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.letter-btn.wrong-letter {
background: var(--error-color);
color: white;
border-color: var(--error-color);
}
@media (max-width: 768px) {
.word-match-board {
grid-template-columns: 1fr;
gap: 20px;
}
.translation-options {
grid-template-columns: 1fr;
}
.mini-game-header {
flex-direction: column;
gap: 10px;
}
}
</style>
`;
// Ajouter les styles
document.head.insertAdjacentHTML('beforeend', tempGamesStyles);
// Enregistrement du module
window.GameModules = window.GameModules || {};
window.GameModules.TempGames = TempGamesModule;