Java-Détection des collisions via une collision stockée dans un tableau


Je travaille actuellement sur collision pour mon jeu 2D. J'ai fait quelques recherches et déduit que je devrais utiliser la méthode de stockage des pixels de valeur alpha dans un "masque" de l'image de l'entité, et la même chose pour l'autre. Ensuite, je prends les co-ords x & y des deux entités, ainsi que la hauteur et la largeur, et crée un objet rectangle et utilise la méthode Rectangle.intersects(Rectangle r) pour vérifier s'ils entrent en collision dans l'ordre pour le rendre plus efficace au lieu de passer par 2 for boucles.

S'ils se croisent, je fais alors un nouveau Tableau avec les dimensions :

 int maxLengthY = Math.max(thisEntity.getMask().length, e.getMask().length);
 int maxLengthX = Math.max(thisEntity.getMask()[0].length, thisEntity.getMask()[0].length);

 int minX = Math.min(thisEntity.getX(), e.getX());
 int minY = Math.min(thisEntity.getY(), e.getY());

 int[][] map = new int[maxLengthX + minX][maxLengthY + minY];

Puis ajoutez les deux autres masques sur celui-ci avec leurs "limites" y & x correspondantes, comme ceci:

for(int curX = 0; curX < maxLengthX + minX; curX++) { //only loop through the co-ords that area affected                                                              
for(int curY = 0; curY < maxLengthY + minY; curY++) {                                                                                                             

    int this_x = thisEntity.getX();                                                                                                                               
    int this_width = thisEntity.getImage().getWidth();                                                                                                            
    int this_y = thisEntity.getY();                                                                                                                               
    int this_height = thisEntity.getImage().getHeight();                                                                                                          
    int[][] this_mask = thisEntity.getMask();                                                                                                                     
    if(curX < (this_x + this_width) && curX < this_x) {//check that the co-ords used are relevant for thisEntity's mask                                           

        if(curY < (this_y + this_height) && curY < this_y) {                                                                                                      
            map[curX][curY] = this_mask[Math.abs(curX - this_x)][Math.abs(curY - this_y)]; // store data from mask to map                                         
        }                                                                                                                                                         
    }                                                                                                                                                             

    int other_x = e.getX();                                                                                        
    int other_width = e.getImage().getWidth();                                                                     
    int other_y = e.getY();                                                                                        
    int other_height = e.getImage().getHeight();                                                                   
    int[][] other_mask = e.getMask();                                                                              

    if(curX < (other_x + other_width) && curX > other_x) { //check that the co-ords used are relevant for e's mask 
        if(curY < (other_y + other_height) && curY > other_y) {                                                    
            if(map[curX][curY] == 1) { //check if this segment is already written by thisEntity                    
                map[curX][curY] = 2;   //if yes, set to 2 instead of e's value to show collision                   
            } else {                                                                                               
                map[curX][curY] = other_mask[curX][curY]; // the minus to nullify minX and minY "requirements"     
            }                                                                                                      
        }                                                                                                          
    }                                                                                                              
}                                                                                                                  
}            

Résultant en la Array "carte"ressemblant à CECI:

img (excusez mes compétences en peinture 1337)

C'est le code dans toute sa beauté:

public Entity[] collisions(Entity thisEntity) {                                                                                                              
ArrayList<Entity> list = new ArrayList<Entity>();                                                                                                        
try {                                                                                                                                                    
    for (Entity e : getLevel().getEntities()) {                                                                                                          

        System.out.println("rect contains = "+thisEntity.getRect().contains(e.getRect()));                                                               

        if (!thisEntity.equals(e)) {                                                                                                                     
            Rectangle r = e.getRect();                                                                                                                   
            r = thisEntity.getRect();                                                                                                                    

            if (thisEntity.getRect().intersects(e.getRect())) {                                                                                          

                //get variables to create a space designated for the intersection areas involved                                                         
                int maxLengthY = Math.max(thisEntity.getMask().length, e.getMask().length);                                                              
                int maxLengthX = Math.max(thisEntity.getMask()[0].length, thisEntity.getMask()[0].length);                                               

                int minX = Math.min(thisEntity.getX(), e.getX());                                                                                        
                int minY = Math.min(thisEntity.getY(), e.getY());                                                                                        

                int[][] map = new int[maxLengthX + minX][maxLengthY + minY]; //create a matrix which merges both Entity's mask's to compare                                                                                                                                                                                                                                                                                                                                       

                for(int curX = 0; curX < maxLengthX + minX; curX++) { //only loop through the co-ords that area affected                                 
                    for(int curY = 0; curY < maxLengthY + minY; curY++) {                                                                                

                        int this_x = thisEntity.getX();                                                                                                  
                        int this_width = thisEntity.getImage().getWidth();                                                                               
                        int this_y = thisEntity.getY();                                                                                                  
                        int this_height = thisEntity.getImage().getHeight();                                                                             
                        int[][] this_mask = thisEntity.getMask();                                                                                        
                        if(curX < (this_x + this_width) && curX > this_x) {//check that the co-ords used are relevant for thisEntity's mask              

                            if(curY < (this_y + this_height) && curY > this_y) {                                                                         
                                map[curX][curY] = this_mask[Math.abs(curX - this_x)][Math.abs(curY - this_y)]; // store data from mask to map            
                            }                                                                                                                            
                        }                                                                                                                                

                        int other_x = e.getX();                                                                                                          
                        int other_width = e.getImage().getWidth();                                                                                       
                        int other_y = e.getY();                                                                                                          
                        int other_height = e.getImage().getHeight();                                                                                     
                        int[][] other_mask = e.getMask();                                                                                                

                        if(curX < (other_x + other_width) && curX > other_x) { //check that the co-ords used are relevant for e's mask                   
                            if(curY < (other_y + other_height) && curY > other_y) {                                                                      
                                if(map[curX][curY] == 1) { //check if this segment is already written by thisEntity                                      
                                    map[curX][curY] = 2;   //if yes, set to 2 instead of e's value to show collision                                     
                                } else {                                                                                                                 
                                    map[curX][curY] = other_mask[curX][curY]; // the minus to nullify minX and minY "requirements"                       
                                }                                                                                                                        
                            }                                                                                                                            
                        }                                                                                                                                
                    }                                                                                                                                    
                }                                                                                                                                                                                                                                                                             
            }                                                                                                                                            
        }                                                                                                                                                
    }                                                                                                                                                    
} catch (Exception excp) {                                                                                                                               
    excp.printStackTrace();                                                                                                                              
}                                                                                                                                                        
return list.toArray(new Entity[1]);                                                                                                                      
}                                                                                                                                                            

Aussi, voici la méthode getMask():

    public int[][] getMask() {
        return mask;
    }

    ...

    private void createMask(BufferedImage image) {

    final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
    final int width = image.getWidth();
    final int height = image.getHeight();
    final boolean hasAlphaChannel = image.getAlphaRaster() != null;

    int[][] result = new int[height][width];
    if (hasAlphaChannel) {
        for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += 4) {
            int alpha = pixels[pixel];
            if(alpha != 0) {
                result[row][col] = 1;
            } else {
                result[row][col] = 0;
            }

            if (col == width) {
                col = 0;
                row++;
            }
        }
    }
    mask = result;

}

Cependant... ce code ne fonctionne pas comme prévu, et, dans certains cas, tous lors de l'ajout de l'individu masques sur la carte, j'obtiens IndexOutOfBounds même si cela devrait fonctionner, donc c'est probablement juste moi qui néglige quelque chose...

Donc, pour conclure, j'ai besoin d'aide avec mon code:

  • Qu'est-ce qui ne va pas avec ça?
  • Comment puis-je le réparer?
  • Existe-t-il une façon plus efficace de faire ce type de collision?
  • Recommandez-vous d'autres types de collision? Si oui, quels sont-ils?
Author: nyxaria, 2015-01-30

1 answers

Lorsque vous créez des entités, créez-vous leurs masques à partir d'images de la même taille? Parce que sinon le masque et la carte d'image de l'entité utiliseraient différents systèmes de coordonnées (entity.mask [0] [0] pourrait être à son coin, lorsque map[0] [0] est au coin du "monde"), et vous comparez les mêmes indices à la ligne:

map[curX][curY] = other_mask[curX][curY];

(ci-dessus dans le code, vous les obtenez réellement dans le même système de coordonnées avec Math.abs(a-b))

Quant à des moyens plus efficaces de détecter collisions, vous pouvez regarder danspartitionnement d'espace binaire et plus surdétection de collision en général sur Wikipedia.

 1
Author: gvlasov, 2015-02-01 01:44:14