Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   [Gelöst] Verwendung von TQueue (https://www.delphipraxis.net/170983-%5Bgeloest%5D-verwendung-von-tqueue.html)

MrMooed 13. Okt 2012 17:02


[Gelöst] Verwendung von TQueue
 
'Nabend DP,

Ich habe da ein kleines Spiel (Tron :) ) geplant. Soweit läuft auch alles gut.
Aaaaber: Mir ist aufgefallen, dass ich 2x ganz schnell eine Taste drücken kann und das 'Bike' fährt gegen seine eigene Mauer (dreht sich um 180°)
Daher habe ich zunächst einfach weitere Tasteneingaben gesperrt, bis das Bike eine Position weiter ist. Das finde ich aber eigenltich sehr unschön, und würde die Tastendrücke gerne nacheinander abaerbeiten.

Somit bin ich dann bei TStack und TQueue gelandet. Soweit ich das richtig verstanden habe gibt es für meine Delphi Version (D7 Enterprise) keine TStack <Integer> ö.Ä. - er nimmt nur Zeiger an :?
Nun zu meinem eigentlichen Problem:

Delphi-Quellcode:
procedure TMain.MainKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    70: Tasten.Push(@Key); // [F] - LINKS
    74: Tasten.Push(@Key); // [J] - RECHTS
    end;
end;
Angenommen es liegt auf dem Stack ein Zeiger der auf Key zeigt. Dann würde doch bei meinem nächsten Tastendruck beide Items auf den selben Key zeigen oder irre ich da :?:

Und wenn es trotzdem unterschiedliche Werte sein sollten - wie wertet man den Stack wieder aus ?
Ich hatte mir gedacht, dass vor jeder Bewegung geprüft wird, welche Richtung er gehen soll:

Delphi-Quellcode:
procedure TMain.Timer1Timer(Sender: TObject);
var
  i: ^Integer;
begin
  i := Tasten.Pop;
  case ^i of
    70: Spieler[0].dreheLinks;
    74: Spieler[0].dreheRechts;
  darstellen(Sender);
end;
Nun meckert der Compiler aber, dass 'i' kein Integer sondern ein Char sein soll .. wobei der Zeiger doch auf einen Integer zeigt :roll:


Ich hoffe ich konnte mich halbwegs verständlich ausdrücken :( Ist für mich das Erste mal dass ich mit Zeigern hantieren muss:oops:


//Edit: Habe es soweit hinbekommen, dass ich keine Fehlermeldung bekomme.
Delphi-Quellcode:
procedure TMain.Timer1Timer(Sender: TObject);
var
  i: ^Integer;
begin
  if Tasten.Count > 0
    then begin
      i := Tasten.Pop;
      case Ord(^i) of
        70: Spieler[0].dreheLinks; // [F] - LINKS
        74: Spieler[0].dreheRechts; // [J] - RECHTS
        end;
      end;
  darstellen(Sender);
end;
allerdings scheint es so, als würde er nichts auf den Stack schieben (jedenfalls enthällt er im Debug mode keine Zeiger) :o

sx2008 13. Okt 2012 17:41

AW: Verwendung von TStack
 
Zitat:

Zitat von MrMooed (Beitrag 1186906)
Mir ist aufgefallen, dass ich 2x ganz schnell eine Taste drücken kann und das 'Bike' fährt gegen seine eigene Mauer (dreht sich um 180°)

Man das Problem auch anderst angehen.
Wenn das Bike frontal gegen seine eigene Mauer fährt, dann wird die Kollision ignoriert und die Richtung um 180 Grad gedreht.

MrMooed 13. Okt 2012 17:55

AW: Verwendung von TStack
 
Zitat:

Zitat von sx2008 (Beitrag 1186911)
Man das Problem auch anderst angehen.
Wenn das Bike frontal gegen seine eigene Mauer fährt, dann wird die Kollision ignoriert und die Richtung um 180 Grad gedreht.

Echt gute Idee :)
Doch angenommen ich habe mich nun 2x nach Rechts bewegt - wie erkennt der Computer, dass ich mich nicht nocheinmal nach Rechts bewegen darf ? Eigendlich soll es dann ja eine Koorlision geben, aber wenn die Position des Bikes mit der seiner Wand entspricht, "prallen" sie ja nicht aufeinaner :?:
So müsste ich irgendwie speichern, welche seine letzte Richtungsänderung war und danach entscheiden ob die nächste Bewegung möglich ist - oder wie hattest du dir das vorgestellt :oops:
(Im Extrem Fall Bewegt man sich 2x Rechts .. wartet .. wieder 2x Rechts. Dann würde sich wieder ein Stack anbieten um die Richtungsänderungen zu speichern :roll:)

Wenn ich es gar nicht mit Stacks hinkrege werde ich wohl dadrauf zurückgreifen. Wäre aber trotzdem nett wenn mir jemand meinen Fehler bei dem Stack zeigen könnte :?

himitsu 13. Okt 2012 17:59

AW: Verwendung von TStack
 
Du poppst die Speicheradresse der Variable auf deinen Stack?

*wo ist der ich hau dir auf die finger*-Smiley ?

Dein Stack wird zeitverzögert aufgerufen, daß heißt die Variable gibt es dann nicht mehr.

Da dieses Variable zufällig auf dem Stack (des Programms) liegt, greifst du also auf irgendwas zu, aber vermutlich nicht mehr auf den Wert der gedrückten Taste.
(da der Stack aber immer da ist, gibt es wenigstens keine Zugriffsverletzung)

Warum poppst du nicht einfach den "Wert" der gedrückten Taste drauf, bzw. warum verarbeitest du das nicht sofort?

nuclearping 13. Okt 2012 18:06

AW: Verwendung von TStack
 
Nur mal nebenbei, nicht auf's Problem konkret bezogen:
Zitat:

Zitat von MrMooed (Beitrag 1186906)
Delphi-Quellcode:
procedure TMain.Timer1Timer(Sender: TObject);
var
  i: ^Integer; // <-- Es gibt auch den Typ PInteger
begin
  i := Tasten.Pop;
  case ^i of // Was ist das? i ist doch schon ^Integer (PInteger) und du willst hier die Adresse der Adresse abfragen? :D
    70: Spieler[0].dreheLinks;
    74: Spieler[0].dreheRechts;
  darstellen(Sender);
end;
Nun meckert der Compiler aber, dass 'i' kein Integer sondern ein Char sein soll .. wobei der Zeiger doch auf einen Integer zeigt :roll:

Ja, probier's mal mit i^ statt ^i ... ;)

MrMooed 13. Okt 2012 18:35

AW: Verwendung von TStack
 
Zitat:

Zitat von himitsu (Beitrag 1186914)
Warum poppst du nicht einfach den "Wert" der gedrückten Taste drauf, bzw. warum verarbeitest du das nicht sofort?

Weil Delphi bei TStack.Push(AItem: TPointer) erwartet. (Was doch soviel bedeutet wie "gib mir einen Zeiger auf deinen Wert" :?:

Zitat:

Zitat von nuclearping (Beitrag 1186916)
Nur mal nebenbei, nicht auf's Problem konkret bezogen:
Ja, probier's mal mit i^ statt ^i ... ;)

Ups :oops: da war mir die Verwendung des Daches wohl nicht 100%ig klar, doch wenn ich es so ändere

Okey wenn ich das so abändere gibt es schonmal keine Fehlermldung. Jedoch scheint er dann auf Speicher zuzugreifen, der nicht mehr meine Tastennummer enthällt :?
Meintest du das himitsu ? Bin da nicht ganz durchgestiegen, was du mit der Zeitverzögerung meintest :cry:

Aber schonmal vielen Dank für die hilfreichen Antworten, ich stelle mich bestimmt mal wieder recht dusselig an :roll:

himitsu 13. Okt 2012 19:16

AW: Verwendung von TStack
 
Zitat:

Zitat von MrMooed (Beitrag 1186919)
Weil Delphi bei TStack.Push(AItem: TPointer) erwartet. (Was doch soviel bedeutet wie "gib mir einen Zeiger auf deinen Wert" :?:

TStack ist wie TList
Es will einen "Wert", den es speichern kann.
Wie bei TList also nicht einen Zeiger auf einen beliebigen Speicher.
Willst du wirklich einen Pointer speichern, dann müßtest du dafür sorgen, daß der Speicher nicht verloren geht, also z.B. per New einen Speicher vom Typ PWord (du willst ja ein Word speichern) erstellen, diesen puschen und am Ende (nach dem Pop) natürlich nicht das Dispose vergessen, oder du kastes das Word infach in einen Pointer und wieder zurück.

Wie gesagt, diese Variable "Key" ist nach Verlassen der Ereignisprozedur ungültig und damit auch der Zeiger auf sie.



In anktuelleren Delphis (D2009+) könnte man stattdessen auch den generischen Stack nutzen TStack<Word>, welcher direkt den "Wert" speichert.

sakura 13. Okt 2012 19:38

AW: Verwendung von TStack
 
Oder einfach den Wert auf Pointer (und später zurück) casten:
Delphi-Quellcode:
procedure TMain.MainKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    70: Tasten.Push(Pointer(Key)); // [F] - LINKS
    74: Tasten.Push(Pointer(Key)); // [J] - RECHTS
    end;
end;
und zurück:
Delphi-Quellcode:
procedure TMain.Timer1Timer(Sender: TObject);
var
  i: ^Integer;
begin
  i := Tasten.Pop;
  case Word(i) of
    70: Spieler[0].dreheLinks;
    74: Spieler[0].dreheRechts;
  darstellen(Sender);
end;
Achtung, TQueue ist die gewünschte Klasse, nicht TStack.

TQueue ist FIFO (First In, First Out), TStack ist FILO (First In, Last Out).

...:cat:...

MrMooed 13. Okt 2012 19:43

AW: Verwendung von TStack
 
Zitat:

Zitat von himitsu (Beitrag 1186923)
TStack ist wie TList
Es will einen "Wert", den es speichern kann.

Wie gesagt, diese Variable "Key" ist nach Verlassen der Ereignisprozedur ungültig und damit auch der Zeiger auf sie.

Aber wie kann ich ihm den Wert übergeben, wenn er einen Zeiger erwartet :gruebel: stehe da gerade auf dem Schlauch

//Edit:
Argh habe den Post von sakura nicht gesehen. Werde es eben mal so testen

//Edit2:
So wie sakura es vorgeschlagen hat klappt es :bouncing4: Das klärt auch meine Frage wie ich ihm einen Wert übergebe wenn er einen Pointer erwartet :) Vielen Dank an euch

nuclearping 13. Okt 2012 22:00

AW: Verwendung von TStack
 
Zitat:

Zitat von MrMooed (Beitrag 1186928)
So wie sakura es vorgeschlagen hat klappt es :bouncing4: Das klärt auch meine Frage wie ich ihm einen Wert übergebe wenn er einen Pointer erwartet :) Vielen Dank an euch

Statt dem Key kannst du ihm auch einen State übergeben.

Delphi-Quellcode:
type
  TDirections = (dirLeft, dirRight);

// ...

case Key of
  70: Tasten.Push(Pointer(dirLeft)); // [F] - LINKS
  74: Tasten.Push(Pointer(dirRight)); // [J] - RECHTS
end;
Ist einfacher, Bezeichner wie "dirLeft" und "dirRight" zu assoziieren, als 70, 74:
Delphi-Quellcode:
procedure TMain.Timer1Timer(Sender: TObject);
var
  i: ^Integer;
begin
  i := Tasten.Pop;
  case TDirection(i) of
    dirLeft: Spieler[0].dreheLinks;
    dirRight: Spieler[0].dreheRechts;
  darstellen(Sender);
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:54 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz