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

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Kowa (Diskussion | Beiträge)
Kowa (Diskussion | Beiträge)
Zeile 530: Zeile 530:
   this.reset(); // initializes further attributes
   this.reset(); // initializes further attributes
}
}
<source>
</source>


'''Öffentliche Methoden'''
'''Öffentliche Methoden'''
Zeile 598: Zeile 598:
     { this.x  += this.vx * p_seconds;
     { this.x  += this.vx * p_seconds;
       this.y  += this.vy * p_seconds;
       this.y  += this.vy * p_seconds;
      this.vx += this.ax * p_seconds;
      this.vx += this.ax * p_seconds;
      this.vy += this.ay * p_seconds;
      this.vy += this.ay * p_seconds;
     },
     },



Version vom 30. November 2016, 14:12 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: index.html (WK_MiniPong04 (SVN))

Leeres Projekt: index.html (WK_MiniPong04_empty (SVN))

Ziel: Das fertige Spiel „MiniPong“

Im vierten Teil des Tutoriums wird eine funktionsfähige Version von MiniPong erstellt.

Use Cases

Use Cases der Tutoriums-Anwendung MiniPong
Use Cases der Tutoriums-Anwendung MiniPong

Ein Spieler kann das Spiel starten (Startknopf) und vorzeitig beenden (Stopp-Knopf). Nach Spielstart kann der Spieler den Schläger am unteren Rand des Spielfeldes mit Hilfe der Richtungstasten des Keyboards nach links und rechts bewegen.

Nachdem das Spiel gestartet wurde, bewegt sich der Ball geradlinig im Spielfeld, wobei die Startrichtung zufällig gewählt wird. Kollisionen mit der linken, oberen oder rechten Wand haben eine Richtungsänderung des Balls zur Folge (Einfallswinkel = Ausfallwinkel). Eine Kollision mit der unteren Wand beendet das Spiel.

Ziel des Spiels sind möglichst viele Kollision des Balls mit dem Schläger. Eine derartige Kollision hat eine Richtungsänderung sowie einen Punktgewinn zur Folge. Der aktuelle Punktestand (Score) wird der Benutzer jederzeit angezeigt.

Wird der Schläger im Moment der Kollision bewegt, so wird der Ball abhängig von der Bewegungsrichtung und Geschwindigkeit des Schlägers abgelenkt (Simulation von Reibung).

Klassenmodell

Klassendiagramm

Eine genauere Analyse der Use Cases zeigt, welche Module benötigt werden. Die verschiedenen Module sind verschieden eingefärbt:

  • grau: Initialisierung der Anwendung
  • blau: Model der Anwendung
  • orange: Controller zur Behandlung der Benutzeraktionen (mit Ausnahme von Formularelementen, die in der View enthalten sind)
  • flieder: Anwendungslogik
  • grün: Anwendungsview
  • gelb: Kollisionserkennung und -behandlung

Die Kollisionserkennung und -behandlung erhält eine eigene Farbe, da sie eine Mischung aus Model und Controller ist. Einerseits verändert sie die Bewegungseigenschaften beweglicher Objekte (Ball und Schläger). Das heißt, sie ist wesentlicher Bestandteil des Models. Andererseits informiert sie die Anwendung über Aktionen des Balls, damit diese entsprechend reagieren kann. Dies ist eine typische Controllertätigkeit.

Das Modul „init“ hat die Aufgabe das Spiel zu initialisieren. Es definiert eine Prozedurinit“, die zunächst die wesentlichen Objekte erstellt und dann das Spiel startet. Im Klassendiagramm sind rote Pfeile zu den Modulen eingezeichnet, die das Init-Modul benötigt. Das sind die beiden Funktionsmodule „logic/minipong“ und „control/keyboard“ sowie diverse Model- und View-Klassen. Für jede dieser Klassen – mit Ausnahme der Klasse „ModelStage“ – erzeugt init ein oder im Falle der Text-Klassen sogar jeweils zwei Objekte. Als Stage-Objekt kommt – wie im dritten Teil des Tutoriums – das in der HTML-Datei enthaltene Canvas-Element zum Einsatz.

Die View-Objekte sind ausschließlich der Prozedur „init“ bekannt. Diese Objekte visualisieren die Model-Objekte, d. h. den aktuellen Zustand des Spiels. Da sich der Zustand des Spiel häufig ändert, erstellt init eine View-Loop, deren Aufgabe es ist, die Visualisierung möglichst häufig, am Besten 60 mal pro Sekunde zu erneuern. Dazu ruft die View-Loop, sobald sie einmal gestartet wurde, regelmäßig die Zeichenmethode „draw“ der einzelnen View-Objekte auf.

Klassendiagramm: Detailansicht der View-Loop

Die View umfasst sechs Elemente:

  • einen Button (Start, Stopp)
  • einen Ball
  • einen Schläger
  • zwei Textfelder (Score und allgemeine Informationen)

Die View-Loop muss diese sechs Objekte selbstverständlich kennen, damit sie sie darstellen kann. Die entsprechenden Beziehungspfeile (blau markiert) werden allerdings nur der nebenstehenden Detailansicht des Klassendiagramms, aber nicht im Übersichtsdiagramm angezeigt (da das Übersichtsdiagramm anderenfalls etwas unübersichtlich werden würde). Die Init-Prozedur erzeugt diese View-Objekte sowie die zugehörigen Model-Objekte, ordnet den View-Objekten die entsprechenden Model-Objekte zu und übergibt dann ein Array mit allen View-Objekten der View-Loop. Sobald diese gestartet wird, aktualisiert sie regelmäßig die grafische Darstellung dieser Objekte im HTML-Dokument.

Die Init-Prozedur lädt ein weiteres Modul: „control/keyboard“. Diese fängt alle Tastaturereignisse ab. Sobald auf der Tastatur eine entsprechende Taste gedrückt wird, ruft sie sie Methode „start“ des Schlägers (d. h. eines Objektes der Klasse „ModelPaddle“) auf und setzt ihn in Bewegung. Welcher Taste welche Bewegungsrichtung zugeordnet ist, wird in der Init-Datei „init.json“ festgelegt.

Danach wird das eigentlich Spiel gestartet. Die Spiellogik wird in der Prozedur „minipong“ implementiert. Diese Prozedur muss die Model-Objekte des Spiels kennen, da sie deren Werte liest und in bestimmten Situationen verändert. Jede Änderung einen Model-Objekts, dem ein View-Objekt zugeordnet ist, wird fast sofort (genau gesagt, bei der nächsten Ausführung der View-Loop) visualisiert. Da dies automatisch geschieht, muss die Prozedur „minipong“ nichts weiter machen, als beispielsweise den Text innerhalb eines Text-Objekts der Klasse „ModelText“ oder die Beschriftung des Buttons innerhalb des Objekts der Klasse „ModelButton“ zu ändern. Sobald dies geschehen ist, wird die Änderung im HTML-Dokument automatisch übernommen.

Die Spiellogik hat zwei wichtige Aufgaben:

  1. Simulation der Ball/Schläger-Physik
  2. Reaktion auf Ereignisse wie Aktivierung des Start-Buttons (Spielstart), Kollision des Schlägers mit dem Ball (Punktgewinn), Verlust des Balles am unteren Bühnenrand (Spielende) etc.
Klassendiagramm: Detailansicht der Model-Loop

Für die erste Aufgabe verwendet sie eine Model-Loop, die alle beweglichen Objekte, d. h. alle Model-Objekte, die über die Methode „move“ verfügen, möglichst oft pro Sekunde mittels dieser Methode an eine neue Position verschiebt. Das nebenstehende Diagramm zeigt abermals eine Detailansicht des Klassendiagramm, in dem alle für die ModelLoop notwendigen Beziehungen eingetragen wurde. Auch hier gilt: Im Übersichtsdiagramm wurden die Beziehungspfeile, die im nebenstehenden Diagramm blau markiert wurden, aus Gründen der Übersichtlichkeit nicht eingetragen.

Die Model-Loop wird nicht von der Init-Prozedur, sondern von der Prozedur „minipong“ erzeugt. Die Init-Prozedur benötigt dieses Objekt nicht. Die MiniPong-Prozedur benötigt es dagegen nicht nur, sondern muss es auch gemäß ihren Bedürfnissen initialisieren: Der ModelLoop muss eine spezielle Kollisionsfunktion übergeben werden.

Die zweite Aufgabe „Reaktion auf Ereignisse“ zerfällt in zwei Aufgaben.

  1. Reaktion auf Aktionen des Benutzers.
  2. Reaktion auf Aktionen des Balls.

In diesem Spiel gibt es nur eine Benutzeraktion, auf die minipong direkt reagieren muss: „Klick auf den Start-Stopp-Button“ . Die zweite Aktion „Bewegung des Schlägers“ wird vom Keyboard-Controller direkt an den Schläger weitergeleitet. Für die Aktion „Button-Klick“ muss minipong dem Button in jedem der beiden Spielzustände „Spiel gestoppt“ und „Spiel gestartet“ eine geeignete Callback-Funktion zuweisen, die die jeweils passende Aktion ausführt. Im Fall „Spiel gestoppt“ muss der Button-Klick das Spiel starten und im Fall „Spiel gestartet“ muss er das Spiel beenden.

Der Ball kann zwei weitere Aktionen ausführen. Er kann mit dem Schläger kollidieren oder das Spielfeld verlassen. Beide Aktionen werden von der Kollisionsbehandlung erkannt. Jedes mal, wenn eine wenn der Ball eine dieser beiden Aktionen durchführt muss die Prozedur „minipong“ darüber informiert werden, damit sie entsprechend reagieren kann. Hierzu definiert sie mit Hilfe der drei Hilfs-Prozeduren „collisionBallPaddle“, „collisionBallPaddle“ und „collisionStagePaddle“ eine geeignete Kollissionsprozedur, die sie der Model-Loop zur Kollisionserkennung und -behandlung übergibt.

Neues Projekt anlegen

Legen Sie ein neues Projekt mit dem Namen „MiniPong04“ an.

Erstellen Sie folgende Ordner:

  • web
  • web/css
  • web/json
  • web/js
  • web/js/lib
  • web/js/lib/require
  • web/js/app
  • web/js/app/collision
  • web/js/app/control
  • web/js/app/logic
  • web/js/app/model
  • web/js/app/view

Kopieren Sie folgende Dateien des Projektes MiniPong03 in das neue Projekt:

  • web/index.html (Ersetzen Sie im Titel „MiniPong03“ durch „MiniPong04“ und ersetzen Sie im Copyright-Kommentar meinen Namen durch Ihren Namen.)
  • web/css/main.css
  • web/json/init.json
  • web/js/lib/require/json.js
  • web/js/lib/require/require.js
  • web/js/lib/require/text.js

Erstellen Sie die Datei „web/js/main.js“ und fügen Sie folgenden Code ein:

requirejs.config
({
  baseUrl: 'js', // By default load any modules from directory js
  paths :
  {
    app:       'app',

    model:     'app/model',
    view:      'app/view',
    control:   'app/control',
    logic:     'app/logic',
    collision: 'app/collision',

    loadjson:  'lib/require/json',
    text:      'lib/require/text',
    json:      '../json'
  }
});

requirejs
( ['loadjson!json/init.json', 'app/init'],
  function(initJSON, init)
  {
    //init(window, initJSON);
  }
);

Für jedes Modulpaket wurden ein Ordner angelegt und eine Kurzbezeichnung des Modulpfades festgelegt:

Farbe Ordner Modulpfad Modulzweck
grau js/app app Initialisierung der Anwendung
blau web/js/app/model model Model der Anwendung
grün web/js/app/view view Anwendungsview
orange web/js/app/controller controller Controller zur Behandlung der Benutzeraktionen
flieder web/js/app/logic logic Anwendungslogik
gelb web/js/app/collision collision Kollisionserkennung und -behandlung

Erstellen Sie für jedes Modul, das im Klassendiagramm aufgeführt ist (mit Ausnahme von ModelStage), eine leere Datei in der dieses Modul implementiert wird. Achten Sie darauf, dass die Farbmarkierung der Module mit den Farbmarkierungen der Modulordner übereinstimmt:

web/js/app

  • init.js

web/js/app/model

  • button.js
  • ball.js
  • paddle.js
  • text.js
  • loop.js

web/js/app/view

  • button.js
  • ball.js
  • paddle.js
  • text.js
  • loop.js

web/js/app/control

  • keyboard.js

web/js/app/logic

  • minipong.js

web/js/app/collision

  • ball_paddle.js
  • stage_ball.js
  • stage_paddle.js

Fügen Sie in jede Datei ein RequireJS-Kommando ein, das dafür sorgt, dass die benötigten Module geladen und die darin definierten Funktionen (d. h. Prozeduren bzw. Konstruktorfunktionen) dem Modul zur Verfügung gestellt werden. Welche Module ein Modul benötigt, erkennt man an den roten Pfeilen im Klassendiagramm.

Von den meisten Module geht kein roter Pfeil aus. In diese können Sie jeweils folgenden Code einfügen:

define
( [],
  function()
  { "use strict";

    return null;
  }
);

Von minipong gehen vier rote Pfeile aus. Das heißt, in die Datei „minipong.js“ müssen sie folgende RequireJS-Kommando einfügen:

define
(['collision/ball_paddle', 'collision/stage_ball', 'collision/stage_paddle',
    'model/loop'
  ],
  function(collisionBallPaddle, collisionCanvasBall, collisionStagePaddle,
           ModelLoop
  )
  { "use strict";

    return null;
  }
);

Die Reihenfolge, in der Sie die benötigten Module laden, ist unwichtig. Wichtig ist nur, dass die Reihenfolge der Kurzbezeichnungen der Modulpfade mit der Reihenfolge der Parameter in der Callback-Funktion übereinstimmt.

Das Init-Modul „app/init“ benötigt sehr viele andere Module, um seine Aufgabe zu erledigen. Entsprechend lang ist die Modulliste:

define
( ['model/button', 'view/button',
   'model/ball',   'view/ball',
   'model/paddle', 'view/paddle',
   'model/text',   'view/text',
   'view/loop',
   'control/keyboard',
   'logic/minipong'
  ],
  function(ModelButton, ViewButton,
           ModelBall,   ViewBall,
           ModelPaddle, ViewPaddle,
           ModelText,   ViewText,
           ViewLoop,
           controlKeyboard,
           minipong
          )
  { "use strict";

    return null;
  }
);

Wenn Sie alles richtig gemacht haben, sollten Sie jetzt die Datei „index.html“ im Browser fehlerfrei laden können. Diese Datei hat noch keine Inhalte, mit Ausnahme eines leeren Canvas-Elements. In der Browser-Konsole sollten aber keine Fehler gemeldet werden.

Es ist allerdings ziemlich unbefriedigend, wenn man eine Web-Anwendung ausführt und überhaupt nichts zu sehen ist, obwohl etwas passiert. Öffnen Sie in den Browser-Entwicklertools die Netzwerkansicht und laden Sie die HTML-Datei erneut. Dann sollten Sie sehen, dass 23 Dateien geladen werden. (Hier ist später noch Optimierungsarbeit angesagt. Die Anzahl der Dateien muss reduziert und die Inhalte müssen komprimiert werden. Das ist aber nicht Thema dieses Tutoriums.)

Sie können probehalber auch mal console.log-Befehle in die einzelnen Dateien einfügen, damit Sie sehen in welcher Reihenfolge die Module geladen werden.

console.log('Modul "MODULNAME" wird geladen'); 
// Ersetzen Sie MODULNAME durch den Namen des aktuellen Moduls.

define
( [],
  function()
  { "use strict";

    console.log('Modul "MODULNAME" wurde geladen'); 
    // Ersetzen Sie MODULNAME durch den Namen des aktuellen Moduls.

    return null;
  }
);

Als Musterlösung gibt es das Projekt WK_MiniPong04_empty (SVN). Die darin enthaltene Datei index.html verwendet allerdings den Befehl „terminal.log“, den Sie als Übungsaufgabe im Praktikum erstellen sollten. Damit werden die Log-Nachrichten im HTML-Dokument und nicht in der Browser-Konsole ausgegeben. Außerdem wurde der Logging-Code etwas erweitert, sodass anhand von Einrückungen zu sehen ist, welcher Code von welchem Modul geladen wird.

Models und Views

Ball

Ball-View und Ball-Model

In den vorangegangenen Teilen des Tutoriums war der Ball ständig sichtbar und ständig in Bewegung. Das heißt, es wurden nur folgende Attribute und Methoden benötigt:

  • r (Radius)
  • x (aktuelle $x$-Position)
  • y (aktuelle $y$-Position)
  • vx (aktuelle Geschwindigkeit in $x$-Richtung)
  • vy (aktuelle Geschwindigkeit in $y$-Richtung)
  • move(p_seconds) (Bewegen des Balls an die neue Position, die sich aus der aktuellen Position, der Geschwindigkeit und der Anzahl der Sekunden seit der letzten Berechnung der Position ergibt)

Im eigentlichen Spiel werden jedoch viel mehr Attribute und Methoden benötigt. Der Ball ist beim Start der Web-Anwendung zunächst unsichtbar, erst beim Spielstart wird er sichtbar gemacht

  • visible (Flag, ob der Ball sichtbar oder unsichtbar ist)
  • show() (Methode, um den Ball sichtbar zu machen)
  • hide() (Methode, um den Ball unsichtbar zu machen)

Solange der Ball unsichtbar ist, bewegt er sich nicht (vx === 0 und vy === 0) und befindet sich an seiner Startposition (x === x_start und y === y_start). Bei einem Reset des Spiels werden Position und Geschwindigkeit auf passende Startwerte gesetzt. Diese werden dem Konstruktor „ModelBall“ im Parameter „p_init“ übergeben und vom Konstruktor dann in folgenden Attribute gespeichert:

  • x_start ($x$-Koordinate der Startposition)
  • y_start ($y$-Koordinate der Startposition)
  • vx_start_min (minimale Startgeschwindigkeit in $x$-Richtung)
  • vx_start_max (maximale Startgeschwindigkeit in $x$-Richtung)
  • vy_start_min (minimale Startgeschwindigkeit in $y$-Richtung)
  • vy_start_max (maximale Startgeschwindigkeit in $y$-Richtung)

Man beachte, dass der Ball bei jedem Spielstart von derselben Position aus startet, aber dass die Startgeschwindigkeit (in Grenzen) zufällig gewählt wird.

Um das Spiel starten, beenden und neu starten zu können, werden drei weitere Methoden benötigt:

  • reset() (Ball anhalten, unsichtbar machen und auf die Startposition setzen)
  • start() (Ball auf eine zufällige Startgeschwindigkeit setzen)
  • stop() (Ball anhalten, d. h., die Geschwindigkeit auf Null setzen)

Insgesamt ergibt sich damit folgender Code:

Konstruktor

function ModelBall(p_init)
{
  this.r            = p_init.r;

  this.x_start      = p_init.pos.x;
  this.y_start      = p_init.pos.y;
  this.vx_start_min = p_init.vel.x.min;
  this.vx_start_max = p_init.vel.x.max;
  this.vy_start_min = p_init.vel.y.min;
  this.vy_start_max = p_init.vel.y.max;

  this.reset(); // initializes further attributes
}

Öffentliche Methoden

ModelBall.prototype =
{
  reset:
    function()
    {
      this.stop(); // By default, the ball does not move around.
      this.hide(); // By default, the ball is invisible.

      this.x = this.x_start;
      this.y = this.y_start;
    },

  show:
    function() { this.visible = true; },

  hide:
    function() { this.visible = false; },

  stop:
    function()
    {
      this.vx = 0;
      this.vy = 0;
    },

  start:
    function()
    {
      // react only if the ball is not already moving
      if (this.visible === true && this.vx === 0 && this.vy === 0)
      {
        this.vx = (Math.random() < 0.5 ? 1 : -1)*
                  (this.vx_start_min + 
                   Math.random()*(this.vx_start_max - this.vx_start_min)
                  );
        this.vy = (Math.random() < 0.5 ? 1 : -1)*
                  (this.vy_start_min +
                   Math.random()*(this.vy_start_max - this.vy_start_min)
                  );
      }
    },

  move:
    function(p_seconds)
    {
      this.x += this.vx * p_seconds;
      this.y += this.vy * p_seconds;
    }
};

Fügen Sie diesen Code in den Rumpf der Callback-Funktion in der Datei „model/ball.js“ ein. Vergessen Sie nicht, in dieser Callback-Funktionen den Return-Befehl

  return null;

durch den Return-Befehl

  return ModelBall;

zu ersetzen.

Die Ball-View ändert sich nur in einem Aspekt gegenüber der Version aus dem zweiten und dritten Teil des Tutoriums. Die Draw-Funktion darf den Ball nur zeichnen, wenn er sichtbar ist. Kopieren Sie also den Inhalt der Datei view/paddle.js aus dem dritten Teil des Tutoriums in die neue Datei view/paddle.js und fügen Sie die If-Anweisung

if (this.model.visible === true)

vor den eigentlichen Zeichenbefehl „p_context.drawImage“ ein.

Paddle

Schläger-Model und Schläger-View

Der Schläger ist sehr ähnlich aufgebaut wie der Ball. (Der Code ist also nicht DRY. Man sollte zwei allgemeine Klassen „ModelGeoObject“ und „ViewGeoObject“ definieren, von denen alle Geo-Objekt-Klassen wie „ModelBall“, „ViewBall“ gemeinsame Eigenschaften erben.)

Dem Schläger ist neben Position und Geschwindigkeit auch noch eine Beschleunigung zugeordnet. Für alle drei Vektoren sind feste Startwerte vorgegeben, d. h. der Schläger befindet sich bei Spielbeginn stets an derselben Stelle, startet, sobald der Benutzer ihn bewegt, mit derselben Geschwindigkeit und wird stets im gleichen Maße schneller, je länger der Spieler die entsprechende Steuertaste gedrückt hält.

Gegenüber dem Ball gibt es ein weiteres Attribut, das für die Realisierung der Use Cases wichtig ist:

  • friction (Reibung, genauer Reibungsfaktor)

Wenn sich der Schläger bei eine Kollision mit dem Ball bewegt, wird der Ball aufgrund der Reibung kurzzeitig vom Schläger in $x$-Richtung mitgezogen. Das heißt, die $x$-Geschwindigkeit des Schlägers ändert sich. Diese wird berechnet, indem zur $x$-Geschwindigkeit des Balls die $x$-Geschwindigkeit mal dem Reibungsfaktor des Schlägers addiert wird. Wenn die Reibung gleich Null ist hat also bei einer Kollision die Geschwindigkeit des Schlägers keine Auswirkung auf die Geschwindigkeit des Balls. Je größer der Reibungsfaktor gewählt wird, desto größer ist die Ablenkung. In der Musterlösung wurde der Reibungsfaktor auf $0,3$ gesetzt.

Zu guter Letzt werden noch vier berechnete Attribute für den Schläger definiert:

  • get left() { return this.x; } (linke $x$-Koordinate des Schlägers)
  • get right() { return this.x + this.width; } (rechte $x$-Koordinate des Schlägers)
  • get top() { return this.y; } (linke $y$-Koordinate des Schlägers)
  • get bottom() { return this.y + this.height; } (rechte $y$-Koordinate des Schlägers)

Diese Attribute vereinfachen die Kollisionsfunktionen etwas, bei denen mehrfach auf die verschiedenen Seiten des Schlägers zugegriffen werden muss.

Insgesamt sieht die Implementierung des Schlägermodells folgendermaßen aus:

Konstruktor

function ModelPaddle(p_init)
{
  this.width    = p_init.width;
  this.height   = p_init.height;

  this.x_start  = p_init.pos.x;
  this.y_start  = p_init.pos.y;
  this.vx_start = p_init.vel.x;
  this.vy_start = p_init.vel.y;
  this.ax_start = p_init.acc.x;
  this.ay_start = p_init.acc.y;

  this.friction = p_init.friction;

  this.reset(); // initializes further attributes
}

Öffentliche Methoden

ModelPaddle.prototype =
{
  reset:
    function()
    {
      this.stop(); // By default, the paddle does not move around.
      this.hide(); // By default, the paddle is invisible.

      this.x = this.x_start;
      this.y = this.y_start;
    },

  show:
    function()
    { this.visible = true; },

  hide:
    function()
    { this.visible = false; },

  stop:
    function()
    { this.vx = 0;
      this.vy = 0;

      this.ax = 0;
      this.ay = 0;
    },

  start:
    function(p_direction)
    {
      // react only if the paddle is visible not already moving
      if (this.visible === true &&
          this.vx === 0 && this.vy === 0
         )
      {
        switch (p_direction)
        {
          case "left":
            this.vx = -this.vx_start;
            this.ax = -this.ax_start;
            break;
          case "right":
            this.vx =  this.vx_start;
            this.ax =  this.ax_start;
            break;

          case "up":
            this.vy = -this.vy_start;
            this.ay = -this.ay_start;
            break;
          case "down":
            this.vy =  this.vy_start;
            this.ay =  this.ay_start;
            break;
        }
      }
    },

  move:
    function(p_seconds)
    { this.x  += this.vx * p_seconds;
      this.y  += this.vy * p_seconds;
      this.vx += this.ax * p_seconds;
      this.vy += this.ay * p_seconds;
    },

  /** The left side of the paddle (read only). */
  get left()   { return this.x; },

  /** The right side of the paddle (read only). */
  get right()  { return this.x + this.width; },

  /** The top side of the paddle (read only). */
  get top()    { return this.y; },

  /** The bottom side of the paddle (read only). */
  get bottom() { return this.y + this.height; }
};

Text

Text-Model und Text-View

Button

Button-Model und Button-View

Model- und View-Loop

Model-Loop und View-Loop

Kollisionserkennung und -behandlung

Hilfsprozeduren für Kollisionserkennung und -behandlung

Initialisierung

Initialisierung der Web-Anwendung

MiniPong

MiniPong: Die Spiellogik

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)