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 Inhalt auf Dreamcodes entsteht mit einem klaren Anspruch: geprüfte Praxis statt schneller Theorie. Was hier veröffentlicht wird, basiert auf Best Practices, echten Projekterfahrungen und technischem Verständnis, das über das Offensichtliche hinausgeht. Unser Ziel ist ein Fundament, auf dem du aufbauen kannst, nicht eines, das beim ersten produktiven Einsatz bricht. Wie du die Inhalte integrierst, absicherst und in deinen Kontext überträgst, liegt bei dir. Die fachliche Grundlage liefern wir, die Verantwortung für den Einsatz bleibt deine.
Vorheriges Tutorial
Nächstes Tutorial

Vielleicht einen Blick WERT?