Neu: 2048
This commit is contained in:
parent
cc4a117358
commit
bc07d9a66c
439
20248/index.html
Normal file
439
20248/index.html
Normal file
@ -0,0 +1,439 @@
|
||||
<!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>
|
@ -164,6 +164,10 @@
|
||||
<h2 class="tool-title">Systeminformationen</h2>
|
||||
<p class="tool-description">Zeigt Infos zu Browser, Gerät, detriebssysten, User-Agent und IPs an.</p>
|
||||
</a>
|
||||
<a href="https://tools.ponywave.de/2048" class="tool-bubble">
|
||||
<h2 class="tool-title">2048</h2>
|
||||
<p class="tool-description">2048 in HTML</p>
|
||||
</a>
|
||||
<a href="https://tools.ponywave.de/pinkie_timer" class="tool-bubble">
|
||||
<h2 class="tool-title">Pinkie Pie Timer</h2>
|
||||
<p class="tool-description">Ein Pinkie Pie Timer</p>
|
||||
|
Loading…
x
Reference in New Issue
Block a user