Search code examples
javaarraylistslick2d

Rendering an ArrayList, sorted by its object's y position


Solved (scroll down)

I'm currently working on a small game in Java using the game library Slick2d. The game itself is 2D, but you can move to the background or foreground.

My problem

I'm currently trying to make something like a render order, which would be equivalent to CSS's "z-index". Otherwise, an object which is behind a player is rendered above the player.

  • How to sort it
  • How to render it correctly

My code so far

public static List<Entity> entities;

public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {
    entities = new ArrayList<Entity>();

    entities.add(new Player(100,100, 0));

    for(int i=0;i<10;i++){
        entities.add(new Fire(new Random().nextInt(Window.WIDTH), new Random().nextInt(Window.HEIGHT), i));
        entities.add(new Torch(new Random().nextInt(Window.WIDTH), new Random().nextInt(Window.HEIGHT), i));
        entities.add(new PassiveMob(new Random().nextInt(Window.WIDTH), new Random().nextInt(Window.HEIGHT), i));
    }
}

As you can see, I'm adding Entities to an ArrayList. Every Entity has a x and y position as well as a width and a height (Fire, Torch, PassiveMob and Player are instances of Entity).

public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
    for(int i=0;i<entities.size();i++){
        entities.get(i).update(delta);
    }
}

Here I'm just updating every entity.

public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
    for(int i=0;i<entities.size();i++){
        entities.get(i).render(g);
    }
}

At the end I'm rendering every entity.

My thoughts

  • Creating a custom "renderOrder" List
  • Sorting every Entity by its Y-axis and rendering it in this custom order
  • Finding a method provided by Slick2D to manage this

Current

The solution

I managed to fix it by using the following code after updating every entity:

    Collections.sort(entities, new Comparator<Entity>() {
        @Override
        public int compare(Entity o1, Entity o2) {
            final int y1 = o1.y+o1.anim.getCurrentFrame().getHeight();
            final int y2 = o2.y+o2.anim.getCurrentFrame().getHeight();
            return y1 < y2 ? -1 : y1 > y2 ? 1 : 0;
        }
    });

This sorts ArrayList<Entity> every tick based on the y-axis!


Solution

  • You should first add a Z index to your Entity class, and make sure that the Z index of the player is either the lowest or the highest of any object in your game (depending on which way you want to sort).

    Then you can just use a custom comparator that sorts by the entity's Z index and then sort your entities list with that comparator. Then, iterate through it like normal and render!

    Here is a SO question that shows you how to do the custom sorting.