Samstag, 17 Januar 2026

Diese Woche am beliebtesten

Vertiefendes Material

Tetris Deluxe

Erleben Sie unsere Adaption des ultimativen Tetris Klassikers direkt im Browser – jetzt mit modernem Design, professionellem Layout und allen Features, die das Spielerlebnis verbessern.

Highlights:

  • Spielbare Tetris-Version direkt im Browser mit animierten Tetrominos, Punktestand und Levelsystem
  • Benutzerkonten: Registrierung, Login und E-Mail-Verifikation für eine sichere und personalisierte Erfahrung
  • Highscores pro Benutzer: Speichern und Abrufen von Punktzahlen, um den Wettbewerb unter Freunden zu fördern
  • Admin-Funktionen: Moderation von Highscores, Bulk-Löschung und Spam-Schutz
  • Professionelles Agentur-Design: Hochwertige Optik, responsive Layouts, moderne Farbgestaltung
  • AJAX & JS Integration: Reibungslose Interaktionen ohne Seitenreload
  • Vollständig in einer Datei: Einfache Installation ohne komplexe Setups

Technische Details:

  • Backend: PHP mit SQLite-Datenbank
  • Frontend: JavaScript & AJAX für reibungslose Spielmechanik und Highscore-Verwaltung
  • E-Mail-Verifikation für echte Benutzerregistrierungen
  • Einfach zu hosten auf jedem Standard-Webserver

Perfekt für:

  • Gaming-Portale, die interaktive Inhalte mit Benutzerverwaltung anbieten
  • Alle, die eine sofort einsetzbare, vollständige Tetris-Umsetzung suchen

Installation:
Einfach die PHP-Datei auf den Server hochladen, Berechtigungen für die Datenbank setzen – fertig! Alle Funktionen laufen sofort.

<?php
session_start();
date_default_timezone_set('Europe/Berlin');

define('DB_FILE', __DIR__.'/tetris.db');
define('ADMIN_PASS', 'admin123'); // Einfaches Admin-Login
define('SITE_NAME', 'Tetris Dreamcodes');
define('MAIL_FROM', 'no-reply@domain.net');

// SQLite DB
$db = new PDO('sqlite:'.DB_FILE);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Tabellen erstellen
$db->exec("CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    username TEXT UNIQUE,
    email TEXT UNIQUE,
    password TEXT,
    verified INTEGER DEFAULT 0,
    verification_code TEXT
)");

$db->exec("CREATE TABLE IF NOT EXISTS highscores (
    id INTEGER PRIMARY KEY,
    user_id INTEGER,
    score INTEGER,
    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY(user_id) REFERENCES users(id)
)");

// E-Mail-Verifikation
function sendVerificationEmail($email,$code){
    $subject = "Tetris Dreamcodes - E-Mail Verifikation";
    $link = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']."?verify=$code";
    $message = "Bitte verifiziere deine E-Mail-Adresse:\n$link";
    $headers = "From: ".MAIL_FROM;
    mail($email,$subject,$message,$headers);
}

// AJAX Aktionen
if(isset($_POST['action'])){
    $action=$_POST['action'];

    if($action==='register'){
        $username=trim($_POST['username']);
        $email=trim($_POST['email']);
        $password=password_hash($_POST['password'],PASSWORD_DEFAULT);
        $code=bin2hex(random_bytes(16));
        try{
            $stmt=$db->prepare("INSERT INTO users(username,email,password,verification_code) VALUES (?,?,?,?)");
            $stmt->execute([$username,$email,$password,$code]);
            sendVerificationEmail($email,$code);
            echo json_encode(['success'=>true]);
        }catch(Exception $e){
            echo json_encode(['success'=>false,'error'=>$e->getMessage()]);
        }
        exit;
    }

    if($action==='login'){
        $username=trim($_POST['username']);
        $password=$_POST['password'];
        $stmt=$db->prepare("SELECT * FROM users WHERE username=?");
        $stmt->execute([$username]);
        $user=$stmt->fetch(PDO::FETCH_ASSOC);
        if($user && password_verify($password,$user['password'])){
            if($user['verified']==0){
                echo json_encode(['success'=>false,'error'=>'E-Mail nicht verifiziert']);
            } else {
                $_SESSION['user_id']=$user['id'];
                $_SESSION['username']=$user['username'];
                echo json_encode(['success'=>true]);
            }
        } else {
            echo json_encode(['success'=>false,'error'=>'Ungültige Daten']);
        }
        exit;
    }

    if($action==='save_score'){
        if(!isset($_SESSION['user_id'])) { echo json_encode(['success'=>false,'error'=>'Nicht angemeldet']); exit; }
        $score=intval($_POST['score']);
        $stmt=$db->prepare("INSERT INTO highscores(user_id,score) VALUES(?,?)");
        $stmt->execute([$_SESSION['user_id'],$score]);
        echo json_encode(['success'=>true]);
        exit;
    }

    if($action==='get_scores'){
        $stmt=$db->query("SELECT u.username,h.score FROM highscores h JOIN users u ON h.user_id=u.id ORDER BY h.score DESC LIMIT 10");
        $scores=$stmt->fetchAll(PDO::FETCH_ASSOC);
        echo json_encode($scores);
        exit;
    }

    if($action==='logout'){
        session_destroy();
        echo json_encode(['success'=>true]);
        exit;
    }

    if($action==='delete_score'){
        if(isset($_POST['admin_pass']) && $_POST['admin_pass']===ADMIN_PASS){
            $id=intval($_POST['id']);
            $stmt=$db->prepare("DELETE FROM highscores WHERE id=?");
            $stmt->execute([$id]);
            echo json_encode(['success'=>true]);
        } else echo json_encode(['success'=>false,'error'=>'Admin-Passwort falsch']);
        exit;
    }
}

// E-Mail Verifikation
if(isset($_GET['verify'])){
    $code=$_GET['verify'];
    $stmt=$db->prepare("UPDATE users SET verified=1 WHERE verification_code=?");
    $stmt->execute([$code]);
    echo "E-Mail verifiziert! Du kannst dich jetzt anmelden.";
    exit;
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?=SITE_NAME?></title>
<style>
body{margin:0;font-family:sans-serif;background:#111;color:#eee;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;min-height:100vh;}
header{padding:20px;text-align:center;font-size:2em;color:#ffcc00;}
#game{position:relative;width:300px;height:600px;background:#222;margin:20px auto;display:grid;grid-template-rows:repeat(20,1fr);grid-template-columns:repeat(10,1fr);border:3px solid #ffcc00;}
.cell{border:1px solid #111;}
#stats{text-align:center;margin:10px;}
#highscores{margin-top:20px;}
footer{margin-top:auto;padding:10px;color:#888;text-align:center;}
button,input{padding:5px 10px;margin-top:5px;background:#ffcc00;border:none;color:#111;font-weight:bold;cursor:pointer;}
#loginForm,#registerForm{text-align:center;margin:10px;}
</style>
</head>
<body>
<header><?=SITE_NAME?></header>

<div id="loginForm">
<h3>Login</h3>
<input type="text" id="loginUser" placeholder="Benutzername">
<input type="password" id="loginPass" placeholder="Passwort">
<button id="loginBtn">Login</button>
<button id="showRegister">Registrieren</button>
</div>

<div id="registerForm" style="display:none;">
<h3>Registrieren</h3>
<input type="text" id="regUser" placeholder="Benutzername">
<input type="email" id="regEmail" placeholder="E-Mail">
<input type="password" id="regPass" placeholder="Passwort">
<button id="regBtn">Registrieren</button>
<button id="showLogin">Zurück zum Login</button>
</div>

<div id="game"></div>
<div id="stats">
Punkte: <span id="score">0</span> | Level: <span id="level">1</span>
</div>
<div id="highscores">
<h3>Highscores</h3>
<ul id="scoreList"></ul>
</div>

<footer>© <?=date('Y')?> <a href="https://www.dreamcodes.net" target="_blank">Dreamcodes</a> — Tetris</footer>

<script>
// Login/Register Toggle
document.getElementById('showRegister').onclick=()=>{document.getElementById('loginForm').style.display='none';document.getElementById('registerForm').style.display='block';};
document.getElementById('showLogin').onclick=()=>{document.getElementById('registerForm').style.display='none';document.getElementById('loginForm').style.display='block';};

// AJAX Register
document.getElementById('regBtn').addEventListener('click',()=>{
    const u=document.getElementById('regUser').value;
    const e=document.getElementById('regEmail').value;
    const p=document.getElementById('regPass').value;
    fetch('',{
        method:'POST',
        headers:{'Content-Type':'application/x-www-form-urlencoded'},
        body:`action=register&username=${encodeURIComponent(u)}&email=${encodeURIComponent(e)}&password=${encodeURIComponent(p)}`
    }).then(r=>r.json()).then(res=>{alert(res.success?'Registrierung erfolgreich! Prüfe E-Mail.':'Fehler: '+res.error);});
});

// AJAX Login
document.getElementById('loginBtn').addEventListener('click',()=>{
    const u=document.getElementById('loginUser').value;
    const p=document.getElementById('loginPass').value;
    fetch('',{
        method:'POST',
        headers:{'Content-Type':'application/x-www-form-urlencoded'},
        body:`action=login&username=${encodeURIComponent(u)}&password=${encodeURIComponent(p)}`
    }).then(r=>r.json()).then(res=>{alert(res.success?'Login erfolgreich!':'Fehler: '+res.error);});
});

// --- TETRIS JS LOGIK ---
const ROWS=20,COLS=10;
let score=0,level=1,board=[],current=null;
const game=document.getElementById('game');

function initBoard(){board=Array.from({length:ROWS},()=>Array(COLS).fill(0));}
function createCells(){for(let r=0;r<ROWS;r++){for(let c=0;c<COLS;c++){let div=document.createElement('div');div.className='cell';div.id=`cell-${r}-${c}`;game.appendChild(div);}}}
createCells();initBoard();

const tetrominos=[
{shape:[[1,1,1,1]],color:'#ff0000'},
{shape:[[1,1],[1,1]],color:'#00ff00'},
{shape:[[0,1,0],[1,1,1]],color:'#0000ff'},
{shape:[[1,0,0],[1,1,1]],color:'#ff00ff'},
{shape:[[0,0,1],[1,1,1]],color:'#00ffff'},
];

function newTetromino(){current={...tetrominos[Math.floor(Math.random()*tetrominos.length)],r:0,c:3};if(collision()){alert('Game Over');initBoard();score=0;level=1;updateStats();}} 
function draw(){board.forEach((row,r)=>{row.forEach((cell,c)=>{document.getElementById(`cell-${r}-${c}`).style.background=cell?cell:'#222';});});current.shape.forEach((row,i)=>{row.forEach((cell,j)=>{if(cell){const el=document.getElementById(`cell-${current.r+i}-${current.c+j}`);if(el)el.style.background=current.color;}});});}
function collision(){for(let i=0;i<current.shape.length;i++){for(let j=0;j<current.shape[i].length;j++){if(current.shape[i][j]){let r=current.r+i,c=current.c+j;if(r>=ROWS||c<0||c>=COLS||board[r][c])return true;}}}return false;}
function merge(){current.shape.forEach((row,i)=>{row.forEach((cell,j)=>{if(cell)board[current.r+i][current.c+j]=current.color;});});}
function clearLines(){let lines=0;for(let r=ROWS-1;r>=0;r--){if(board[r].every(c=>c)){board.splice(r,1);board.unshift(Array(COLS).fill(0));lines++;r++;}}if(lines>0){score+=lines*100;level=Math.floor(score/500)+1;updateStats();}}
function drop(){current.r++;if(collision()){current.r--;merge();clearLines();newTetromino();}draw();}
function move(dir){current.c+=dir;if(collision())current.c-=dir;draw();}
function updateStats(){document.getElementById('score').textContent=score;document.getElementById('level').textContent=level;}
document.addEventListener('keydown',e=>{if(e.key==='ArrowLeft')move(-1);if(e.key==='ArrowRight')move(1);if(e.key==='ArrowDown')drop();});
setInterval(drop,1000-(level*50));

function loadScores(){fetch('?action=get_scores').then(r=>r.json()).then(data=>{const list=document.getElementById('scoreList');list.innerHTML='';data.forEach(s=>{const li=document.createElement('li');li.textContent=`${s.username}: ${s.score}`;list.appendChild(li);});});}
document.getElementById('saveScore')?.addEventListener('click',()=>{const u=document.getElementById('username').value.trim();if(u){fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:`action=save_score&username=${encodeURIComponent(u)}&score=${score}`}).then(r=>r.json()).then(()=>{loadScores();});}});
newTetromino();draw();updateStats();loadScores();
</script>
</body>
</html>
Dreamcodes Redaktion
Dreamcodes Redaktion
Jeder auf Dreamcodes bereitgestellte Codeschnipsel sowie jede Tutorial Anleitung basiert auf geprüften Best Practices und fundierter Praxiserfahrung. Ziel ist es, ein belastbares technisches Fundament bereitzustellen und keine unausgereiften oder experimentellen Lösungen zu veröffentlichen. Die konkrete Nutzung, Integration, Anpassung und Absicherung der Inhalte obliegt jedoch dem Anwender. Vor dem produktiven Einsatz sind sämtliche Inhalte eigenverantwortlich zu prüfen, zu testen und gegebenenfalls abzusichern. Dreamcodes stellt die technische Grundlage zur Verfügung, die finale Umsetzung und Verantwortung verbleibt beim Nutzer.
Vorheriges Tutorial
Nächstes Tutorial

Vielleicht einen Blick WERT?