Forums Développement Multimédia

Aller au contenu

Soustraction approximative ?

AS3 Flashbuilder Array Math Soustraction CODE Actionscript

11 réponses à ce sujet

#1 Alcarion

    Ceinture Marron

  • Members
  • PipPipPipPipPipPip
  • 115 messages

Posté 18 June 2012 - 20:20 PM

Salut tout le monde,

J'ai un tableau à 2 dimensions représentant un plateau de tuiles, dans lequel je stock des valeurs simples (0=vide, 1=herbe, 2=terre...)

Je souhaite maintenant stocker la rotation désirée de la tuile, et pour ce faire, j'utilise des décimales
(1.45 = une tuile d'herbe pivotée à 45°, 2.180 = une tuile de terre pivotée à 180°, etc)

Voici mon problème :
J'essaie de récuperer mes décimales avec une bête soustraction :
arr[0][0] = 1.90
arr[0][0] - Math.floor(arr[0][0]) devrait donc me donner 0.9... or je me retrouve avec une valeur de 0.8999.

Comment se fait-ce que la soustraction ne donne pas la valeur correcte ?
Y a t-il un moyen de régler ce problème ?
Et sinon, ma méthode pour stocker les rotations vous parait t-elle correcte ou faudrait t-il que je fasse un tableau à part ?

D'avance, merci pour vos lumières

#2 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 18 June 2012 - 21:25 PM

Hello !

Citation

Y a t-il un moyen de régler ce problème ?
Non, mais tu peux contourner le probleme en passant par une String

var rota:Number = Number( ("" + arr[0][0]).split(".")[1]);
 

Citation

Et sinon, ma méthode pour stocker les rotations vous parait t-elle correcte ou faudrait t-il que je fasse un tableau à part ?
Je pense que je ferais sensiblement la même chose, en passant une string contenant plusieurs valeurs séparé par un...séparateur (genre une virgule) destiné à être splitté et traité comme un tableau.

#3 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 18 June 2012 - 22:22 PM

Perso, je ferais plutôt un objet, ou même une classe si j'ai besoin de rapidité d'exécution.

Avec une petite fonction pou créer l'objet, c'est même assez propre puisque les variables sont typées (à l'entrée)


arr[0][0]=objet(1,90);
arr[0][1]=objet(2,180);
trace(arr[0][0].rotation); // 90
trace(arr[0][1].genre); // 2
function objet($genree:int;$rotation:Number):Object
{
  return {genre:$genre,rotation:$rotation};
}
 


#4 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 18 June 2012 - 23:02 PM

En fait ca dépend de la taille du tableau, moi aussi je prefere les objets :)

Mais pour créer un tableau d'objets de 255x255 , cela prend déjà 40 ms sur un PC récent. Je ne sais pas du tout si 255x255 c'est beaucoup pour un jeu à base de tiles (je n'ai jamais fait de jeu à base de tiles...) , mais si le tableau fait 1000x1000 par exemple (ou plus), on risque de freezer l'animation pendant plusieurs seconde le temps du traitement.

Sinon, je pensais à une méthode plus simpliste qui consisterait à utiliser 4 id différente pour chaque bloc en fonction de son orientation, par exemple
0 -> bloc pierre , rotation = 0
1 -> bloc pierre , rotation = 90
2 -> bloc pierre , rotation = 180
3 -> bloc pierre , rotation = 270
4 -> herbe , rotation = 0
5 -> ...

ces indexs pourrait correspondre aux indexs d'un Vector.<BitmapDatas> contenant toutes tes tiles.

Tout dépend ce que tu veux en faire en fait, si l'idée est de dessiner les blocs le plus rapidement possible, cette manière de procéder me parait la plus optimisée, mais ce n'est pas la plus lisible (et ce n'est peut être pas ce que tu veux).

#5 Alcarion

    Ceinture Marron

  • Members
  • PipPipPipPipPipPip
  • 115 messages

Posté 18 June 2012 - 23:02 PM

merci pour vos réponses,

pour vous répondre à mon tour, j'ai un peu plus de 11 000 valeurs dans mon tableau, et 100 types de tiles différents.
je risque de stocker d'autres informations après le séparateur, telle qu'une ID pour une tile "warp", donc exit la dernière solution pour moi, mais je la garde en tête pour d'autres applications :)

étant donnée la grande quantité de valeurs dans le tableau, créer autant d'objets ne risque t-il pas d'être lourd?
je ne sais pas si les objets consomment beaucoup de ressource...

#6 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 18 June 2012 - 23:03 PM

11 000 objets, ce n'est rien !

EDIT : plus précisément, 11 000 objets contenant aussi peu d'informations que ceux là, ce n'est rien. Ce qui serait couteux serait d'essayer de modifier les 11 000 objets dans la même frame (et encore pour des objets de ce type, ça ne poserai aucun problème). Mais ce n'est pas ton cas, tu vérifieras seulement les case à proximité direct du perso, c'est à dire 8 (voire une seule) donc rien :)

#7 sebastien.portebois

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 3876 messages

Posté 18 June 2012 - 23:18 PM

Salut

Comme Didier, je pencherai non pas pour une manipulation de type, qu'on décompose/recompose sans arret. Par définition les tiles, en général il y en a beaucoup, donc au plus c'est simple, au plus c'est sur, au plus c'est rapide, au mieux c'est !

Si la rapidité n'est pas le premier critère, et qu'on veut faire un truc simple et lisible, je pencherai pour une très simple petite classe, ca permet un typage fort et c'est toujours agréable d'avoir quelque chose qui permette de relever la moindre erreur dès la compilation.
Avoir Vector.<TileDef> sera beaucoup plus facile à manipuler et étendre qu'un Array d'Object.

Sinon, si on a besoni de vitesse, alors le mieux est de ne pas le coder sur plusieurs variables, ou sur une variable qu'on décompose/recompose (comme une chaine), mais sur une seule et unique variable uint dont tu alloues chaque octet à une information (plus ou moins, selon les niveaux de précisions requis).
C'est déjà ce que tu fais au quotidien avec les rgb que tu encodes en un seul uint 0xrrggbb ;-)

Et pour que ce soit lisible, tu définis les valeurs dans des const, et voila un code rapide, fiable et lisible :



static public const TILE_TYPE_EMPTY:uint  = 0x00001;
static public const TILE_TYPE_HERBE:uint  = 0x00002;
static public const TILE_TYPE_TERRE:uint  = 0x00004;
static public const TILE_TYPE_EAU:uint  = 0x00008;

static public const TILE_ROTATION_0:uint = 0x00100;
static public const TILE_ROTATION_45:uint = 0x00200;
static public const TILE_ROTATION_90:uint = 0x00400;

/**
* Raccourci pour composer un uint de définition de tile  
* @param type
* @param rotation
* @return
*
*/

protected function getTile(type:uint=TILE_TYPE_HERBE, rotation:uint=TILE_ROTATION_0):uint
{
return type | rotation;
}

protected function testTypes():void
{
var tileDef:uint;

// Une tuile de type herbe, 0°
trace("** tile herbe, 0°");
tileDef = getTile();

trace("herbe  :"  + ((tileDef & TILE_TYPE_HERBE) > 0));
trace("terre  :"  + ((tileDef & TILE_TYPE_TERRE) > 0));
trace("eau      :"  + ((tileDef & TILE_TYPE_EAU) > 0));
trace("rotation 0   :"   + ((tileDef & TILE_ROTATION_0) > 0));
trace("rotation 45  :"  + ((tileDef & TILE_ROTATION_45) > 0));
trace("rotation 90  :"  + ((tileDef & TILE_ROTATION_90) > 0));

trace("** tile eau, 90°");
tileDef = getTile(TILE_TYPE_EAU, TILE_ROTATION_90);

trace("herbe  :"  + ((tileDef & TILE_TYPE_HERBE) > 0));
trace("terre  :"  + ((tileDef & TILE_TYPE_TERRE) > 0));
trace("eau      :"  + ((tileDef & TILE_TYPE_EAU) > 0));
trace("rotation 0   :"   + ((tileDef & TILE_ROTATION_0) > 0));
trace("rotation 45  :"  + ((tileDef & TILE_ROTATION_45) > 0));
trace("rotation 90  :"  + ((tileDef & TILE_ROTATION_90) > 0));


}
 

Ce qui te retournera :

** tile herbe, 0°
herbe  :true
terre  :false
eau     :false
rotation 0   :true
rotation 45  :false
rotation 90  :false
** tile eau, 90°
herbe  :false
terre  :false
eau     :true
rotation 0   :false
rotation 45  :false

Bonne soirée,
Séb

#8 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 19 June 2012 - 00:06 AM

Le fait d'utiliser un très grand nombre d'objets ne pose aucun problème (hormis le temps de création).

Je n'ai jamais créé de jeu à base de tile, mais le nombre d'accés "simultané" aux tableaux devrait être assez restreint : dans le pire des cas, si on marche en diagonal, on doit faire apparaitre le nombre de tile que compte notre écran en largeur, idem en hauteur (le tout multiplié par 2 pour virer les tiles invisibles), c'est à dire, en voyant large , 100 accés aux tableaux par "passe" (les passes n'ayant lieu que lorsqu'on franchit une tile).

Ce qui est important, ce n'est pas le nombre d'objet en mémoire mais le nombre d'objet utilisé en même temps (dans la même frame). Et 100 c'est vraiment peu, d'autant plus qu'il n'y a aucun calcul à faire au sein de chacun de ces objets.
Donc à ta place, je me ferais une classe TileObj contenant les propriétés voulues (histoire de conserver le typage et surtout l'autocomplétion dans flashdevelop :) ) , et j'utiliserais un objet de ce type par tile.

@seb : ta méthode est super! Et je vais d'ailleurs m'en resservir pour d'autres projets qui n'ont rien à voir et qui nécessite un max d'optimisation :) Mais elle n'est pas super lisible pour un humain (pour moi du moins :mrgreen: ) et j'ai tendance à penser que le temps gagné par le processeur sera perdu par celui qui devra lire le code pendant la création du projet ^^ (mais c'est parce que je suis nul en opération binaire)

#9 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 19 June 2012 - 12:02 PM

Voir le messagesebastien.portebois, le 18 June 2012 - 23:18 PM, dit :

Sinon, si on a besoni de vitesse, alors le mieux est de ne pas le coder sur plusieurs variables, ou sur une variable qu'on décompose/recompose (comme une chaine), mais sur une seule et unique variable uint dont tu alloues chaque octet à une information (plus ou moins, selon les niveaux de précisions requis).
C'est déjà ce que tu fais au quotidien avec les rgb que tu encodes en un seul uint 0xrrggbb ;-)

Salut,

Comme le code d'exemple de Sébastien m'a surpris, en voici une autre version qui se rapproche d'avantage du stockage des couleurs rgb:

En utilisant
- 8 bits pour stocker le type de tuile (donc 256 valeurs différentes possibles)
- 2 bits pour stocker la rotation de la tuile (donc 4 valeurs différentes possibles: 0, ou 1 pour 90 degrés, ou 2 pour 180 degrés, ou 3 pour 270 degrés)
- 16 bits pour stocker un ID (donc 65536 valeurs différentes possibles) (même si je ne vois pas ce que serait cet ID, mais c'est pour l'exemple)
Ça donnerait:


// Ecriture de la variable dans le tableau
var type:int = 2; // terre
var rotation:int = 1; // 90 degrés
var id:int = 754;
arr[12][36] = id << 10 | rotation << 8 | type;
 


// Lecture des valeurs dans le tableau
var val:uint = arr[12][36]; // créer une variable temporaire pour n'accéder qu'une fois au tableau
var type:int = val & 0xFF;
var rotation:int = val >> 8 & 0x03;
// ou pour l'avoir en degrés:
// var rotation:int = (val >> 8 & 0x03) * 90;
var id:int = val >> 10;
trace(type, rotation, id);
 


P.S: Je viens de chercher un petit tuto pour expliquer les manipulations des bits de Sébastien et les miennes, mais j'ai pas trouvé, désolé. Mais Ça existe, c'est obligé :)

#10 sebastien.portebois

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 3876 messages

Posté 19 June 2012 - 12:31 PM

Voir le messagelilive, le 19 June 2012 - 12:02 PM, dit :

P.S: Je viens de chercher un petit tuto pour expliquer les manipulations des bits de Sébastien et les miennes, mais j'ai pas trouvé, désolé. Mais Ça existe, c'est obligé :)

Salut

Je n'ai pas réinventé l'eau chaude, c'est le principe qui est utilisé depuis des décennies pour les flags. C'est pourquoi dans plein de languages, les valeurs des enums sont des puissances de 2. Pour trouver de la littérature, il suffit de chercher sur google "flag binary tutorial" ou des mot clé similaires et il y aura trop à lire plutôt que pas assez ;)

Perso je l'utilse surtout pour des objets de configuration, quand j'ai besoin de tests rapides (sinon je reste souvent sur des classes avec de nombreux membres, plus lisible quand la performance n'est pas absolument indispensable).
De fait dans mes snippets sur evernote (chacun son organisation ^^) j'ai ce bout de code qui me sert de base chaque fois que j'ai un doute sur les tests pour les flags. On s'éloigne un peu de la question initiale, mais ca permet de compléter la réponse



        static public CONST FLAG_A:uint = 0x0001;
        static public CONST FLAG_B:uint = 0x0002;
        static public CONST FLAG_C:uint = 0x0004;
        static public CONST FLAG_D:uint = 0x0008;
        static public CONST FLAG_E:uint = 0x0010;
        static public CONST FLAG_F:uint = 0x0020;
        static public CONST FLAG_G:uint = 0x0040;

        protected var _flags:uint = 0;

   /**
        * flags d'option
        */

        public function set flags(flags:uint) : void
        {
                _flags = flags;
        }
        public function get flags():uint
        {
                return _flags;
        }

        /// Ajout d'un ou plusieurs flags
        public function appendFlags(flags:uint):MyClass
        {
                _flags |= flags;
                return this;
        }

        /// Suppression d'un flag ou plusieurs flags.
        public function clearFlags(flags:uint):MyClass
        {
                _flags &= ~flags;
                return this;
        }

        // Définition rapide de flags
        myClassInstance.flags = MyClass.FLAG_A | MyClass.FLAG_B | MyClass.FLAG_C;

        // Test rapide de flags
        if (flags & MyClass.FLAG_A) {
                ...
        }


 

edit :
A noter, selon les habitudes et préférences, on peut remplacer le 0x0001, 0x002,... par (1<<1), (1<<2), (1<<3) :

 static public CONST FLAG_A:uint = 0x0001; // = (1<<0);
        static public CONST FLAG_B:uint = 0x0002; // = (1<<1);
        static public CONST FLAG_C:uint = 0x0004; // = (1<<2);
        static public CONST FLAG_D:uint = 0x0008; // = (1<<3);
        static public CONST FLAG_E:uint = 0x0010; // = (1<<4);
        static public CONST FLAG_F:uint = 0x0020; // = (1<<5);
        static public CONST FLAG_G:uint = 0x0040; // = (1<<6);
 


#11 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 19 June 2012 - 12:49 PM

Flag, c'est bien le mot! C'est pour cela que j'ai fait ce petit ajout de code, qui n'utilise pas des flags pour dire si une tuile est de type herbe (oui ou non) et de type terre (oui ou non) et de type vide (oui ou non), mais qui utilise 8 bits pour stocker une valeur entre 0 et 255. Cela permet d'avoir 256 types de tuile possibles en utilisant 8 bits, contre seulement 8 types possibles avec le système des flags. Mais ça tu le savais Sébastien, puisque tu parlais justement du codage rgb. J'ai essayé de le rendre (un peu) plus clair pour Alcarion (au cas où cette démarche l'intéresse :mrgreen: ).

#12 Alcarion

    Ceinture Marron

  • Members
  • PipPipPipPipPipPip
  • 115 messages

Posté 21 June 2012 - 23:40 PM

Merci à tous pour vos réponses plus que satisfaisantes,

J'opte pour la solution des objets sans classe dans le tableau, étant donné que je devrais stocker mes tableaux dans une BDD...
Je conserve précieusement la méthode de Sebastien et vos déclinaisons, cette technique va m'être utile à plus d'un titre !

Vous déchirez,
Merci encore ; )



1 utilisateur(s) li(sen)t ce sujet

0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)

authorised training centre

Centre de Formation Mediabox - Adobe et Apple Authorised Training Center.

Déclaré auprès de la Direction du Travail et de la Formation Professionnelle

Mediabox : SARL au capital de 62.000€ - Numéro d'activité : 11 75 44555 75 - SIRET : 49371646800035

MEDIABOX, 23, rue de Bruxelles, 75009 PARIS

FFP