HTML5-Tutorium: Canvas: MiniPong 01: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Zeile 264: Zeile 264:
<dt>Tunneln
<dt>Tunneln
<dd>Da die Wände im Kollisionstest unendlich dick gewählt wurden, kann der Ball diese nicht durchdringen. Wenn Sie aber die Breite der Wände in der Funktion  
<dd>Da die Wände im Kollisionstest unendlich dick gewählt wurden, kann der Ball diese nicht durchdringen. Wenn Sie aber die Breite der Wände in der Funktion  
<code>0_redraw</code> auf Null reduzieren, haben Sie nicht lange Freude an Ihrem Ball:
<code>o_redraw</code> (in der Datei <code>main.js</code>) auf Null reduzieren, haben Sie nicht lange Freude an Ihrem Ball:
<source lang="javascript">
<source lang="javascript">
   if (g_ball.x == g_ball.r || g_ball.x == CANVAS_WIDTH  - g_ball.r)
   if (g_ball.x == g_ball.r || g_ball.x == CANVAS_WIDTH  - g_ball.r)

Version vom 24. Oktober 2013, 11:11 Uhr

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 3
(einige wichtige Fakten fehlen)
Quellenangaben: 5
(vollständig vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 5
(ausgezeichnet)

HTML-Tutorium: MiniPong

MiniPong: | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5

Musterlösung: Minipong 1 (SVN-Repository)

Voraussetzung

Sie sollten die Inhalte des Tutoriums HTML5-Tutorium: Canvas: Hello World kennen.

Ziel: Animation des Balls

Im ersten Teil des Tutoriums wird beschrieben, wie man eine einfache Ball-Animation erstellt.

Zwei Objekte werden implementiert: Das ROOT-Objekt der Anwendung und das zu animierende Ball-Objekt. miniatur|ohne|381px|Das Objektmodell von MiniPong 01

Das ROOT-Objekt wird bei Programmstart von JavaScript automatisch erzeugt. Variablen und Konstanten, die in diesem Objekt enthalten sind, sind global zugänglich. Das heißt, alle Objekte können darauf zugreifen.

Das MiniPong-01-Root-Objekt enthält eine Reihe von Konstanten, drei globale Variablen sowie zwei Funktionen:

  • g_context (der 2D-Kontext der Bühne, auf der der Ball animiert wird)
  • g_timer (das Timerobjekt; es ruft regelmäßig o_redraw auf)
  • g_ball (der zu animierende Ball)
  • f_init (initialisiert die Anwendung, nachdem die zugehörige HTML-Seite geladen wurde)
  • o_redraw (positioniert den Ball unter Berücksichtigung von Kollisionen mit der Wand neu und zeichnet anschließend den Bühneninhalt neu)

Das Ball-Objekt enthält fünf Attribute sowie zwei Methoden:

  • r (Radius des Balls)
  • x (x-Postion des Ball auf der Bühne)
  • y (x-Postion des Ball auf der Bühne)
  • vx (Geschwindigkeit des Ball in x-Richtung)
  • vy (Geschwindigkeit des Ball in y-Richtung)
  • move (bewegt dne Ball abhängig von seiner aktuellen Geschwindikkeit an eine neue Position)
  • draw (zeichnet den Ball an seiner akutellen Position auf den 2D-Kontext der Bühne)

Achtung: Die im Objektmodell angegebenen ObjektnamenROOT“ und „ball“ existieren in JavaScript nicht. In JavaScript gibt es nur Objektidentifikatoren (und zwar Speicheradressen im Heap-Bereich), die nach Erstellung eines Objektes i. Allg. in einer Variablen, einem Array oder einem Funktionsparameter gespeichert werden. In der hier vorgestellten Implementierung von MiniPong 01 wird beispielsweise der OID des Ball-Objekts in der Variablen g_ball abgelegt.

Anwendung „MiniPongCanvas01

Neues Projekt anlegen

Legen Sie ein neues „Statisches Web-Projekt“ mit dem Namen MiniPongCanvas01 an.

Speichern Sie dieses Projekt wie üblich in Ihrem Repository.

Dateien erstellen

index.html

Erstellen Sie im Ordner WebContent des Projektes die Datei index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>HTML5-Tutorium: MiniPong 01 (Canvas)</title>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

    <link rel="stylesheet" href="css/main.css"   />

    <script type="text/javascript" src="js/CONSTANT.js"></script>
    <script type="text/javascript" src="js/main.js"    ></script>
 </head>
  <body>
    <canvas id="d_canvas">
      Ihr Browser unterstützt HTML5 leider nicht!
    </canvas>
  </body>
</html>

Anstelle von main.css und main.js können Sie auch wieder all.min.css und all.min.js einbinden, sofern Sie diese Dateien mit Hilfe von yuicompressor erzeugen (vgl. HTML5-Tutorium: Canvas: Hello World 03).

main.css

Erstellen Sie im Ordner WebContent/css des Projektes die Datei main.css:

body
{ text-align:       center;
  padding:          10px;
  background-color: #AAA;
}

#d_canvas
{ border-color: #777; 
  border-width: 2px; 
  border-style: solid;
  
  background-color: #CCC;
}

CONSTANT.js

Erstellen Sie im Ordner WebContent/js des Projektes die Datei CONSTANT.js:

"use strict";

const CANVAS_WIDTH  = 400,
      CANVAS_HEIGHT = 300,

      FPS = 50, // Frames Per Second

      BALL_RADIUS = 8,   // pixels
      BALL_X      = CANVAS_WIDTH  / 2,
      BALL_Y      = CANVAS_HEIGHT / 2,
      BALL_VX_MIN = 100, // pixels per second
      BALL_VX_MAX = 200, // pixels per second
      BALL_VY_MIN = 100, // pixels per second
      BALL_VY_MAX = 200, // pixels per second

      BALL_BORDER_WIDTH = 1,
      BALL_BORDER_COLOR = "#000000",
      BALL_COLOR        = "#55AA55";

main.js

Erstellen Sie im Ordner WebContent/js des Projektes die Datei main.js.

Für die Animation des Balles braucht man zwei Hilfsbjekte: Den 2D-Kontext, auf dem sich der Ball bewegen soll, sowie einen Timer, der regelmäßig (FPS mal pro Sekunde; FPS steht für Frames Per Second) eine Neuberechnung der Ballposition sowie ein Neuzeichnen der Bühne veranlasst.

// the 2d context of the canvas
var g_context,

// the "physics engine" timer
    g_timer,

Als nächstes wird ein Ball-Objekt erstellt. Diese Objekt hat fünf (öffentliche) Attribute, die mit sinnvollen Werten initialisiert werden:

  • r (Radius des Balls)
  • x (Aktuelle x-Positions des Balls)
  • y (Aktuelle y-Positions des Balls)
  • vx (Aktuelle Geschwindigkeit des Balls in x-Richtung in Pixeln/Sekunde)
  • vy (Aktuelle Geschwindigkeit des Balls in y-Richtung in Pixeln/Sekunde)

Darüber hinaus besitzt dieses Objekt zwei Methoden:

  • move bewegt den Ball an seine neue Position; dieses wird aus dem Geschwindigkeitsvektor und der Zeitspanne, die zwischen zwei Aufrufen des move-Befehls vergeht, berechnet
  • draw visualisiert das (zweidimensionale) Ball-Objekt auf dem 2D-Kontext einer Bühne (Canvas).
// the ball
    g_ball = 
    { r:  BALL_RADIUS,
      x:  BALL_X,
      y:  BALL_Y,
      vx:   (Math.random() < 0.5 ? 1 : -1)
          * (BALL_VX_MIN + Math.random() * (BALL_VX_MAX - BALL_VX_MIN)), 
      vy:   (Math.random() < 0.5 ? 1 : -1)
          * (BALL_VY_MIN + Math.random() * (BALL_VY_MAX - BALL_VY_MIN)),

      // Moves the ball in direction (vx,vy); the step size depends on FPS.
      move: 
        function()
        { this.x += this.vx/FPS;
          this.y += this.vy/FPS;
        },

      // Draws the ball at its current position onto a 2d context.
      draw:
        function(p_context)
        { p_context.beginPath();
          p_context.arc(this.x, this.y, this.r, 0, 2*Math.PI);
          p_context.lineWidth = BALL_BORDER_WIDTH;
          p_context.lineStyle = BALL_BORDER_COLOR;
          p_context.fillStyle = BALL_COLOR;
          p_context.stroke();
          p_context.fill();
        }
    };

Sobald die HTML-Seite vollständig geladen worden ist, werden die Bühne initialisiert und der Timer gestartet.

// Execute the init function after the HTML page has been loaded.
window.onload = f_init;

// Has to be called after the HTML page has been loaded.
function f_init() 
{ var l_canvas = document.getElementById("d_canvas");

  // Initialize the canvas.
  l_canvas.width  = CANVAS_WIDTH;
  l_canvas.height = CANVAS_HEIGHT;
  g_context       = l_canvas.getContext("2d");

  // Start the timer for redrawing the canvas every 1000/FPS seconds.
  g_timer = window.setInterval(o_redraw, 1000/FPS);
}

Die so genannte Observer-Methode o_redraw() wird alle paar Millisekunden vom Timer aufgerufen. Diese Methode hat drei Aufgabe:

  1. Kollisionen zwischen Ball und Wand erkennen und gegebennenfalls die Bewegungsrichtung des Balls ändern.
  2. Den Ball an seine neue Position bewegen.
  3. Den aktuellen Inhalt der Bühne löschen und den Ball an der neuen Position auf die Bühne zeichnen.
// An event observer: 
// It is called every 1000/FPS seconds.
function o_redraw() 
{ // Collision detection: ball <-> wall 
  // Collision response:  change the moving direction of the ball
  if (g_ball.x <= g_ball.r || g_ball.x >= CANVAS_WIDTH  - g_ball.r)
  { g_ball.vx = -g_ball.vx; }
  if (g_ball.y <= g_ball.r || g_ball.y >= CANVAS_HEIGHT - g_ball.r)
  { g_ball.vy = -g_ball.vy; }
  
  // Move the ball.
  g_ball.move();

  // Clear and redraw the canvas
  g_context.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  g_ball.draw(g_context);
}

Dieses Skript realisiert die eigentliche Ball-Animation. Zum Einsatz kommen dabei Techniken, die im Tutorium von Alexander Lawrence genauer beschrieben werden: AS3-Tutorium:Physics. Sehen Sie sich insbesondere folgende Abschnitte an:

Anwendung testen und sichern

Testen Sie Ihre Anwendung in gewohnter Weise.

Vergessen Sie nicht, sie im SVN-Repository zu sichern.

Probleme der Kollisionserkennung

Die A-posteriori-Kollissionserkennung, die in Minipong 1 bei der Erkennung von Kollisionen zwischen Ball und Wand angewandt wurde, ist nicht ganz unproblematisch, da zwei unerwünschte Effekte auftreten können:

Überlappung (penetration = Eindringung)
Der Ball dringt i.Allg. etwas in die Wand ein, bevor eine Kollision erkannt wird. Wenn dieses Eindringen durch die Kollissionsbehandlung nicht rückgängig gemacht wird, kann es passieren, dass der Ball in der Wand hängen bleibt, da er sich in allen folgenden Animationsschritten in der Wand befindet und daher in jedem Schritt seine Richtung ändert.
Tunneln (tunneling)
Wenn der Ball besonders schnell ist, kann er ein anderes Objekt eventuell durchtunneln. Dies passiert immer dann, wenn der Ball in einem Schritt eine so große Distanz zurücklegt, dass weder am Startpunkt noch am Endpunkt dieses Schritts eine Kollision erkannt wird, obwohl entlang des Weges eine Kollision stattgefunden hätte.

Beide Effekte können Sie beobachten, wenn Sie Ihren Minipong-1-Code etwas modifizieren.

Überlappung
Setzen Sie BALL_Y = CANVAS_HEIGHT (in der Datei CONSTANT.js), d.h., platzieren Sie den Ball gleich zu Beginn in der Wand, und starten Sie die Anwendung. Nach dem Sie den Effekt bewundert haben, sollten Sie den Fehler auch wieder beheben. :-)
Tunneln
Da die Wände im Kollisionstest unendlich dick gewählt wurden, kann der Ball diese nicht durchdringen. Wenn Sie aber die Breite der Wände in der Funktion o_redraw (in der Datei main.js) auf Null reduzieren, haben Sie nicht lange Freude an Ihrem Ball:
  if (g_ball.x == g_ball.r || g_ball.x == CANVAS_WIDTH  - g_ball.r)
  { g_ball.vx = -g_ball.vx; }
  if (g_ball.y == g_ball.r || g_ball.y == CANVAS_HEIGHT - g_ball.r)
  { g_ball.vy = -g_ball.vy; }

Erweiterung

Erweitern Sie die Anwendung so, dass sich zwanzig Bälle gleichzeitig über die Bühne bewegen. Kollisionen zwischen den Bällen brauchen Sie nicht zu behandeln. Beachten Sie aber das Programmierprinzip „Don't repeat yourself“ (Dry).

miniatur|ohne|691px|Das Objektmodell von MiniPong 01a

Musterlösung: Minipong 1a (SVN-Repository)

Varianten

Die folgenden Beispiele wurden gegenüber der zuvor beschrieben Version in zweierlei Hinsicht erweitert:

  1. Die Implementierung is klassenbasierte und nicht objektbasiert.
  2. Die Bälle reagieren auf Mausklicks.
Canvas, externe Bibliotheken: keine
Minipong 1a (SVN-Repository)
Canvas, externe Bibliotheken: Prototype
Minipong 1a (SVN-Repository)
Canvas, externe Bibliotheken: jQuery, jCanvas, jQueryMX (class.js)
Minipong 1a (SVN-Repository)
SVG, externe Bibliotheken: jQuery, jCanvas, jQueryMX (class.js), Raphaël
Minipong 1a (SVN-Repository)

Quellen

  1. Braun (2011): Herbert Braun; Webanimationen mit Canvas; in: c't Webdesign; Band: 2011; Seite(n): 44–48; Verlag: Heise Zeitschriften Verlag; Adresse: Hannover; 2011; Quellengüte: 5 (Artikel)
  2. Kowarschick (MMProg): Wolfgang Kowarschick; Vorlesung „Multimedia-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 3 (Vorlesung)
  3. Musterlösungen, Musterlösungen (SVN)

Fortsetzung des Tutoriums

Sie sollten nun Teil 2 des Tutoriums bearbeiten.