Herzlich willkommen zum SELF-Treffen 2026
vom 24.04. – 26.04.2026 in Halle (Saale)

Arcade-Spiele

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Neben der Verbreitung von Computern und PCs kamen in den 70ern Arcade-Spiele auf. [1] An einem Arcade-Automaten mit Bildschirm und Steuerung durch Joystick oder wenige Knöpfe konnten Spieler ihre Geschicklichkeit und ihr Können beweisen. In einem Jump 'n Run bewegt sich eine Spielfigur durch immer neue Szenen.[2]

In vielen Browsergames wie Quizspielen verwenden wir normale HTML-Elemente, um die Benutzeroberfläche zu erstellen. In diesem Arcade-Tutorial verwenden wir jedoch das HTML-Canvas-Element, mit der wir alles direkt auf dem Bildschirm zeichnen und steuern können.

Da das HTML-Canvas-Element lediglich eine Zeichenfläche ist, weiß der Browser nicht, welche Objekte gezeichnet wurden. Daher müssen Klickbereiche und Kollisionen in JavaScript berechnet werden.

Pong

Der Klassiker Pong[3] wurde zuerst auf Geräten in Spielhallen bekannt und simuliert ein simples Tischtennis-Duell:

  • Zwei Spieler steuern ihre Schläger.
  • Ein Ball bewegt sich über das Spielfeld.
  • Ziel ist, den Ball zurückzuschlagen.
  • Wird der Ball verpasst, erhält der Gegner einen Punkt.
<!-- nur mit HTML und JavaScript (ohne Canvas) -->
<div id="spielfeld">
    <div id="mittellinie"></div>
    <div id="punkte-spieler" class="punkte">0</div>
    <div id="punkte-computer" class="punkte">0</div>
    <div class="schlaeger" id="schlaeger-spieler"></div>
    <div class="schlaeger" id="schlaeger-computer"></div>
    <div id="ball"></div>
// Konfiguration zentralisiert
const KONFIG = {
  ball: { radius: 7, maxGeschwindigkeit: 18 },
  schlaeger: { hoehe: 80, geschwindigkeit: 7 },
  siegPunkte: 5,
};
// Verwendung im Code per Name – nie als nackte Zahl:
ball.x += ball.vx * dt;


// Logik und Darstellung getrennt
function aktualisieren(deltaMs) { // nur Zahlen
  const dt = deltaMs / (1000 / KONFIG.schleife.basisFps);
}
function zeichnen() { // nur DOM
  const { ball, spieler, computer } = zustand;
  dom.schlaegerSpieler.style.transform = `translate3d(0,${spieler.y}px,0)`;
}


// Töne ohne Dateien (Web Audio API)
const ctx = new (window.AudioContext();
function ton(typ, freqStart, freqEnde, lautstaerke, dauer, versatz = 0) {
    const t = ctx.currentTime + versatz;
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    
}

Zur Umsetzung dieser WAAPI Version:

Ohne Canvas: Nur mit HTML und JavaScript realisiert.

Konfiguration zentralisiert: Alle Spielparameter in einem Objekt – keine Magic Numbers im Code verteilt.

Logik und Darstellung getrennt: aktualisieren() rechnet, zeichnen() zeigt an – keine Physik im Render-Code.

Töne ohne Dateien (Web Audio API): Kurze Klänge direkt im Browser synthetisiert – kein Download, keine Latenz.

Zoom Auswahl: Script steuert CSS <html style="zoom: 0.8;"> (Stand Anfang 2026: Firefox bei über 100% noch mit Fehlern).

Touch ready: Das Spiel kann per Tastatur, Maus und Finger gesteuert werden.

Breakout

Diese Version des Spielhallenklassikers Breakout[4] kann per Tastatur, Maus und Finger gesteuert werden.

Spielprinzip:

  • Ein Ball prallt durchs Spielfeld und zerstört bunte Steinreihen am oberen Rand.
  • Du steuerst den Schläger unten.
  • Verpasst du den Ball, verlierst du eines von drei Leben.
  • Ziel ist es, alle Steine zu zerstören.
  • Hast du alle Leben verbraucht, bevor alle Steine weg sind, ist das Spiel vorbei.

Bei schmalem Viewport wird einmalig beim Laden der Canvas verkleinert.

Breakout ansehen …
<!-- HTML mit Canvas -->
<body>
  <p id="info">PUNKTE: 0 | LEBEN: 3</p>
  <canvas id="c"></canvas>
  <p>← → Pfeiltasten / Maus · Leertaste / Klick für Start</p>

Game Loop

Ein Canvas-Spiel läuft normalerweise in einer kontinuierlichen Schleife:


Game Loop
  function loop() {
    update();
    draw();
    if (state.paused) {
      showMessage(state.pauseMsg, 'Punkte: ' + state.score);
      rafId = null;
    } else {
      rafId = requestAnimationFrame(loop);
    }
  }
  1. Aktualisiere den Spielstatus update()
  2. Zeichne den neuen Status draw()
  3. Wiederhole dies mehrmals pro Sekunde
    Wenn das Spiel nicht pausiert oder gestoppt wird, wird loop() erneut durch requestAnimationFrame() aufgerufen (in der Regel ~60 Mal pro Sekunde).
    Dadurch wird der nächste Frame geplant.

Canvas

Die Funktion draw() ist für die Darstellung des aktuellen Spielzustands auf der Leinwand verantwortlich. Sie zeichnet alles neu, was du im Spiel siehst: Hintergrundtext, Steine, Schläger und Ball.

draw() - die Leinwand wird befüllt
  function draw() {
    const { paddle: P, ball: B, steine: S, schrift: F } = KONFIG;
    ctx.clearRect(0, 0, W, H);

    ctx.save();
    ctx.globalAlpha  = 0.15;
    ctx.fillStyle    = '#fff';
    ctx.font         = `bold ${Math.round(W * 0.18)}px monospace`;
    ctx.textAlign    = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('BREAKOUT', W/2, H * 0.83);
    ctx.restore();

    for (const b of bricks) {
      if (!b.alive) continue;
      ctx.fillStyle = b.color;
      ctx.fillRect(b.x, b.y, S.breite, S.hoehe);
    }

    ctx.fillStyle = '#fff';
    ctx.fillRect(paddle.x, paddle.y, P.breite, P.hoehe);

    ctx.beginPath();
    ctx.arc(ball.x, ball.y, B.radius, 0, Math.PI * 2);
    ctx.fillStyle = '#fff';
    ctx.fill();
  }
const { paddle: P, ball: B, steine: S, schrift: F } = KONFIG;

Diese Zeile extrahiert Werte aus dem Konfigurationsobjekt und gibt ihnen kurze Namen:

P → Paddel-Einstellungen

B → Ball-Einstellungen

S → Brick-Einstellungen

F → Schriftart-Einstellungen

Dadurch wird der Code kürzer und leichter lesbar.

ctx.clearRect(0, 0, W, H);

Die vorhandene Leinwand wird gelöscht. Ohne diesen Schritt würde jeder Frame über den vorherigen gezeichnet werden und Spuren hinterlassen.

for (const b of bricks) {
  if (!b.alive) continue;
  ctx.fillStyle = b.color;
  ctx.fillRect(b.x, b.y, S.breite, S.hoehe);
}

Diese Schleife durchläuft jeden Stein im Spiel.

Wenn der Stein zerstört ist (!b.alive) → überspringen

Andernfalls ein Rechteck an seiner Position zeichnen

fillRect(x, y, width, height) zeichnet jeden Stein.

ctx.fillStyle = '#fff';
ctx.fillRect(paddle.x, paddle.y, P.breite, P.hoehe);

Dadurch wird das Spielerpaddel anhand seiner aktuellen Position als weißes Rechteck gezeichnet.

Kollisionserkennung

Ziel des Spiels ist es ja, die Steine mit dem Ball zu treffen und zu zerstören. Dafür benötigt man eine Kollisionserkennung (collision detection), bei der überprüft wird, ob sich zwei Elemente berühren, bzw. übereinanderliegen. Für HTML gibt es die Element.getBoundingClientRect()-Methode, mit der die Abmessungen berechnet und dann verglichen werden können.[5]

if (ball.x + B.radius > b.x &&
    ball.x - B.radius < b.x + S.breite &&
    ball.y + B.radius > b.y &&
    ball.y - B.radius < b.y + S.hoehe)

In Canvas verwenden wir diese Standardfunktion axis-aligned bounding box (AABB). Sie beantwortet eine Frage:

Überlappen sich die Bereiche zweier Objekte?[6]

Eine Kollision tritt auf, wenn sich zwei Objekte gleichzeitig horizontal und vertikal überlappen.
Die Funktion überprüft die vier Kanten der Objekte. Wenn keine davon voneinander getrennt ist, müssen sich die Objekte berühren.

Snake

Snake [7] beinhaltet ein ganzes Genre von Spieleklassikern mit verschiedenen Namen.

  • Du steuerst die Schlange, die sich durchs Spielfeld bewegt.
  • Frisst die Schlange einen Apfel, wird sie länger und du bekommst einen Punkt.
  • Berührt die Schlange sich selbst, ist das Spiel vorbei.
  • Ziel ist es, möglichst viele Äpfel zu fressen, ohne sich selbst in den Weg zu kommen.
  • Mit steigender Punktzahl wird die Schlange schneller.

Diese Version kann nur per Tastatur gesteuert werden. Stand Anfang 2026: Beim Laden setzt einzig der Safari Browser den Fokus nicht gleich auf das Spielfeld, dort muss zuerst per TAB-Taste oder Mausklick der Fokus gesetzt werden.

Besonderheiten:

  • Canvas-Rendering mit Glüheffekten (shadowBlur) und abgerundeten Zellen (roundRect).
  • Spielschleife via setInterval, Intervall sinkt dynamisch mit dem Level.
  • Richtungspuffer verhindert sofortige Umkehr.
  • localStorage speichert den Bestwert dauerhaft.
  • Konstanten zentral konfiguriert.
<!-- HTML mit Canvas) -->
  <div class="anzeige">
    <span>Punkte <b id="punkte">0</b></span>
    <span>Bestwert <b id="bestwert">0</b></span>
    <span>Level <b id="level">1</b></span>
  </div>

  <div class="spielfeld">
  
    <canvas id="leinwand"></canvas>

    <div class="einblendung" id="einblendung">
      <h1 id="einblendungTitel">Snake</h1>
      <p id="einblendungText"></p>
      <p class="steuerung">Leertaste zum Starten</p>
    </div>
  </div>
// Steuerung per Tasten
document.addEventListener('keydown', e => {
  const taste = e.key.toLowerCase();

  if (taste === ' ') { e.preventDefault(); laeuft ? pauseUmschalten() : spielStarten(); return; }

  const neueRichtung = TASTEN_RICHTUNG[taste];
  if (!neueRichtung) return;
  if (!gleich(neueRichtung, gegenrichtung(richtung))) naechsteRichtung = neueRichtung;
  if (taste.startsWith('arrow')) e.preventDefault();
});

Space Invaders

Diese vereinfachte Mini-Version von Space Invaders [8] verzichtet auf Details, verschiedene Gegner und deren Animation.

Das Spiel wird per Tastatur gesteuert. Stand Anfang 2026: Beim Laden setzt einzig der Safari Browser den Fokus nicht gleich auf das Spielfeld, dort muss zuerst per TAB-Taste oder Mausklick der Fokus gesetzt werden.

Spielprinzip:

  • Aliens rücken von oben heran und werfen Bomben auf dich.
  • Du steuerst ein Raumschiff am unteren Rand und schießt mit der Leertaste.
  • Triffst du alle Aliens, gewinnst du.
  • Wirst du dreimal getroffen, ist das Spiel vorbei.
  • Schutzblöcke in der Mitte halten ein paar Treffer ab, bevor sie zerstört werden.
  • Je weniger Aliens noch leben, desto schneller bewegen sie sich.

Besonderheiten:

  • Game Loop per requestAnimationFrame mit ca. 60FPS, ruft sich selbst rekursiv auf.
  • Gesamter Spielzustand als ein Objekt.
  • Dynamische Alien-Geschwindigkeit.
  • Pixel-Art-Sprites rein durch fillRect, kein einziges Bild.
Beispiel ansehen …
// Game Loop
function spielSchleife() {
  if (!zustand.laeufst) return;
  aktualisieren();
  zeichnen();
  requestAnimationFrame(spielSchleife);
}

// Spielzustand, darin "leben" alle veränderlichen Daten
let zustand = erstelleNeuesSpiel();
function erstelleNeuesSpiel() {
  return { laeufst: false, punkte: 0, leben: 3, spieler: {...}, laser: [], ... };
}

// Aliens werden schneller, je weniger von ihnen noch leben
const tempo = ALIEN_GESCHWINDIGKEIT_X *
  (1 + (1 - lebendeAliens.length / (ALIEN_REIHEN * ALIEN_SPALTEN)));

// Grafik in Pixel-Art, bestehend nur aus Rechtecken
ctx.fillRect(x +  6, y,      18, 4); // Kopf
ctx.fillRect(x +  2, y +  4, 26, 8); // Körper

Siehe auch

Eine noch komplexere Möglichkeit ist WebGPU, mit der man hardwarebeschleunigte 3D-Grafiken im canvas-Element direkt im Browser – ohne zusätzliche Erweiterungen – darstellen kann. Allerdings ist hier wirklich zu empfehlen, Frameworks einzusetzen, um nicht immer wieder das Rad neu erfinden zu müssen.

Bewegung und Animation

Schießen, Werfen und Aufprallen, sowie das Hüpfen eines Balles bestehen nicht aus einer linearen Bewegung, sondern aus Kurven, denen Objekte mit unterschiedlicher (meist abnehmender) Geschwindigkeit folgen.


  • Canvas
  • WebGPU

    hardwarenahe, beschleunigte Grafik- und Computer-Berechnungen

  • Web Animations (WAAPI)

    Animationen mit JavaScript steuern

Weblinks

  1. Wikipedia: Arcade-spiel
  2. Wikipedia: Jump ’n’ Run (auf englisch platform games)
  3. Wikipedia: Pong
  4. Wikipedia: Breakout
  5. Stack Overflow: How to detect if two divs are touching/ collision detection
  6. MDN: 2D collision detection
  7. Wikipedia: Snake
  8. Wikipedia: Space Invaders



Abgerufen am 8.03.2026
von "http://wiki.selfhtml.org/wiki/Arcade-Spiele"