Wie kann ich ...
- meine Übungen strukturieren und speichern?
- ein neues Objekt in das Programm einfügen?
- die Methoden verändern von TRobot (oder anderen Klassen) ?
- ein Bild als Attribut eines Objekts einfügen?
- dem Roboter beibringen, ein Objekt zu
identifizieren, damit er es z. B. aufnehmen kann?
- eine Aktion in Karels Gedächtnis aufnehmen?
- das Protokoll der Roboter-Actions
aktivieren?
- einen Roboter zu einem entfernten Feld
springen lassen?
- einen Roboter schneller machen?
- eine Meldung ausgeben?
Antworten
1. meine Übungen strukturieren und speichern?
Zur Strukturierung
Vor 30 Jahren war man in der Schule stolz, wenn als 1. Programm auf
einem ansonsten schwarzen Bildschirm in grüner Schrift erschien: HALLO
WORLD
Das ganze Programm dazu so aus:
Genauso winzig war die Datei, die
das Programm speicherte. |
program hallo;
begin
writeln('HALLO WORLD');
end. |
Sie haben den Vorzug mit einem professionellen Programm zu arbeiten,
das entsprechend umfangreich ist. Dabei operieren Sie zunächst
immer nur an einem ziemlich kleinen Teil eines lebenden Organismus. Man
muß die
Übersicht behalten und kann nicht für jede kleine Änderung jedesmal das gesamte
Projekt mit seinen rund 2 MB abspeichern. Läßt man alle
Änderungen im ControlFrm stehen, wird das schnell lang und
unübersichtlich.
Anfangs werden Sie wahrscheinlich im ControlFrm arbeiten. Nehmen wir an,
die Aufgabe lautet
RD1 soll dreimal im Kreis herumlaufen.
A)
In vielen Delphi-Anfängerbüchern würden Sie
einen
Vorschlag wie diesen finden. Oder noch vielleicht viel längere Prozeduren
bei anderen Problemen.
|

So nicht !
|
Ein Lichtschalter an der Wand produziert weder die Elektrizität noch
erhellt er den Raum. Er schaltet nur den Strom ein. Genau das soll ein
Button tun.
B) Die bessere Lösung ist aufgeteilt:
in die Ereignismethode (der Button-Click)
procedure
TControlFrm.Button1Click(Sender: TObject);
begin
ImKreisHerum;
end; |
und eine private Methode, die das Problem
bearbeitet und bei Bedarf aufgerufen wird
procedure TControlFrm.ImKreisHerum;
var i : integer;
begin
for i := 1 to 12 do
begin
RD1.Vor;
RD1.RechtsDrehen
end;
end; |
Das ist guter Programmierstil. Es sieht zunächst umständlich aus,
schafft aber klar strukturierte Programme, in denen das an der Stelle
steht, wo es hingehört (Lokalität). Sie brauchen auch nur einen
Button, um verschiedene Methoden aufzurufen und zu testen.
C) Genau genommen haben Sie eine neue Methode für Roboter
entwickelt, die in die Roboterklasse
aufgenommen werden kann und dann für jeden
Roboter zur Verfügung steht.
Zum Speichern von Übungen im ControlFrm
- Die pragmatische Lösung: Statt das gesamte Projekt zu speichern,
können Sie einzelne Prozeduren / Lösungen aus dem ControlFrm
ausschneiden und in eine separate Textdatei zur Speicherung kopieren
und bei Bedarf später wieder zurückkopieren. Das funktioniert aber
nicht mit der Lösung A, sondern nur mit B (ohne die
ButtonClick-Methode).
- Die professionelle Lösung: Wenn es eine gute Methode wert ist, als
neue allgemeine Roboter-Methode implementiert zu werden, gehen wie in C
vor und speichern die Unit mit der Roboterklasse.
2. ein neues Objekt in das Programm einfügen?
var Auto : TCritter; // in
ControlFrm bei var deklarieren
Auto := TAuto.Create; // Objekt erzeugen
z.B. Auto
in procedure ItemsErzeugen
Auto.SetPos ('G',2); // und an die gewünschte Stelle setzen
|
3. die Methoden von TRobot (oder anderen Klassen) verändern?
Im Prinzip in der Unit uRobot. Davon wird aber dringend abgeraten, wenn
Sie nicht sehr genau wissen, was Sie tun, weil jede Änderung sich in den
Unterklassen ebenfalls auswirkt.
Es ist besser, eine neue Unterklasse TMyRobot (oder so ähnlich genannt)
zu erstellen und dort die geerbte Methode zu überschreiben und dann mit
TMyKarel weiterarbeiten.
Beispiel:
Unit uMyRobot;
INTERFACE
uses uRobot;
type
TMyRobot = class (TRobot) // erbt alles
procedure Vor; override;
// hier überschreiben mit der eigenen Methode
... |
4. ein Bild als Attribut einfügen?
Zweckmäßigerweise sollten alle Exemplare der betreffenden Klasse
dasselbe Bild tragen. Dann fügen Sie in die Initialisierungsprozedur
die Zeile ein:
procedure Txyz.Init;
begin
...
Blume.SetBild ('.\bilder\blume.bmp');
end; |
Zuvor müssen Sie das Bild blume.bmp in
das Verzeichnis \bilder kopieren. Format : 28 x 28 pixel.
5. dem Roboter beibringen, ein Objekt zu
identifizieren, damit er es z. B. aufnehmen kann?
Man kann Objekte fragen, zu welchem Typ sie gehören. Wenn Karel z. B.
vor einem Baum steht, liefert seine Methode 'HindernisPruefen : TItem' die
entsprechende Klasse.
if (RD1.HindernisPruefen
is TBaum)
then ... |
6. eine Aktion in Karels Gedächtnis
aufnehmen?Derzeitig werden die Methoden 'Vor' und 'RechtsDrehen' ins
Gedächtnis gemerkt.
Fügen Sie die Anweisung 'InsGedaechtnis ('...'); in die gewünschte
Prozedur der Roboterklasse ein. Im Parameter steht der string, der die Aktion bezeichnet.
Beispiel:
procedure
TMyKarel.Rueckwaerts;
begin
...
InsGedaechtnis('Rueckwaerts');
end; |
7. das Protokoll der Roboter-Actions
aktivieren?Da bei der Entwicklung dieses Programms noch nicht bekannt ist, wie
Ihr Roboter später vielleicht heißen wird, aktivieren Sie das Protokoll
selbst. Das Protokollformular bekommt mitgeteilt, welcher Roboter
die Daten zur Anzeige liefert, z. B. RD1:
ProtokollFrm.Aktualisieren(RD1);
Fügen Sie im ControlFrm diese Anweisung in die Methode ein, mit der Sie
den Roboter starten.
Beispiel:
procedure
TControlFrm.GoBtnClick(Sender: TObject);
begin
inherited;
while NOT RD1.BatterieLeer do
begin
if RD1.VorneFrei
then RD1.Vor
....
...
ProtokollFrm.Aktualisieren(RD1);
// jede Aktion wird angezeigt
end;
end; |
Sie können die Anweisung auch in
mehreren Prozeduren implementieren;
außer in TControlFrm.ItemsErzeugen (Absturz!)
8. einen Roboter zu einem entfernten Feld
springen lassen?
Am besten gar nicht!
Angenommen beim Programmstart heißt es 'RD1.SetPos('B',1)'. Diese
Anweisung registriert ihn mit dieser Position in der Welt. Mit einer
Anweisung 'RD1.Vor' würde er sich sauber abmelden, mit einem Sprung z.
B. nach ('D',5) aber nicht: damit ist er dann zweimal in der Welt
registriert.
Im unmittelbaren Programmablauf scheint das zunächst nicht zu stören,
hat aber Probleme. B,1 ist besetzt, obwohl nichts zu sehen ist und spätestens beim Programmende erscheint eine
Fehlermeldung, weil die Welt nicht sauber geschlossen werden kann.
Wenn Sie dennoch den Roboter 'fliegen' lassen wollen, sorgen Sie für
eine korrekte Abmeldung mit der Anweisung
Begin
...
Welt.Abmelden(RD1);
RD1.SetPos(...); // neue Position
... |
9. einen Roboter schneller machen?
Die Darstellungsgeschwindigkeit hängt einerseits von uGrafik und dem
darin implementierten Modell und zweitens von der
Prozessorgeschwindigkeit ab.
Setzen Sie zunächst die Geschwindigkeit des Objekts herauf mit z. B.
RD1.SetGeschwindigkeit(8);
(max. 10). Wenn das nicht hilft und Sie einen langsamen Rechner haben,
hilft nur noch eine Anpassung in uZeit.pas bei der
procedure TZeit.SetPause(millisec : longint);
(* ------------------------------------------------- *)
var i : LongInt;
begin
for i := 1 to 22400 * millisec do // ca. 1 mSek
Bratzeit
Application.ProcessMessages;
end;
Die Schleife verheizt einfach Prozessorzeit: setzen Sie den Wert
herunter bis die Pause (die in allen Critter-Bewegungen steckt) kürzer
wird. Dadurch werden die Bewegungen schneller.
10. eine Meldung ausgeben?
Beispiel:
procedure
TControlFrm.GoBtnClick(Sender: TObject);
// -----------------------------------------------------------------------
begin
inherited;
RD1.AllesEinsammeln;
Meldung(' Fertig');
end;
|