Entwickler-Ecke

Multimedia / Grafik - Zwei Tasten werden gleichzeitig gedrückt


Karlson - Mi 22.06.05 16:20
Titel: Zwei Tasten werden gleichzeitig gedrückt
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 - 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 ;)


Lossy eX - 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.


Phobeus - 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.


Pansenen - 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.


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


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


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


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


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 - Mi 17.05.06 19:27


Delphi-Quelltext
1:
var keys : array[0..3of byte;                    

markier mal array in delphi und drück F1 ^^


NeoInDerMATRIX - Mi 17.05.06 20:53

Hallo,

das geht recht einfach! Schau mal im CVS Repo von Omorphia nach dem KeyMapper (OIncKeyList.inc [http://omorphia.cvs.sourceforge.net/*checkout*/omorphia/omorphia/library/source/OIncKeyList.inc?revision=1.5], OIncKeyName.inc [http://omorphia.cvs.sourceforge.net/*checkout*/omorphia/omorphia/library/source/OIncKeyNames.inc], OCtrlKeyMapper.pas [http://omorphia.cvs.sourceforge.net/*checkout*/omorphia/omorphia/library/source/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 - 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 [http://omorphia.cvs.sourceforge.net/*checkout*/omorphia/omorphia/library/source/OIncKeyList.inc?revision=1.5], OIncKeyName.inc [http://omorphia.cvs.sourceforge.net/*checkout*/omorphia/omorphia/library/source/OIncKeyNames.inc], OCtrlKeyMapper.pas [http://omorphia.cvs.sourceforge.net/*checkout*/omorphia/omorphia/library/source/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] = 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 - 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


0xCC - 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
http://www.delphi-library.de/viewtopic.php?t=44374&highlight=delphix


Joachim Knutson - 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
http://www.delphi-library.de/viewtopic.php?t=44374&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 - 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 - 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.


0xCC - Fr 19.05.06 19:02

user profile iconJoachim Knutson hat folgendes geschrieben:
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.

was willst du mit der dritten prozedur wenn du nicht mal weisst was sie macht ?

was willst du denn nun eigentlich machen ?


Joachim Knutson - Sa 20.05.06 15:15

user profile icon0xCC hat folgendes geschrieben:
user profile iconJoachim Knutson hat folgendes geschrieben:
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.

was willst du mit der dritten prozedur wenn du nicht mal weisst was sie macht ?

was willst du denn nun eigentlich machen ?


also ich habe ein timage, welches ich schon nach allen seiten steuern kann.
doch ich will auch, dass man es in 2 richtungen zugleich gehen kann. also z.b. nach oben-rechts.

und dazu brauch ich ja noch 2 extra prozeduren. ich habe schon bei onkeydown und onkeyup reingeschrieben:

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;

und nun muss ich doch noch sagen was ich machen soll wenn nun 2 tasten gedrückt werden oder?
und dazu hab ich für jeweils eine taste das hier:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm4.FormKeyPress(Sender: TObject; var Key: Char);
 begin
if key = 'd' then
Image1.Left:=Image1.Left+10;
if key = 'a' then
Image1.left:=Image1.left-10;
if key = 'w' then
Image1.top:=Image1.top-10;
if key = 's' then
Image1.top:=Image1.top+10;
end;

und jetz brauch ich halt noch das für 2 tasten, weiß aber nich wie ichs machen soll.
Pansenen hatte ja in seiner porzedur das:

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;

nur da weiß ich nich wie ich speed deklariere.
villeicht hast du ja ne idee?


0xCC - Sa 20.05.06 15:33

benötigt ein timer mit interval 10:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if GetForeGroundWindow = handle then
  begin
     if GetKeyState(byte('W'))and $8000 >0 then
       image1.Top:=image1.Top-10;
     if GetKeyState(byte('S'))and $8000 >0 then
       image1.Top:=image1.Top+10;
     if GetKeyState(byte('A'))and $8000 >0 then
       image1.Left:=image1.Left-10;
     if GetKeyState(byte('D'))and $8000 >0 then
       image1.Left:=image1.Left+10;
  end;
end;


NeoInDerMATRIX - Sa 20.05.06 18:52

Hallo,

dann brauchst du garkeine onKeyPress mehr!


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm4.CalcMovement;  
 begin  
  if key[1then  
   Image1.Left:=Image1.Left+10;  
  if key[2then  
   Image1.left:=Image1.left-10;  
  if key[3then  
   Image1.top:=Image1.top-10;  
  if key[4then  
   Image1.top:=Image1.top+10;  
End;


Und das rufst du for dem Rendern auf! Kann sein das du die Key Var sachen anpassen must! Weis leider nicht genau wie die deklariert sind.
Und wenn du das noch mit Movement Speed machen willst, dann machste noch ne var die nen durchlauf Timer beinhaltet.

Cu
Neo

P.S.: Habe mich mal eben hingesetzt und sowas in der art zusammen gebastelt.

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:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    StaticText1: TStaticText;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    KeyState: Array[0..255]of Boolean;
    KeyTime: Array[0..255]of Integer;
    Procedure onIdle(Sender: TObject; var Done: Boolean);
    Procedure CalcMovement;
    Procedure CheckPlace;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
Const
 km_BackSlash = 8;
 km_TAB = 9;
 km_Return = 13;
 km_Shift = 16;
 km_Ctrl = 17;
 km_Alt = 18{ ? }
 km_Break = 19;
 km_ESC = 27;
 km_Lehrtaste = 32;
 km_ScreenUp = 33;
 km_ScreenDown = 34;
 km_End = 35;
 km_Home = 36;
 km_Left = 37;
 km_Up = 38;
 km_Rigth = 39;
 km_Down = 40;
 km_Print = 44;
 km_Ins = 45;
 km_Del = 46;
 km_0 = 47;
 km_1 = 48;
 km_2 = 49;
 km_3 = 50;
 km_4 = 51;
 km_5 = 52;
 km_6 = 53;
 km_7 = 54;
 km_8 = 55;
 km_9 = 56;
 km_A = 65;
 km_B = 66;
 km_C = 67;
 km_D = 68;
 km_E = 69;
 km_F = 70;
 km_G = 71;
 km_H = 72;
 km_I = 73;
 km_J = 74;
 km_K = 75;
 km_L = 76;
 km_M = 77;
 km_N = 78;
 km_O = 79;
 km_P = 80;
 km_Q = 81;
 km_R = 82;
 km_S = 83;
 km_T = 84;
 km_U = 85;
 km_V = 86;
 km_W = 87;
 km_X = 88;
 km_Y = 89;
 km_Z = 90;
 km_WinLeft = 91;
 km_WinRigth = 92;
 km_WinKontect =93;
 km_NUM0 = 96;
 km_NUM1 = 97;
 km_NUM2 = 98;
 km_NUM3 = 99;
 km_NUM4 = 100;
 km_NUM5 = 101;
 km_NUM6 = 102;
 km_NUM7 = 103;
 km_NUM8 = 104;
 km_NUM9 = 105;
 km_NUMMul = 106;
 km_NUMPlus = 107;
 km_NUMMinus = 109;
 km_NUMKomma = 110;
 km_NUMDiv = 111;
 km_F1 = 112;
 km_F2 = 113;
 km_F3 = 114;
 km_F4 = 115;
 km_F5 = 116;
 km_F6 = 117;
 km_F7 = 118;
 km_F8 = 119;
 km_F9 = 120;
 km_F10 = 121{ Geht nicht koreckt }
 km_F11 = 122;
 km_F12 = 123;
 km_NUMLook = 144;
 km_Roll = 145;
 km_Plus = 187;
 km_Komma = 188;
 km_Minus = 189;
 km_Punkt = 190;
 km_Raute = 191;
 km_Fragezeichen = 219;
 km_Dead0 = 220{ ^ }
 km_Dead2 = 221{ ´ }
 km_Dead1 = 226{ < }
{ Kann sein das dieses noch verlegt werden muss }
 km_MouseLeft = 246;
 km_MouseRigth = 247;
 km_MouseUp = 248;
 km_MouseDown = 249;
 km_MouseButtonLeft = 250;
 km_MouseButtonRigth = 251;
 km_MouseButtonMiddle = 252;
 km_MouseWheelUp = 253;
 km_MouseWheelDown = 254;
 km_MouseWheelPressed = 255;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 If KeyState[Key] Then
   KeyTime[Key]:=KeyTime[Key] + 1
  Else Begin
   KeyState[Key]:=TRUE;
   KeyTime[Key]:=1;
  End;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 KeyState[Key]:=FALSE;
 KeyTime[Key]:=0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 KeyPreview:=TRUE;
 Application.onIdle:=onIdle;
end;

Procedure tForm1.CalcMovement;
Begin
 If KeyState[km_S] Then
  Button1.Top:=Button1.Top + KeyTime[km_S];
 If KeyState[km_W] Then
  Button1.Top:=Button1.Top - KeyTime[km_W];
 If KeyState[km_A] Then
  Button1.Left:=Button1.Left - KeyTime[km_A];
 If KeyState[km_D] Then
  Button1.Left:=Button1.Left + KeyTime[km_D];
End;

Procedure tForm1.CheckPlace;
Begin
 If Button1.Left<5 Then
  Button1.Left:=5;
 If Button1.Left+Button1.Width>Width - 10 Then
  Button1.Left:=Width - Button1.Left - 10;
 If Button1.Top<5 Then
  Button1.Top:=5;
 If Button1.Top + Button1.Height>Height - 10 Then
  Button1.Top:=Height - Button1.Height - 10;
End;

Procedure tForm1.onIdle(Sender: TObject; var Done: Boolean);
Begin
 CalcMovement;
 CheckPlace;
 StaticText1.Caption:='X = ' + IntToStr(Button1.Left) + ' | Y = ' + IntToStr(Button1.Top);
End;

end.

Das geht bei mir bis auf die Kollision rechts und unten! Aber darn solltest du sehen wie du das recht simpel machen kannst! Ohne Polling.


Joachim Knutson - Sa 20.05.06 20:52

user profile iconNeoInDerMATRIX hat folgendes geschrieben:
Hallo,
P.S.: Habe mich mal eben hingesetzt und sowas in der art zusammen gebastelt.

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:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    StaticText1: TStaticText;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    KeyState: Array[0..255]of Boolean;
    KeyTime: Array[0..255]of Integer;
    Procedure onIdle(Sender: TObject; var Done: Boolean);
    Procedure CalcMovement;
    Procedure CheckPlace;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
Const
 [...]

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 If KeyState[Key] Then
   KeyTime[Key]:=KeyTime[Key] + 1
  Else Begin
   KeyState[Key]:=TRUE;
   KeyTime[Key]:=1;
  End;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 KeyState[Key]:=FALSE;
 KeyTime[Key]:=0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 KeyPreview:=TRUE;
 Application.onIdle:=onIdle;
end;

Procedure tForm1.CalcMovement;
Begin
 If KeyState[km_S] Then
  Button1.Top:=Button1.Top + KeyTime[km_S];
 If KeyState[km_W] Then
  Button1.Top:=Button1.Top - KeyTime[km_W];
 If KeyState[km_A] Then
  Button1.Left:=Button1.Left - KeyTime[km_A];
 If KeyState[km_D] Then
  Button1.Left:=Button1.Left + KeyTime[km_D];
End;

Procedure tForm1.CheckPlace;
Begin
 If Button1.Left<5 Then
  Button1.Left:=5;
 If Button1.Left+Button1.Width>Width - 10 Then
  Button1.Left:=Width - Button1.Left - 10;
 If Button1.Top<5 Then
  Button1.Top:=5;
 If Button1.Top + Button1.Height>Height - 10 Then
  Button1.Top:=Height - Button1.Height - 10;
End;

Procedure tForm1.onIdle(Sender: TObject; var Done: Boolean);
Begin
 CalcMovement;
 CheckPlace;
 StaticText1.Caption:='X = ' + IntToStr(Button1.Left) + ' | Y = ' + IntToStr(Button1.Top);
End;

end.

Das geht bei mir bis auf die Kollision rechts und unten! Aber darn solltest du sehen wie du das recht simpel machen kannst! Ohne Polling.

cool thx, jetz hab ich hinbekommen. das leuchtet soweit ein.

(lustige sache mit dem StaticText1. :wink: )

also weißt du nich genau woran das liegt, dass er ganz rechts dann auf einmal wieder links erscheint?


NeoInDerMATRIX - Sa 20.05.06 21:09

Ist nur nen rechen oder prüf fehler den ich so auf die schnelle nicht seh! Aber ich denke das bekommst du mit ein wenig testen hin! Ach übrigens das ist so ungefair der source denn ich dir auch schon am anfang gezeigt habe. Nur das hier noch kein Mappen der Tasten gemacht wird. Und vergess nicht das du sicher auch noch etwas in der Time sache anpassen must!


Joachim Knutson - Sa 20.05.06 21:40

user profile iconNeoInDerMATRIX hat folgendes geschrieben:
Ist nur nen rechen oder prüf fehler den ich so auf die schnelle nicht seh! Aber ich denke das bekommst du mit ein wenig testen hin! Ach übrigens das ist so ungefair der source denn ich dir auch schon am anfang gezeigt habe. Nur das hier noch kein Mappen der Tasten gemacht wird. Und vergess nicht das du sicher auch noch etwas in der Time sache anpassen must!

ja das werd ich machen. nichts geht übers testen... :D

danke dafür.


Joachim Knutson - Mo 22.05.06 17:16

ich habe zwar nun schon sehr sehr (sehr) lange getestet, aber das nicht meinen bedürfnissen anpassen können.

also das größte problem ist:
je länger man auf eine taste drückt, desto schneller wird er. (d.h. irgendwann ist er so schnell, dass man ihn kaun noch sieht.)

sieht da jemand ne lösung? bin echt am ende, kann nich mehr.

ich denke ja, dass es an folgender prozedur liegt (bzw. die makierte zeile):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Procedure tForm4.CalcMovement;
Begin  
 If KeyState[km_S] Then  
 -------> Image1.Top:=Image1.Top + KeyTime[km_S]; <-------
 If KeyState[km_W] Then 
  ------->  Image1.Top:=Image1.Top - KeyTime[km_W];<-------
 If KeyState[km_A] Then  
  ------->  Image1.Left:=Image1.Left - KeyTime[km_A];<-------
 If KeyState[km_D] Then  
  ------->  Image1.Left:=Image1.Left + KeyTime[km_D];<-------
End;


NeoInDerMATRIX - Mo 22.05.06 18:03

Hallo,

Du must dazu den KeyTime ein maximal wert zuordnen und dies vor jedem Verwenden Prüfen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
Procedure tForm4.CalcMovement; 
Var
 Lauf: Integer;
  Begin   
   For Lauf:=0 to 255 do
    If KeyTime[Lauf]>10 Then
     KeyTime[Lauf]:=10;
   If KeyState[km_S] Then   
   -------> Image1.Top:=Image1.Top + KeyTime[km_S]; <------- 
   If KeyState[km_W] Then  
    ------->  Image1.Top:=Image1.Top - KeyTime[km_W];<------- 
   If KeyState[km_A] Then   
    ------->  Image1.Left:=Image1.Left - KeyTime[km_A];<------- 
   If KeyState[km_D] Then   
    ------->  Image1.Left:=Image1.Left + KeyTime[km_D];<------- 
  End;


Cu
Neo