Comparison error for isometric sorting

122 views Asked by At

So I'm implementing an isometric sorter for my sprites and I'm having some issues with the comparison of when the tiles should be rendered. I'm sorting all the isometric sprites that will be rendered by implementing them as comparable.

The problem is, when I'm implementing the following compareTo method:

// 1 = render this after
// 0 == render same
// -1 = render this before
@Override
public int compareTo(IsoSprite o) {
    if(z >= o.z && maxY <= o.minY && maxX <= o.minX){
        return 1;
    }
    if(z >= o.z && maxY >= o.minY && maxX >= o.minX){
        return -1;
    }
    if(z > o.z){
        return 1;
    }
    if(z < o.z){
        return -1;
    }

    //z == o.z && maxY == o.maxY && minY == o.minY && minX == o.minX && maxX == o.maxX
    return 0;
}

I get the error "Comparison method violates its general contract!" from the array.sort call in the LibGDX Array (which I use for sorting). I can't tell how I am supposed to solve this when looking at other peoples issue with this error, but those problems are mostly trivial. Anyone know how I should solve this in my isometric comparison?

My isometric world (for reference): enter image description here

Edit: Found something interesting when only sorting by Z:

//Doesn't work
public int compareTo(IsoSprite o) {

    if(maxZ > o.z){
        return 1;
    }
    if (maxZ < o.z){
        return -1;
    }
    return 0;
}

//Works
@Override
public int compareTo(IsoSprite o) {
    if(z > o.z){
        return 1;
    }
    if(z < o.z){
        return -1;
    }
    return 0;
}
2

There are 2 answers

0
Deminth On

I realised I won't be able to do the comparisons needed in a comparable. So instead I'm using my own implementation of Quicksort to sort using my own compareTo method that basically checks if a sprite is behind or infront of another one.

Thanks for all the help anyway!

2
MaxZoom On

This message indicates that there is something wrong with transitive logic in comparator, for if A > B then also B < A must be true. The compiler is smart enough to point it out to the user.
The problem in code is that a different values are compared to each other. To correct it you have to compare the same values minY < o.minY, and not to use <= and >= operators.

This should work:

public int compareTo(IsoSprite o) {
  if (isoDepth > o.isoDepth) return 1;
  if (isoDepth < o.isoDepth) return -1;
  return 0;
}

See algorithm to calculate isoDepth that could be used to sort /compare IsoSprites.