Allegro, Beispielprogramm für Tastaturabfragen funktioniert nicht.



  • Ich habe folgendes Programm aus dem Buch "Spieleprogrammierung", jedoch funktioniert
    die Bewegung des Joysticks bzw die Animation nicht wenn ich den Modus auf F2
    umschalte.
    Auch mit der kompilierten Version auf der CD geht es nicht.
    Ist da ein Fehler im Quellcode oder woran könnte es liegen?

    #include <allegro.h>
    #include <cstring>
    
    const int COUNT_JOY_IMAGES = 5;
    
    const int KEY_UNCHANGED = 0;
    const int KEY_PRESSED = 1;
    const int KEY_RELEASED = 2;
    
    const int MODE_STATE = 0;
    const int MODE_STATE_CHANGE = 1;
    
    BITMAP *JoystickPics[COUNT_JOY_IMAGES];
    
    int set_graphic_mode () {
    
    	int depths[] = {32, 16, 15, 16};
    	int modes[] = { GFX_AUTODETECT_FULLSCREEN, // 32Bit Fullscreen
    					GFX_AUTODETECT_FULLSCREEN, // 16Bit Fullscreen
    					GFX_AUTODETECT_FULLSCREEN, // 15Bit Fullscreen
    					GFX_AUTODETECT_WINDOWED}; // 16Bit Fenster
    
    	for (int a = 0; a < 4; a++) {
    		set_color_depth(depths[a]);
    		if (set_gfx_mode(modes[a], 1024, 768, 0, 0) >= 0) {
    			return 1;
    		}
    	}
    
    	return 0;
    
    }
    
    int getKeyState (int keycode) {
    
    	static int keyState[KEY_MAX];
    	static int firstTime = 1;
    
    	// Bei erstem Aufruf das Array mit nullen initialisieren
    	if (firstTime) {
    		firstTime = 0;
    		memset (keyState, 0, sizeof (int) * KEY_MAX);
    	}
    
    	if (key[keycode]) {
    		if (keyState[keycode]) {
    			return KEY_UNCHANGED; // Taste weiterhin gedrückt
    		}
    		else {
    			keyState[keycode] = 1; // Taste wurde gedrückt 
    		}
    	}
    	else {
    		if (keyState[keycode]) {
    			keyState[keycode] = 0;
    			return KEY_RELEASED; // Taste wurde losgelassen
    		}
    		else {
    			return KEY_UNCHANGED; // Taste ungedrückt
    		}
    	}
    
    }
    
    int main (int argc, char **argv) {
    
    	//-----------Main----------
    	allegro_init ();
    
    	if (!set_graphic_mode ()) {
    		allegro_message ("Unable to set Graphic Mode!");
    		exit (0);
    	}
    
    	install_keyboard ();
    
    	BITMAP *puffer = create_bitmap (SCREEN_W, SCREEN_H);
    	BITMAP *bild = load_bitmap ("ALLEGRO.TGA", 0);
    
    	char *filenames[] = { "JOY_NORM.BMP", "JOY_LEFT.BMP", "JOY_RIGHT.BMP", "JOY_UP.BMP", "JOY_DOWN.BMP" };
    
    	for (int i = 0; i < COUNT_JOY_IMAGES; i++) {
    		JoystickPics[i] = load_bitmap (filenames[i], 0);
    	}
    
    	//-------Main------------
    
    	int curImage = 0;
    	int mode = MODE_STATE;
    
    	while (!key[KEY_ESC]) {
    		if (key[KEY_F1]) {
    			mode = MODE_STATE;
    		}
    		else if (key[KEY_F2]) {
    			mode = MODE_STATE_CHANGE;
    		}
    
    		switch (mode) {
    			case MODE_STATE:
    				if (key[KEY_UP]) {
    					curImage = 3;
    				}
    				else if (key[KEY_DOWN]) {
    					curImage = 4;
    				}
    				else if (key[KEY_LEFT]) {
    					curImage = 1;
    				}
    				else if (key[KEY_RIGHT]) {
    					curImage = 2;
    				}
    				else {
    					curImage = 0;
    				}
    				break;
    			case MODE_STATE_CHANGE:
    				if (getKeyState (KEY_UP) == KEY_PRESSED) {
    					curImage = 3;
    				}
    				else if (getKeyState (KEY_DOWN) == KEY_PRESSED) {
    					curImage = 4;
    				}
    				else if (getKeyState (KEY_LEFT) == KEY_PRESSED) {
    					curImage = 1;
    				}
    				else if (getKeyState (KEY_RIGHT) == KEY_PRESSED) {
    					curImage = 2;
    				}
    				else {
    					curImage = 0;
    				}
    				break;
    		}
    
    		//--------DISPLAY---------
    		acquire_bitmap (puffer);
    		clear (puffer);
    		blit (bild, puffer, 0, 0, (SCREEN_W - bild->w)/2, (SCREEN_H - bild->h)/2, bild->w, bild->h);
    		blit (JoystickPics[curImage],
    			  puffer,
    			  0,
    			  0,
    			  (SCREEN_W - JoystickPics[curImage]->w)/2,
    			  (SCREEN_H - bild->h)/2 + bild->h + 15,
    			  JoystickPics[curImage]->w,
    			  JoystickPics[curImage]->h );
    		release_bitmap (puffer);
    		vsync ();
    
    		blit (puffer, screen, 0, 0, 0, 0, puffer->w, puffer->h);
    	}
    
    	destroy_bitmap (puffer);
    	for (int l = 0; l < COUNT_JOY_IMAGES; l++) {
    		destroy_bitmap (JoystickPics[l]);
    	}
    
    	return 0;
    
    } END_OF_MAIN ();
    

    So lange ich den Modus F1 also den Standardmodus habe funktioniert die Animation
    so lange ich eine Taste gedrückt habe bleibt der Stick in dieser Richtung,
    sobald ich aber mit F2 den Modus wechsle passiert gar nichts mehr. Dann ist
    der Stick immer zentriert.
    Ich vermute der Fehler liegt in der Funktion getKeyState, finde da allerdings
    keinen Fehler.

    Edit:
    Habe den Fehler eben gefunden, wie soll die Funktion auch funktionieren, wenn
    bei drücken der Taste KEY_UNCHANGED zurückgegeben wird, es muss KEY_PRESSED
    lauten.
    Wobei ich mir nicht sicher bin ob der Autor eigentlich wollte, dass man einmal
    drückt und das Bild "eingerastet" bleibt. Wenn ich das wollte, wie müsste ich
    das machen?



  • Habe es jetzt selbst hinbekommen, was haltet ihr von dieser Lösung:

    Ich habe das Switch in main um folgendes erweitert:

    case MODE_STATE_FIX:
        int scancode = readkey () >> 8;
        int key = fixKey (scancode);
        clear_keybuf ();
    
        switch (key) {
    	case KEY_UP:
    	    curImage = 3;
    	    break;
    
    	case KEY_DOWN:
                curImage = 4;
    	    break;
    
    	case KEY_LEFT:
                curImage = 1;
    	    break;
    
    	case KEY_RIGHT:
                curImage = 2;
                break;
    
    	default:
                curImage = 0;
    }
    break;
    

    Und die Funktion fixKey:

    int fixKey (int keycode) {
    	static int key = 0; // Enthält die derzeit gedrückte Position, 0 stellt die Normalstellung dar
    
    	switch (keycode) {
    
    		case KEY_UP:
    			if (key == KEY_UP)
    				key = 0;
    			else
    				key = KEY_UP;
    			break;
    
    		case KEY_DOWN:
    			if (key == KEY_DOWN)
    				key = 0;
    			else
    				key = KEY_DOWN;
    			break;
    
    		case KEY_LEFT:
    			if (key == KEY_LEFT)
    				key = 0;
    			else
    				key = KEY_LEFT;
    			break;
    
    		case KEY_RIGHT:
    			if (key == KEY_RIGHT)
    				key = 0;
    			else 
    				key = KEY_RIGHT;
    			break;
    	}
    	return key; // Neue Position zurückgeben
    }
    

    Was haltet ihr davon? Was könnte man verbessern?



  • SirLant schrieb:

    Was könnte man verbessern?

    Wenn es so klappt wie Du willst solltest Du nichts daran verbessern...
    Performance-Tuning lohnt sich da nicht so wirklich... 😉 🤡 👍



  • Ok, ich dachte eigentlich nicht eher an Performance bzw eigentlich doch, eher
    ob ich das jetzt ziemlich umständlich gelöst habe oder ob es so gut ist.



  • Abgesehen davon: in den Keyboardgeschichten ist meiner Meinung nach was faul - jedenfalls in der MSVC-Version. Und das hat wohl was mit DirectInput zu tun.
    z.B. kommst Du nicht ohne weiteres an die <>|-Taste dran - bei Scancodegeschichten. Auch eine Umstellung des Ländercodes hilft da nicht.



  • Du könntest ein Array über alle Keycodes machen, dann bräuchtest du die case Sachen nur einmal schreiben.

    Bye, TGGC


Anmelden zum Antworten