Forums Développement Multimédia

Aller au contenu

calcul Isometric

CODE

4 réponses à ce sujet

#1 milo210

    Ceinture Blanche

  • Members
  • Pip
  • 2 messages

Posté 14 June 2011 - 18:32 PM

Bonsoir,

Je suis actuellement en train de bricoler un moteur isométrique histoire de voir comment ça marche en interne. Mais je bute sur le calcul des profondeurs. J'ai regardé pas mal de chose, notamment sur le forum :

bannalia

topic1

topic2

as3Isolib

Mais je dois avouer que ça n'est pas très clair ; est ce que quelqu'un aurait des liens plus précis ou un exemple a me donner s'il vous plaie?

bonne soirée,

#2 frangois

    Ceinture Noire

  • Members
  • PipPipPipPipPipPipPip
  • 224 messages

Posté 14 June 2011 - 20:47 PM

C'est facile:
- tu travailles avec 2 systèmes de coordonnées: le repère classique de Flash (x,y = 0,0 au coin supérieur gauche) que l'on notera Screen, et le repère isométrique (x,y = 0,0 arbitrairement choisi à un "coin" de ton niveau) que l'on notera World
- chaque objet visuel à afficher a des coordonnées World uniquement
- le rôle du rendu est de transformer les coordonnées World en coordonnées Screen, puis de l'afficher.
- la fonction mathématique World -> Screen dépend de ton angle.
- inversement tu as besoin d'une fonction Screen -> World, pour détecter les objets sous un clic de souris par exemple.

Pour le z-sort, si tu bosses comme ça, c'est tout à fait trivial:

Citation

SI
ObjA.worldX < ObjB.worldX && ObjA.worldY < ObjB.worldY
ALORS
ObjA est derrière ObjB

Attention cas particulier d'as3isolib: tu trouveras une coordonnée Z, ce n'est pas le depth, mais la hauteur dans World(x,y,z). C'est totalement accessoire, la hauteur ne change pas le côté devant/derrière.

2ème warning: en bossant comme ça (en 2D dans un repère cartésien), il y a des cas insolvables: les solides concaves - les pièces en forme de C ou de L par exemple. Solution: ne pas en avoir

as3isolib est une bonne base, mais travaille avec des Sprites/MovieClip et la DisplayList de Flash. Hors, le nombre d'objets affichés suit fatalement une progression quadratique: nombre total = (longueur d'un coté du niveau)². Tu vas donc ramer à 90 tiles de côté. C'est déjà pas mal.

Modifié par frangois, 14 June 2011 - 20:48 PM.

Je suis dispo en free-lance. Et j'ai un blog.

#3 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 14 June 2011 - 22:02 PM

Citation

SI
ObjA.worldX < ObjB.worldX && ObjA.worldY < ObjB.worldY
ALORS
ObjA est derrière ObjB

Si je peux me permettre, comment décider si l'inégalité de gauche est vérifiée mais pas celle de droite, ou inversement ?

Je persiste et signe, il faut en fait formuler comme suit:

Si ObjA.worldX + ObjA.worldY < ObjB.worldX + ObjB.worldY
- alors ObjA s'affiche derrière ObjB
Sinon si ObjA.worldX + ObjA.worldY > ObjB.worldX + ObjB.worldY
- alors ObjA s'affiche devant ObjB
Sinon, égalité (peu importe)

Pourquoi j'insiste ? Parce qu'en établissant rigoureusement une relation d'ordre totale, on peut passer à un algo de tri rapide. A savoir, qu'en plus l'AS3 implémente de base un tri rapide avec ordre total customisé: Array.sort.

En pratique, j'ai fait un petit FLA, histoire de démontrer tout ça.

Le code est le suivant:


// génération d'un réseau de cubes, la classe Cube étant un symbole de librairie
var tabCubes:Array = new Array();
var cube:Cube;
for ( var i:int=0 ; i<10 ; i++ )
{
        for ( var j:int=0 ; j<10 ; j++ )
        {
                cube = new Cube();
                cube.isoX = i*15;
                cube.isoY = j*15;
                tabCubes.push( cube );
                this.addChild( cube );
        }
}

// l'idée ici est de mélanger les cubes afin de les faire apparaître
// n'importe comment à'écran:
tabCubes.sort( rand );

for ( var p:int=0 ; p<tabCubes.length ; p++ )
{
        this.addChild( tabCubes[p] );
}

function rand( a:Object, b:Object ):int
{
        return (Math.random() > 0.5) ? 1 : -1;
}
// fin du mélange

// le (0, 0) du monde iso sera affiché à l'écran aux coordonnées suivantes:
var centreX:Number = 275;
var centreY:Number = 200;

// on projete de coordonnées iso à coordonnées écran:
for ( var k:int=0 ; k<tabCubes.length ; k++ )
{
        tabCubes[k].x = centreX + tabCubes[k].isoX - tabCubes[k].isoY;
        tabCubes[k].y = centreY + (tabCubes[k].isoX + tabCubes[k].isoY)/2;
}

////

// mettez cette ligne en commentaire et vous verrez que tout s'affiche n'importe comment.
// C'est elle qui commande le tri:
tabCubes.sort( triIso );

// on demande à replacer dans la displayList les cubes selon l'ordre calculé précédemment
for ( var n:int=0 ; n<tabCubes.length ; n++ )
{
        this.addChild( tabCubes[n] );
}

// ici la fameuse fonction de comparaison, qui est totale:
function triIso( clip1:MovieClip, clip2:MovieClip ):int
{
        var resultat:int;
        if ( (clip1.isoX + clip1.isoY) < (clip2.isoX + clip2.isoY) )
                resultat = -1;
        else if ( (clip1.isoX + clip1.isoY) > (clip2.isoX + clip2.isoY) )
                resultat = 1;
        else
                resultat = 0;
        return resultat;
}

 

Fichier(s) joint(s)


Modifié par Logic, 14 June 2011 - 22:05 PM.


#4 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 14 June 2011 - 22:22 PM

Ca s'étend tout naturellement dans le cas où on est dans des coordonnées iso à 3 dimensions (x, y, z).

Si ObjA.worldX + ObjA.worldY + ObjA.worldZ < ObjB.worldX + ObjB.worldY + ObjB.worldZ
- alors ObjA s'affiche derrière ObjB
Sinon si ObjA.worldX + ObjA.worldY + ObjA.worldZ > ObjB.worldX + ObjB.worldY + ObjB.worldZ
- alors ObjA s'affiche devant ObjB
Sinon, égalité (peu importe)


// la génération de cubes dans 3 dimensions:
var tabCubes:Array = new Array();
var cube:Cube;
for ( var h:int=0 ; h<10 ; h++ )
{
        for ( var i:int=0 ; i<10 ; i++ )
        {
                for ( var j:int=0 ; j<10 ; j++ )
                {
                        cube = new Cube();
                        cube.isoZ = h*15;
                        cube.isoX = i*15;
                        cube.isoY = j*15;
                        tabCubes.push( cube );
                        this.addChild( cube );
                }
        }
}

// le mélange aléatoire
tabCubes.sort( rand );

for ( var p:int=0 ; p<tabCubes.length ; p++ )
{
        this.addChild( tabCubes[p] );
}

function rand( a:Object, b:Object ):int
{
        return (Math.random() > 0.5) ? 1 : -1;
}
// fin du mélange

var centreX:Number = 275;
var centreY:Number = 200;

// projection
for ( var k:int=0 ; k<tabCubes.length ; k++ )
{
        tabCubes[k].x = centreX + tabCubes[k].isoX - tabCubes[k].isoY;
        tabCubes[k].y = centreY + (tabCubes[k].isoX + tabCubes[k].isoY)/2 - tabCubes[k].isoZ;
}

////

// la ligne à activer pour allumer le tri, sans elle tout s'affiche n'importe comment:
//tabCubes.sort( triIso );

for ( var n:int=0 ; n<tabCubes.length ; n++ )
{
        this.addChild( tabCubes[n] );
}


function triIso( clip1:MovieClip, clip2:MovieClip ):int
{
        var resultat:int;
        if ( (clip1.isoX + clip1.isoY + clip1.isoZ) < (clip2.isoX + clip2.isoY + clip2.isoZ) )
                resultat = -1;
        else if ( (clip1.isoX + clip1.isoY + clip1.isoZ) > (clip2.isoX + clip2.isoY + clip2.isoZ) )
                resultat = 1;
        else
                resultat = 0;
        return resultat;
}

 

Fichier(s) joint(s)


Modifié par Logic, 14 June 2011 - 22:22 PM.


#5 milo210

    Ceinture Blanche

  • Members
  • Pip
  • 2 messages

Posté 16 June 2011 - 08:23 AM

Merci pour ces réponses ça va bien m'aider.

Le plus drôle dans l'histoire c'est qu'au départ j'étais partie sur la même idée d'additionner les trois axes pour comparer les résultats entre objets, mais en regardant les divers liens, je me suis dis que je devais me planter, que c'était trop simple.



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

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