Zur Themenübersicht        

Billard: Die Klasse TBillardspiel

Als Ausgangslage der folgenden Überlegungen nehmen wir das eben entwickelte Billardspiel mit Reflexionsboxen, beschrieben durch das folgende UML-Diagramm::

Störend ist hier die Projektdatei: Sie ist "der Kern" der gesamten Programmsteuerung aber kein Objekt. Wir können die zugehörige Klasse mit unserem Design-Werkzeug, dem UML-Editor,  nicht "richtig" bearbeiten. Einfacher und einheitlicher wäre unsere Arbeit in Zukunft, wenn auch diese Projektdatei ein eigenes Objekt - also Exemplar einer Klasse - wäre.  

Ziel: Entwicklung einer Zentralen Steuerungsklasse für das Billardspiel. Wir nennen sie : TBallspiel

Schauen wir uns einmal die Projektdatei mit Kommentaren und ohne eigentlichen Programmcode an,

Projektdatei : Billard mit Reflexionsboxen
program Reflexionsbox;

uses
  mSum,
  mUhr,
  mTSpielfeld in 'mTSpielfeld.pas',
  mTReflexionsbox in 'mTReflexionsbox.pas',
  mTKugel in 'mTKugel.pas';

var
  derBildschirm    : Bildschirm;
  dieMaus          : Maus;
  meinStift        : Stift;
  meineUhr         : Uhr;
  ersteKugel       : TKugel;
  zweiteKugel      : TKugel;
  dritteKugel      : TKugel;
  vierteKugel      : TKugel;
  erstesSpielfeld  : TSpielfeld;
  zweitesSpielfeld : TSpielfeld;
  Reflexionsbox1   : TReflexionsbox;
  Reflexionsbox2   : TReflexionsbox;
begin

  // Initialisierung

  // Kugeln erzeugen

  //Spielfelder erzeugen

  //Reflexionsboxen erzeugen

  // Anfangswerte der Kugeln festsetzen

  // eigentlicher Ablauf des Spieles

  // Aufräumen
end.

dann stellen wir fest, dass der Programmablauf aus drei Phasen besteht:

Unsere Klasse TBallspiel, muss für diese drei Aufgaben (Vorbereitung, Ablauf und Aufräumen) , drei Dienste zur Verfügung stellen.  
Damit haben wir schon einmal Folgendes: 

Der Dienst init ist der Constructor für Objekte der Klasse. Er erzeugt das eigentliche Objekt und alle die Objekte, welche das Ballspiel verwaltet. Hierfür ist es nötig, dass für jedes der am Ballspiel beteiligten Objekte ein Attribut zur Verfügung steht. Damit wird unsere Klasse TBallspiel zu:

Vergleichen wir dies mit dem Code der ursprünglichen Projektdatei, dann stellen wir fest, dass alle Variablen dieser Projektdatei nun zu Attributen der Ballspielklasse geworden sind. Dis ist nicht verwunderlich: Die Variablen der Projektdatei waren das "Gedächtnis" des Projektes genau so wie die Attribute das Gedächtnis eines Objektes sind.

Nach diesen Vorüberlegungen müssen die Methoden der Klasse TBallspiel noch mit Code gefüllt werden. Dieser kann ganz einfach aus den entsprechenden Teilen der ehemaligen Projektdatei übernommen werden. 

Es ergibt sich folgender Code der Klasse TBallspiel:




Im uses-Teil müssen
alle Units auftauchen,
deren Objekte benutzt
werden.



Die Attribute entsprechen
den Variablen der
ursprünglichen
Projektdatei










Nur Kommentar:
Die Objektbeziehungen
mit ihren Attributen


Die drei angebotenen
Dienste der Klasse.





Es folgt der Code,
in dem beschrieben wird,
auf welche Weise die
Dienste realisiert werden.





Beteiligte Objekte
erzeugen

























und mit Anfangswerten
versehen.





























Der eigentliche
Programmablauf.













Beseitigen der 
beteiligten
Objekte.
UNIT mTBallspiel;

interface

uses mSum, mUhr, mTKugel, mTReflexionsbox, mTSpielfeld;



type
  TBallspiel = class

  private //Attribute
    derBildschirm : Bildschirm;
    dieMaus : Maus;
    meinStift : Stift;
    dritteKugel : TKugel;
    ersteKugel : TKugel;
    vierteKugel : TKugel;
    zweiteKugel : TKugel;
    Reflexionsbox1 : TReflexionsbox;
    Reflexionsbox2 : TReflexionsbox;
    erstesSpielfeld : TSpielfeld;
    zweitesSpielfeld : TSpielfeld;
    meineUhr : Uhr;

     //Objektbeziehungen:
        // hatTKugel1, // hatTKugel2, // hatTKugel3, // hatTKugel4 : TKugel;
        // hatTReflexionsbox1, // hatTReflexionsbox2 : TReflexionsbox;
        // hatTSpielfeld1, // hatTSpielfeld2 : TSpielfeld;

  public //Methoden
    constructor init; virtual;
    procedure laufeab; virtual;
    destructor gibFrei; virtual;

   end;

implementation

//+---------------------------------------------------------------------
//|         TBallspiel: Methodendefinition 
//+---------------------------------------------------------------------

//-------- init (public) -----------------------------------------------
constructor TBallspiel.init;
begin
  // Initialisierung
    derBildschirm := Bildschirm.init;
    dieMaus       := Maus.init;
    meinStift     := Stift.init;
    meineUhr      := Uhr.init;

  // Kugeln erzeugen
    ersteKugel    := TKugel.init;
    zweiteKugel   := TKugel.init;
    dritteKugel   := TKugel.init;
    vierteKugel   := TKugel.init;

  //Spielfelder erzeugen
     erstesSpielfeld := TSpielfeld.init(400, 300);
     zweitesSpielfeld := TSpielfeld.init(350, 400);

  //Reflexionsboxen erzeugen
     Reflexionsbox1 := TReflexionsbox.init(150, 150);
     Reflexionsbox2 := TReflexionsbox.init(75, 100);
     Reflexionsbox1.setzePosition(200, 200);
     Reflexionsbox2.setzePosition(750, 250);


  //Spielfelder zeichnen
     erstesSpielfeld.setzePosition(100, 100);
     zweitesSpielfeld.setzePosition(600, 100);

     ersteKugel.lerneSpielfeldkennen(erstesSpielfeld);
     ersteKugel.lerneReflexionsboxkennen(Reflexionsbox1);
     ersteKugel.setzePosition(erstesSpielfeld.GibXPos+12, 
                erstesSpielfeld.GibYPos+erstesSpielfeld.GibHoehe/3.5);
     ersteKugel.SetzexGeschwindigkeit(2);
     ersteKugel.SetzeyGeschwindigkeit(1);

     zweiteKugel.lerneSpielfeldkennen(erstesspielfeld);
     zweiteKugel.lerneReflexionsboxkennen(Reflexionsbox1);
     zweiteKugel.setzePosition(erstesSpielfeld.GibXPos+erstesSpielfeld.GibBreite-12,
                 erstesSpielfeld.GibYPos+erstesSpielfeld.GibHoehe/1.5);
     zweiteKugel.SetzexGeschwindigkeit(-2);
     zweiteKugel.SetzeyGeschwindigkeit(-0.5);

     dritteKugel.lerneSpielfeldkennen(zweitesSpielfeld);
     dritteKugel.lerneReflexionsboxkennen(Reflexionsbox2);
     dritteKugel.setzePosition(zweitesSpielfeld.GibXPos+12, 
                 zweitesSpielfeld.GibYPos+zweitesSpielfeld.GibHoehe/3.5);
     dritteKugel.SetzexGeschwindigkeit(1.5);
     dritteKugel.SetzeyGeschwindigkeit(1);

     vierteKugel.lerneSpielfeldkennen(zweitesSpielfeld);
     vierteKugel.lerneReflexionsboxkennen(Reflexionsbox2);
     vierteKugel.setzePosition(zweitesSpielfeld.GibXPos+12, 
                 zweitesSpielfeld.GibYPos+zweitesSpielfeld.GibHoehe/3.5);
     vierteKugel.SetzexGeschwindigkeit(2);
     vierteKugel.SetzeyGeschwindigkeit(-0.3);
end;

//-------- laufeab (public) --------------------------------------------
procedure TBallspiel.laufeab;
begin
  repeat
     ersteKugel.bewege;
     zweiteKugel.bewege;
     dritteKugel.bewege;
     vierteKugel.bewege;
     meineUhr.warte(1);
  until dieMaus.istGedrueckt;
end;

//-------- gibFrei (public) --------------------------------------------
destructor TBallspiel.gibFrei;
begin
  // Aufräumen
  dieMaus.gibFrei;
  derBildschirm.gibFrei;
  ersteKugel.gibfrei;
  zweiteKugel.gibfrei;
  dritteKugel.gibfrei;
  vierteKugel.gibfrei;
  erstesSpielfeld.gibfrei;
  zweitesSpielfeld.gibfrei;
  Reflexionsbox1.gibFrei;
  Reflexionsbox2.gibFrei;
end;

end.

Die Projektdatei hingegen vereinfacht sich zu folgender Kurzform:
Die kleine Rest der Projektdatei:



program Reflexionsbox;

uses
  mSum,
  mUhr,
  mTSpielfeld in 'mTSpielfeld.pas',
  mTReflexionsbox in 'mTReflexionsbox.pas',
  mTKugel in 'mTKugel.pas',
  mTBallspiel in 'mTBallspiel.pas';

var
  meinBallspiel : TBallspiel;
begin

  meinBallspiel:= TBallspiel.init;
  meinBallspiel.laufeab;
  meinBallspiel.gibfrei;
 
end.

Download des zugehörigen Projektes: Reflexionsboxen mit der Klasse TBallspiel.