Tastenverzögerung ausschalten/umgehen



  • Moin,

    bin grad dabei Space Invaders zu schreiben. Dabei is mir ein kleines Problem über den Weg gelaufen das ich nicht lösen kann.

    Wenn ich nach links drücke geht der Spieler ein Pixel nach links, macht dann Pause, und geht erst nach ner halben Sekunden wieder durchgehend weiter. Kenn ja jeder.

    Die Suchfunktion und Google haben mir keine Hilfe. In nem Delphi-Forum hab ich irgendwas von GetKeyState gelesen aber entweder mach ichs falsch oder ich habs wohl nich verstanden. Hier hab von der SystemParametersInfo gelesen. Das hat eigentlich funktioniert. Doch der niedrigste einstellbare Wert sind dann immernoch 250ms die man im Spiel dann doch auch bemerkt.

    Gibts denn sonst keine Möglichkeit diese Verzögerung zu umgehen?

    greets



  • Ohje, genau das selbe Problem hatte ich zu Anfang auch. Probiers mit einer vektorbasierten Kamera, dann wirds klappen.



  • Du speicherst einfach in einer bool-Variable, ob die Taste gedrückt ist, oder nicht.
    Wird die Taste gedrückt, wird die Variable auf true gesetzt, wird sie wieder losgelassen, setzt du die Variable auf false.

    In der Bewegungsfunktion brauchst du dann nur noch abzufragen, ob die Variable auf true steht.



  • So mach ich das bereits... leider wird damit die Verzögerung genauso mit übertragen.



  • Camera.h

    struct tVector3	
    {			
    	tVector3() {} 
    
    	tVector3 (float new_x, float new_y, float new_z) 	 
    	{
    		x = new_x; y = new_y; z = new_z;
    	}
    
    	tVector3 operator+(tVector3 vVector) 
    	{
    		return tVector3(vVector.x+x, vVector.y+y, vVector.z+z);
    	}
    
    	tVector3 operator-(tVector3 vVector) 
    	{
    		return tVector3(x-vVector.x, y-vVector.y, z-vVector.z);
    	}
    
    	tVector3 operator*(float number)	 
    	{
    		return tVector3(x*number, y*number, z*number);
    	}
    
    	tVector3 operator/(float number)	
    	{
    		return tVector3(x/number, y/number, z/number);
    	}
    
    	float x, y, z;						
    };
    
    class CCamera
    {
    public:
    	tVector3 mPos;
    	tVector3 mView;
    	tVector3 mUp;
    
    	void Strafe_Camera(float speed);
    	void Move_Camera(float speed);
    	void Rotate_View(float speed);
    	void Mouse_Move(int wndWidth, int wndHeight);
    
    	void Position_Camera(float pos_x,float pos_y,float pos_z,
    		                 float view_x,float view_y,float view_z,
    						 float up_x,float up_y,float up_z);
    };
    

    Camera.cpp

    void CCamera::Position_Camera(float pos_x, float pos_y, float pos_z,
    							  float view_x, float view_y, float view_z,
    							  float up_x, float up_y, float up_z)
    {
    	mPos = tVector3(pos_x, pos_y, pos_z);
    	mView = tVector3(view_x, view_y, view_z);
    	mUp = tVector3(up_x, up_y, up_z);
    }
    
    void CCamera::Move_Camera(float speed)
    {
    	tVector3 vVector = mPos - mView;
    
    	mPos.x = vVector.x + mPos.x * speed;
        mPos.z = vVector.z + mPos.z * speed;
    
    	mView.x = vVector.x + mView.x * speed;
    	mView.z = vVector.z + mView.z * speed;
    }
    
    void CCamera::Rotate_View(float speed)
    {
    	tVector3 vVector = mView - mPos;
    
    	mView.z = (float)(mPos.z + sin(speed)*vVector.x + cos(speed)*vVector.z);
    	mView.x = (float)(mPos.x + cos(speed)*vVector.x - sin(speed)*vVector.z);
    }
    
    void CCamera::Strafe_Camera(float speed)
    {
    	tVector3 vVector = mPos - mView;
    	tVector3 vOrthoVector;
    
    	vOrthoVector.x = -vVector.z;
    	vOrthoVector.z = vVector.x;
    
    	mPos.x = vOrthoVector.x + mPos.x * speed;
    	mPos.z = vOrthoVector.z + mPos.z * speed;
    
    	mView.x = vOrthoVector.x + mView.x * speed;
    	mView.z = vOrthoVector.z + mView.z * speed;
    }
    
    void CCamera::Mouse_Move(int wndWidth, int wndHeight)
    {
    	POINT mousePos;
    	int mid_x = wndWidth >>  1;
    	int mid_y = wndHeight >> 1;
        float angle_y = 0.0f;
    	float angle_z = 0.0f; 
    
    	GetCursorPos(&mousePos);
    
    	if((mousePos.x == mid_x) && (mousePos.y == mid_y))
    	return;
    
    	SetCursorPos(mid_x, mid_y);
    
    	angle_y = (float)((mid_x - mousePos.x))/100;
    	angle_z = (float)((mid_y - mousePos.y))/100;
    
    	mView.y += angle_z*4;
    
    	Rotate_View(-angle_y);
    }
    

    Wobei hier jetzt noch die Maus miteingebunden ist. Naja, Maus rausgekickt, die Translatierung angepasst, die Tasten abgefragt und es geht.



  • Dergel schrieb:

    So mach ich das bereits... leider wird damit die Verzögerung genauso mit übertragen.

    Dann zeig mal bitte deinen Code.
    Weil das kann eigentlich überhaupt nicht sein.
    Die Variable darf nur dann wieder auf false gesetzt werden, wenn die Taste auch wirklich losgelassen wurde!



  • Also das ist die Bewegungsfunktion:

    void objects::Move(bool *keys)
    {
    	if(keys[VK_LEFT] && vObj[0].X >= -48)
    	{
    		for(unsigned int j=0; j<vObj.size(); j++)
    		{
    			vObj[j].X -= 1;
    		}
    	}
    	else if(keys[VK_RIGHT] && vObj[0].X <= 43)
    	{
    		for(unsigned int j=0; j<vObj.size(); j++)
    		{
    			vObj[j].X += 1;
    		}
    	}
    }
    

    Und hier wird die Nachricht abgefangen:

    case WM_KEYDOWN: // Drückt der Benutzer eine Taste???
        {
          keys[wParam] = TRUE; 
          // Der Wert im Array keys[] der dem Code 
          // der Taste entspricht, wird true gesetzt
    
    	  if(keys[VK_LEFT] || keys[VK_RIGHT])
    	  {
    		  vDraw[0].Move(keys);
    	  }
    
          return 0; // und zurück...
        }
    
        case WM_KEYUP: // Wurde eine Taste losgelassen?
        {
          keys[wParam] = FALSE; 
          // Wen ja, dann soll dieser Wert im Array keys[] 
          // auf FALSE gesetzt werden
        }
    


  • Jup, kein Wunder.
    Du rufst die Move-Funktion ja auch nur auf, wenn eine Taste gedrückt wird.
    Das geht natürlich nicht, du müsstest schon in in jedem Frame checken, ob die Taste gedrückt ist. Da diese Verzögerung ja vom System her kommt, sind die Tasten-Messages ja auch schon verzögert.
    So wie es jetzt ist, ist es zudem doppelt gemoppelt: Die Move-Funktion wird nur aufgerufen, wenn die LEFT-Taste gedrückt wird, und in der Funktion selbst prüfst du noch einmal, ob die LEFT-Taste überhaupt gedrückt ist.

    Also, genau genommen sollte die Move-Funktion in deine Hauptprogrammschleife.
    Ansonsten ist das aber mit dem Tasten-Array schon richtig 😉



  • Wenn du auf die Nachrichten reagierst sollte es schon durchgehend funktionieren.
    Du setzt einfach den entsprechenden ArrayEintrag auf true wenn KeyDown aktiviert wird - und auf false wenn KeyUp aktiviert wird.
    Ganz einfach - zumindest wenn du es bei den Messages belassen willst.

    Das funktioniert aber eigentlich doch flüssig, weil die Bewegung ja nur anhält wenn KeyUp aktiviert wurde.



  • hier die details zum key-repeat verinnerlichen.



  • hellihjb schrieb:

    hier die details zum key-repeat verinnerlichen.

    ?

    Because of the autorepeat feature, more than one WM_KEYDOWN message may be posted before a WM_KEYUP message is posted. The previous key state (bit 30) can be used to determine whether the WM_KEYDOWN message indicates the first down transition or a repeated down transition.

    Ist doch egal wie oft die KeydownMessage reinkommt, das Feld wird ja an der Stelle immer auf true gesetzt und erst dann false wenn KeyUp erfolgt.
    Und die Messages kommen doch der Reihe nach an, oder?
    Somit verstehe ich die Problematik nicht - klar gibts eine aber ....



  • Auto-Repeat ist der Grund weshalb Dergels Ansatz zunaechst den Anschein machte zu funktionieren. Du hast zwar erklaert wie man es loesen kann aber nicht warum es notwendig ist. Mein Hinweis war also keine Kritik sondern eine Ergaenzung.



  • hellihjb schrieb:

    Auto-Repeat ist der Grund weshalb Dergels Ansatz zunaechst den Anschein machte zu funktionieren. Du hast zwar erklaert wie man es loesen kann aber nicht warum es notwendig ist. Mein Hinweis war also keine Kritik sondern eine Ergaenzung.

    Hab ich falsch verstanden...kk



  • Alles klar danke Leute.

    Hab den Move-Aufruf in die Main gepackt jetz funktionierts. Warum is mir das nicht gleich in den Sinn gekommen???
    Naja egal...

    Problem gelöst!

    Danke nochma
    greets


Anmelden zum Antworten