[Geöst] Repeat Until und trotzdem Multitasking

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

[Geöst] Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Hallo Leutz,

ich versuche gerade ein stinknormales PingPong-Spiel zu programmieren. Dabei scheitere ich schon beim Grundlegendsten: den Schlägern.
Denn die Spieler müssen diese ja logischerweise gleichzeitig bewegen können. Und da liegt schon das Problem:

Es bewegt sich immer nur ein Schläger.

Zuerst habe ich es so probiert:

Code: Alles auswählen

procedure Form1.FormKeyDown(***der ganze normale Kram***);
begin
case Key of
$25: ShapeLeft.Top:=ShapeLeft.Top-10;
$27: ShapeLeft.Top:=ShapeLeft.Top+10;
$26: ShapeRight.Top:=ShapeRight.Top-10;
$28: ShapeRight.Top:=ShapeRight.Top+10;
end;
end;
 

Da gabs aber dann das oben beschriebene Ergebnis.

Dann hab ichs mit repeat until Schleifen probiert:

Code: Alles auswählen

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
  );
begin
  if pause=false then
  begin
    case Key of
      $25: if (ShapeLeft.Top>ShapeGround.Top) and (LeftStopvar=true) then LeftUp(self);
      $27: if (ShapeLeft.Top<(ShapeGround.Top+ShapeGround.Height-ShapeLeft.Height)) and (LeftStopvar=true) then LeftDown(self);
      $26: if (ShapeRight.Top>ShapeGround.Top) and (RightStopvar=true) then RightUp(self);
      $28: if (ShapeRight.Top<(ShapeGround.Top+ShapeGround.Height-ShapeRight.Height)) and (RightStopvar=true) then RightDown(self);
    end;
  end;
end;
 
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  case Key of
    $25, $27: LeftStopvar:=true;
    $26, $28: RightStopvar:=true;
  end;
end;
 
procedure TForm1.LeftUp(Sender: TObject);
var n:byte;
begin
  n:=1;
  repeat
    if n=1 then
    begin
      ShapeLeft.Top:=ShapeLeft.Top-10;
      Application.ProcessMessages;
      Sleep(75);
    end
    else
    begin
      Sleep(30);
      ShapeLeft.Top:=ShapeLeft.Top-10;
    end;
    LeftStopvar:=false;
    Application.ProcessMessages;
    n:=n+1;
  until (LeftStopvar=true) or (ShapeLeft.Top=ShapeGround.Top);
end;
 
procedure TForm1.LeftDown(Sender: TObject);
var n:byte;
begin
  n:=1;
  repeat
    if n=1 then
    begin
      ShapeLeft.Top:=ShapeLeft.Top+10;
      Application.ProcessMessages;
      Sleep(75);
    end
    else
    begin
      Sleep(30);
      ShapeLeft.Top:=ShapeLeft.Top+10;
    end;
    LeftStopvar:=false;
    Application.ProcessMessages;
    n:=n+1;
  until (LeftStopvar=true) or (ShapeLeft.Top=(ShapeGround.Top+ShapeGround.Height-ShapeLeft.Height));
end;
 
procedure TForm1.RightUp(Sender: TObject);
var n:byte;
begin
  n:=1;
  repeat
    if n=1 then
    begin
      ShapeRight.Top:=ShapeRight.Top-10;
      Application.ProcessMessages;
      Sleep(75);
    end
    else
    begin
      Sleep(30);
      ShapeRight.Top:=ShapeRight.Top-10;
    end;
    RightStopvar:=false;
    Application.ProcessMessages;
    n:=n+1;
  until (RightStopvar=true) or (ShapeRight.Top=ShapeGround.Top);
end;
 
procedure TForm1.RightDown(Sender: TObject);
var n:byte;
begin
  n:=1;
  repeat
    if n=1 then
    begin
      ShapeRight.Top:=ShapeRight.Top+10;
      Application.ProcessMessages;
      Sleep(75);
    end
    else
    begin
      Sleep(30);
      ShapeRight.Top:=ShapeRight.Top+10;
    end;
    RightStopvar:=false;
    Application.ProcessMessages;
    n:=n+1;
  until (RightStopvar=true) or (ShapeRight.Top=(ShapeGround.Top+ShapeGround.Height-ShapeRight.Height));
end;
 

Und wieder das gleiche Spiel...

Kann mir da jemand weiter helfen, so dass sich beide Schläger unabhängig voneinander bewegen können?

Dankschöööööön,
ConcAPPtLab
Zuletzt geändert von ConcAPPtLab am So 26. Okt 2014, 02:10, insgesamt 1-mal geändert.
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Repeat Until und trotzdem Multitasking

Beitrag von Mathias »

Ich würde mit einem Timer arbeiten.

Mit KeyDown setzt den Schritt, mit KeyUp stoppt den Schritt. Der Timer bewegt dann die Shape.

Das sieht dann etwa so aus:

Code: Alles auswählen

procedure TForm1.FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
const
  Schritt = 1;
begin
  case key of
    VK_A: begin
      SchrittLinks := -Schritt;
    end;
    VK_Y: begin
      SchrittLinks := +Schritt;
    end;
    VK_K: begin
      SchrittRechts := -Schritt;
    end;
    VK_M: begin
      SchrittRechts := +Schritt;
    end;
  end;
end;
 
procedure TForm1.FormKeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  case key of
    VK_A: begin
      SchrittLinks := 0;
    end;
    VK_Y: begin
      SchrittLinks := 0;
    end;
    VK_K: begin
      SchrittRechts := 0;
    end;
    VK_M: begin
      SchrittRechts := 0;
    end;
  end;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Shape1.Top := Shape1.Top + SchrittLinks;         // Hier muss noch eine Bereichsprüfung rein.
  Shape2.Top := Shape2.Top + SchrittRechts;
end;


PS:Anstelle von $25-$28 würde ich die Key-Bezeichnung von der Unit LCLType verwenden. Da sieht man auf den ersten Blick was für Tasten du verwendest.

In deinem Code sind es folgende Bezeichnungen.

Code: Alles auswählen

  VK_LEFT       = 37;
  VK_UP         = 38;
  VK_RIGHT      = 39;
  VK_DOWN       = 40;
 
Zuletzt geändert von Mathias am Di 30. Sep 2014, 20:13, insgesamt 1-mal geändert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

cool, danke. Und der Timer startet sich automatisch? Ich habe bisher noch nicht damit gearbeitet.
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Repeat Until und trotzdem Multitasking

Beitrag von Mathias »

cool, danke. Und der Timer startet sich automatisch?

Ja der ist defaultmässig auf Enabled.
Interval habe ich auf 10 gestellt.

PS: Ich hatte im obigen Code + und - vertauscht, habe es jetzt korrigiert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

oke. werds freitag ausprobiern
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Hallo Mathias,

ich hab jetzt mal deins ausprobiert und ein wenig angepasst, damit es den Anforderungen entspricht. Und soweit funktioniert das alles schon mal sehr schön. Allerdings passiert es nun, dass, wenn beide Spieler gleichzeitig ein Taste runterdrücken, bei dem einen der Schläger 'losläuft', bei dem anderen der Schläger aber stehen bleibt. Dieser Spieler muss dann noch einmal drücken, um den Schläger zu bewegen.
Der Grund dafür ist schnell gefunden:
Werden zwei Tasten gleichzeitig gedrückt, wird zwar der Form1KeyDown gestartet, jedoch wird ja nur eine im Form1KeyDown zugelassen - die andere wird solange vernachlässigt, bis der KeyDown erneut gestartet wird und die Variable Key neu beschrieben wird.

Ich hätte jetzt folgende Lösungsidee: Es wird in zwei weiteren Timern (einer für links, einer für rechts) unabhängig voneinander geprüft, ob die benötigten Tasten gedrückt sind (also A oder D, < oder >).
Allerdings kenn ich keine Abfragemöglichkeit dafür. Habs zwar schon mit GetKeyState und GetASyncKeyState probiert, jedoch kommt immer die Fehlermeldung mit fehlender Identifizierung...scheint so als bräuchte das ne Extra-Klasse. Außerdem habe ich keine Ahnung wie ich die beiden Sache händele. Könnt ihr mir da vielleicht wieder weiterhelfen?

Bis dann
ConcAPPtLab
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Repeat Until und trotzdem Multitasking

Beitrag von Mathias »

Wir nehmen mal nur den linken Schlager.

Wen ich ^, geht es nach oben, drücke gleichzeitig auch v, geht es nach unten, lasse ich dann ^ loss, steht es still. Weil das losslassen des ^ den Schritt auf 0 stellt.

Um dieses Problem zu umgehen, muss man sich den Tastendruck merken.

Ich habe das so gelöst.

Kleines Manko, wen man ^ und v gleichzeitig drück bleibt es stehen. Bei einem Auto kannst ja auch nicht gleichzeitig links und rechts steuern.

Code: Alles auswählen

procedure TForm1.FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  case key of
    VK_A: begin
      LUp := True;
    end;
    VK_Y: begin
      LDn := True;
    end;
    VK_K: begin
      RUp := True;
    end;
    VK_M: begin
      RDn := True;
    end;
  end;
end;
 
procedure TForm1.FormKeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  case key of
    VK_A: begin
      LUp := False;
    end;
    VK_Y: begin
      LDn := False;
    end;
    VK_K: begin
      RUp := False;
    end;
    VK_M: begin
      RDn := False;
    end;
  end;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
var
  p: integer;
begin
  p := Shape1.Top;
  if LUp then begin
    p -= 1;
  end;
  if LDn then begin
    p += 1;
  end;
  if p < 10 then begin
    p := 10;
  end else if p > ClientHeight - Shape1.Height - 10 then begin
    p := ClientHeight - Shape1.Height - 10;
  end;
  Shape1.Top := p;
 
  p := Shape2.Top;
  if RUp then begin
    p -= 1;
  end;
  if RDn then begin
    p += 1;
  end;
  if p < 10 then begin
    p := 10;
  end else if p > ClientHeight - Shape2.Height - 10 then begin
    p := ClientHeight - Shape2.Height - 10;
  end;
  Shape2.Top := p;
 
  Shape2.Left := ClientWidth - Shape2.Width - 10;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Okay. Aber da müsste doch jetzt genau der gleiche Fehler kommen wie bei mir: wenn beide Spieler gleichzeitig jeweils eine Taste drücken, bewegt sich nur der Schläger von EINEM Spieler.
Ansonsten funktioniert das ja alles. Sogar sehr gut. Aber das ist halt das Einzige was nicht funktioniert...
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Repeat Until und trotzdem Multitasking

Beitrag von Mathias »

wenn beide Spieler gleichzeitig jeweils eine Taste drücken, bewegt sich nur der Schläger von EINEM Spieler.

Ich kann beide Schläger unabhängig steuern.

Hast du auch nur ein Timer ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Nein, ich habe 2. Einen für Links, einen für Rechts. Ich poste gleich mal den Code
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Code: Alles auswählen

var
  Form1 : TForm1;
  pause : boolean;
  LeftStopvar, RightStopvar, LeftFirstTap, RightFirstTap:boolean;
  SchrittLinks, SchrittRechts:integer;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormDeactivate(Sender: TObject);
begin
  Pause:=true;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  pause:=false;
  LeftFirstTap:=true;
  RightFirstTap:=true;
end;
 
procedure TForm1.FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
const  Schritt = 10;
begin
  case key of
    VK_A:
      begin
        SchrittLinks := -Schritt;
        TimerLeft.Enabled:=true; //Timer (de-)aktivieren um Arbeitsspeicher zu schonen
        //LeftFirstTap:=true;
      end;
    VK_D:
      begin
        SchrittLinks := +Schritt;
        TimerLeft.Enabled:=true;
        //LeftFirstTap:=true;
      end;
    VK_Left:
      begin
        SchrittRechts := -Schritt;
        TimerRight.Enabled:=true;
        //RightFirstTap:=true;
      end;
    VK_Right:
      begin
        SchrittRechts := +Schritt;
        TimerRight.Enabled:=true;
        //RightFirstTap:=true;
      end;
  end;
end;
 
procedure TForm1.FormKeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  case key of
    VK_A:
      begin
        SchrittLinks := 0;
        TimerLeft.Enabled:=false;
        LeftFirstTap:=true;
      end;
    VK_D:
      begin
        SchrittLinks := 0;
        TimerLeft.Enabled:=false;
        LeftFirstTap:=true;
      end;
    VK_Left:
      begin
        SchrittRechts := 0;
        TimerRight.Enabled:=false;
        RightFirstTap:=true;
      end;
    VK_Right:
      begin
        SchrittRechts := 0;
        TimerRight.Enabled:=false;
        RightFirstTap:=true;
      end;
  end;
end;
 
procedure TForm1.TimerLeftTimer(Sender: TObject);
begin
  if LeftFirstTap=true then
  begin
    ShapeLeft.Top := ShapeLeft.Top + SchrittLinks;
    Application.ProcessMessages;
    Sleep(100);
    TimerLeft.Interval:=30;
    LeftFirstTap:=false;
  end
  else
  begin
    ShapeLeft.Top := ShapeLeft.Top + SchrittLinks;
  end;
end;
 
procedure TForm1.TimerRightTimer(Sender: TObject);
begin
  if RightFirstTap=true then
  begin
    ShapeRight.Top := ShapeRight.Top + SchrittRechts;
    Application.ProcessMessages;
    Sleep(100);
    TimerRight.Interval:=30;
    RightFirstTap:=false;
  end
  else
  begin
    ShapeRight.Top := ShapeRight.Top + SchrittRechts;
  end;
end;
end.

Und ich muss meine Beschreibung des Fehlers ändern: der Schläger reagiert nur nicht, wenn ein Spieler eine Taste drückt (und gedrückt lässt), dann die andere drückt und dann wieder loslässt. Das ist aber eigentlich genauso zu lösen. Indem ich aktiv immer wieder Abfrage ob eine Taste gedrückt ist... Kannst du mir da GetKeyState() und GetASyncKeyState() erklären?
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Also ich habs jetzt nochmal probiert. Ich bin mir ziemlich sicher, dass ich den an sich Timer richtig programmiert habe...und trotzdem kommt immer die Fehlermeldung 'unit1.pas(124,22) Error: Identifier not found "GetASyncKeyState"'. Muss ich eine extra Unit dafür einbinden? Wenn ja, welche?
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Repeat Until und trotzdem Multitasking

Beitrag von Mathias »

und trotzdem kommt immer die Fehlermeldung
Dafür muss du die Unit Windows einbinden.

Diese 3 Befehle brauchst du nicht im Timer:

Application.ProcessMessages;
Sleep(100);
TimerRight.Interval:=30


Application.ProcessMessages wird gebraucht, z.B. das einem die Anwendung in einer grossen Schleife nicht einfriert und auf weitere Ereignisse reagiert.
Sleep macht eine Pause, wird im Timer nicht benötigt, da es nach jedem Timer-Aufruf sowieso eine Pause gibt.
Der Intervall musst du nur einmal setzen, in deinem Programm am besten im Objectinspector.

Da beide Timer gleich schnell sind, reicht ein Timer.

Hast du meinen Code schon ausprobiert ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

ConcAPPtLab
Beiträge: 89
Registriert: Fr 18. Apr 2014, 18:57

Re: Repeat Until und trotzdem Multitasking

Beitrag von ConcAPPtLab »

Jup. Hab ich. Aber bei mir bewegt sich nichts

EDIT:

doch. es bewegt sich immer Shape2. Und zwar bewegt es sich immer so, dass es immer im gleichen Abstand zum Fensterrand ist xD
Zuletzt geändert von ConcAPPtLab am Sa 4. Okt 2014, 17:41, insgesamt 1-mal geändert.
Definition "Strategische Fehlerkorrektur":
Solange rumprobieren bisses klappt :D

Cybermonkey342
Beiträge: 109
Registriert: Sa 1. Mär 2008, 15:19
OS, Lazarus, FPC: Kubuntu 22.04 (FPC 3.2.2) / Win11 Pro (FPC 3.2.2) / macOS Ventura (FPC 3.2.2)
CPU-Target: x86/x64
Kontaktdaten:

Re: Repeat Until und trotzdem Multitasking

Beitrag von Cybermonkey342 »

Nur kurz zur Info, auf Lazplanet gibt es ein Tutorial für ein Pong-Spiel: http://lazplanet.blogspot.de/2014/10/cr ... rself.html
Mit besten Grüßen,
Cybermonkey

Antworten