Autor Beitrag
Karlson
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 2088



BeitragVerfasst: 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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: Mi 22.06.05 16:33 
mit directinput sollte das auf jeden fall gehen Suche bei Google 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: 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.

ausblenden 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
ontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1280

Linux (FC6), WinXP Pro (Box)
D6 Pers, D7 Pro, FPC 2.x
BeitragVerfasst: 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
BeitragVerfasst: Di 28.06.05 09:55 
Titel: yo, ich hatte das problem auch
hab das aber anders ( und wie ich sagen muss ganz gut) geregelt. Die Tasten werden im Variablenarray keys abgespeichert und bei procedure keyup wieder gelöscht. Ich habs bei 2 Playern probiert und man kann ohne Probleme bis zu Acht Tasten gleichzeitig drücken. P[1] ist die Spielfigur des ersten Spielers und pmove ist ein Timer der alle 30 Millisekunden den Player bewegt.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if (key = vk_up)  then keys[1]:= 1;
if (key = vk_down) then keys[2]:=1;
if (key = vk_left) then keys[3]:=1;
if (key = vk_right) then keys[4]:=1;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if (key = vk_up)  then keys[1]:= 0;
if (key = vk_down) then keys[2]:=0;
if (key = vk_left) then keys[3]:=0;
if (key = vk_right) then keys[4]:=0;
end;

procedure TForm1.pmoveTimer(Sender: TObject);
begin
if (keys[1] = 1and (P[1].top>speed[1]+21then P[1].Top := P[1].top-speed[1];
if (keys[2] = 1and (P[1].top<form1.ClientHeight-65-speed[1]) then P[1].Top := P[1].top+speed[1];
if (keys[3] = 1and (P[1].left>0then P[1].left := P[1].left-speed[1];
if (keys[4] = 1and (P[1].left<form1.Width-65-speed[1]) then P[1].left := P[1].left+speed[1];
end;


Moderiert von user profile iconUGrohne: Code- durch Delphi-Tags ersetzt.
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Di 28.06.05 10:57 
user profile iconLossy 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.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var Keys: array[0..255of 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



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 79

Windows XP
C#, VS2005 / VS2008
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Mi 10.08.05 06:20 
Titel: Nicht funktionierendes KeyUp-Ereignis...
Hallo,

user profile iconBwK 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: 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.

ausblenden 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



BeitragVerfasst: 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 :D ) ...

also so gehts:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 27



BeitragVerfasst: Mi 17.05.06 16:22 
user profile iconBwK hat folgendes geschrieben:
so ... ich habs hinbekommen ... ich hab anstatt der pfeiltasten buchstaben genommen (wollte ich sowieso, ich dachte nur die coursortasten gehen erst mal einfacher :D ) ...

also so gehts:

ausblenden 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

mich würde jetz ma noch interessieren, wie du das array deklariert hast.
kann mir das ma einer erklähren? arrays sind immer so ne sache, hab bei mir nich immer so gute erfahrungen damit gemacht :roll: .(versuche die eigendlich wo's geht zu vermeiden)
0xCC
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 150



BeitragVerfasst: Mi 17.05.06 19:27 
ausblenden Delphi-Quelltext
1:
var keys : array[0..3of byte;					

markier mal array in delphi und drück F1 ^^
NeoInDerMATRIX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
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
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 27



BeitragVerfasst: Do 18.05.06 21:10 
user profile iconNeoInDerMATRIX 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
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.pmoveTimer(Sender: TObject);  
begin  
if (keys[1] = 1and (P[1].top>speed[1]+21then P[1].Top := P[1].top-speed[1];  
if (keys[2] = 1and (P[1].top<form1.ClientHeight-65-speed[1]) then P[1].Top := P[1].top+speed[1];  
if (keys[3] = 1and (P[1].left>0then P[1].left := P[1].left-speed[1];  
if (keys[4] = 1and (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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
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
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 150



BeitragVerfasst: Fr 19.05.06 15:48 
user profile iconJoachim 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 27



BeitragVerfasst: Fr 19.05.06 18:05 
user profile icon0xCC hat folgendes geschrieben:
user profile iconJoachim 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
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
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 27



BeitragVerfasst: Fr 19.05.06 18:29 
user profile iconNeoInDerMATRIX 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.