Nov 04 2010

La détection de collision

Tag: android,flash,Jeux indépendants,jeux vidéo,openglTurbo Connard @ 19:58

A mes débuts de “flasher” j’avais était super impressionné par “N” : un vrai jeu avec un moteur de collisions + physique poussé. Ce jeu fonctionne vraiment bien et on ne tombe jamais sur aucun glitch de collision très courant à l’époque des jeux flashs : Passage au travers d’un mur, décalage plus qu’approximatif dans le calcul de la trajectoire etc. Je me suis replongé dans la détection de collision l’autre jour et j’ai tout de suite pensé à ce jeu comme base de réflexion.

Je sais qu’il existe des moteurs très puissant de physique tel que box 2D (largement exploité en minigame iphone, android flash…) mais malheureusement je trouve que trop de physique peut nuire grandement au gameplay et j’ai pas envie de m’embêter avec des poids, vélocité etc… pour un jeu de plateforme. Sur le plutôt bon Angrybirds la physique m’énerve un peu trop des fois.

Dans “new super mario bros wii” par exemple, il y a une super bonne détection de collisions qui est loin d’être réaliste (heureusement) et pourtant on s’en passe et le jeu arrache tout. Mario est soumis à la gravité, il peut marcher sur des plateformes rondes (qui tournent), en pentes, qui bougent, des rectangulaires qui tournent etc… C’est ce compromis que je recherche et aujourd’hui, à ma connaissance, il n’y a pas de moteur de collisions / faussement physique.

Exemple de belles plateformes rectangulaires qui tournent dans le niveau 9-1 :

En cherchant un peu je suis tombé sur les tutoriels de N : http://www.metanetsoftware.com/technique/tutorialA.html
Ils expliquent assez bien et sont très utiles pour comprendre les concepts de collisions entre différents objets. Et bien sûr la fameuse technique de l’axe séparateur qui semble faire l’unanimité chez les développeurs.

Récap :

  • on peut dire que deux objets ne se touchent pas tant qu’on peut tirer un trait entre les deux.
  • un de ces traits est forcément parallèle à un coté d’un des objets.

Partant de là, il est assez facile par “projection” de trouver (ou pas) les collisions. Encore faut il comprendre la projection, sur quoi projeter et pourquoi.

En informatique 2D on teste souvent la collision entre “hitbox” (une boîte rectangulaire qui entoure la totalité ou une partie seulement d’un sprite.) Ça facilite grandement les calculs, on gagne en performance mais des fois c’est pas suffisant. On verra néanmoins que ce calcul rapide est à effectué dans certains cas. Le principe est simple : si les distances respectives en x et y entre les centres des deux objets sont inférieures à la moitié de la somme de leurs longueurs et hauteurs, il y a collision.

La soustraction de ces distances et des sommes des longueurs et hauteurs donnent des valeurs de superpositions des objets : des vecteurs de pénétration.

Ça marche très bien, mais seulement pour les AABB : Axis Aligned Bounding Box. Comprendre “Boites rectangulaires sans rotation”

Ce principe de détection de collisions marche super bien dans beaucoup de cas (Shmup, jeux de plateforme etc…) mais il est limite quand on veut pousser l’expérience de l’utilisateur un peu plus loin. (voir exemple de mario ci dessus)

Si on commence à faire tourner les boites ca devient compliqué car la petite astuce précédente ne marche plus :

Pourtant, on voit bien que l’on peut tracer ce fameux trait entre les deux boites ! et on voit bien qu’il devrait être parallèle au côté de la boite rouge comme précédemment énoncé.

Avec la précédente technique ça ne marche pas car on ne vérifie que le recouvrement sur les axes x et y. Sauf qu’ici, ce n’est pas sur ces axes qu’il faut chercher mais bien sur tous les axes décrits par les arêtes des boites. Pour “voir” que les boîtes ne se touchent pas, il faut se positionner au niveau de la boite rouge et de regarder le long de son côté à droite sur le dessin.

en supprimant les doublons on trouve 4 axes…

Pour le cas des AABB il n’y avait que 2 axes, ici on en a 4 mais le principe reste le même. Il faut calculer les superpositions des deux boites sur les 4 axes. Je ne vais pas vous expliquer comment faire parce que pour le coup, les tutoriels de N expliquent très bien les vecteurs et tout le bordel mais le principe est pas forcément simple à comprendre.

En écartant les axes ca devient un peu plus lisible (c’est pas nécessaire pour le code, en général on teste les axes en 0,0).

Première projection, je trouve une collision.

Deuxième projection, pas de collision…

En faisant les mêmes calculs sur tous les axes séparateurs, on obtient donc les collisions ou pas. En prenant le vecteur de pénétration le plus court de toutes les collisions des projections on trouve la position “idéale” où l’objet devrait être.

Dans ce test, on ne parle pas de physique, de rebonds ou de gravité… C’est un autre sujet, cependant un petit test flash donne déjà des résultats surprenants :

Dans cet exemple, on peut déplacer les formes à la souris et le rectangle gris à l’aide des touches. Le moteur physique se résume à “vitY += 1; ” autrement dit seulement une gravité basique. C’est pour ça que les plateformes ne transmettent pas leur vitesse de rotation au sprite rectangulaire. Mais ce n’est pas ce que l’on teste ici.


Oct 06 2010

Graffiti Analysis Flash Test 2

Tag: flash,gmlTurbo Connard @ 21:20

Ok, j’avais laissé en plan le “graffiti analysis test” mais il fallait quand même que je règle ce problème de vecteur “UP”. J’ai donc trouvé la formule magique pour orienter les graffitis dans le “bon” sens.

En gros les applications qui enregistrent les tags doivent préciser un vecteur “UP” qui détermine l’orientation du graffiti. Certaines applications (ex : Coding With Attitude GML Drawer : MFF2010  ) ne le font pas donc on prendra l’axe Y par défaut, c’est l’orientation qui est la plus “normale”.

Mais d’autres applications (presque toutes d’ailleurs puisqu’il s’agit de portages) ont par défaut un vecteur “UP” sur l’axe des x  : (1,0,0);

Si on opère pas de transformation, certains graffitis vont s’écrire de haut en bas et non pas de gauche à droite. La première solution est de choisir arbitrairement : “bon ben si c’est Y, on touche à rien et si c’est X ben on fait une rotation de -90° et c’est marre…” Mais on vaut quand même mieux que ça !

Donc la technique c’est de trouver l’axe et l’angle de rotation puis d’appliquer la transformation.
Le code est dans le “onload” du xml.

package {
        import flash.display.DisplayObject;
        import flash.display.MovieClip;
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Matrix3D;
        import flash.geom.Rectangle;
        import flash.geom.Vector3D;
        import flash.net.URLLoader;
        import flash.net.URLRequest;
        /**
         * @author Turboconnard
         */

        public class Test3D extends MovieClip {
                private var yaxis : Sprite;
                private var zaxis : Sprite;
                private var xaxis : DisplayObject;
                private var axe : Sprite;
                private var container : Sprite;
                private var graf : Sprite;
       
                public function Test3D() {
                        //waiting for stage to be instanciate
                        addEventListener(Event.ADDED_TO_STAGE, _add);
                }       
                private function _add(event : Event) : void {
                        /* remember 3D objects may have a z if you want transform thme */
                       
                       
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
                        stage.addEventListener(Event.RESIZE,resize);
               
                        //creating global container
                        container = new Sprite();
                        container.z = 0;
                        graf = new Sprite();           
                        graf.z = 0;
                        addChild(container);
                        container.addChild(graf);       
                       
                        //building 3D axis viewer
                        xaxis = getLine(0x0000ff);
                        yaxis = getLine(0x00ff00);
                        zaxis = getLine(0xff0000);
                       
                        xaxis.z = 0;
                        yaxis.z = 0;
                        zaxis.z = 0;
                        yaxis.transform.matrix3D.appendRotation(90, Vector3D.Z_AXIS);
                        zaxis.transform.matrix3D.appendRotation(90, Vector3D.Y_AXIS);

                        axe = new Sprite();
                        axe.z = 0;
                        axe.addChild(xaxis);
                        axe.addChild(yaxis);
                        axe.addChild(zaxis);
                        addChild(axe);
                        //load a graffiti
                        load(null);
                        //resize
                        resize(null);
                }
                /**
                 * load a random graffiti
                 */

                public function load(e:MouseEvent) : void {
                        stage.removeEventListener(MouseEvent.CLICK,load);
                        alpha = 0.2;
                        var urlLoader : URLLoader = new URLLoader();
                        urlLoader.addEventListener(Event.COMPLETE, _onLoad);                   
                        urlLoader.load(new URLRequest("http://000000book.com/data/" +"random"+ ".gml"));
                }
                /**
                 *
                 */

                private function _onLoad(event : Event) : void {
                        stage.addEventListener(MouseEvent.CLICK,load);
                        alpha = 1;
                        var gml:XML = XML(URLLoader(event.target).data);
                        var env:XMLList = gml.tag.environment;
                       
                        //Some graffitis aren’t drawn with Y as up axis.
                        //we have to rotate our world to mach our Y up axis.
                        //my up vector in flash                
                        var up:Vector3D =  new Vector3D(0,1,0);
                        //graffiti’s up vector
                        var modelup:Vector3D;
                        if(int(env.up.x) + int(env.up.y) + int(env.up.z) == 0 ) modelup = new Vector3D(0,1,0);
                        else modelup = new Vector3D(env.up.x, env.up.y, env.up.z);
                        //looking for axis to rotate
                        var rotationaxis:Vector3D = up.crossProduct(modelup);
                        //looking for rotation angle
                        var angle:Number = Math.acos( up.dotProduct(modelup) );
                        //rotate objects
                       
                        axe.transform.matrix3D = new Matrix3D();
                        graf.transform.matrix3D = new Matrix3D();
                        axe.transform.matrix3D.appendRotation(angle/Math.PI*180, rotationaxis);
                        graf.transform.matrix3D.appendRotation(angle/Math.PI*180, rotationaxis);
               
                        //draw graffiti
                        graf.graphics.clear();
                        graf.graphics.lineStyle(8,0);
                        for(var i:int=0;i<XMLList(gml.tag.drawing.stroke).length();i++){
                                var pts:XMLList = XMLList(gml.tag.drawing.stroke)[i].pt;
                                for(var k:int=0;k<pts.length();k++){   
                                        if(k==0) graf.graphics.moveTo(pts[k].x*env.screenBounds.x,pts[k].y*env.screenBounds.y);
                                        else graf.graphics.lineTo(pts[k].x*env.screenBounds.x,pts[k].y*env.screenBounds.y);
                                }                              
                        }
                       
                        resize(null);
                }
                /**
                 * resize
                 * @param e Event
                 */

                private function resize(e:Event) : void {
                        axe.x = stage.stageWidth/2;
                        axe.y = stage.stageHeight/2;
                       
                        //moving objects to center
                        var box:Rectangle = container.getRect(container);
                        container.x = – box.x + stage.stageWidth/2 – box.width/2;
                        container.y = – box.y + stage.stageHeight/2 – box.height/2;
                }

                /**
                 * draw an arrow
                 * @param pColor arraow color
                 */

                public  function getLine(pColor : uint) : Sprite {
                        var s : Sprite = new Sprite();
                        s.graphics.lineStyle(1, pColor,1,false,"none");
                        s.graphics.lineTo(20, 0);
                        s.graphics.lineTo(15, -2);
                        s.graphics.moveTo(20, 0);
                        s.graphics.lineTo(15, 2);                      
                        return s;
                }
        }
}
 


Jun 27 2010

Turboconnard Android Game Developpement

Tag: android,Eclipse,Jeux indépendantsTurbo Connard @ 16:52

Bon, c’est un peu pompeux comme nom mais c’est la seule chose qui me soit venue…

J’ai donc commencé un petit framework pour développer des jeux sur android. Flash ressemble énormément au java dans sa syntaxe mais les logiques de développement sont un peu différentes. J’avoue avoir des automatismes de flasheurs et n’arrive pas trop à concevoir des applications différemment qu’en pensant “Flash”. Le concept d’imbrication de clips, sprites est quand même pas mal. J’ai donc recréé ce système d’imbrication pour ne pas m’emmerder à recalculer à chaque fois les translations et rotations de canvas avant les “draw”. J’ai aussi complètement pompé le système événementiel qui me plait bien… Bref, pour l’instant ça me convient pas mal et je vais surement ajouter des choses à ce framework au fur et à mesure de mes avancées dans le monde magique d’android.

C’est par ici : http://code.google.com/p/turboconnard-agd/

mini proto :


Oct 07 2009

Adobe sur Iphone : encore un effet d’annonce ?

Tag: UncategorizedTurbo Connard @ 09:43

Youpi, super on va tous devenir millionnaire en développant des applications flash pour Iphone !

Adobe a encore fait “fort” en publiant des news, technotes etc… sur cette nouveauté. On s’imagine déjà en train de jouer à nos meilleurs jeux flash sur Iphone, développer des sites contrôlables avec le gyroscope, apporter quelque chose de nouveau dans la façon de naviguer et hop ! première déception : “non mais en fait c’est pas le player flash hein, c’est des applications développés en flash…”.

Ok, donc en gros au lieu de jouer à bejewel développé en Objective C, on y jouera sur une application développée en actionscript 3. Youpi :|

Je ne suis pas possesseur d’Iphone mais il me semble qu’il y a déjà pléthore de trucs de merde sur l’I-store. Pour l’instant très peu d’applications m’ont bluffées. Alors oui, vous allez me dire :”Non mais t’as pas d’iphone donc tu peux pas savoir et en plus de ça t’es pro pc/linux blah blah…”.
Mais comme j’ai une vie sociale (et oui) environ 97% des mes amis, collègues, entourage passent la journée à me montrer la dernière trouvaille achetée / téléchargée sur l’i-store ou à me prouver via allociné / imdb que l’acteur qu’on cherche au cour d’un diner n’est autre que “Chevy Chase”.

Pour naviguer sur internet, l’iphone est très bon. Pour l’applicatif, j’ai vu deux trois trucs sympas qui apportent plus qu’un “t’as vu ton téléphone à toi il sait pas faire”, mais pour le jeu honnêtement c’est naze.

Cette petite parenthèse sur l’iphone fermée, je vais vous faire part de mon scepticisme concernant l’effet d’annonce d’adobe. Chaque année ils nous font la même et le résultat est toujours le même : déceptions.

Souvenez vous :

L’annonce : L’accélération graphique du flash player, super on va ENFIN avoir un player qui rame pas quand on fait une rotation d’un jpg !
La déception : à mince, c’est juste sur un rectangle quand on passe en fullscreen.

L’annonce : animez de façon mortelle graçe au puppet tool !
La déception : à mince, ça marche que sur les formes qu’ont moins de 9 vecteurs…

L’annonce : L’actionScript 2 ! une révolution !
La déception : Ah merde, en fait c’est de l’as1 compilé.

L’annonce : Flash sur téléphone graçe à flash lite
La déception : “ha merde toutes les fonctionnalités cool de flash ont été enlevées..” quelqu’un a un souvenir d’une application flash lite ?

L’annonce : Les filtres !
La déception : cool, je mets un blur je perds 15 fps

L’annonce : Un vrai debugger!
La déception : Un quoi ?

J’en ai environ douze milliards des comme ça donc vous comprendrez mieux mon scepticisme concernant cette annonce. Et vous vous en avez des bonnes en réserve ?