Autor |
Beitrag |
Karlson
      
Beiträge: 2088
|
Verfasst: Mi 22.06.05 16:20
Moin,
In jedem über die Tastatur gesteuertem Spiel, sollte es möglich sein z.B. gleichzeitig nach vorne zu laufen und dabei nach links zu strafen.
Wie kann man das denn abfragen, ob zwei Tasten gedrückt sind mein ich.
Meine Ansätze:
1.) KeyDown Event - solang ich nur eine Taste abfrage klappt es, wenn ich eine zweite Taste dazu drücke wird die erste als losgelassen angezeigt und nur die zweite als gedrückt.
2.) KeyPress Event - gleiches Spiel
3.) GetAsyncKeyState - gleiches Spiel
4.) GetKeyState - gleiches Spiel
Hinzukommt folgendes Problem wenn man mit einer der oben geannten Methode arbeitet.
Ich zeige das mal anhand einer logdatei. Diese hat mittels GetAsyncKeyState abgefragt ob die Taste vk_left gedrückt ist, und zwar in einem Intervall von 50 ms. Wenn sie gedrückt war, wurde 1 vermerkt, wenn nicht 0:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| 0 0 0 0 0 0 0 0 1 /// Jetzt Habe ich vk_left gedrückt, und lies es auch gedrückt 1 0 // Das sieht evt. unwichtig aus, in einem Spiel stört es aber enorm! 0 0 1 1 1 1 1 1 1 1 |
Die Taste wird für ~300 ms nach dem Drücken als nicht gedrückt angezeigt.
|
|
retnyg
      
Beiträge: 2754
SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
|
Verfasst: Mi 22.06.05 16:33
mit directinput sollte das auf jeden fall gehen DIRECTINPUT DELPHI
gibt aber sicher auch nen anderen weg, den ich aber nicht kenne 
_________________ es gibt leute, die sind genetisch nicht zum programmieren geschaffen.
in der regel haben diese leute die regel...
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Do 23.06.05 09:16
Also ich kann das Verhalten mit GetAsyncKeyState absolut nicht bestätigen. Normal funktioniert das 100%tig richtig. Und GetAsyncKeyState greift auch nur auf die Tastatur zu. Ich denke mal da würde dann auch Directinput nicht ändern.
Delphi-Quelltext 1: 2: 3: 4:
| if GetAsyncKeyState(VK_LEFT) <> 0 then Memo1.Lines.Add('gedrückt') else Memo1.Lines.Add('nicht gedrückt'); |
Du könntest das Verhalten von GetAsyncKeyState auch mit Hilfe von einem Array[0..255] of Boolean und KeyDown und KeyUp simulieren. Jedes mal wenn du ein KeyDown bekommst setzt du das entsprechende Bool auf True und wenn du ein KeyUp bekommst dann löscht du es wieder. Um abzufragen ob eine Taste gedrückt ist überprüfst du dann nur noch die entsprechde Stelle im Array.
Aber wie gesagt. Normal sollte es 100%tig mit GetAsyncKeyState funktionieren. Anderenfalls würde ich mal testen ob deine Hardware und Windows richtig funktionieren. Also eine Testanwednung auf anderen Rechnern ausprobieren. Evtl auch mal ne andere Tastatur ausprobieren etc. Veilleicht hat die ja nen Wackelkontakt der sich so äußerst.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Phobeus
      
Beiträge: 1280
Linux (FC6), WinXP Pro (Box)
D6 Pers, D7 Pro, FPC 2.x
|
Verfasst: Do 23.06.05 10:01
Ja, man muss nicht DirectInput verwenden um so etwas zu lösen. Der häufigste Codierungsfehler in diesem Zusammenhang besteht meistens darinne, dass die Tasten in der Event-Loop verarbeitet werden. Ich erinnere mich da an einen Fehler im Zusammenhang mit SDL als jemand nur innerhalb der Event-Schleife die Tasten verarbeitete (mit der Absicht dies nach dem Tastensignal zu tun). Spätestens ab dem zweiten Durchgang gab es dann meist weniger Signale als Tasten und Signale gingen verloren. Versuche daher genausten nachzuvollziehen wie dies bei Dir geschieht.
Generell bietet es sich gerade bei Spielen der Weg an den SDL geht. Beim Drücken und loslassen der Tasten werden die Signale in ein Array of Boolean geschrieben. Wird eine Taste gedrückt wird dessen Index auf True gesetzt, und beim Release wieder auf false. Die Verarbeitung erfolgt dann bei jedem Zeichengang. Man erhält so die volle Kontrolle über den Datenfluss und kann sogar Tastensignale auf diese Weise leicht "rücksetzen" (z.B. beim Feuern mit der Rakete, darf kein Laser mehr abgefeuert werden). Nur ein Gedankengang, der mir beim lesen deines Problems in den Sinn kam.
_________________ "Menschen sterben nicht wenn man sie zu Grabe trägt, sondern wenn sie ihre Träume verlieren..."
|
|
Pansenen
Hält's aus hier
Beiträge: 15
D 7
|
Verfasst: Di 28.06.05 09:55
Titel: yo, ich hatte das problem auch
|
|
Heiko
      
Beiträge: 3169
Erhaltene Danke: 11
|
Verfasst: Di 28.06.05 10:57
Lossy eX hat folgendes geschrieben: | Du könntest das Verhalten von GetAsyncKeyState auch mit Hilfe von einem Array[0..255] of Boolean und KeyDown und KeyUp simulieren. Jedes mal wenn du ein KeyDown bekommst setzt du das entsprechende Bool auf True und wenn du ein KeyUp bekommst dann löscht du es wieder. Um abzufragen ob eine Taste gedrückt ist überprüfst du dann nur noch die entsprechde Stelle im Array. |
Mit diesem Verfahren arbeite ich, allerdings hat es einen Nachteil: Es kann dir passieren, dass das loslassen/drücken einer Taste nicht registriert wird. Dieser Fall war bisher allerdings ein Einzelfall, der bisher nur bei einem Freund von mir passiert ist.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| var Keys: array[0..255] of Boolean;
procedure TForm1.WMKeyDown(var Msg: TWMKeyDown); begin Keys[Msg.CharCode]:=true; end;
procedure TForm1.WMKeyUp(var Msg: TWMKeyUp); begin Keys[Msg.CharCode]:=false; end; |
Und dann kannst du Tastenkombinationen abfragen, so wie du die willst  .
|
|
BwK
Hält's aus hier
Beiträge: 7
|
Verfasst: Di 09.08.05 23:32
kann mir einer sagen, warum TForm1.FormKeyDown bei mir nich geht ?? TForm1.FormKeyUp geht, das andere nich ... Form1.KeyPreview is auf true ... da müsste das doch gehn oder ??
|
|
Speedmaster
      
Beiträge: 79
Windows XP
C#, VS2005 / VS2008
|
Verfasst: Mi 10.08.05 00:52
Gibt es nicht normal ein Softwareinterrupt wenn eine Taste gedrückt wird? So hatte ich das glaube ich mal irgendwo gehört!
|
|
Logikmensch
      
Beiträge: 390
Win XP
Delphi 2007 Prof., XE2, XE5
|
Verfasst: Mi 10.08.05 06:20
Titel: Nicht funktionierendes KeyUp-Ereignis...
Hallo,
BwK hat folgendes geschrieben: | kann mir einer sagen, warum TForm1.FormKeyDown bei mir nich geht ?? TForm1.FormKeyUp geht, das andere nich ... Form1.KeyPreview is auf true ... da müsste das doch gehn oder ?? |
Grundsätzlich tritt nach dem Drücken einer Taste ein entsprechender KeyDown (und im Falle von 'normalen' Tasten KeyPress) ein. Beim Loslassen wird ein zuvor erreichtes KeyDown durch ein KeyUp-Ereignis wieder aufgehoben. Es muss eigentlich funktionieren. Zeig mal Deine betreffenden Event-Prozeduren, vielleicht kann man dort den Fehler erkennen.
Liebe Grüße,
Claus.
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Mi 10.08.05 08:38
Es wird nicht immer bei allen Tasten aufgerufen. Ich meine bei Tab wird es nicht von Hause aus aufgerufen. Bei einem Panel glaube ich werden die Cursortasten auch nicht aufgerufen.
Mit folgendem Code kannst du Windows sagen, dass du sie dennoch gerne hättest.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| type TForm1 = class(TForm) protected procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; end;
implementation
procedure TForm1.WMGetDlgCode(var Message: TWMGetDlgCode); begin Message.Result := DLGC_WANTALLKEYS or DLGC_WANTTAB or DLGC_WANTARROWS; end; |
PS: Wenn du es bei einem Panel ermöglichen möchtest musst du das Panel ableiten und den Codeschnipsel auch dort einfügen.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
BwK
Hält's aus hier
Beiträge: 7
|
Verfasst: Mi 10.08.05 11:30
so ... ich habs hinbekommen ... ich hab anstatt der pfeiltasten buchstaben genommen (wollte ich sowieso, ich dachte nur die coursortasten gehen erst mal einfacher  ) ...
also so gehts:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (key = Ord('U')) then keys[0]:= 1; if (key = Ord('J')) then keys[1]:=1; if (key = Ord('H')) then keys[2]:=1; if (key = Ord('K')) then keys[3]:=1; end;
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (key = Ord('U')) then keys[0]:= 0; if (key = Ord('J')) then keys[1]:=0; if (key = Ord('H')) then keys[2]:=0; if (key = Ord('K')) then keys[3]:=0; end; |
mfg BwK
|
|
Joachim Knutson
      
Beiträge: 27
|
Verfasst: Mi 17.05.06 16:22
|
|
0xCC
      
Beiträge: 150
|
Verfasst: Mi 17.05.06 19:27
Delphi-Quelltext 1:
| var keys : array[0..3] of byte; |
markier mal array in delphi und drück F1 ^^
|
|
NeoInDerMATRIX
      
Beiträge: 245
Win95, Win98(+se), WinNT, Win2000, WinME, WinXP(+pro), VISTA, Linux(SuSe), DOS [MultiMon(3)], Vista
D6 PeE + (FP 2.0l) + D3 Pe + D2005+ D2006 Arch
|
Verfasst: Mi 17.05.06 20:53
Hallo,
das geht recht einfach! Schau mal im CVS Repo von Omorphia nach dem KeyMapper ( OIncKeyList.inc, OIncKeyName.inc, OCtrlKeyMapper.pas)! In diesen Units siehst du wie das das anstellen kannst! Ist recht simpel.
Cu
Neo
P.S.: Irgend wie geht das mit den Link's auf SF nicht! Oder hab ich mal wieder etwas falsch gemacht!
|
|
Joachim Knutson
      
Beiträge: 27
|
Verfasst: Do 18.05.06 21:10
NeoInDerMATRIX hat folgendes geschrieben: | Hallo,
das geht recht einfach! Schau mal im CVS Repo von Omorphia nach dem KeyMapper (OIncKeyList.inc, OIncKeyName.inc, OCtrlKeyMapper.pas)! In diesen Units siehst du wie das das anstellen kannst! Ist recht simpel.
Cu
Neo
P.S.: Irgend wie geht das mit den Link's auf SF nicht! Oder hab ich mal wieder etwas falsch gemacht! |
boa da seh ich echt nich durch. sitz jetz seit ner 3/4 stunde und weiß noch nich mehr.
@0xCC danke
also hab noch ne frage dazu:
ich woltts eigendlich wie Pansenen machen (schien mir einfach zu sein), doch
follgendes versteh ich nich
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.pmoveTimer(Sender: TObject); begin if (keys[1] = 1) and (P[1].top>speed[1]+21) then P[1].Top := P[1].top-speed[1]; if (keys[2] = 1) and (P[1].top<form1.ClientHeight-65-speed[1]) then P[1].Top := P[1].top+speed[1]; if (keys[3] = 1) and (P[1].left>0) then P[1].left := P[1].left-speed[1]; if (keys[4] = 1) and (P[1].left<form1.Width-65-speed[1]) then P[1].left := P[1].left+speed[1]; end; |
und zwar das mit speed. wie definiere ich das? oder am besten wie mach ichs das ich kein speed drin hab? will ja eigendlich nur zwei tasten und ein ereignis haben.
oder soll ich lieber doch ne andere variante nehmen????
|
|
NeoInDerMATRIX
      
Beiträge: 245
Win95, Win98(+se), WinNT, Win2000, WinME, WinXP(+pro), VISTA, Linux(SuSe), DOS [MultiMon(3)], Vista
D6 PeE + (FP 2.0l) + D3 Pe + D2005+ D2006 Arch
|
Verfasst: Do 18.05.06 22:10
Hallo,
also mit einem Time (POLLING) solte man solche sachen in zeiten von Windows und Co. nicht mehr machen. So hab ich das noch unter DOS gemacht. Damit ist dann die CPU aber mehr damit beschäftigt das Polling zu erledigen als wie alles andere. Und wenn du das mit einem Timer machst kannst du nicht jeder Zeit den aktuellen status der Tasten erfahren!
Ich habe mal einen etwas älteren Code raus gesucht, ohne den overhead von Omorphia. Der sollte dir denke ich etwas mehr helfen. Und wenn nicht dann frag mich bei den sachen die du nicht verstehst.
Eigentlich ist es recht simpel:
1. Im Form wo du den KeyMapper nutzen möchtest must du ihn via InitMapper(Self) Initzialisieren.
2. Und dann natürlich auch noch die Tasten, via BindKey, mit Commandos Binden.
3. In der Form Class die Procedure WndProc überschreiben.
In der Unit Main.pas siehst du recht gut wie man das anwenden kann.
Ich hoffe das es so etwas Informativer ist.
Cu
Neo
Einloggen, um Attachments anzusehen!
|
|
0xCC
      
Beiträge: 150
|
Verfasst: Fr 19.05.06 15:48
Joachim Knutson hat folgendes geschrieben: |
ich woltts eigendlich wie Pansenen machen (schien mir einfach zu sein) |
lass die finger von code, den du nicht verstehst, sondern schreib deinen eigenen.
das kommt natürlich darauf an, was du machen willst.
ich nehme mal an, es geht um ein objekt, dass sich auf cursordruck rumbewegen soll
am besten liest du dir hierzu folgendes tutorial durch
www.delphi-library.d...mp;highlight=delphix
|
|
Joachim Knutson
      
Beiträge: 27
|
Verfasst: Fr 19.05.06 18:05
0xCC hat folgendes geschrieben: | Joachim Knutson hat folgendes geschrieben: |
ich woltts eigendlich wie Pansenen machen (schien mir einfach zu sein) |
lass die finger von code, den du nicht verstehst, sondern schreib deinen eigenen.
das kommt natürlich darauf an, was du machen willst.
ich nehme mal an, es geht um ein objekt, dass sich auf cursordruck rumbewegen soll
am besten liest du dir hierzu folgendes tutorial durch
www.delphi-library.d...mp;highlight=delphix |
nur das problem is ich habe nur delphi6 personal zur verfügung und KANN auch nichts anderes nehmen. (hat so seine gründe)
kann mir trotzdem einer helfen?? bitte
|
|
NeoInDerMATRIX
      
Beiträge: 245
Win95, Win98(+se), WinNT, Win2000, WinME, WinXP(+pro), VISTA, Linux(SuSe), DOS [MultiMon(3)], Vista
D6 PeE + (FP 2.0l) + D3 Pe + D2005+ D2006 Arch
|
Verfasst: Fr 19.05.06 18:20
Hallo,
ich verstehe nicht wo das problem ist! Du hast jetzt zwei mögliche ansätze, sogar mit Source. Du must für dich selber entscheiden welcher weg für dich einfacher zu verstehen ist und welcher besser für dein program ist. Und wenn du dich entschieden hast, dann probiere den source zu verstehen. Wenn dann fragen aufkommen können / werden wir dir helfen. Im moment vestehe ich halt nicht wobei du hilfe brauchst!
Cu
Neo
|
|
Joachim Knutson
      
Beiträge: 27
|
Verfasst: Fr 19.05.06 18:29
NeoInDerMATRIX hat folgendes geschrieben: | Hallo,
ich verstehe nicht wo das problem ist! Du hast jetzt zwei mögliche ansätze, sogar mit Source. Du must für dich selber entscheiden welcher weg für dich einfacher zu verstehen ist und welcher besser für dein program ist. Und wenn du dich entschieden hast, dann probiere den source zu verstehen. Wenn dann fragen aufkommen können / werden wir dir helfen. Im moment vestehe ich halt nicht wobei du hilfe brauchst!
Cu
Neo |
also ich wollte ursprünglich wissen, wie man nach Pansenen's variante diese variable 'speed' dekariert.
eigenlich weiß ich gar nich wie ich die dritte prozedur in mein progri bringe.
|
|