Initial commit - Kinderspiele
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>Puzzle - KinderWelt</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
|
||||
body {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
|
||||
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 10px;
|
||||
}
|
||||
h1 { color: white; margin-bottom: 10px; font-size: 24px; }
|
||||
.level-select { display: flex; gap: 10px; margin-bottom: 15px; }
|
||||
.level-btn {
|
||||
background: rgba(255,255,255,0.2); border: 2px solid white; border-radius: 10px;
|
||||
padding: 8px 15px; color: white; font-size: 14px; cursor: pointer; font-family: inherit;
|
||||
}
|
||||
.level-btn.active { background: white; color: #f5576c; }
|
||||
.image-select { display: flex; gap: 10px; margin-bottom: 15px; flex-wrap: wrap; justify-content: center; }
|
||||
.img-btn {
|
||||
background: white; border: 3px solid transparent; border-radius: 10px;
|
||||
padding: 5px; cursor: pointer; font-size: 30px;
|
||||
}
|
||||
.img-btn.active { border-color: #4ade80; }
|
||||
.puzzle-container {
|
||||
display: grid; gap: 2px; background: rgba(0,0,0,0.2); padding: 5px;
|
||||
border-radius: 10px; touch-action: none;
|
||||
}
|
||||
.puzzle-piece {
|
||||
background-size: 300px 300px; cursor: pointer; border-radius: 5px;
|
||||
transition: all 0.2s; position: relative;
|
||||
}
|
||||
.puzzle-piece:hover { transform: scale(1.02); }
|
||||
.puzzle-piece.selected { box-shadow: 0 0 10px #4ade80; z-index: 10; }
|
||||
.puzzle-piece.correct {
|
||||
animation: pulse 0.5s;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.1); }
|
||||
}
|
||||
.preview {
|
||||
background: white; border-radius: 10px; padding: 10px; margin: 10px 0;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
.preview-img { font-size: 80px; }
|
||||
.controls { display: flex; gap: 15px; margin-top: 15px; flex-wrap: wrap; justify-content: center; }
|
||||
.btn {
|
||||
background: white; border: none; border-radius: 10px; padding: 12px 25px;
|
||||
font-size: 16px; cursor: pointer; font-family: inherit; font-weight: bold;
|
||||
}
|
||||
.btn-back { background: #ff6b6b; color: white; text-decoration: none; }
|
||||
.status { color: white; font-size: 18px; margin: 10px 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🧩 Puzzle</h1>
|
||||
|
||||
<div class="level-select">
|
||||
<button class="level-btn" onclick="setLevel(2)" id="l2">2×2 (Leicht)</button>
|
||||
<button class="level-btn active" onclick="setLevel(3)" id="l3">3×3 (Mittel)</button>
|
||||
<button class="level-btn" onclick="setLevel(4)" id="l4">4×4 (Schwer)</button>
|
||||
</div>
|
||||
|
||||
<div class="image-select" id="imageSelect"></div>
|
||||
|
||||
<div class="preview">
|
||||
<div class="preview-img" id="previewImg">🐶</div>
|
||||
<p style="color:#666;font-size:12px">So soll es aussehen!</p>
|
||||
</div>
|
||||
|
||||
<div class="status" id="status">Klicke zwei Teile zum Tauschen!</div>
|
||||
|
||||
<div class="puzzle-container" id="puzzleContainer"></div>
|
||||
|
||||
<div class="controls">
|
||||
<button class="btn" onclick="shufflePuzzle()">🔀 Mischen</button>
|
||||
<button class="btn" onclick="showHint()">💡 Tipp</button>
|
||||
<a href="../index.html" class="btn btn-back">⬅️ Zurück</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const emojis = ['🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🐨','🐯','🦁','🐷','🐸','🐵','🐔'];
|
||||
|
||||
let gridSize = 3;
|
||||
let selectedPiece = null;
|
||||
let pieces = [];
|
||||
let currentEmoji = '🐶';
|
||||
let solved = false;
|
||||
|
||||
function init() {
|
||||
// Bildauswahl
|
||||
const imgSelect = document.getElementById('imageSelect');
|
||||
emojis.slice(0, 8).forEach((emoji, i) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'img-btn' + (i === 0 ? ' active' : '');
|
||||
btn.textContent = emoji;
|
||||
btn.onclick = () => selectImage(emoji, btn);
|
||||
imgSelect.appendChild(btn);
|
||||
});
|
||||
|
||||
createPuzzle();
|
||||
}
|
||||
|
||||
function setLevel(n) {
|
||||
gridSize = n;
|
||||
document.querySelectorAll('.level-btn').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById('l' + n).classList.add('active');
|
||||
createPuzzle();
|
||||
}
|
||||
|
||||
function selectImage(emoji, btn) {
|
||||
currentEmoji = emoji;
|
||||
document.getElementById('previewImg').textContent = emoji;
|
||||
document.querySelectorAll('.img-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
createPuzzle();
|
||||
}
|
||||
|
||||
function createPuzzle() {
|
||||
const container = document.getElementById('puzzleContainer');
|
||||
container.innerHTML = '';
|
||||
container.style.gridTemplateColumns = `repeat(${gridSize}, 80px)`;
|
||||
|
||||
pieces = [];
|
||||
const totalPieces = gridSize * gridSize;
|
||||
|
||||
// Canvas für Emoji-Bild
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 300;
|
||||
canvas.height = 300;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Emoji zeichnen
|
||||
ctx.fillStyle = '#f0f0f0';
|
||||
ctx.fillRect(0, 0, 300, 300);
|
||||
ctx.font = '200px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(currentEmoji, 150, 150);
|
||||
|
||||
const imageData = canvas.toDataURL();
|
||||
|
||||
// Teile erstellen
|
||||
for (let i = 0; i < totalPieces; i++) {
|
||||
const correctPos = i;
|
||||
const piece = {
|
||||
id: i,
|
||||
correctPos: correctPos,
|
||||
currentPos: i
|
||||
};
|
||||
pieces.push(piece);
|
||||
}
|
||||
|
||||
// Rendern
|
||||
renderPuzzle(imageData);
|
||||
|
||||
// Kurz warten dann mischen
|
||||
setTimeout(shufflePuzzle, 500);
|
||||
}
|
||||
|
||||
function renderPuzzle(imageData) {
|
||||
const container = document.getElementById('puzzleContainer');
|
||||
container.innerHTML = '';
|
||||
|
||||
const pieceSize = 80;
|
||||
|
||||
// Nach currentPos sortieren für Anzeige
|
||||
const displayPieces = [...pieces].sort((a, b) => a.currentPos - b.currentPos);
|
||||
|
||||
displayPieces.forEach((piece, index) => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'puzzle-piece';
|
||||
div.style.width = pieceSize + 'px';
|
||||
div.style.height = pieceSize + 'px';
|
||||
div.style.backgroundImage = `url(${imageData})`;
|
||||
|
||||
// Hintergrund-Position basierend auf correctPos
|
||||
const row = Math.floor(piece.correctPos / gridSize);
|
||||
const col = piece.correctPos % gridSize;
|
||||
div.style.backgroundPosition = `-${col * pieceSize}px -${row * pieceSize}px`;
|
||||
div.style.backgroundSize = `${gridSize * pieceSize}px ${gridSize * pieceSize}px`;
|
||||
|
||||
div.onclick = () => selectPiece(piece);
|
||||
container.appendChild(div);
|
||||
});
|
||||
|
||||
checkWin();
|
||||
}
|
||||
|
||||
function selectPiece(piece) {
|
||||
if (solved) return;
|
||||
|
||||
const container = document.getElementById('puzzleContainer');
|
||||
const divs = container.querySelectorAll('.puzzle-piece');
|
||||
|
||||
// Index in display order finden
|
||||
const displayIndex = pieces.findIndex(p => p.id === piece.id);
|
||||
|
||||
if (!selectedPiece) {
|
||||
selectedPiece = piece;
|
||||
divs[displayIndex].classList.add('selected');
|
||||
document.getElementById('status').textContent = 'Wähle ein anderes Teil zum Tauschen!';
|
||||
} else if (selectedPiece.id === piece.id) {
|
||||
// Gleiches Teil = abwählen
|
||||
selectedPiece = null;
|
||||
divs[displayIndex].classList.remove('selected');
|
||||
document.getElementById('status').textContent = 'Klicke zwei Teile zum Tauschen!';
|
||||
} else {
|
||||
// Tauschen
|
||||
const tempPos = selectedPiece.currentPos;
|
||||
selectedPiece.currentPos = piece.currentPos;
|
||||
piece.currentPos = tempPos;
|
||||
|
||||
selectedPiece = null;
|
||||
|
||||
// Neu rendern
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 300; canvas.height = 300;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.fillStyle = '#f0f0f0';
|
||||
ctx.fillRect(0, 0, 300, 300);
|
||||
ctx.font = '200px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(currentEmoji, 150, 150);
|
||||
renderPuzzle(canvas.toDataURL());
|
||||
}
|
||||
}
|
||||
|
||||
function shufflePuzzle() {
|
||||
if (solved) solved = false;
|
||||
|
||||
// Fisher-Yates Shuffle für currentPos
|
||||
for (let i = pieces.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
const temp = pieces[i].currentPos;
|
||||
pieces[i].currentPos = pieces[j].currentPos;
|
||||
pieces[j].currentPos = temp;
|
||||
}
|
||||
|
||||
// Neu rendern
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 300; canvas.height = 300;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.fillStyle = '#f0f0f0';
|
||||
ctx.fillRect(0, 0, 300, 300);
|
||||
ctx.font = '200px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(currentEmoji, 150, 150);
|
||||
renderPuzzle(canvas.toDataURL());
|
||||
|
||||
document.getElementById('status').textContent = 'Klicke zwei Teile zum Tauschen!';
|
||||
}
|
||||
|
||||
function checkWin() {
|
||||
const isSolved = pieces.every(p => p.currentPos === p.correctPos);
|
||||
|
||||
if (isSolved && !solved) {
|
||||
solved = true;
|
||||
document.getElementById('status').textContent = '🎉 Super! Puzzle gelöst!';
|
||||
|
||||
// Alle Teile grün blinken
|
||||
const divs = document.querySelectorAll('.puzzle-piece');
|
||||
divs.forEach(div => {
|
||||
div.style.boxShadow = '0 0 20px #4ade80';
|
||||
});
|
||||
|
||||
if ('speechSynthesis' in window) {
|
||||
const utterance = new SpeechSynthesisUtterance('Super! Du hast das Puzzle gelöst!');
|
||||
utterance.lang = 'de-DE';
|
||||
speechSynthesis.speak(utterance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showHint() {
|
||||
// Zeige für 2 Sekunden die richtige Position an
|
||||
const container = document.getElementById('puzzleContainer');
|
||||
const divs = container.querySelectorAll('.puzzle-piece');
|
||||
|
||||
divs.forEach((div, index) => {
|
||||
const piece = pieces.find(p => p.currentPos === index);
|
||||
if (piece && piece.correctPos === index) {
|
||||
div.style.boxShadow = '0 0 10px #4ade80';
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
divs.forEach(div => {
|
||||
div.style.boxShadow = '';
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
document.getElementById('status').textContent = '💡 Grün markierte Teile sind richtig!';
|
||||
}
|
||||
|
||||
// Init
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user