Stilgardt Posté(e) 4 mars 2010 Share Posté(e) 4 mars 2010 Bonjour, Tout d'abord, j'ai trouvé un excellent exemple de code très simple pour tous ceux qui veulent s'amuser à afficher des sprites et les faire progresser à l'écran dans une direction donnée: http://www.anddev.org/basic_and_simple_ … t3085.html Ici, ce sont des petites boules qui se balladent et qui sont dessinées à l'aide de canvas.drawBitmap. Maintenant, j'aimerai pouvoir améliorer ce code et empêcher la collision entre ces boules pour les faire rebondir avant le choc :P En Java, il y a la méthode Intersects qui existent pour détecter dès qu'il y a une intersection entre deux objets et qui fait ça simplement (avec des rectangles par exemple). Par contre, sur Android, je ne trouve pas l'équivalent avec les canvas. Est-ce que quelqu'un aurait une idée? :) Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Pierre87 Posté(e) 4 mars 2010 Share Posté(e) 4 mars 2010 http://developer.android.com/intl/fr/reference/android/graphics/Rect.html#intersect%28android.graphics.Rect%29 de rien Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Stilgardt Posté(e) 4 mars 2010 Auteur Share Posté(e) 4 mars 2010 http://developer.android.com/intl/fr/reference/android/graphics/Rect.html#intersect%28android.graphics.Rect%29de rien Merci Pierre87! Seulement, comme j'utilise des Canvas et non des lignes ou des rectangles, je crains de devoir gérer deux objets à la fois (en superposant le rectangle au canvas...). Ou peut-être que je n'ai rien compris? :| Bon, je vais y réfléchir! Merci beaucoup en tout cas! :) Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Pierre87 Posté(e) 4 mars 2010 Share Posté(e) 4 mars 2010 je ne sait pas ce que tu utilisais en java "classique" mais pour un "objet" de ton jeu, c'est peut être plus propre de séparer collision et dessin un peu comme dans les jeux en 3D, où tu sépares le modele de la hitbox comme ça le modele peut etre très détaillé, alors que la hitbox est relativement simple bon dans ton cas c'est des canvas, mais ... :P Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Stilgardt Posté(e) 5 mars 2010 Auteur Share Posté(e) 5 mars 2010 je ne sait pas ce que tu utilisais en java "classique"mais pour un "objet" de ton jeu, c'est peut être plus propre de séparer collision et dessin un peu comme dans les jeux en 3D, où tu sépares le modele de la hitbox comme ça le modele peut etre très détaillé, alors que la hitbox est relativement simple bon dans ton cas c'est des canvas, mais ... :P Je jouais juste avec des lignes et des rectangles en java "classique" et là mes ambitions sont donc un peu plus élevées :) Mais ce que tu écris me parait plein de bon sens alors je vais me lancer comme ça :lol: Merci encore! Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
glhu Posté(e) 6 mars 2010 Share Posté(e) 6 mars 2010 Salut, si tu as des sprites, une solution pour detecter les collisions de maniere precise (c'est a dire que si tu as des spheres qui se deplacent, tu veux tester l'intersection de la sphere "geometrique" et non l'intersection du rectangle du bitmap) est de faire un test par pixel. L'idee est que si tu as des sprites avec un background transparent (ie l'alpha de la couleur du background est 0), il suffit alors de tester si pour une position donnee, les 2 pixels correspondant dans tes sprites ont une couleur avec un alpha !=0. Si c'est le cas, alors il y a collision, car il s'agit de deux pixels qui ne font pas partis du background des sprites. Ci-dessous un petit code qui sera plus clair que mon charabia ;-) : ou`: sprite1 et sprite2 sont tes 2 sprites a` tester, cdata1 est le resultat de sprite1.getBitmap().getPixels(...); cdata2 idem, private Rect checkCollision(BitmapDrawable sprite1, BitmapDrawable sprite2) { Rect rect1 = sprite1.getBounds(); Rect rect2 = sprite2.getBounds(); Rect inters = new Rect(rect1); if (inters.intersect(rect2)) { for (int y = inters.top; y < inters.bottom; ++y) { for (int x = inters.left; x < inters.right; ++x) { int c1 = cdata1[(x - rect1.left) + (y - rect1.top) * rect1.width()]; int c2 = cdata2[(x - rect2.left) + (y - rect2.top) * rect2.width()]; int a1 = (int) (c1 >> 24); int a2 = (int) (c2 >> 24); if (a1 != 0 && a2 != 0) return inters; } } } return null; } On regarde d'abord l'intersection des deux bitmaps. Si il y a une intersection, alors on verifie pour chaque pixel de l'intersection la couleur des pixels correspondant pour les 2 sprites. Si les 2 couleurs ont une alpha != 0 (c'est a dire que ce ne sont pas des couleurs transparentes, donc que ce ne sont pas des couleurs du background), alors il y a collision. Si ce n'est pas clair, je joindrai un petit exemple. Patrick Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Pierre87 Posté(e) 6 mars 2010 Share Posté(e) 6 mars 2010 t'as pas plus compliqué ? c'est une detection de collision de SPHERE/CERCLE ! Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
glhu Posté(e) 6 mars 2010 Share Posté(e) 6 mars 2010 Et bien..... parfois on veut afficher d'autres trucss que des sphères. Si si, vraiment... Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Pierre87 Posté(e) 6 mars 2010 Share Posté(e) 6 mars 2010 là en l'occurrence, c'est des collisions entre "disques" Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
glhu Posté(e) 6 mars 2010 Share Posté(e) 6 mars 2010 (modifié) et bien la` en l'occurence il s'agit de collisions de sprites, et une question en amenant une autre, il aura ainsi une methode pour le jour ou` les spheres seront remplacees par des sprites plus compliques. La curiosite' n'est pas un vilain defaut ;-) Patrick Modifié 6 mars 2010 par glhu Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Stilgardt Posté(e) 7 mars 2010 Auteur Share Posté(e) 7 mars 2010 et bien la` en l'occurence il s'agit de collisions de sprites, et une question en amenant une autre, il aura ainsi une methode pour le jour ou` les spheres seront remplacees par des sprites plus compliques. La curiosite' n'est pas un vilain defaut ;-)Patrick Salut Patrick! Merci pour ton intervention. :P Ca tombe plutôt bien car en effet, en gérant avec des rectangles mes collisions, je n'ai parfois pas un super résultat: quand les deux boules rentrent en collision en diagonale, on voit bien que je teste mes collisions sur des rectangles car elles ne se touchent même pas avant de se repousser! Je vais donc tenter ta méthode. :) C'est vrai que ça devient tout de suite plus compliqué par contre. Si je comprends bien, tu testes ligne par ligne la collision entre chaque pixel de sprite1 et sprite2. Mais si c'est ça, je ne pige pas la suite car j'ai l'impression que dans c1 et c2, tu considères des zônes bien plus grandes... Qu'est supposé contenir le tableau cdata1 (et cdata2) ? La réponse à cette question m'éclairera sur le shift de 24 bits aussi j'imagine!). :lol: Merci bien en tout cas! Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Pierre87 Posté(e) 7 mars 2010 Share Posté(e) 7 mars 2010 @Stilgardt : si tu veux toujours faire des collisions entre boules, il y a beaucoup plus simple ! Il suffit de calculer la distance entre les 2 boules ! distance entre les 2 centres - somme des rayons Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
glhu Posté(e) 7 mars 2010 Share Posté(e) 7 mars 2010 (modifié) Salut Stilgardt, Si je comprends bien, tu testes ligne par ligne la collision entre chaque pixel de sprite1 et sprite2. Mais si c'est ça, je ne pige pas la suite car j'ai l'impression que dans c1 et c2, tu considères des zônes bien plus grandes... Qu'est supposé contenir le tableau cdata1 (et cdata2) ? La réponse à cette question m'éclairera sur le shift de 24 bits aussi j'imagine!). :lol: Je ne teste pas chaque pixel de sprite1 et sprite2 (cela serait inutilement couteux), mais seulement l'intersection des deux sprites (regarde la doc de rect.intersect, cette methode modifie 'rect' avec le rectangle d'intersection). Donc, pour chaque point de cette intersection, je regarde dans chaque bitmap la valeur du pixel correspondant. Pour cela, j'utilise l'api Bitmap.getPixels, qui stocke dans un tableau (ici cdata1) les valeurs de la couleur de chaque pixel du bitmap. Et comme la position (x,y) que je teste lorsque j'itere sur les points de mon intersection est exprimee dans le systeme de coordonnees de l'ecran, je fais juste un changement de coordonnees pour me remettre dans le systeme du sprite (d'ou le x-spritePos.x, etc.). Enfin, ayant les deux couleurs pour une position donnee, je regarde leur channel alpha. Comme la represention 'int' d'une couleur est exprimee en AARRGGBB, je decale de 24 bits. Tu peux tout aussi bien utilise Color.alpha(int color). qui fait la meme chose et qui a le merite de ne pas compliquer ton code pour rien :) Je remets ci-dessous une version plus propre du code de la View. Dans cette exemple, les deux sprites cessent de se deplacer des qu'une intersection est detectee. Et une image qui montre le resultat avec un bitmap autre qu'une sphere.... http://yfrog.com/5ecollisionbp J'espere que c'est plus clair. A toi de jouer ;) Patrick import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.view.View; public class BounceView extends View { protected GameEntity sprite1; protected GameEntity sprite2; private boolean nomove = false; protected enum HorizontalDirection { LEFT, RIGHT } protected enum VerticalDirection { UP, DOWN } public class GameEntity { private HorizontalDirection myXDirection = HorizontalDirection.RIGHT;; private VerticalDirection myYDirection = VerticalDirection.UP;; // The sprite public BitmapDrawable sprite; // The sprite position private Point spritePos; // The bitmap pixels value (ie colors) private int[] colors; private int bmpW; private int bmpH; public GameEntity(BitmapDrawable sprite, Point initPos){ this.sprite = sprite; this.spritePos = initPos; Bitmap bmp = sprite.getBitmap(); bmpW = bmp.getWidth(); bmpH = bmp.getHeight(); colors = new int[bmpW*bmpH]; bmp.getPixels(colors, 0, bmpW, 0, 0, bmpW, bmpH); sprite.setBounds(spritePos.x, spritePos.y, spritePos.x + bmpW, spritePos.y + bmpH); } public void update() { if (spritePos.x >= BounceView.this.getWidth() - bmpW) { myXDirection = HorizontalDirection.LEFT; } else if (spritePos.x <= 0) { myXDirection = HorizontalDirection.RIGHT; } if (spritePos.y >= BounceView.this.getHeight()- bmpH) { myYDirection = VerticalDirection.UP; } else if (spritePos.y <= 0) { myYDirection = VerticalDirection.DOWN; } if (myYDirection == VerticalDirection.DOWN) { spritePos.y += 2; } else { spritePos.y -= 2;// mHeading; } if (myXDirection == HorizontalDirection.RIGHT) { spritePos.x += 2; } else { spritePos.x -= 2; } sprite.setBounds(spritePos.x, spritePos.y, spritePos.x + bmpW, spritePos.y + bmpH); } public void draw(Canvas canvas){ sprite.draw(canvas); } public int getPixelAlpha(int x, int y){ return Color.alpha(colors[(x - spritePos.x) + (y - spritePos.y)* bmpW]); } } public BounceView(Context context) { super(context); // Set the background this.setBackgroundDrawable(this.getResources().getDrawable( R.drawable.icon)); sprite1 = new GameEntity((BitmapDrawable) this.getResources().getDrawable( R.drawable.ball2), new Point()); sprite2 = new GameEntity((BitmapDrawable) this.getResources().getDrawable( R.drawable.arrow), new Point(320,-20)); } @Override protected void onDraw(Canvas canvas) { /* * Set the location, where the sprite will draw itself to the canvas */ if (!nomove) { sprite1.update(); sprite2.update(); Rect r = checkCollision(sprite1, sprite2); if (r != null) { this.nomove = true; } } /* Make the sprite draw itself to the canvas */ sprite1.draw(canvas); sprite2.draw(canvas); } private static Rect checkCollision(GameEntity sprite1, GameEntity sprite2) { Rect rect1 = sprite1.sprite.copyBounds(); Rect rect2 = sprite2.sprite.getBounds(); if (rect1.intersect(rect2)) { for (int y = rect1.top; y < rect1.bottom; ++y) { for (int x = rect1.left; x < rect1.right; ++x) { int a1 = sprite1.getPixelAlpha(x,y); int a2 = sprite2.getPixelAlpha(x,y); if (a1 != 0 && a2 != 0) return rect1; } } } return null; } } Modifié 7 mars 2010 par glhu Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Stilgardt Posté(e) 7 mars 2010 Auteur Share Posté(e) 7 mars 2010 Chouette! Merci :-) Sans tes explications, j'aurai passé beaucoup de temps à chercher (on dit que ça forme le caractère mais parfois, c'est bien d'aller plus vite! ;-)) Je pense avoir compris tout ton code cette fois :) et je vais pouvoir m'amuser à gérer des collisions. Par contre, j'ai dû ajouter: // refresh the canvas invalidate(); à la fin de la méthode OnDraw sinon les sprites restaient immobiles. Merci encore Patrick et à charge de revanche! ;-) Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Profete162 Posté(e) 7 mars 2010 Share Posté(e) 7 mars 2010 Génial le code, je vais vite essayer celà! Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
glhu Posté(e) 7 mars 2010 Share Posté(e) 7 mars 2010 Par contre, j'ai dû ajouter: // refresh the canvas invalidate(); à la fin de la méthode OnDraw sinon les sprites restaient immobiles. Ah, bizarre. De mon cote', j'utilisais cette vue dans l'exemple de Profete162 (modifie' pour ne pas utiliser l'accelerometre). Bon, l'essentiel est que tu ais reussi a` l'adapter pour tes besoins. Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
glhu Posté(e) 7 mars 2010 Share Posté(e) 7 mars 2010 Une derniere remarque: je pense qu'il faudrait que tu invalides juste la zone de tes sprites et non tout l'ecran (avec invalidate(rect), ou` rect est l'union des bounds des sprites) Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Profete162 Posté(e) 7 mars 2010 Share Posté(e) 7 mars 2010 Oui, je l'ai essayé via l'exemple que j'avais donné ( 2 lignes à effacer dans mon exemple ) et ca fonctionne direct, comme le dit glhu Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Stilgardt Posté(e) 7 mars 2010 Auteur Share Posté(e) 7 mars 2010 Une derniere remarque: je pense qu'il faudrait que tu invalides juste la zone de tes sprites et non tout l'ecran (avec invalidate(rect), ou` rect est l'union des bounds des sprites) Ok, je vais modifier ça ce soir pour voir si je constate une différence. Il ne reste plus qu'à trouver une réaction cohérente aux sprites lors de leur collision et ce sera parfait! Je joue en ce moment à Crysis sur PC et leur gestion de la physique des objets et de l'environnement me fait bien rêver... :cool: Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Recommended Posts
Rejoignez la conversation
Vous pouvez poster maintenant et vous enregistrez plus tard. Si vous avez un compte, connectez-vous maintenant pour poster.