|
![]() |
|
Registriert seit: 12. Dez 2013 Ort: Dresden 172 Beiträge Delphi 10.2 Tokyo Professional |
#1
Bevor ihr versucht durch Quantität eine bessere Note als dieses Snake Projekt zu bekommen solltet ihr euch informieren, warum es da nur 6 Punkte gegeben hat.
Ich wette, dass es nicht daran liegt, dass es nur ein Spiel ist sondern an der gesamten Umsetzung (einfach so dahingerotzt, keine Dokumentation, kein Projektplan, ...). Und falls/sobald du den Grund kennst, dann erläutere ihn bitte hier. Wenn ich das nochmal zitieren darf: ![]() Ich kann mir vorstellen, dass die komplette Dokumentation (Konzepterstellung, usw.) mindestens genauso wichtig ist, wie das eigentliche Programm. Deshalb kann auch ein normalerweise anspruchsvolles Spiel (Snake) in die Hose gehen. Macht lieber etwas simples und dann aber solide von Anfang bis Ende.
Man merkt anhand der Fragen, die ihr stellt, dass ihr (nicht krumm nehmen) bisher kaum Ahnung von der Thematik habt. Deshalb solltet ihr, wie hier bereits SEHR oft empfohlen, erstmal etwas einfaches probieren. Das aber wirklich gut dokumentieren usw. Wenn ihr merkt, dass ihr noch freie Valenzen habt, dann könnte ihr das Projekt noch erweitern und komplexer gestalten. Ich denke die meisten hier wissen, wie Lehrer ticken, da sie das Schulsystem bereits einmal komplett durchlaufen haben. Ich wette es kommt am wenigsten darauf an, ob möglichst viel auf dem Bildschirm blinkt und sich was bewegt. Es ist aber auf jeden Fall gut, dass ihr etwas zur Besinnung gekommen seid. Programmiert erstmal eines der simplen Spiele. Hier werdet ihr schon merken, ob euch das ganze leicht von der Hand geht oder eben nicht. Vllt seid ihr auch Naturtalente - wer weiß. Das dann aber erstmal ordentlich dokumentieren usw. Danach geht's weiter ![]() Grüße Headbucket |
![]() |
Registriert seit: 12. Nov 2014 21 Beiträge |
#2
QQ hätten wir über das mit der Snake Geschichte vorher noch mal nachgedacht :/ naja das was ich beim letzten mal hier gepostet habe war aber leider schon der finale Aufgabenentwurf ... Was ja Snake nicht ausschließt aber uns zumindest dazu verpflichtet mehr als ein Programm zu erstellen. Womit wir nun also zum Kritikpunkt Quantität kommen ein Tic Tac Toe ist schnell gemacht, wir hatten an ein Form 2 (Form 1 ist Startbildschirm) mit 9 Feldern (wir wollten dazu 9 Buttons verwenden, die entweder ein X oder ein O angeben und durch Editfenster eingegeben werden) ^^ so etwas ähnliches haben wir schon mal im Unterricht gemacht und der Arbeitsaufwand hält sich doch in Grenzen.
Wir werden uns also steigernd von Tic tac toe zu Snake und dann gucken wie viel vom Halbjahr übrig ist. ![]() Ich denke die meisten hier wissen, wie Lehrer ticken, da sie das Schulsystem bereits einmal komplett durchlaufen haben. Ich wette es kommt am wenigsten darauf an, ob möglichst viel auf dem Bildschirm blinkt und sich was bewegt.
Wie ein Tic Tac Toe aussieht weiß ja jeder, dennoch würden wir uns über Vorschläge zum Oben genannten Plan ![]() wir hatten an ein Form 2 (Form 1 ist Startbildschirm) mit 9 Feldern (wir wollten dazu 9 Buttons verwenden, die entweder ein X oder ein O angeben und durch Editfenster eingegeben werden) ^^
![]() So Far Felix |
![]() |
Registriert seit: 12. Nov 2014 21 Beiträge |
#3
Ach ja und
![]() Und falls/sobald du den Grund kennst, dann erläutere ihn bitte hier.
|
![]() |
Registriert seit: 12. Dez 2013 Ort: Dresden 172 Beiträge Delphi 10.2 Tokyo Professional |
#4
Ein paar Anregungen zu TicTacToe:
- zunächst würde ich ![]() das ganze kann dann z.B. so aussehen:
Delphi-Quellcode:
Das sind alle Zustände, die ein Feld besitzen kann.
type
TState = (State_none, State_X, State_O); - Außerdem solltet ihr stets darauf achten, die "Datenspeicherung" von der Oberfläche zu trennen. Dazu wurde mir selbst mal ein toller Link gegeben: ![]() - Am Anfang besitzen alle Buttons den Zustand "State_none" - Natürlich müsst ihr irgendwo eine Variable mitlaufen haben, die angibt, ob der nächste Klick ein X oder ein O erzeugt. - Wird ein Button angeklickt, welcher den Zustand "State_none" besitzt, dann wird der jeweilige Zustand vergeben - Danach werden alle Buttons aktualisiert - ... Um mal ein paar kleine Anregungen zu geben. Grüße Headbucket |
![]() |
Registriert seit: 9. Dez 2010 Ort: Mönchengladbach 1.740 Beiträge Delphi 6 Enterprise |
#5
Ich weiß ja nicht, zu wie vielen ihr eure Gruppenarbeit umsetzt. Euer Ansatz bietet ja dabei die Möglichkeit, das jeder ein eigenes Spiel entwickelt (der eine macht TicTacTo, der andere Snake, ...). Auf diese Art sollte man doch dann mehr Substanz zusammen bekommen. Das nachher in ein Programm zusammen zu bekommen, ist doch dann schnell gemacht.
Wenn ihr pro Spiel ein eigenes Form benutzt (wie ihr ja vor zu haben scheint) hat das auf jeden Fall den Vorteil, dass ihr mehrere Spiele parallel schreiben und nachher alles zusammenwürfeln könntet. Als Tip zur weiteren Vorgehensweise bei den einzelnen Spielen solltet ihr beherzigen, was hier in Forum oft genannt wird: Plant das erstmal "auf Papier": Wie sehen die Abläufe aus, was habe ich wo für Daten, was muss wann geprüft werden (z.B. wann ist die Siegbedingung erfüllt o.ä.). Versucht die dabei entstehende "Logik" so abzubilden, dass für die Datenhaltung nicht die GUI-Elemente Missbraucht werden (nicht: if Checkbox11.Checked and Checkbox12.Checked and Checkbos13.Checked then SIEG) sondern Klassen oder Werte in Arrays oder Listen. Dieses trennen der Anzeige von der Logik ist dann bereits ein erstes Qualitätsmerkmal, dass der Lehrer hoffentlich zu würdigen weiß.
Ralph
|
![]() |
Registriert seit: 12. Nov 2014 21 Beiträge |
#6
![]() Das sind alle Zustände, die ein Feld besitzen kann.
- Außerdem solltet ihr stets darauf achten, die "Datenspeicherung" von der Oberfläche zu trennen. Dazu wurde mir selbst mal ein toller Link gegeben: MVC - Am Anfang besitzen alle Buttons den Zustand "State_none" - Natürlich müsst ihr irgendwo eine Variable mitlaufen haben, die angibt, ob der nächste Klick ein X oder ein O erzeugt. - Wird ein Button angeklickt, welcher den Zustand "State_none" besitzt, dann wird der jeweilige Zustand vergeben - Danach werden alle Buttons aktualisiert - ... Ach ja wir sind zwei Ich (Felix) und Toni aber es ist vielleicht trotzdem sinnvoll an zwei Programmen Parallel zu arbeiten ![]() Auf jeden fall Danke für den Tic Tac Toe Ansatz Felix |
![]() |
Registriert seit: 5. Jan 2005 Ort: Stadthagen 9.454 Beiträge Delphi 10 Seattle Enterprise |
#7
Hier mal ein kleines Beispiel, wie man so etwas aufbauen und vor allem die Arbeit aufteilen kann:
Wir haben das Spiel Fang-Den-Button (ja, sehr sinnvoll) Auf dem Spielfeld soll ein Button erscheinen und nach einer bestimmten Zeit die Position wechseln. Ziel ist es den Button zu treffen und nicht das Spielfeld. Für jeden getroffenen Button erhält man 10 Punkte. Trifft man mehr als 10 mal daneben, dann ist das Spiel vorbei. Gemeinerweise verändert sich bei jedem Positionswechsel auch die Größe des Buttons und nach jedem Treffer wechselt der Button immer schneller seine Position. Die Arbeit soll aufgeteilt werden, so dass einer sich um die Oberfläche und der Andere sich um die Logik kümmern kann. Dazu vereinbart man, was man wie und wo erwartet und skizziert sich folgende abstrakte Klasse (die kann quasi nix, gibt aber den Rahmen vor):
Delphi-Quellcode:
Nun können beide loslegen. Der für die Anzeige baut sich jetzt eine minimale funktionierende Klasse, damit er seine Anzeige auch testen kann
unit FangDenButton;
interface uses System.Types, System.Classes; type TFangDenButton = class abstract private FOnChange: TNotifyEvent; { System.Classes.TNotifyEvent } FPlaygroundSize: TPoint; { System.Types.TPoint } procedure SetOnChange( const Value: TNotifyEvent ); procedure SetPlaygroundSize( const Value: TPoint ); protected // Wird etwas geändert, dann diese Methode aufrufen, // damit die Anzeige darauf reagieren kann procedure NotifyChange( ); protected // Konkrete Ableitungen müssen diese Methoden mit Leben füllen procedure DoButtonCatched; virtual; abstract; procedure DoButtonMissed; virtual; abstract; procedure DoStart; virtual; abstract; procedure DoSetPlaygroundSize( const Value: TPoint ); virtual; function GetPunkte: Integer; virtual; abstract; function GetPosition: TPoint; virtual; abstract; function GetButtonSize: TPoint; virtual; abstract; function GetSpielAktiv: Boolean; virtual; abstract; public // Button getroffen procedure ButtonCatched; // Button nicht getroffen procedure ButtonMissed; // Startet das Spiel procedure Start; // Ereignis bei einer Änderung property OnChange: TNotifyEvent read FOnChange write SetOnChange; // ANzahl der Punkte property Punkte: Integer read GetPunkte; // Position des Buttons property Position: TPoint read GetPosition; // Größe des buttons property ButtonSize: TPoint read GetButtonSize; // Größe des Spielfelds (wird von der Anzeige geliefert) property PlaygroundSize: TPoint read FPlaygroundSize write SetPlaygroundSize; // Ist das Spiel am laufen? property SpielAktiv: Boolean read GetSpielAktiv; end; implementation { TFangDenButton } procedure TFangDenButton.ButtonCatched; begin DoButtonCatched; end; procedure TFangDenButton.ButtonMissed; begin DoButtonMissed; end; procedure TFangDenButton.DoSetPlaygroundSize( const Value: TPoint ); begin end; procedure TFangDenButton.NotifyChange; begin if Assigned( FOnChange ) then FOnChange( Self ); end; procedure TFangDenButton.SetOnChange( const Value: TNotifyEvent ); begin FOnChange := Value; if Assigned( FOnChange ) then FOnChange( Self ); end; procedure TFangDenButton.SetPlaygroundSize( const Value: TPoint ); begin if FPlaygroundSize <> Value then begin FPlaygroundSize := Value; // Wir benachrichtigen mal nach innen, wer weiß ob das benötigt wird DoSetPlaygroundSize( Value ); // Vorsichtshalber informieren wir mal die Anzeige, man kann nie wissen :o) NotifyChange; end; end; procedure TFangDenButton.Start; begin DoStart; end; end.
Delphi-Quellcode:
Damit baut er sich die Anzeige, die minimal so aussehen sollte
unit FangDenButtonTest;
interface uses System.Types, FangDenButton; type TFangDenButtonTest = class( TFangDenButton ) private // Punkte FPunkte: Integer; // Spielstatus FSpielAktiv: Boolean; protected procedure DoButtonCatched; override; procedure DoButtonMissed; override; procedure DoSetPlaygroundSize( const Value: TPoint ); override; procedure DoStart; override; function GetButtonSize: TPoint; override; function GetPosition: TPoint; override; function GetPunkte: Integer; override; function GetSpielAktiv: Boolean; override; end; implementation { TFangDenButtonTest } procedure TFangDenButtonTest.DoButtonCatched; begin inherited; // Punkte hochzählen Inc( FPunkte ); // Anzeige benachrichtigen NotifyChange; end; procedure TFangDenButtonTest.DoButtonMissed; begin inherited; // Punkte herunterzählen Dec( FPunkte ); // Anzeige benachrichtigen NotifyChange; end; procedure TFangDenButtonTest.DoSetPlaygroundSize( const Value: TPoint ); begin inherited; // Anzeige benachrichtigen NotifyChange; end; procedure TFangDenButtonTest.DoStart; begin inherited; // Punkte zurücksetzen, wenn das Spiel aktiv war if not FSpielAktiv then FPunkte := 0; // Einfaches umschalten zwischen an und aus FSpielAktiv := not FSpielAktiv; // Anzeige benachrichtigen NotifyChange; end; function TFangDenButtonTest.GetButtonSize: TPoint; begin // Der Button bekommt die halbe Breite und Höhe des Spielfelds Result := TPoint.Create( PlaygroundSize.X div 2, PlaygroundSize.Y div 2 ); end; function TFangDenButtonTest.GetPosition: TPoint; begin // Der Button kommt in die Mitte des Spielfelds // eigentlich ( ( Spielfeld.Breite - Button-Breite ) / 2 ) // aber da der halb so groß ist wie das Spielfeld (s.o.) // können wir auch vereinfacht ( Spielfeld.Breite / 4 ) nehmen Result := TPoint.Create( PlaygroundSize.X div 4, PlaygroundSize.Y div 4 ); end; function TFangDenButtonTest.GetPunkte: Integer; begin // Punkte zurückliefern Result := FPunkte; end; function TFangDenButtonTest.GetSpielAktiv: Boolean; begin // Spielstatus zurückliefern Result := FSpielAktiv; end; end.
Delphi-Quellcode:
An Ende könnte das dann so aussehen
unit Form.Main;
interface uses FangDenButton, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons; type TForm1 = class( TForm ) private // Die Spiel-Instanz FGame: TFangDenButton; // Benachrichtigungs-Methode wenn sich am Spiel etwas ändert procedure GameOnChange( Sender: TObject ); public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; var Form1: TForm1; implementation {$R *.dfm} uses FangDenButtonTest; { TForm1 } procedure TForm1.AfterConstruction; begin inherited; // Spiel-Instanz erzeugen (ist erstmal die Test-Klasse) FGame := TFangDenButtonTest.Create; // Mit dem OnChange-Event verbinden FGame.OnChange := GameOnChange; end; procedure TForm1.BeforeDestruction; begin // Spiel-Instanz wieder aufräumen FGame.Free; inherited; end; procedure TForm1.GameOnChange( Sender: TObject ); begin // Wird aufgerufen, wenn sich am Spiel etwas geändert hat end; end.
Delphi-Quellcode:
Der Kollege mit der Logik ist dann auch soweit und bringt uns seine Unit FangDenButtonKonkret
mit
unit Form.Main;
interface uses FangDenButton, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons; type TForm1 = class( TForm ) PunkteLabel: TLabel; PlayGroundPanel: TPanel; { OI: OnClick => PlaygroundPanelClick } { OI: OnDblClick => PlaygroundPanelClick } { OI: OnResize => PlaygroundPanelResize } HeaderPanel: TPanel; StartButton: TButton; { OI: OnClick => StartButtonClick } FangButton: TSpeedButton; { OI: OnClick => FangButtonClick } procedure FangButtonClick( Sender: TObject ); procedure PlayGroundPanelClick( Sender: TObject ); procedure StartButtonClick( Sender: TObject ); procedure PlayGroundPanelResize( Sender: TObject ); private FGame: TFangDenButton; procedure GameOnChange( Sender: TObject ); procedure NotifyPlaygroundSize; public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; var Form1: TForm1; implementation {$R *.dfm} uses FangDenButtonTest; { TForm1 } procedure TForm1.AfterConstruction; begin inherited; FGame := TFangDenButtonTest.Create; FGame.OnChange := GameOnChange; NotifyPlaygroundSize; end; procedure TForm1.BeforeDestruction; begin FGame.Free; inherited; end; procedure TForm1.FangButtonClick( Sender: TObject ); begin FGame.ButtonCatched; end; procedure TForm1.GameOnChange( Sender: TObject ); begin PunkteLabel.Caption := IntToStr( FGame.Punkte ); FangButton.Visible := FGame.SpielAktiv; FangButton.Left := FGame.Position.X; FangButton.Top := FGame.Position.Y; FangButton.Width := FGame.ButtonSize.X; FangButton.Height := FGame.ButtonSize.Y; end; procedure TForm1.NotifyPlaygroundSize; begin FGame.PlaygroundSize := TPoint.Create( PlayGroundPanel.Width, PlayGroundPanel.Height ); end; procedure TForm1.PlayGroundPanelClick( Sender: TObject ); begin FGame.ButtonMissed; end; procedure TForm1.PlayGroundPanelResize( Sender: TObject ); begin NotifyPlaygroundSize; end; procedure TForm1.StartButtonClick( Sender: TObject ); begin FGame.Start; end; end.
Delphi-Quellcode:
Das ist nett, die werden wir doch gleich mal testen. Dazu müssen wir in unsere Anzeige nur ganz wenig ändern:
unit FangDenButtonKonkret;
interface uses System.Types, Vcl.ExtCtrls, FangDenButton; type TFangDenButtonKonkret = class( TFangDenButton ) private FTimer: TTimer; { Vcl.ExtCtrls.TTimer } FSpielAktiv: Boolean; FPunkte: Integer; FDaneben: Integer; FButtonSize: TPoint; FPosition: TPoint; procedure TimerCalled( Sender: TObject ); procedure NewPosition; procedure SetButtonSize( ASize: Integer ); protected procedure DoButtonCatched; override; procedure DoButtonMissed; override; procedure DoSetPlaygroundSize( const Value: TPoint ); override; procedure DoStart; override; function GetButtonSize: TPoint; override; function GetPosition: TPoint; override; function GetPunkte: Integer; override; function GetSpielAktiv: Boolean; override; public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; implementation uses System.Math; { TFangDenButtonKonkret } procedure TFangDenButtonKonkret.AfterConstruction; begin inherited; FTimer := TTimer.Create( nil ); FTimer.Enabled := False; FTimer.OnTimer := TimerCalled; end; procedure TFangDenButtonKonkret.BeforeDestruction; begin FTimer.Free; inherited; end; procedure TFangDenButtonKonkret.DoButtonCatched; begin inherited; if FSpielAktiv then begin FTimer.Enabled := False; FPunkte := FPunkte + 10; FTimer.Interval := Max( 150, FTimer.Interval - 50 ); NewPosition; NotifyChange; FTimer.Enabled := True; end; end; procedure TFangDenButtonKonkret.DoButtonMissed; begin inherited; if FSpielAktiv then begin Inc( FDaneben ); if FDaneben = 10 then begin FSpielAktiv := False; end; NotifyChange; end; end; procedure TFangDenButtonKonkret.DoSetPlaygroundSize( const Value: TPoint ); begin inherited; NewPosition; end; procedure TFangDenButtonKonkret.DoStart; begin inherited; if not FSpielAktiv then begin FSpielAktiv := True; FPunkte := 0; FDaneben := 0; SetButtonSize( 100 ); NewPosition; FTimer.Interval := 1000; FTimer.Enabled := True; NotifyChange; end; end; function TFangDenButtonKonkret.GetButtonSize: TPoint; begin Result := FButtonSize; end; function TFangDenButtonKonkret.GetPosition: TPoint; begin Result := FPosition; end; function TFangDenButtonKonkret.GetPunkte: Integer; begin Result := FPunkte; end; function TFangDenButtonKonkret.GetSpielAktiv: Boolean; begin Result := FSpielAktiv; end; procedure TFangDenButtonKonkret.NewPosition; begin SetButtonSize( Random( 100 ) + 50 ); FPosition.X := Random( PlaygroundSize.X - FButtonSize.X ); FPosition.Y := Random( PlaygroundSize.Y - FButtonSize.Y ); NotifyChange; end; procedure TFangDenButtonKonkret.SetButtonSize( ASize: Integer ); begin FButtonSize.X := ASize; FButtonSize.Y := ASize; NotifyChange; end; procedure TFangDenButtonKonkret.TimerCalled( Sender: TObject ); begin NewPosition; end; end.
Delphi-Quellcode:
Und laufen lassen ...
implementation
{$R *.dfm} uses FangDenButtonTest, { Unit einbinden } FangDenButtonKonkret; { TForm1 } procedure TForm1.AfterConstruction; begin inherited; // FGame := TFangDenButtonTest.Create; // Statt der Test-Klasse, die Konkrete-Klasse FGame := TFangDenButtonKonkret.Create; FGame.OnChange := GameOnChange; NotifyPlaygroundSize; end; Was sagt die Maus dazu? ![]() Das war Delphi!
Kaum macht man's richtig - schon funktioniert's
![]() Zertifikat: Sir Rufo (Fingerprint: ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60) |
![]() |
Registriert seit: 5. Jan 2005 Ort: Stadthagen 9.454 Beiträge Delphi 10 Seattle Enterprise |
#8
Da habe ich doch gerade meine Animation Unit wiedergefunden und damit den FangButton animiert.
dp_182706.PNG Das kompilierte Ergebnis ist im Anhang zu finden. Man wird feststellen, dass die Zeitabstände ein wenig zu hart verringert wird, denn bei ca. 13-15 Treffern (130-150 Punkten) ist irgendwie Schluss. Aber es ist ja nur ein Beispiel.
Kaum macht man's richtig - schon funktioniert's
![]() Zertifikat: Sir Rufo (Fingerprint: ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60) |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |