Partage
  • Partager sur Facebook
  • Partager sur Twitter

[sdl2] mouse motion - déplacement d'image

Sujet résolu
    29 août 2021 à 16:45:59

    Bonjour à tous,

    Le problème est très simple, et je fais sans doute une énorme bêtise, mais lorsque je tente de déplacer une image (sélectionnée par un clic gauche), pour peu que j'accélère le mouvement de la souris, le pointeur souris quitte l'image, et le déplacement cesse. Il y a un "décrochage".

    J'ai testé avec la même image en .jpg et .bmp, même problème. J'ai également testé avec un poll event plutôt qu'un wait event, le problème persiste.

    Voici un code compilable qui reproduit l'erreur. Je crois que le problème se trouve entre les lignes 30 et 74, mais je ne vois pas où j'ai fait une bêtise.

    #include <stdio.h>
    #include <stdbool.h>
    
    #include <sdl2/sdl.h>
    #include <sdl2/sdl_image.h>
    
    #define R(x)		((x) >> 16)
    #define G(x)		((x) >> 8 & 0xff)
    #define B(x)		((x) & 0xff)
    
    #define BGCOLOR		0x606060
    
    struct card {
    	SDL_Rect coo;
    	SDL_Texture *tx;
    };
    
    struct {
    	int w,h;
    	SDL_Window *wnd;
    	SDL_Renderer *rdr;
    	struct card back;
    } game;
    
    void QuitSDL(void);
    bool InitSDL(void);
    void DisplayGame(void);
    bool LoadBackOfCard(void);
    
    bool MouseIsOnCard(SDL_Event *event) {
    	return
    		game.back.coo.x < event->motion.x &&
    		game.back.coo.x+game.back.coo.w > event->motion.x &&
    		game.back.coo.y < event->motion.y &&
    		game.back.coo.y+game.back.coo.h > event->motion.y;
    }
    
    bool CardIsSelected(SDL_Event *event) {
    	if((event->motion.state & SDL_BUTTON_LEFT) && MouseIsOnCard(event)) {
    		game.back.coo.x+=event->motion.xrel;
    		game.back.coo.y+=event->motion.yrel;
    		return(true);
    	}
    	
    	return(false);
    }
    
    int main(int argc,char *argv[]) {
    	(void)argc;
    	(void)argv;
    	
    	if(!InitSDL())
    		return(1);
    	
    	if(LoadBackOfCard()) {
    		game.back.coo.x=(game.w-game.back.coo.w)/2;
    		game.back.coo.y=(game.h-game.back.coo.h)/2;
    		SDL_ShowWindow(game.wnd);
    		bool done=false;
    		bool need_to_display=true;
    		while(!done) {
    			if(need_to_display) {
    				DisplayGame();
    				need_to_display=false;
    			}
    			SDL_Event event;
    			SDL_WaitEvent(&event);
    			if(event.type==SDL_QUIT || (event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_ESCAPE))
    				done=true;
    			if(event.type==SDL_MOUSEMOTION)
    				if(CardIsSelected(&event))
    					need_to_display=true;
    		}
    	}
    	
    	QuitSDL();
    	
    	return(0);
    }
    
    void DisplayBkg(void) {
    	SDL_SetRenderDrawColor(game.rdr,R(BGCOLOR),G(BGCOLOR),B(BGCOLOR),SDL_ALPHA_OPAQUE);
    	SDL_RenderFillRect(game.rdr,NULL);
    }
    
    void DisplayTestCard(void) {
    	SDL_RenderCopy(game.rdr,game.back.tx,NULL,&game.back.coo);
    }
    
    void DisplayGame(void) {
    	DisplayBkg();
    	DisplayTestCard();
    	SDL_RenderPresent(game.rdr);
    }
    
    void QuitSDL(void) {
    	SDL_DestroyRenderer(game.rdr);
    	SDL_DestroyWindow(game.wnd);
    	SDL_Quit();
    }	
    	
    bool InitSDL(void) {
    	if(SDL_Init(SDL_INIT_VIDEO)) {
    		fprintf(stderr,"SDL_Init error : %s",SDL_GetError());
    		return(false);
    	}
    
    	SDL_DisplayMode mode;
    	SDL_GetCurrentDisplayMode(0,&mode);
    	game.wnd=SDL_CreateWindow("mm",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,mode.w-30,mode.h-65,SDL_WINDOW_HIDDEN);
    	if(!game.wnd) {
    		fprintf(stderr,"SDL_CreateWindow error: %s",SDL_GetError());
    		return(false);
    	}
    
    	game.rdr=SDL_CreateRenderer(game.wnd,-1,SDL_RENDERER_ACCELERATED);
    	if(!game.rdr) {
    		fprintf(stderr,"SDL_CreateRenderer error: %s",SDL_GetError());
    		return(false);
    	}
    	SDL_GetRendererOutputSize(game.rdr,&game.w,&game.h);
    
    	return(true);
    }
    
    bool LoadBackOfCard(void) {	
    	SDL_Surface *s=IMG_Load("bb.png");
    	if(!s) {
    		fprintf(stderr,"IMG_Load error: %s",IMG_GetError());
    		return(false);
    	}
    	game.back.tx=SDL_CreateTextureFromSurface(game.rdr,s);
    	game.back.coo.w=s->w;
    	game.back.coo.h=s->h;
    	SDL_FreeSurface(s);
    	
    	return(true);
    }

    image:

    Pour l'exécutable:

    gcc -std=c11 -Wunused -Wswitch-default -Wall -Wextra %1.c -o %1.exe -lmingw32 -lsdl2main -lsdl2 -lsdl2_image

    Je suis sous win7

    D'avance merci à vous.

    Edgar.

    -
    Edité par edgarjacobs 29 août 2021 à 16:54:23

    • Partager sur Facebook
    • Partager sur Twitter

    Il y a ceux qui font des sauvegardes, et ceux qui n'ont pas encore eu d'incident....

      30 août 2021 à 0:08:27

      Salut,

      Je vois dans ta fonction CardIsSelected que tu fais additionnes l'image selon xrel, yrel.

      Même si en théorie l'image devrait suivre, je pense que l'idée est plutôt la suivante :

      - quand tu cliques, tu notes la position de la souris dans l'image (par exemple tu as cliqué sur le pixel 12,10 de l'image).

      - quand tu déplaces, tu repositionnes l'image selon la position absolue de la souris moins 12,10 (pour l'exemple). Et ainsi tu es sur qu'à chaque nouvelle frame, le curseur est toujours sur 12,10, peu importe comment il a bougé.


      Ainsi, au lieu de gérer une accumulation de position relatives, tu gères tout en absolu.

      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        5 septembre 2021 à 20:12:29

        Hello,

        Merci de ta réponse, et sorry de revenir si tard.

        Ton idée est bonne (et sans doute la bonne), j'ai modifié (très) légèrement mon code de la manière suivante, et je n'ai plus de décrochage:

        struct card {
        	SDL_Rect coo;
        	SDL_Texture *tx;
        	bool selected;
        	int x_sel,y_sel;
        };
        
        ....
        
        bool CardIsSelected(SDL_Event *event) {
        	if(event->motion.state & SDL_BUTTON_LEFT) {
        		if(!game.back.selected && MouseIsOnCard(event)) {
        			game.back.selected=true;
        			game.back.x_sel=game.back.coo.x-event->button.x;
        			game.back.y_sel=game.back.coo.y-event->button.y;
        		}
        	}
        	else
        		game.back.selected=false;
        
        	return(game.back.selected);		
        }
        
        ....
        
        int main(int argc,char *argv[]) {
        	....
        	if(LoadBackOfCard()) {
        		....
        		while(!done) {
        			....
        			if(event.type==SDL_MOUSEMOTION)
        				if(CardIsSelected(&event)) {
        					game.back.coo.x=event.motion.x+game.back.x_sel;
        					game.back.coo.y=event.motion.y+game.back.y_sel;
        					need_to_display=true;
        				}
        		}
        	}
        


        Reste à mettre les contrôles pour vérifier que l'image ne sorte pas de la fenêtre, mais c'est (presque) un détail.

        Merci à toi,

        Edgar.

        -
        Edité par edgarjacobs 5 septembre 2021 à 20:18:08

        • Partager sur Facebook
        • Partager sur Twitter

        Il y a ceux qui font des sauvegardes, et ceux qui n'ont pas encore eu d'incident....

        [sdl2] mouse motion - déplacement d'image

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        • Editeur
        • Markdown