Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Tastatursteuerung für Objekt im 3D-Raum (https://www.delphipraxis.net/193060-tastatursteuerung-fuer-objekt-im-3d-raum.html)

ZYLAGON 15. Jun 2017 22:26

Tastatursteuerung für Objekt im 3D-Raum
 
Schönen guten Abend zusammen,

ich habe mir eine primitive 3D-Steuerung zusammengebastelt.
Das Objekt fährt immer in Blickrichtung solange die Geschwindigkeit positiv ist.
Sieht auch so aus als ob alles korrekt funktioniert.
Bin allerdings mit der Tastatursteuerung unzufrieden und hoffe auf Hilfe.

Hier mal der Code der Steuerung:

Delphi-Quellcode:
unit Test_Vektor;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Viewport3D,
  System.Math.Vectors, FMX.Controls3D, FMX.Objects3D, FMX.StdCtrls,
  FMX.Controls.Presentation, Windows, FMX.MaterialSources;

type
  TForm1 = class(TForm)
    ColorMaterialSource2: TColorMaterialSource;
    Viewport3D1: TViewport3D;
    Dummy1: TDummy;
    Figur: TCube;
    Auge: TSphere;
    Zielpunkt: TSphere;
    procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char;
      Shift: TShiftState);
  private
    { Private-Deklarationen }
    fZielpunktVektor:TVector3D;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char;
  Shift: TShiftState);
begin
  if GetAsyncKeystate(VK_UP)<0 then
    begin
      fZielpunktVektor:=Zielpunkt.LocalToAbsoluteVector(Zielpunkt.Position.Vector);
      Figur.Position.Vector:= fZielpunktVektor;
    end;

  if GetAsyncKeystate(VK_LEFT)<0 then
    begin
      Figur.RotationAngle.Y:=Figur.RotationAngle.Y-1;
    end;

  if GetAsyncKeystate(VK_RIGHT)<0 then
    begin
      Figur.RotationAngle.Y:=Figur.RotationAngle.Y+1;
    end;

  if GetAsyncKeystate(VK_Prior)<0 then
    begin
      Figur.RotationAngle.X:=Figur.RotationAngle.X+1;
    end;

  if GetAsyncKeystate(VK_Next)<0 then
    begin
      Figur.RotationAngle.X:=Figur.RotationAngle.X-1;
    end;

  if GetAsyncKeystate(VK_HOME)<0 then
    begin
      Figur.RotationAngle.Z:=Figur.RotationAngle.Z+1;
    end;

  if GetAsyncKeystate(VK_END)<0 then
    begin
      Figur.RotationAngle.Z:=Figur.RotationAngle.Z-1;
    end;

end;

end.


Wenn ich z.B. Pfeiltaste hoch gedrückt halte, bewegt sich das Objekt in Blickrichtung.
Drücke ich jetzt zusätzlich Pfeiltaste links, gibt´s einen kurzen Aussetzer, Objekt bewegt sich dann allerdings korrekt nach vorne links aus Blickwinkelsicht.
Lasse ich irgendwann die Pfeiltaste links los, dann bleibt das Objekt stehen.
Das kann ich noch umgehen, wenn ich eine beliebige Taste (z.B. Taste F) beim Loslassen der Pfeiltaste Links drücke.
Dann habe ich wieder diesen kurzen Aussetzer und das Objekt bewegt sich wie gewünscht nach vorne in Blickrichtung.

Also gibt es 2 Probleme:
1) Kurzer Aussetzer bei Zuschalten einer weiteren Taste.
2) Bei Loslassen einer Taste wird eine zusätzliche, unbeteiligte Taste benötigt, damit Objekt nicht zum Stillstand kommt. Das führt allerdings auch zu einem kurzen Aussetzer.


Falls jemand den obigen Code testen möchte, bedarf es möglicherweise noch ein paar Erklärungen:

Struktur:
Viewport ist Parent von Dummy
Dummy ist Parent von Figur (Dummy wird nicht unbedingt benötigt. Dann wäre Viewport der Parent für Figur)
Figur (hier habe ich einfach nur einen StandardCube der Größe 1 genommen) ist Parent von sowohl Auge als auch von Zielpunkt

Das Auge der Figur dient zur Erkennung der Blickrichtung.
Ich habe hier eine Sphere Größe 0,2 gewählt bei einer Z-Position von 0,51.
Als MaterialSource habe ich ColorMaterialSource2 zugeordnet, um das Auge erkennen zu können.

Jetzt zum Zielpunkt.
Die Figur fährt immer in Richtung Zielpunkt.
So ist es möglich, in Blickrichtung zu fahren.
Ich habe hier eine Sphere Größe 0,1 gewählt bei einer Z-Position von 0,01.
Die Z-Position ist sozusagen die Geschwindigkeit.

VG
ZYL

Rollo62 16. Jun 2017 09:33

AW: Tastatursteuerung für Objekt im 3D-Raum
 
Was genau soll denn passieren ?

Vielleicht musst du KeyDown UND KeyUp benutzen um das gewünschte Verhalten hinzubekommen ?
KeyDown merkt sich dann den KeyPress und feuert nur einmal, weitere Bewegung könntest du selber über einen Timer steuern.
KeyUp setzt dann diese Bewegung (Timer) wieder zurück.

Rollo

ZYLAGON 16. Jun 2017 21:29

AW: Tastatursteuerung für Objekt im 3D-Raum
 
Hallo Rollo62,

beispielsweise drücke ich gleichzeitig die Pfeiltaste oben und die Pfeiltaste links.
Das Objekt fährt in die gewünschten Richtungen.
Lasse ich dann Pfeiltaste links los, bleibt das Objekt leider stehen.

Ich weiß noch nicht, welcher Code im OnKeyUp-Ereignis das gewünschte Resultat bringen kann.
Habe da noch eine Idee, welche ich aber erst am Montag überprüfen kann, da der dazugehörige Code momentan leider nicht verfügbar ist.

VG
ZYL

himitsu 16. Jun 2017 21:41

AW: Tastatursteuerung für Objekt im 3D-Raum
 
Das liegt vorallem davon, weil DU hier zwei Methoden vermischst.

AsyncKey liefert immer den aktuellen Status aller Tasten.
Die KeyDown/KeyUp-Events liefern immer nur für die letzte Taste ein Repeat-Ereignis und lässt du eine Taste los, dann wird kein Repeat mehr ausgelöst und die Messages stoppen.

ZYLAGON 16. Jun 2017 23:38

AW: Tastatursteuerung für Objekt im 3D-Raum
 
Hallo himitsu,

habe das jetzt verstanden.
Anstelle alles über OnKeyDown abzufragen, löse ich das Problem über den von Rollo62 erwähnten Timer.
Der OnKeyDown-Code kommt in das OnTimer-Ereignis des Timers (Intervall habe ich jetzt mal so niedrig wie möglich auf 1 gesetzt.)
Funktioniert alles (weder Aussetzer noch Anhalten).

Kann man auch anders lösen als mit einem Timer wegen Performance?

Jedenfalls mal schon vielen Dank, dass die Steuerung funktioniert.

VG
ZYL

Rollo62 17. Jun 2017 23:00

AW: Tastatursteuerung für Objekt im 3D-Raum
 
Kann man auch anders machen.
Die Frage ist ob du eine GameLoop irgendwo laufen hast, mit Timer oder auch in z.B. IdleEvents o.ä.
Da kann man auch die AsyncKey-Abfrage reinlegen.

Ich denke das du womöglich im Moment die ersten Versuche machst, und da würde ich auch erstmal einen Teimer nehmen.
Dasist nicht schlecht, da musst du nur aufpassen das es kein EventFlodding gibt, also Timer.Interval 100ms
reicht vielleicht aus für eine flüssige Bewegung, und deine Bearbeitungsroutine sollte weitere TimerEvents ignorieren während du in der Routine noch rechnest.

Rollo

ZYLAGON 18. Jun 2017 19:28

AW: Tastatursteuerung für Objekt im 3D-Raum
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke für die Tipps, Rollo62.
Habe jetzt den Timer ein wenig entschärft und bin auf 30ms hoch.
Einfaches Projekt im Anhang, falls sich jemand mit den gleichen Problemen herumplagt.
Ergänzt wurden noch Kleinigkeiten wie Kamerasteuerung, Beschleunigung, Station.
Insgesamt beurteilt, ist das für den Anfang schon eine recht ordentliche Steuerung.
Vielen Dank nochmals für die Hilfe.

VG ZYL


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:21 Uhr.

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