[C++] Tic Tac Toe mit GUI (Borland c++-Builder 5 VCL) [Teil 3 von 4]
Im letzten Teil habe ich versucht, euch die Funktionsweise des Controllers (Teil 2) näher zu bringen.
Im dritten Teil des „Tic Tac Toe“-Tutorials geht es um das Optionsmenü, bei dem mir meiner Meinung nach die Umsetzung des MVC ziemlich gut gelungen ist. Die View-Schicht kommuniziert mit dem Controller nur insofern, dass sie alle Anfragen (Klicks) an ihn weiterleitet und das, was sie vom Controller befohlen bekommt, ausführt. Zum Model besteht überhaupt keine Verbindung.
Das hat zur Folge, dass die Methoden allesamt ziemlich kurz geraten sind (fast nur 1-Zeiler) und auch nicht viel Erklärung von Nöten ist.
Dafür hat es aber der Option-Controller in sich. Doch dazu kommen wir dann später noch!
Code der GUI
Den Code der GUI vom Optionsmenü möchte ich euch nicht länger vorenthalten. Im Bild seht ihr, wie das Menü aussieht. Es gibt einige Buttons, die alle einen Auftrag für den Controller bedeuten, wenn sie angeklickt werden.
#include "__headers.h" __fastcall TForm2::TForm2(TComponent* Owner) //Konstruktor : TForm(Owner) { this->controller = new ControllerOptions(this, Form1->getController()); //Model für Einstellungen erstellen } //Setzt die Farbe des ersten Spielers void __fastcall TForm2::button_farbe_spieler1Click(TObject *Sender) { this->farbauswahl->Execute(); //Farbauswahl anzeigen this->farbe_spieler1->Color = this->farbauswahl->Color; //gewählte Farbe übernehmen } //Setzt die Farbe des zweiten Spielers void __fastcall TForm2::button_farbe_spieler2Click(TObject *Sender) { this->farbauswahl->Execute(); //Farbauswahl anzeigen this->farbe_spieler2->Color = this->farbauswahl->Color; //gewählte Farbe übernehmen } //Behandelt den Klick des OK-Buttons void __fastcall TForm2::button_okClick(TObject *Sender) { this->controller->ok(); //an Controller delegieren } //Einstellen der Hintergrundfarbe void __fastcall TForm2::button_farbe_hintergrundClick(TObject *Sender) { this->farbauswahl->Execute(); //Farbauswahl anzeigen this->farbe_hintergrund->Color = this->farbauswahl->Color; //gewählte Farbe übernehmen } //Alles auf Standarteinstellungen setzen void __fastcall TForm2::button_resetClick(TObject *Sender) { this->controller->reset(); } //Einstellungen exportieren void __fastcall TForm2::button_exportClick(TObject *Sender) { this->controller->exportSettings(); } //Importieren der Einstellungen void __fastcall TForm2::button_importClick(TObject *Sender) { this->controller->importSettings(); } //Formular initialisieren void __fastcall TForm2::FormCreate(TObject *Sender) { this->controller->init(); } //Farbe eines leeren Felds ändern void __fastcall TForm2::button_farbe_leeresfeldClick(TObject *Sender) { this->farbauswahl->Execute(); //Farbdialog anzeigen this->farbe_leeresfeld->Color = this->farbauswahl->Color; //Gewählte Farbe übernehmen } //Wenn der Typ des ersten Spielers geänder wird, wird diese Methode ausgeführt void __fastcall TForm2::typ_spieler1Click(TObject *Sender) { this->controller->changeTypeOfPlayer(1); } //Wenn der Typ des zweiten Spielers geänder wird, wird diese Methode ausgeführt void __fastcall TForm2::typ_spieler2Click(TObject *Sender) { this->controller->changeTypeOfPlayer(2); } //Schwierigkeitsstufe des ersten PCs ändern void __fastcall TForm2::dif_pc1Click(TObject *Sender) { this->controller->setRestartOnSave(true); //Neustart, weil Schwierigkeit geändert wurde } //Schwierigkeitsstufe des zweiten PCs ändern void __fastcall TForm2::dif_pc2Click(TObject *Sender) { this->controller->setRestartOnSave(true); //Neustart, weil Schwierigkeit geändert wurde } //Schließen des Optionsmenüs void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action) { //Das Schließen des Optionsmenüs soll das gleiche wie ein Klick auf OK bewirken. this->controller->ok(); }
Wie beim letzten Teil der Artikelserie wird auch hier der Controller beim Erzeugen des Formulars vom Formular selbst instanziiert. Danach liegt aber die Macht über die Anwendung beim Controller.
Der Options-Controller
Da es zur GUI nicht viel zu sagen gibt, komme ich gleich zum Controller des Optionsmenüs, den ich im restlichen Beitrag der Einfachheit halber einfach nur Controller nennen werde.
/* Der Controller für die Optionen schafft eine Verbindung zwischen GUI und Model. Er gibt die Daten zur Speicherung weiter und gibt die ausgelesenen Daten an die GUI zur Anzeige. */ class ControllerOptions { private: ModelOptions* model; //Pointer auf Model TForm2* gui; //Pointer auf GUI Controller* main_controller; //Pointer auf Hauptcontroller bool restart_on_save; //Nach Speichern neu starten? public: ControllerOptions(TForm2* pgui, Controller* maincontroller) { this->restart_on_save = false; //Beim Speichern das Spiel neustarten? this->model = new ModelOptions; //Erstellen des Models this->gui = pgui; //GUI zuweisen this->main_controller = maincontroller; //Hauptcontroller zuweisen } void storeSettings(); //Einstellungen speichern void importSettingsFromFile(AnsiString); //INI-Datei importieren void ok(); //Schließen der Optionen void reset(); //Zurücksetzen der Optionen void exportSettings(); //Exportieren void importSettings(); //Importieren void init(); //Initialisieren void setRestartOnSave(bool); //Beim Speichern neu starten? void changeTypeOfPlayer(int nr); //Spielertyp ändern }; //Wird beim Klick auf OK oder beim Schließen aufgerufen. void ControllerOptions::ok() { this->storeSettings(); //Einstellungen übernehmen this->gui->Visible = false; //Optionsmenü verstecken } //Hier kann eingestellt werden, ob das Spiel nach dem Speichern neu gestartet //werden muss void ControllerOptions::setRestartOnSave(bool r) { this->restart_on_save = r; } /* Wird aufgerufen, wenn das Formular erzeugt wird (Also beim Programmstart) Hier werden Werte übernommen und Einstellungen aus einer INI-Importiert, falls eine existiert. */ void ControllerOptions::init() { //Die aktuellen Farben müssen in der GUI angezeigt werden (Optionsmenü) this->gui->farbe_spieler1->Color = this->main_controller->getSpieler(1)->getColor(); this->gui->farbe_spieler2->Color = this->main_controller->getSpieler(2)->getColor(); this->gui->farbe_hintergrund->Color = this->main_controller->getModel()->getBackgroundColor(); this->gui->farbe_leeresfeld->Color = this->main_controller->getModel()->getEmptyFieldColor(); //Die aktuellen Spielernamen anzeigen this->gui->spieler1_name->Text = this->main_controller->getSpieler(1)->getName(); this->gui->spieler2_name->Text = this->main_controller->getSpieler(2)->getName(); //Prüfen, ob Pfad zur INI existiert. if(this->model->getINIPath() != "") { //Importieren der Einstellungen aus der in pathinfo.ttt angegebenen Datei this->importSettingsFromFile(this->model->getINIPath()); //Spiel zurücksetzen this->main_controller->reset(); } } //Einstellungen in eine INI-Datei exportieren void ControllerOptions::exportSettings() { //Es soll automatisch als erstes der Ordner angezeigt werden, wo das letzte Mal //gespeichert wurde this->gui->SaveDialog1->InitialDir = ExtractFilePath(this->model->getINIPath()); //Den Dialog zur Auswahl der INI-Datei anzeigen this->gui->SaveDialog1->Execute(); //Prüfen, ob eine Datei gewählt wurde if(this->gui->SaveDialog1->FileName == "") { ShowMessage("Keine Datei gewählt"); return; //Abbrechen } //Prüfen, ob gewählte Datei existiert if(FileExists(this->gui->SaveDialog1->FileName)) { //Fragen, ob überschrieben werden darf if(Application->MessageBox((this->gui->SaveDialog1->FileName +(AnsiString)" ist schon vorhanden").c_str(), "Sicher?", MB_YESNO) == IDNO) { return; //Abbrechen } } //Ein neues Zugriffsobjekt auf die INI-Datei wird erstellt TIniFile* ini = new TIniFile(this->gui->SaveDialog1->FileName); this->model->setINIPath(this->gui->SaveDialog1->FileName); //Spielernamen in Einstellungsdatei schreiben ini->WriteString("name", "spieler1", this->gui->spieler1_name->Text); ini->WriteString("name", "spieler2", this->gui->spieler2_name->Text); //Alle Farben als (int) kodiert in Einstellungsdatei schreiben ini->WriteInteger("farben", "hintergrund", (unsigned int)this->gui->farbe_hintergrund->Color); ini->WriteInteger("farben", "leer", (unsigned int)this->gui->farbe_leeresfeld->Color); ini->WriteInteger("farben", "spieler1", (unsigned int)this->gui->farbe_spieler1->Color); ini->WriteInteger("farben", "spieler2", (unsigned int)this->gui->farbe_spieler2->Color); //Spielertypen in Einstellungsdatei schreiben ini->WriteInteger("spieler", "spieler1", this->gui->typ_spieler1->ItemIndex); ini->WriteInteger("spieler", "spieler2", this->gui->typ_spieler2->ItemIndex); //PC-Schwierigkeit schreiben ini->WriteInteger("schwierigkeit", "pc1", this->gui->dif_pc1->ItemIndex); ini->WriteInteger("schwierigkeit", "pc2", this->gui->dif_pc2->ItemIndex); //Erfolgsmeldung anzeigen ShowMessage("Die Einstellungen wurden unter "+this->gui->SaveDialog1->FileName+" abgespeichert"); //Speicher wieder freigeben delete ini; } //Importieren der Einstellungen void ControllerOptions::importSettings() { //Es soll automatisch als erstes der Ordner angezeigt werden, wo das letzte Mal //gespeichert wurde this->gui->OpenDialog1->InitialDir = ExtractFilePath(this->model->getINIPath()); //Datei öffnen-Dialog anzeigen this->gui->OpenDialog1->Execute(); //Wurde eine Datei gewählt? if(this->gui->OpenDialog1->FileName == "") { ShowMessage("Es wurde keine Datei gewählt"); return; //Abbruch } //Diese Methode importiert dann die Einstellungen aus der gewählten Datei this->importSettingsFromFile(this->gui->OpenDialog1->FileName); } //Alles auf Standarteinstellungen setzen void ControllerOptions::reset() { //Zuerst fragen, ob die Einstellungen zurückgesetzt werden sollen if(Application->MessageBox("Einstellungen zurücksetzen?", "Sicher?", MB_YESNO) == IDYES) { //Spielernamen setzen this->gui->spieler1_name->Text = CONST__default_spieler1_name; this->gui->spieler2_name->Text = CONST__default_spieler2_name; //Die Spielertypen-Auswahl setzen this->gui->typ_spieler1->ItemIndex = 0; this->gui->typ_spieler2->ItemIndex = 1; //Die Schwierigkeit einstellen this->gui->dif_pc1->ItemIndex = 0; this->gui->dif_pc2->ItemIndex = 1; //Spielerfarben setzen this->gui->farbe_spieler1->Color = CONST__default_spieler1_color; this->gui->farbe_spieler2->Color = CONST__default_spieler2_color; //Andere Farben setzen this->gui->farbe_hintergrund->Color = CONST__default_background_color; this->gui->farbe_leeresfeld->Color = CONST__default_emptyField_color; } } //Speichern der Einstellungen void ControllerOptions::storeSettings() { //Wenn die Spielereinstellungen geändert wurden //Dann muss das Spiel neugestartet werden. //Davor werden die Spieler so erzeugt, wie eingestellt wurde. if(this->restart_on_save) { //Typ des ersten Spielers setzen this->main_controller->setPlayerType(1, this->gui->typ_spieler1->ItemIndex == 0 ? "Mensch" : "Computer"); //Typ des zweiten Spielers setzen this->main_controller->setPlayerType(2, this->gui->typ_spieler2->ItemIndex == 0 ? "Mensch" : "Computer"); //Falls der erste Spieler ein PC ist, wird noch die Schwierigkeit eingestellt if(this->gui->typ_spieler1->ItemIndex == 1) { //der Cast macht aus Spieler* Computer* dynamic_cast(this->main_controller->getSpieler(1)) ->setSchwierigkeit(this->gui->dif_pc1->ItemIndex == 0 ? 1 : 2); } //Falls der zweite Spieler ein PC ist, wird noch die Schwierigkeit eingestellt if(this->gui->typ_spieler2->ItemIndex == 1) { //der Cast macht aus Spieler* Computer* dynamic_cast(this->main_controller->getSpieler(2)) ->setSchwierigkeit(this->gui->dif_pc2->ItemIndex == 0 ? 1 : 2); } //Spiel neustarten this->main_controller->reset(); } //Die Spielernamen setzen this->main_controller->getSpieler(1)->setName(this->gui->spieler1_name->Text); this->main_controller->getSpieler(2)->setName(this->gui->spieler2_name->Text); //Die Spielerfarben setzen this->main_controller->getSpieler(1)->setColor(this->gui->farbe_spieler1->Color); this->main_controller->getSpieler(2)->setColor(this->gui->farbe_spieler2->Color); //Die anderen Farben setzen this->main_controller->getModel()->setBackgroundColor(this->gui->farbe_hintergrund->Color); this->main_controller->getModel()->setEmptyFieldColor(this->gui->farbe_leeresfeld->Color); this->main_controller->refreshStatus(); //Status aktualisieren this->main_controller->getGUI()->RefreshField(); //Spielfeld neu aufbauen } //Anhand einer Datei, deren Name übergeben wird, importiert diese Methode //alle Einstellungen aus dieser Datei und weißt sie dem Spiel zu. void ControllerOptions::importSettingsFromFile(AnsiString filename) { //Wenn die Datei nicht existiert, wird einfach abgebrochen. if(!FileExists(filename)) { return; } this->model->setINIPath(filename); //Neues Objekt zum INI-Zugriff TIniFile* ini = new TIniFile(filename); //Read*() erwartet immer 3 Parameter: //-Die [Sektion] in der INI-Datei //-Den Namen des Attributs //-Den Standartwert, falls das Attribut in der INI nicht gefunden wird //Hier werden Farben zugewiesen. (der letzte Paramter ist der "aktuelle" wert, der momentan eingestellt ist) this->gui->farbe_hintergrund->Color = (TColor)ini->ReadInteger("farben", "hintergrund", this->gui->farbe_hintergrund->Color); this->gui->farbe_leeresfeld->Color = (TColor)ini->ReadInteger("farben", "leer", this->gui->farbe_leeresfeld->Color); this->gui->farbe_spieler1->Color = (TColor)ini->ReadInteger("farben", "spieler1", this->gui->farbe_spieler1->Color); this->gui->farbe_spieler2->Color = (TColor)ini->ReadInteger("farben", "spieler2", this->gui->farbe_spieler2->Color); //Hier werden die Spielertypen zugewiesen this->gui->typ_spieler1->ItemIndex = ini->ReadInteger("spieler", "spieler1", this->gui->typ_spieler1->ItemIndex); this->gui->typ_spieler2->ItemIndex = ini->ReadInteger("spieler", "spieler2", this->gui->typ_spieler2->ItemIndex); //Die Schwierigkeiten der Bots this->gui->dif_pc1->ItemIndex = ini->ReadInteger("schwierigkeit", "pc1", this->gui->dif_pc1->ItemIndex); this->gui->dif_pc2->ItemIndex = ini->ReadInteger("schwierigkeit", "pc2", this->gui->dif_pc2->ItemIndex); //Die Spielernamen this->gui->spieler1_name->Text = ini->ReadString("name", "spieler1", CONST__default_spieler1_name); this->gui->spieler2_name->Text = ini->ReadString("name", "spieler2", CONST__default_spieler2_name); //Die Einstellungen speichern (Dem Spiel/den Objekten zuweisen) this->storeSettings(); //Speicher freigeben delete ini; } /* Ändert den Spielertyp (speichert nichts, sondern zeigt nur die richtigen Werte an) */ void ControllerOptions::changeTypeOfPlayer(int nr) { TRadioGroup* rgrp_type = NULL; //Radiogroup Typ TEdit* edt_name = NULL; //Textfeld Name TRadioGroup* rgrp_diff = NULL; //Radiogroup Schwierigkeit //Um den richtigen Spieler zu erwischen, werden jetzt ein paar Werte zugewiesen if(nr == 1) { rgrp_type = this->gui->typ_spieler1; edt_name = this->gui->spieler1_name; rgrp_diff = this->gui->dif_pc1; } else { rgrp_type = this->gui->typ_spieler2; edt_name = this->gui->spieler2_name; rgrp_diff = this->gui->dif_pc2; } if(rgrp_type->ItemIndex == 0) //Mensch { edt_name->Text = "Mensch"; rgrp_diff->Enabled = false; //Mensch hat keine Schwierigkeitsstufe } else //PC { edt_name->Text = "Computer"; rgrp_diff->Enabled = true; //PC-Schwierigkeit wird einstellbar } this->setRestartOnSave(true);//Das Spiel muss neugestartet werden, //Wenn der Spielertyp geändert wurde }
Der Controller bietet folgende Möglichkeiten
- Speichern von Einstellungen
- Laden von Einstellungen
- Resetten von Einstellungen
- Spielertyp ändern
- …
Konstruktor
ControllerOptions(TForm2* pgui, Controller* maincontroller) { this->restart_on_save = false; //Beim Speichern das Spiel neustarten? this->model = new ModelOptions; //Erstellen des Models this->gui = pgui; //GUI zuweisen this->main_controller = maincontroller; //Hauptcontroller zuweisen }
Im Konstruktor werden Model und GUI zugewiesen und es wird bekanntgegeben, wer der Hauptcontroller ist. (Controller aus dem letzten Artikel, also die Spielsteuerung) Außerdem wird restart_on_save auf false gesetzt. Steht restart_on_save auf true, wird das Spiel neugestartet, wenn die Einstellungen gespeichert werden. Dazu später noch mehr!
Initialisierung
/* Wird aufgerufen, wenn das Formular erzeugt wird (Also beim Programmstart) Hier werden Werte übernommen und Einstellungen aus einer INI-Importiert, falls eine existiert. */ void ControllerOptions::init() { //Die aktuellen Farben müssen in der GUI angezeigt werden (Optionsmenü) this->gui->farbe_spieler1->Color = this->main_controller->getSpieler(1)->getColor(); this->gui->farbe_spieler2->Color = this->main_controller->getSpieler(2)->getColor(); this->gui->farbe_hintergrund->Color = this->main_controller->getModel()->getBackgroundColor(); this->gui->farbe_leeresfeld->Color = this->main_controller->getModel()->getEmptyFieldColor(); //Die aktuellen Spielernamen anzeigen this->gui->spieler1_name->Text = this->main_controller->getSpieler(1)->getName(); this->gui->spieler2_name->Text = this->main_controller->getSpieler(2)->getName(); //Prüfen, ob Pfad zur INI existiert. if(this->model->getINIPath() != "") { //Importieren der Einstellungen aus der in pathinfo.ttt angegebenen Datei this->importSettingsFromFile(this->model->getINIPath()); //Spiel zurücksetzen this->main_controller->reset(); } }
Bei der Initialisierung des Controllers, die in der init()-Methode stattfindet, werden die Elemente des Optionsmenüs mit den entsprechenden Daten gefüttert, die sie anzeigen sollen. Falls eine INI-Datei mit Einstellungen existiert, werden die Einstellungen daraus geladen und angezeigt.
Exportieren der Einstellungen
//Einstellungen in eine INI-Datei exportieren void ControllerOptions::exportSettings() { //Es soll automatisch als erstes der Ordner angezeigt werden, wo das letzte Mal //gespeichert wurde this->gui->SaveDialog1->InitialDir = ExtractFilePath(this->model->getINIPath()); //Den Dialog zur Auswahl der INI-Datei anzeigen this->gui->SaveDialog1->Execute(); //Prüfen, ob eine Datei gewählt wurde if(this->gui->SaveDialog1->FileName == "") { ShowMessage("Keine Datei gewählt"); return; //Abbrechen } //Prüfen, ob gewählte Datei existiert if(FileExists(this->gui->SaveDialog1->FileName)) { //Fragen, ob überschrieben werden darf if(Application->MessageBox((this->gui->SaveDialog1->FileName +(AnsiString)" ist schon vorhanden").c_str(), "Sicher?", MB_YESNO) == IDNO) { return; //Abbrechen } } //Ein neues Zugriffsobjekt auf die INI-Datei wird erstellt TIniFile* ini = new TIniFile(this->gui->SaveDialog1->FileName); this->model->setINIPath(this->gui->SaveDialog1->FileName); //Spielernamen in Einstellungsdatei schreiben ini->WriteString("name", "spieler1", this->gui->spieler1_name->Text); ini->WriteString("name", "spieler2", this->gui->spieler2_name->Text); //Alle Farben als (int) kodiert in Einstellungsdatei schreiben ini->WriteInteger("farben", "hintergrund", (unsigned int)this->gui->farbe_hintergrund->Color); ini->WriteInteger("farben", "leer", (unsigned int)this->gui->farbe_leeresfeld->Color); ini->WriteInteger("farben", "spieler1", (unsigned int)this->gui->farbe_spieler1->Color); ini->WriteInteger("farben", "spieler2", (unsigned int)this->gui->farbe_spieler2->Color); //Spielertypen in Einstellungsdatei schreiben ini->WriteInteger("spieler", "spieler1", this->gui->typ_spieler1->ItemIndex); ini->WriteInteger("spieler", "spieler2", this->gui->typ_spieler2->ItemIndex); //PC-Schwierigkeit schreiben ini->WriteInteger("schwierigkeit", "pc1", this->gui->dif_pc1->ItemIndex); ini->WriteInteger("schwierigkeit", "pc2", this->gui->dif_pc2->ItemIndex); //Erfolgsmeldung anzeigen ShowMessage("Die Einstellungen wurden unter "+this->gui->SaveDialog1->FileName+" abgespeichert"); //Speicher wieder freigeben delete ini; }
Es ist möglich, alle Einstellungen in eine INI-Datei zu exportieren. Dazu kann man in einem Dateibrowser den Speicherort auswählen. Sollte die Datei bereits existieren, wird gefragt, ob sie überschrieben werden darf.
Wenn die Einstellungen gespeichert wurden, legt das Programm noch eine pathinfo.ttt an, die den Pfad zur INI enthält. Dadurch ist es möglich, dass beim Starten des Spiels automatisch die zuletzt gespeicherten Einstellungen geladen werden, ohne dass der Benutzer es manuell tun muss.
Zum Speichern sämtlicher Informationen verwende ich übrigens die Klasse TIniFile der VCL, die eine einfache Schnittstelle zu INI-Files bietet.
Importieren der Einstellungen
//Importieren der Einstellungen void ControllerOptions::importSettings() { //Es soll automatisch als erstes der Ordner angezeigt werden, wo das letzte Mal //gespeichert wurde this->gui->OpenDialog1->InitialDir = ExtractFilePath(this->model->getINIPath()); //Datei öffnen-Dialog anzeigen this->gui->OpenDialog1->Execute(); //Wurde eine Datei gewählt? if(this->gui->OpenDialog1->FileName == "") { ShowMessage("Es wurde keine Datei gewählt"); return; //Abbruch } //Diese Methode importiert dann die Einstellungen aus der gewählten Datei this->importSettingsFromFile(this->gui->OpenDialog1->FileName); }
Beim Importieren der Einstellungen wird wieder ein Dateibrowser angezeigt. Wurde die Datei gefunden, wird der Dateiname an importSettingsFromFile() übergeben. In dieser Methode wird die INI-Datei geöffnet und alle Werte extrahiert. Diese Werte werden dann den entsprechenden GUI-Elementen zugewiesen. Da dies aber noch nicht ausreicht, wird danach noch storeSettings() ausgeführt. In storeSettings werden die Einstellungen dann letztendlich übernommen. Wie das funktioniert, erfahrt ihr im folgenden Abschnitt.
storeSettings()
//Speichern der Einstellungen void ControllerOptions::storeSettings() { //Wenn die Spielereinstellungen geändert wurden //Dann muss das Spiel neugestartet werden. //Davor werden die Spieler so erzeugt, wie eingestellt wurde. if(this->restart_on_save) { //Typ des ersten Spielers setzen this->main_controller->setPlayerType(1, this->gui->typ_spieler1->ItemIndex == 0 ? "Mensch" : "Computer"); //Typ des zweiten Spielers setzen this->main_controller->setPlayerType(2, this->gui->typ_spieler2->ItemIndex == 0 ? "Mensch" : "Computer"); //Falls der erste Spieler ein PC ist, wird noch die Schwierigkeit eingestellt if(this->gui->typ_spieler1->ItemIndex == 1) { //der Cast macht aus Spieler* Computer* dynamic_cast(this->main_controller->getSpieler(1)) ->setSchwierigkeit(this->gui->dif_pc1->ItemIndex == 0 ? 1 : 2); } //Falls der zweite Spieler ein PC ist, wird noch die Schwierigkeit eingestellt if(this->gui->typ_spieler2->ItemIndex == 1) { //der Cast macht aus Spieler* Computer* dynamic_cast(this->main_controller->getSpieler(2)) ->setSchwierigkeit(this->gui->dif_pc2->ItemIndex == 0 ? 1 : 2); } //Spiel neustarten this->main_controller->reset(); } //Die Spielernamen setzen this->main_controller->getSpieler(1)->setName(this->gui->spieler1_name->Text); this->main_controller->getSpieler(2)->setName(this->gui->spieler2_name->Text); //Die Spielerfarben setzen this->main_controller->getSpieler(1)->setColor(this->gui->farbe_spieler1->Color); this->main_controller->getSpieler(2)->setColor(this->gui->farbe_spieler2->Color); //Die anderen Farben setzen this->main_controller->getModel()->setBackgroundColor(this->gui->farbe_hintergrund->Color); this->main_controller->getModel()->setEmptyFieldColor(this->gui->farbe_leeresfeld->Color); this->main_controller->refreshStatus(); //Status aktualisieren this->main_controller->getGUI()->RefreshField(); //Spielfeld neu aufbauen }
Manche Änderungen an den Optionen erfodern einen Neustart des Spiels. z.B. wenn der Spielertyp geändert wurde. Wenn eine solche Einstellung geändert wurde, wird intern restartOnSave auf true gesetzt. Ist dieses Attribut true, dann werden die Spielertypen geändert. Danach wird der Hauptcontroller damit beauftragt, das Spiel neuzustarten.
In jedem Fall aber (auch wenn der Spielertyp nicht geändert wurde), werden die Namen und die Farben gespeichert. Diese Änderungen erfordern keinen Neustart, aber einen Neuaufbau des Spielfelds.
Es gibt hier übrigens einen Artikel zum Speichern von Farben, der die unterschiedlichen Speichermöglichkeiten vergleicht.
Wer sich fragt, wozu die dynamic_casts in dieser Methode nötig sind, wird im letzten Teil dieses Tutorials eine Erklärung finden. Soviel kann ich schonmal verraten: Es hat was mit der Vererbung zu tun!
Weiter gehts!
Da jetzt das Wichtigste geklärt wurde, können jetzt ein paar Worte zum ganzen Rest des Spiels (Teil 4) folgen.
[…] Tipps und Tricks für Webmaster PHP (OOP, MVC), HTML, MySQL, Javascript, AJAX und vieles mehr! « [C++] Tic Tac Toe mit GUI (Borland c++-Builder 5 VCL) [Teil 3 von 4] […]
DAs is doch alles scheiße