Comment gérer une vitesse de déplacement en diagonale ?

Aller en bas

Comment gérer une vitesse de déplacement en diagonale ?

Message par Spirale le Ven 16 Fév 2018 - 15:03

Bonjour,

Quand j'ai un moment de libre, j'aime bien écrire quelques lignes de codes pour essayer de m'améliorer en programmation de jeu, et il y a du boulot (boulet ?? ) Comme j'ai déjà quelques connaissances avec Bex, je continue avec lui.

Je suis en train de revoir les déplacements de sprites et j'ai une question qui m'est venu et qui pourra vous sembler absurde mais comment gérez-vous la vitesse de déplacement en diagonale ?

Je m'explique :

Je déplace un sprite dans les 4 directions : haut, bas, gauche, droite de 2 pixels à la fois.

Je souhaite qu'il se déplace en diagonale également, par exemple haut-gauche mais du coup il monte de 2 et va à gauche de 2. La diagonale étant plus longue à parcourir pour un même temps, la vitesse de déplacement du sprite est donc plus rapide. J'ai vérifier en tapant le code et effectivement, on voit que les déplacements en diagonale se font plus rapidement.

Comme j'aimerai que la vitesse apparaisse la même dans toutes les directions, j'ai choisi de procéder de la manière suivante :
 pour la direction haut seulement : le sprite monte de 3 pixels (donc y-3)
 pour la direction gauche seulement : le sprite se déplace de 3 pixels (donc x-3)
 pour la direction haut gauche en même temps : le sprite monte de 2 et va à gauche de 2 donc (y-2 et x-2) , ce qui correspont à une longueur parcouru presque équivalente à 3 pixels.

Y a-t-il un autre moyen ? une sorte de temporisation pour les diagonales ? 

Surtout que je ne souhaite pas forcément que mon sprite se déplace de 3 pixels.

Comment faite-vous ?

Merci.
avatar
Spirale
Patient contaminé

Masculin Nombre de messages : 175
Age : 40
Localisation : 71
Date d'inscription : 28/03/2015

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Tryphon le Ven 16 Fév 2018 - 15:20

J'utilise des nombres à virgule pour les positions. Si ma vitesse est v, j'ajoute (v, 0) à (x, y) pour aller à droite, et (v/racine(2), v/racine(2)) pour aller en bas à droite.

Bien sûr, le v/racine(2) est pré-calculé.
avatar
Tryphon
Docteur *
Docteur *

Masculin Nombre de messages : 11808
Age : 41
Localisation : Un peu plus à l'Ouest
Date d'inscription : 23/07/2016

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Tryphon le Ven 16 Fév 2018 - 15:34

Pour être plus précis : j'utilise des nombres à virgule fixe, pas des flottants. C'est aussi rapide que des entiers.

Ça s'implémente très facilement.
avatar
Tryphon
Docteur *
Docteur *

Masculin Nombre de messages : 11808
Age : 41
Localisation : Un peu plus à l'Ouest
Date d'inscription : 23/07/2016

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Spirale le Ven 16 Fév 2018 - 15:53

Merci Tryphon,

Je ne sais pas pourquoi mais je croyais que la Megadrive ne savait pas gérer des nombres à virgule. Je viens de faire une recherche rapide et je suis tombé sur un post de Vetea qui explique que Bex ne peut pas gérer les nombres à virgule flottante. Donc c'est bon pour ta méthode. (Même si je n'ai aucune idée de ce qu'est un nombre à virgule flottante, je vais regarder ça de plus près, ça semble important Embarassed )

Je testerai dès que possible. Je te remercie beaucoup.
avatar
Spirale
Patient contaminé

Masculin Nombre de messages : 175
Age : 40
Localisation : 71
Date d'inscription : 28/03/2015

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Tryphon le Ven 16 Fév 2018 - 17:24

Sur SGDK, ce sont des fix16 et fix32. fix parce que ce sont des nombres à virgule fixe, cad toujours le même nombre de chiffres après la virgule.

Un nombre à virgule flottante, c'est un peu plus difficile a gérer en effet. La MD pourrait, mais ce serait lent. Les fix sont amplement suffisants pour 99,9% des jeux.

Si tu as besoin d'explications dessus, n'hésite pas (mais quand j'aurai l'ordinateur parce qu'au téléphone c'est une horreur de taper Very Happy)
avatar
Tryphon
Docteur *
Docteur *

Masculin Nombre de messages : 11808
Age : 41
Localisation : Un peu plus à l'Ouest
Date d'inscription : 23/07/2016

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par shingosama le Ven 16 Fév 2018 - 20:29

Le problème avec les fix16 et fix32 c'est que de toute façon, il faut les convertir en int afin de les faire passer à SPR_setPosition();

Donc en gros les déplacements sont plus lents n'est-ce pas ?
avatar
shingosama
Infirmier

Masculin Nombre de messages : 4937
Age : 32
Localisation : SEGA Toulouse
Date d'inscription : 02/11/2016

https://www.genku.net

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Tryphon le Ven 16 Fév 2018 - 20:35

Non, la conversion fix -> int est un simple décalage de bits, ça coûte quasi-rien (mais on pourrait faire encore mieux avec un fix 16 + 16).
avatar
Tryphon
Docteur *
Docteur *

Masculin Nombre de messages : 11808
Age : 41
Localisation : Un peu plus à l'Ouest
Date d'inscription : 23/07/2016

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Spirale le Sam 17 Fév 2018 - 13:50

Merci Tryphon et shingosama.

Depuis hier je regarde des explications sur les nombres à virgule flottante, c'est très intéressant et je commence à comprendre comment ça marche. Je me rappel avoir appris ça, il y a trèèès longtemps, mais je n'y avais pas compris grand chose.

Je te remercie Tryphon pour ta proposition d'explications supplémentaires, c'est très sympa. Je vais continuer mes investigations et lorsque je bloquerai trop je reviendrai vers toi.

Pour l'instant, mon problème, c'est comment utilisé ça avec Bex.
Si Vetea ou F.L qui sont des experts Bex passent pas là pour me donner une piste. Car j'ai l'impression que Bex ne peut pas gérer les nombres à virgule que ce soit flottante ou fixe.

Je vais faire des recherches à ce sujet.

Sinon j'ai réfléchi à une astuce que je n'ai pas encore testé, qui consisterai à corriger les positions de mon sprite après un certain nombre de cycle.
Par exemple si ma vitesse de déplacement est 2 pixels pour les directions haut, bas, gauche, droite, ce qui fait 4 pixels pour 2 cycles, pour les diagonales : x et  y s'incrémente de 1 pour le 1er cycle et x et y s'incrémente de 2 au 2e cycle. Ce qui va correspondre en arrondissant large à 4 pixels.
avatar
Spirale
Patient contaminé

Masculin Nombre de messages : 175
Age : 40
Localisation : 71
Date d'inscription : 28/03/2015

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Fax le Sam 17 Fév 2018 - 15:29

Mon avis est que ton idée est bonne mais que tu peux encore perfectionner le tout.
En gros tu peux enregistrer la position "parfaite" dans une variable avec des coordonnées x et y à virgules (ou bien avec un nombre entier fictif), faire tes calculs de positions à partir de ces positions.
Par exemple en partant de 0,0, si tu bouge à une vitesse de 2 tu peux avoir :
0,2 -> bas
2,0 -> droite
0,-2 -> haut
-2,0 -> gauche
ou en diagonale en bas à droite
Cas ou tu peux utiliser des virgules :
cos(45) * 2(vitesse) = 1.41 en x et en y
Ou alors tu multiplie cette valeur par 100 pour avoir un entier équivalent = 141
Ensuite pour chaque cycle, tu positionne ton sprite à la position la plus proche de ta position "parfaite".
Ce qui donnerais pour le premier cycle en diagonal : 
1.41 ou 141 donnerait 1 en x et 1 en y
Deuxième cycle
2.82 ou 282 donnerait 3 en x et 3 en y

C'est la même chose que ta solution mais tu conserve la position "juste" dans une variable qui te permet de ne pas répercuter une approximation.

Je m'embrouille tout seul avec mon explication mais j'espère que tu comprends le fond de ma pensée ^^.
avatar
Fax
Patient en incubation

Masculin Nombre de messages : 86
Age : 31
Localisation : Nancy
Date d'inscription : 03/05/2017

http://Www.terre-et-glace.com

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Spirale le Sam 17 Fév 2018 - 16:27

Ouiii !!!

C'est une idée géniale.

Je vais regarder ça tout de suite.

Je te remercie Fax de t'être penché sur mon problème.
avatar
Spirale
Patient contaminé

Masculin Nombre de messages : 175
Age : 40
Localisation : 71
Date d'inscription : 28/03/2015

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Tryphon le Sam 17 Fév 2018 - 16:49

Euh... C'est très exactement la même chose que mon premier post Mr. Green

Et tu auras le même problème si Bec ne sait pas gérer les nombres à virgule.

Cela dit, la partie de la réponse où il te dit d'utiliser des nombres entiers et de diviser par 100 est une solution possible SAUF qu'il ne faut surtout pas utiliser 100 mais une puissance de 2 (par exemple 128).

En effet, les divisions par un nombre quelconque sont les opérations les plus lentes qui existent sur un CPU, au point que ça peut flinguer ton jeu.

Par contre, une division par 2^n peut se remplacer par un décalage de n bits vers la droite, et ça c'est très rapide.

Donc il te faut savoir une chose :

Comment fait-on un décalage de bits vers la droite en Bec ?

En C, c'est >>, y'a des chances que ça soit pareil.
avatar
Tryphon
Docteur *
Docteur *

Masculin Nombre de messages : 11808
Age : 41
Localisation : Un peu plus à l'Ouest
Date d'inscription : 23/07/2016

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Invité le Sam 17 Fév 2018 - 18:43

Coucou,
Désolé de la réponse tardive.
Je t'ai codé un petit exemple en BEX tout fait modifiable à souhait. Wink

Code:

 global x as integer
 global y as integer
 global sprite as integer

 Palettes Palette1,1,0,16
 sprite=addsprite(2,2)
 loadtiles IconeZombi,4,128
 propsprite sprite,128,1
 x=128+160
 y=128+112
 
 'soit 0.1 si 0.01 alors 100
 ' 10 : 0.1
 '100 : 0.001
 '20 : 0.2
 '1 : 1 ^^
 ' etc ...
 VF=1
 SpeedInit=1
 TempoSpeed=SpeedInit*VF
 TempoSpeedDiag=(TempoSpeed<<1)
 
'//////////////////////////////
'///// Boucle principale //////
'//////////////////////////////

 do
 valt
 j=joypad(0)
 'Routine de conversion virgule fixe
 if j then SpeedTempo+=SpeedInit else SpeedTempo=0
 'Diagonale ?
 if (j.0 and j.2) or (j.0 and j.3) or (j.1 and j.2) or (j.1 and j.3) then Tempo=TempoSpeedDiag else Tempo=TempoSpeed
 if SpeedTempo>=Tempo then
  SpeedSprite=SpeedInit
  SpeedTempo=0
 else
  SpeedSprite=0
 end if
 
 'Déplacement Sprite
 if j.0 and y>=130 then y-=SpeedSprite
 if j.1 and y<=330 then y+=SpeedSprite
 if j.2 and x>=130 then x-=SpeedSprite
 if j.3 and x<=430 then x+=SpeedSprite
 movesprite sprite,x,y
 loop
 
'=========================
'===== Routines ASM ======
'=========================

'Calcul de Racine carré
'Le Résultat est stocké dans Result !
Declare Asm Sub RacineCarre(d0 As Integer)    
  moveq   #0,d1            
  moveq   #0,d2            
  moveq   #0,d3            
  moveq   #15,d4          
Sqrt32_LOOP:
  add.l   d3,d3          
  add.l   d0,d0          
  addx.l  d1,d1          
  add.l   d0,d0            
  addx.l  d1,d1            
  move.l  d3,d2            
  add.l   d2,d2          
  addq.w  #1,d2            
  cmp.l   d2,d1            
  bcs.b   Sqrt32_SKIP      
  Sub.l   d2,d1          
  addq.w  #1,d3          
Sqrt32_SKIP:
  dbra    d4,Sqrt32_LOOP  
  exg     d3,d0
  move.w d0,__INTEGER_Result        
  rts
End Sub

'//////////////////
'/// Palettes /////
'//////////////////

Palette1:
    DATAINT $0E0E, $0000, $0024, $0226, $0228, $0240, $0246, $0262
    DATAINT $0280, $064E, $0668, $026A, $068A, $0AAA, $08CE, $0EEE

'///////////////
'//// GFX //////
'///////////////
 
IconeZombi:
    DATAINT $0111, $1111, $1191, $1111, $1411, $1111, $1311, $1111
    DATAINT $1188, $5551, $1511, $1188, $151F, $F118, $181F, $1F18
    DATAINT $1875, $FF11, $1875, $5575, $1858, $8888, $0185, $4949
    DATAINT $0184, $1F1F, $0014, $1A1A, $0014, $4949, $0001, $1111
    DATAINT $1111, $1110, $1111, $4911, $1111, $1191, $1111, $1131
    DATAINT $1517, $7131, $1881, $1111, $8511, $FF11, $851F, $1F11
    DATAINT $8F1F, $F511, $5575, $5571, $8888, $8581, $4949, $5811
    DATAINT $1F1F, $4810, $1A1A, $4810, $4949, $4100, $1111, $1000

Je t'ai même intégré une fonction ASM de calcul de Racine carré si tu veux faire des tests ...
Ici, la conversion se fait à base de tempo en fonction des Frames, c'est tout bête.

SpeedInit est notre vitesse de base.
VF le coefficient pour les virgules fixes, ou la vitesse que tu souhaites régler.

Pour les Diagonales, ben on double la tempo, ou sinon on peut aussi jouer avec le calcul de Racine carrée, etc ...
Bref, le tout est qu'à l'écran ça soit cohérent, le code derrière fera le reste. Wink
Pas de calcul compliqué ici.

C'est une manière de faire parmi tant d'autre ... A toi de bidouiller, réfléchir, etc ...
Amuses toi bien ! Wink

Invité
Invité


Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Spirale le Sam 17 Fév 2018 - 22:53

Oui c'est vrai Tryphon, désolé, Embarassed . Mon post précédent a été un peu rapide car en fait quand je disais que c'était une idée géniale c'était par rapport à l'entier 141 car ça m'a donné une idée que j'ai commencé à codé dans l'après-midi mais que je n'ai pas encore eu le temps de terminer.
Par contre, je ne savais pas pour les divisions par un nombre quelconque. Merci pour l'info. Very Happy

Génial Vetea, comme d'hab Wink . Merci pour ton code que je vais m'empresser de décortiquer.
Par contre, j'ai voulu tester la fonction ASM de calcul de Racine carré, lors de la compilation, Bex me met un message d'erreur : basic.s:325: *** Error:  Symbol '__INTEGER_RESULT' undefined ***
003508 33C0 00000000      move.w d0,__INTEGER_Result


Comme c'est de l'asm, je n'ai pas osé toucher quoique ce soit (déjà qu'en basic je galère...)

Merci à tous pour votre aide, je vais à présent cogiter sur toutes les infos dont je dispose pour essayer de comprendre et j'adore ça !
avatar
Spirale
Patient contaminé

Masculin Nombre de messages : 175
Age : 40
Localisation : 71
Date d'inscription : 28/03/2015

Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Invité le Sam 17 Fév 2018 - 22:55

Ah oui !
Il faut déclarer la variable "Result" en global. 

Code:
 global x as integer
 global y as integer
 global sprite as integer
 global Result as integer

 Palettes Palette1,1,0,16
 sprite=addsprite(2,2)
 loadtiles IconeZombi,4,128
 propsprite sprite,128,1
 x=128+160
 y=128+112
 
 'soit 0.1 si 0.01 alors 100
 ' 10 : 0.1
 '100 : 0.001
 '20 : 0.2
 '1 : 1 ^^
 ' etc ...
 VF=1
 SpeedInit=1
 TempoSpeed=SpeedInit*VF
 TempoSpeedDiag=(TempoSpeed<<1)
 
'//////////////////////////////
'///// Boucle principale //////
'//////////////////////////////

 do
 valt
 j=joypad(0)
 'Routine de conversion virgule fixe
 if j then SpeedTempo+=SpeedInit else SpeedTempo=0
 'Diagonale ?
 if (j.0 and j.2) or (j.0 and j.3) or (j.1 and j.2) or (j.1 and j.3) then Tempo=TempoSpeedDiag else Tempo=TempoSpeed
 if SpeedTempo>=Tempo then
  SpeedSprite=SpeedInit
  SpeedTempo=0
 else
  SpeedSprite=0
 end if
 
 'Déplacement Sprite
 if j.0 and y>=130 then y-=SpeedSprite
 if j.1 and y<=330 then y+=SpeedSprite
 if j.2 and x>=130 then x-=SpeedSprite
 if j.3 and x<=430 then x+=SpeedSprite
 movesprite sprite,x,y
 loop
 
'=========================
'===== Routines ASM ======
'=========================

'Calcul de Racine carré
'Le Résultat est stocké dans Result !
Declare Asm Sub RacineCarre(d0 As Integer)   
  moveq  #0,d1           
  moveq  #0,d2           
  moveq  #0,d3           
  moveq  #15,d4         
Sqrt32_LOOP:
  add.l  d3,d3         
  add.l  d0,d0         
  addx.l  d1,d1         
  add.l  d0,d0           
  addx.l  d1,d1           
  move.l  d3,d2           
  add.l  d2,d2         
  addq.w  #1,d2           
  cmp.l  d2,d1           
  bcs.b  Sqrt32_SKIP     
  Sub.l  d2,d1         
  addq.w  #1,d3         
Sqrt32_SKIP:
  dbra    d4,Sqrt32_LOOP 
  exg    d3,d0
  move.w d0,__INTEGER_Result       
  rts
End Sub

'//////////////////
'/// Palettes /////
'//////////////////

Palette1:
    DATAINT $0E0E, $0000, $0024, $0226, $0228, $0240, $0246, $0262
    DATAINT $0280, $064E, $0668, $026A, $068A, $0AAA, $08CE, $0EEE

'///////////////
'//// GFX //////
'///////////////
 
IconeZombi:
    DATAINT $0111, $1111, $1191, $1111, $1411, $1111, $1311, $1111
    DATAINT $1188, $5551, $1511, $1188, $151F, $F118, $181F, $1F18
    DATAINT $1875, $FF11, $1875, $5575, $1858, $8888, $0185, $4949
    DATAINT $0184, $1F1F, $0014, $1A1A, $0014, $4949, $0001, $1111
    DATAINT $1111, $1110, $1111, $4911, $1111, $1191, $1111, $1131
    DATAINT $1517, $7131, $1881, $1111, $8511, $FF11, $851F, $1F11
    DATAINT $8F1F, $F511, $5575, $5571, $8888, $8581, $4949, $5811
    DATAINT $1F1F, $4810, $1A1A, $4810, $4949, $4100, $1111, $1000

Et donc, modifies les variables à ta guise pour avoir le rendu visuel le plus juste à tes yeux. Wink

Invité
Invité


Revenir en haut Aller en bas

Re: Comment gérer une vitesse de déplacement en diagonale ?

Message par Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Revenir en haut


 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum