ArrayList error

Hey, I was reading this tutorial and I got an error with some of the code (I would reply to the thread, but it is too old to reply to).

The code I’m using from the tutorial is:


private List<Entity>[][] grid = null;
private int rows, cols;
private int cellSize;

public Grid ( int mapWidth, int mapHeight, int cellSize)
{
    this.cellSize = cellSize;
    rows = (mapHeight + cellSize - 1) / cellSize;
    cols = (mapWidth + cellSize - 1) / cellSize;

    grid = new ArrayList<Entity>[cols][rows];
}

And I get this error “Cannot create a generic array of ArrayList”.
I am not sure why it seems to work in the thread, but not on my tests. Maybe it is something to do with the Java versions?

If this simply cannot be done, could you recommend a method for collision checking that runs fast (currently I’m using brute force, with around 100+ entities at a time).

Thanks! :3

You can’t create an array of generics (which an arraylist technically is). Stack overflow: http://stackoverflow.com/a/897258

This is probably not a good coding practice, but you could just wrap the ArrayList in an object, such as this:

public class EntityArray {
    public ArrayList<Entity> entities;
}

and just have:

private EntityArray[][] grid;

CopyableCougar4

Hello @hugotheman

I’m the author of that article you’re referring to. The above code was valid in Java 1.5, but not under newer Java versions. You have to follow what CopyableCougar4 has suggested.

Field grid is already declared as List[][].
Why not simply skip the generics part when instantiating it?
grid = new ArrayList[cols][rows];
What matters is that when accessed via grid, it’s gonna be treated as List[][] after all! ::slight_smile:

I don’t get what you’re saying. ???

I would simply recommend you go with my earlier solution.

Replace your code with this

private EntityArray[][] grid = null;
private int rows, cols;
private int cellSize;

public Grid ( int mapWidth, int mapHeight, int cellSize)
{
    this.cellSize = cellSize;
    rows = (mapHeight + cellSize - 1) / cellSize;
    cols = (mapWidth + cellSize - 1) / cellSize;

    grid = new EntityArray[cols][rows];
}

public static class EntityArray 
{
    public ArrayList<Entity> entities;
}

Any questions?

CopyableCougar4

Yeah this seems the best way. I take it I add methods like “clear()” to EntityArray, right?

Thanks everyone.

To circumvent the issue without changing the rest of the code, use a rawtype:


grid = new ArrayList[cols][rows];

instead of grid = new ArrayList[u]<Entity>[/u][cols][rows];

The declaration can stay as it is.

[quote]Yeah this seems the best way. I take it I add methods like “clear()” to EntityArray, right?
[/quote]
You don’t have to.

When you access value from the array, you just do:

grid[x][y].entities.clear(); // etc.

CopyableCougar4

That’s exactly what I’ve told them some posts above yours! :yawn:
And btW, creating a wrapper array for it isn’t the best solution, since it’s another redundant & useless indirection! >:(
Just instantiate it raw! :stuck_out_tongue:

Ah, sorry, didn’t see it.

I may misunderstand something, but isn’t using a rawtype not a good idea? I know mine is far from the best idea, but at least there isn’t any possibility of contaminating the list, such as putting a string in a boolean list.

CopyableCougar4

I’m getting a NullPointerException here:


public Grid ( int mapWidth, int mapHeight, int cellSize)
    {
        this.cellSize = cellSize;
        // Calculate rows and cols
        rows = (mapHeight + cellSize - 1) / cellSize;
        cols = (mapWidth + cellSize - 1) / cellSize;
        // Create the grid
        grid = new EntityArray[cols][rows];
    }

    public void addEntity(Entity e)
    {
    	int topLeftX = (int) Math.max(0, e.getX() / cellSize);
        int topLeftY = (int) Math.max(0, e.getY() / cellSize);
        int bottomRightX = (int) Math.min(cols - 1, (e.getX() + e.getW() - 1) / cellSize);
        int bottomRightY = (int) Math.min(rows - 1, (e.getY() + e.getH() - 1) / cellSize);
    	
    	for (int x = topLeftX; x <= bottomRightX; x++)
    	{
    	    for (int y = topLeftY; y <= bottomRightY; y++)
    	    {
    	    	System.out.println(x + ":" + y);
    	        grid[x][y].entities.add(e);
    	    }
    	}
    }


grid [ x ][ y ] is null, where x and y are both 0.

One should always prefer the genric of course, but in this case (arrays) it’s not possible, and in fact you loose no type saftey with a raw type: (because the declaration isn’t raw, only the initializer)


@SuppressWarnings("unchecked")
List<Boolean>[][] lists = new ArrayList[2][2];

lists[0][1] = new ArrayList<>();
lists[0][1].add(5); // Compiler error; just like you would expect

Make the entityarray class this:

public static class EntityArray 
{
    public ArrayList<Entity> entities = new ArrayList<Entity>)();
}

CopyableCougar4

Okay it is working now, thanks again for your time.

How would you recommend using the Grid? Should I have one big ArrayList for every Entity and should I update the grid’s entities every tick and what would be a good cellsize with a mapsize of 1024x1024?

Grids are better when used against static objects (Even in other case, they are better than brute-force). For moving objects, generally QuadTrees are preferred. If you need to use them for moving objects, you have to re-construct the grid every frame. Or better, only update the entity which moves.

So you have to store the grid cells in the entity too, then remove the entity from those cells. Calculate the new cells and insert the entity there. This will be a lot more better.