1
0
PonyWave-Tools/2048/index.html
2025-03-04 15:24:19 +01:00

439 lines
15 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>2048</title>
<script defer src="https://stats.ponywave.de/script" data-website-id="9ef713d2-adb9-4906-9df5-708d8a8b9131" data-tag="2048"></script>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif;
background-color: #faf8ef;
}
#grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
background-color: #bbada0;
padding: 10px;
border-radius: 5px;
margin: 20px 0;
}
.cell {
width: 80px;
height: 80px;
background-color: rgba(238, 228, 218, 0.35);
border-radius: 3px;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
font-weight: bold;
transition: all 0.15s ease;
}
@keyframes newTile {
from { transform: scale(0); }
to { transform: scale(1); }
}
@keyframes mergedTile {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.new-tile {
animation: newTile 0.15s ease-out;
}
.merged-tile {
animation: mergedTile 0.15s ease-out;
}
.number {
background-color: #eee4da;
color: #776e65;
}
.number-2 { background-color: #eee4da; }
.number-4 { background-color: #ede0c8; }
.number-8 { background-color: #f2b179; color: white; }
.number-16 { background-color: #f59563; color: white; }
.number-32 { background-color: #f67c5f; color: white; }
.number-64 { background-color: #f65e3b; color: white; }
.number-128 { background-color: #edcf72; color: white; }
.number-256 { background-color: #edcc61; color: white; }
.number-512 { background-color: #edc850; color: white; }
.number-1024 { background-color: #edc53f; color: white; }
.number-2048 { background-color: #edc22e; color: white; }
#score {
font-size: 24px;
margin: 10px 0;
}
button {
padding: 10px 20px;
margin: 10px;
background-color: #8f7a66;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
#anleitung {
background-color: #bbada0;
padding: 20px;
border-radius: 5px;
margin: 20px;
max-width: 500px;
color: white;
}
/* Game Over Popup */
.game-over-popup {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #bbada0;
padding: 2rem;
border-radius: 10px;
text-align: center;
z-index: 100;
box-shadow: 0 0 20px rgba(0,0,0,0.3);
color: white;
}
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 99;
}
/* Highscore Anzeige */
#highscore {
font-size: 20px;
margin-bottom: 10px;
color: #776e65;
}
</style>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
</head>
<body>
<h1>2048</h1>
<div id="score">Punktestand: 0</div>
<div id="highscore">Highscore: 0</div>
<div id="grid"></div>
<div id="anleitung">
<h2>Spielanleitung</h2>
<p>🎮 <strong>Spielziel:</strong> Kombiniere Zahlenkacheln, um die 2048-Kachel zu erreichen!</p>
<p>🕹️ <strong>Steuerung:</strong> Benutze die Pfeiltasten:</p>
<ul>
<li>← →: Kacheln nach links/rechts bewegen</li>
<li>↑ ↓: Kacheln nach oben/unten bewegen</li>
</ul>
<p><strong>Spielmechanik:</strong></p>
<ul>
<li>Gleiche Zahlen verschmelzen bei Kollision</li>
<li>Jeder Zug generiert eine neue 2er- oder 4er-Kachel</li>
<li>Spielende wenn keine Züge mehr möglich</li>
</ul>
</div>
<button onclick="startNewGame()">Neues Spiel</button>
<button onclick="takeScreenshot()">Screenshot machen 📸</button>
<div class="game-over-popup" id="gameOverPopup">
<h2>Game Over!</h2>
<p>Dein Punktestand: <span id="finalScore">0</span></p>
<button onclick="startNewGame()">Neues Spiel</button>
</div>
<div class="overlay" id="overlay"></div>
<script>
class Game2048 {
constructor() {
this.grid = Array(4).fill().map(() => Array(4).fill(0));
this.previousGrid = JSON.parse(JSON.stringify(this.grid));
this.score = 0;
this.highscore = localStorage.getItem('2048-highscore') || 0;
this.init();
}
init() {
this.updateHighscoreDisplay();
this.addNewNumber();
this.addNewNumber();
this.updateDisplay();
this.setupControls();
}
addNewNumber() {
const emptyCells = [];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (this.grid[i][j] === 0) {
emptyCells.push({x: i, y: j});
}
}
}
if (emptyCells.length > 0) {
const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
this.grid[randomCell.x][randomCell.y] = Math.random() < 0.9 ? 2 : 4;
}
}
updateDisplay() {
const gridContainer = document.getElementById('grid');
gridContainer.innerHTML = '';
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
if (this.grid[i][j] !== 0) {
cell.classList.add('number', `number-${this.grid[i][j]}`);
cell.textContent = this.grid[i][j];
}
gridContainer.appendChild(cell);
}
}
document.getElementById('score').textContent = `Score: ${this.score}`;
}
showGameOver() {
document.getElementById('gameOverPopup').style.display = 'block';
document.getElementById('overlay').style.display = 'block';
document.getElementById('finalScore').textContent = this.score;
}
updateHighscore() {
if (this.score > this.highscore) {
this.highscore = this.score;
localStorage.setItem('2048-highscore', this.highscore);
this.updateHighscoreDisplay();
}
}
updateHighscoreDisplay() {
document.getElementById('highscore').textContent = `Highscore: ${this.highscore}`;
}
resetGame() {
this.grid = Array(4).fill().map(() => Array(4).fill(0));
this.score = 0;
this.previousGrid = JSON.parse(JSON.stringify(this.grid));
document.getElementById('gameOverPopup').style.display = 'none';
document.getElementById('overlay').style.display = 'none';
this.init();
}
move(direction) {
let moved = false;
this.previousGrid = JSON.parse(JSON.stringify(this.grid));
switch(direction) {
case 'ArrowUp': moved = this.moveUp(); break;
case 'ArrowDown': moved = this.moveDown(); break;
case 'ArrowLeft': moved = this.moveLeft(); break;
case 'ArrowRight': moved = this.moveRight(); break;
}
if (moved) {
this.addNewNumber();
this.updateDisplay();
this.updateHighscore();
if (this.isGameOver()) {
this.showGameOver();
}
}
}
updateDisplay() {
const gridContainer = document.getElementById('grid');
gridContainer.innerHTML = '';
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
if (this.grid[i][j] !== 0) {
const prevVal = this.previousGrid[i][j];
const currentVal = this.grid[i][j];
cell.classList.add('number', `number-${currentVal}`);
cell.textContent = currentVal;
// Animation-Klassen hinzufügen
if (prevVal === 0) {
cell.classList.add('new-tile');
} else if (currentVal > prevVal) {
cell.classList.add('merged-tile');
}
}
gridContainer.appendChild(cell);
}
}
document.getElementById('score').textContent = `Punktestand: ${this.score}`;
}
moveLeft() {
let moved = false;
for (let i = 0; i < 4; i++) {
let row = this.grid[i].filter(x => x !== 0);
for (let j = 0; j < row.length - 1; j++) {
if (row[j] === row[j + 1]) {
row[j] *= 2;
this.score += row[j];
row.splice(j + 1, 1);
moved = true;
}
}
const newRow = row.concat(Array(4 - row.length).fill(0));
if (JSON.stringify(this.grid[i]) !== JSON.stringify(newRow)) moved = true;
this.grid[i] = newRow;
}
return moved;
}
moveRight() {
let moved = false;
for (let i = 0; i < 4; i++) {
let row = this.grid[i].filter(x => x !== 0);
for (let j = row.length - 1; j > 0; j--) {
if (row[j] === row[j - 1]) {
row[j] *= 2;
this.score += row[j];
row.splice(j - 1, 1);
moved = true;
}
}
const newRow = Array(4 - row.length).fill(0).concat(row);
if (JSON.stringify(this.grid[i]) !== JSON.stringify(newRow)) moved = true;
this.grid[i] = newRow;
}
return moved;
}
moveUp() {
let moved = false;
for (let j = 0; j < 4; j++) {
let col = this.grid.map(row => row[j]).filter(x => x !== 0);
for (let i = 0; i < col.length - 1; i++) {
if (col[i] === col[i + 1]) {
col[i] *= 2;
this.score += col[i];
col.splice(i + 1, 1);
moved = true;
}
}
const newCol = col.concat(Array(4 - col.length).fill(0));
if (JSON.stringify(this.grid.map(row => row[j])) !== JSON.stringify(newCol)) moved = true;
for (let i = 0; i < 4; i++) {
this.grid[i][j] = newCol[i];
}
}
return moved;
}
moveDown() {
let moved = false;
for (let j = 0; j < 4; j++) {
let col = this.grid.map(row => row[j]).filter(x => x !== 0);
for (let i = col.length - 1; i > 0; i--) {
if (col[i] === col[i - 1]) {
col[i] *= 2;
this.score += col[i];
col.splice(i - 1, 1);
moved = true;
}
}
const newCol = Array(4 - col.length).fill(0).concat(col);
if (JSON.stringify(this.grid.map(row => row[j])) !== JSON.stringify(newCol)) moved = true;
for (let i = 0; i < 4; i++) {
this.grid[i][j] = newCol[i];
}
}
return moved;
}
isGameOver() {
// Check for empty cells
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (this.grid[i][j] === 0) return false;
}
}
// Check possible merges
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
const current = this.grid[i][j];
if ((i < 3 && current === this.grid[i + 1][j]) ||
(j < 3 && current === this.grid[i][j + 1])) {
return false;
}
}
}
return true;
}
setupControls() {
document.addEventListener('keydown', (e) => {
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
e.preventDefault();
this.move(e.key);
}
});
}
}
function startNewGame() {
game.resetGame();
}
// Screenshot-Funktion
function takeScreenshot() {
const gameArea = document.body;
html2canvas(gameArea, {
ignoreElements: (element) => element.tagName === 'BUTTON',
backgroundColor: '#faf8ef'
}).then(canvas => {
const link = document.createElement('a');
link.download = '2048-screenshot.png';
link.href = canvas.toDataURL();
link.click();
}).catch(err => {
console.error('Fehler beim Erstellen des Screenshots:', err);
alert('Screenshot konnte nicht erstellt werden!');
});
}
// Spiel starten
new Game2048();
let game = new Game2048();
</script>
</body>
</html>