Détection Pixel Perfect Collision entre une vue personnalisée et une ImageView

J’ai un CustomView et une vue d’image. Le CustomView est une balle qui bouge sur l’écran et rebondit sur les murs. L’image est un quart de cercle que vous pouvez faire pivoter dans un cercle au toucher. J’essaie de créer mon jeu de manière à ce qu’une collision soit détectée lorsque les pixels remplis de CustomView se croisent avec les pixels remplis de ImageView. Le problème que je rencontre est que je ne sais pas comment récupérer l’emplacement des pixels remplis dans chaque vue.

Voici mon code XML

  

Mon activité principale

 public class MainActivity extends AppCompatActivity { private static Bitmap imageOriginal, imageScaled; private static Masortingx masortingx; private ImageView dialer; private int dialerHeight, dialerWidth; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // load the image only once if (imageOriginal == null) { imageOriginal = BitmapFactory.decodeResource(getResources(), R.drawable.quartercircle); } // initialize the masortingx only once if (masortingx == null) { masortingx = new Masortingx(); } else { // not needed, you can also post the masortingx immediately to restore the old state masortingx.reset(); } dialer = (ImageView) findViewById(R.id.quartCircle); dialer.setOnTouchListener(new MyOnTouchListener()); dialer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // method called more than once, but the values only need to be initialized one time if (dialerHeight == 0 || dialerWidth == 0) { dialerHeight = dialer.getHeight(); dialerWidth = dialer.getWidth(); // resize Masortingx resize = new Masortingx(); resize.postScale((float) Math.min(dialerWidth, dialerHeight) / (float) imageOriginal.getWidth(), (float) Math.min(dialerWidth, dialerHeight) / (float) imageOriginal.getHeight()); imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false); // translate to the image view's center float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2; float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2; masortingx.postTranslate(translateX, translateY); dialer.setImageBitmap(imageScaled); dialer.setImageMasortingx(masortingx); } } }); } 

Classe MyOnTouchListener:

 private class MyOnTouchListener implements View.OnTouchListener { private double startAngle; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startAngle = getAngle(event.getX(), event.getY()); break; case MotionEvent.ACTION_MOVE: double currentAngle = getAngle(event.getX(), event.getY()); rotateDialer((float) (startAngle - currentAngle)); startAngle = currentAngle; break; case MotionEvent.ACTION_UP: break; } return true; } } private double getAngle(double xTouch, double yTouch) { double x = xTouch - (dialerWidth / 2d); double y = dialerHeight - yTouch - (dialerHeight / 2d); switch (getQuadrant(x, y)) { case 1: return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; case 2: return 180 - Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; case 3: return 180 + (-1 * Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI); case 4: return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; default: return 0; } } /** * @return The selected quadrant. */ private static int getQuadrant(double x, double y) { if (x >= 0) { return y >= 0 ? 1 : 4; } else { return y >= 0 ? 2 : 3; } } /** * Rotate the dialer. * * @param degrees The degrees, the dialer should get rotated. */ private void rotateDialer(float degrees) { masortingx.postRotate(degrees, dialerWidth / 2, dialerHeight / 2); dialer.setImageMasortingx(masortingx); } 

Et mon AnimatedView

 public class AnimatedView extends ImageView { private Context mContext; int x = -1; int y = -1; private int xVelocity = 10; private int yVelocity = 5; private Handler h; private final int FRAME_RATE = 60; public AnimatedView(Context context, AtsortingbuteSet attrs) { super(context, attrs); mContext = context; h = new Handler(); } private Runnable r = new Runnable() { @Override public void run() { invalidate(); } }; protected void onDraw(Canvas c) { BitmapDrawable ball = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.smallerball); if (x<0 && y  this.getWidth() - ball.getBitmap().getWidth()) || (x  this.getHeight() - ball.getBitmap().getHeight()) || (y < 0)) { yVelocity = yVelocity*-1; } } c.drawBitmap(ball.getBitmap(), x, y, null); h.postDelayed(r, FRAME_RATE); } public float getX() { return x; } public float getY() { return y; } } 

Ma question est la suivante: comment puis-je récupérer les pixels remplis de ces deux vues et les transmettre à travers une fonction qui détecte une collision?

Merci d’avance pour l’aide!:)

Vous devez vraiment définir “pixels remplis”. Je suppose que vous parlez des pixels non transparents. Le moyen le plus simple de les trouver consiste à convertir l’ensemble de votre vue en image bitmap et à effectuer une itération à travers ses pixels. Vous pouvez convertir une View en Bitmap comme ceci:

 private Bitmap getBitmapFromView(View view) { view.buildDrawingCache(); Bitmap returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(returnedBitmap); canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN); Drawable drawable = view.background; drawable.draw(canvas); view.draw(canvas); return returnedBitmap; } 

Vous devez également obtenir l’emplacement absolu des vues:

 Point getViewLocationOnScreen(View v) { int[] coor = new int[]{0, 0}; v.getLocationOnScreen(coor); return new Point(coor[0], coor[1]); } 

Ensuite, il vous suffit de parcourir les pixels de chaque Bitmap , de vérifier leurs couleurs pour savoir si elles sont “remplies”, et de vérifier si elles se chevauchent en fonction de leur coordination dans les bitmaps et de l’emplacement absolu des vues à l’écran. .

Itérer à travers un bitmap se fait comme ceci:

 for (int x = 0; x < myBitmap.getWidth(); x++) { for (int y = 0; y < myBitmap.getHeight(); y++) { int color = myBitmap.getPixel(x, y); } } 

Mais je dois dire que je ne pense pas que l'exécution de ce type de calculs lourds sur le fil de l'interface utilisateur soit vraiment une bonne idée. Il existe des dizaines de façons bien meilleures de détecter les collisions que la vérification au pixel près. Cela va probablement sortir extrêmement lageux.

Vous pouvez encapsuler vos images avec un tableau de points marquant vos coordonnées de bordure (et les mettre à jour lors du déplacement / les calculer en fonction de l’origine), puis vous pourrez décider si un object opposé est en contact ou non même point)