Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create 2D map on which objects can be placed and move in Java

I am new to Java and I'm trying to make a 2D text-based game that internally consists of a world map on which objects can interact and move. However, I'm already confused at the very beginning. Let's say that I have a 3x3 map. Each tile then, is a value in a multidimensional array (e.g. the tile on coordinates [0][2]). However, each tile must be an array of objects (e.g. either a tile object (Forest, Ground, Desert) or an entity (Person, Rock, Duck)). It should be an array since each tile must at least contain one tile object (Forest, Ground, Desert) but can contain a theoretical infinite number of entities.

I tried and combined some of the answers here. Current idea is to make a superclass entity that has nothing but coordinates. When the entity is created (given some coordinates), the object is linked to the world map on that position (doesn't seem to work). The World Map is a multidimensional array that can hold Entities.

The entity isn't linked to the world map, and I can't figure out why. It's definitely going wrong in the Entity.java and the World.java files, but I'm still unsure how to set the position to the world map. Note that I would need to set or change the position of the entity from the map later on, or remove the entity as a whole (including its position on the map).

like image 459
Bram Vanroy Avatar asked Mar 14 '23 04:03

Bram Vanroy


2 Answers

I don't think your tile should be an entity. I think tile should encapsulate entities.Eg.

public class Tile {
    final int xPos,yPos;
    private String type;
    List<Entity> entities = new ArrayList<>();
    public Tile(int xPosition, int yPosition) {
        xPos = xPosition;
        yPos = yPosition;
    }

    public void setType(String type){
        this.type = type;
    }
    public String getType() {
        return type;
    }
    public void addEntity(Entity e){
        entities.add(e);
    }
    public void removeEntity(Entity e){
        entities.remove(e);
    }
}

Then the world class will contain entites:

public class World {
    Tile[][] coordinates;
    List<Tile> tiles = new ArrayList<>();

    // Creates an instance of a map with a user-defined size
    public World(int width, int height) {
        coordinates = new Tile[width][height];
        for(int i = 0; i<width; i++){
            for(int j = 0; j<height; j++){
                coordinates[i][j] = new Tile(i,j);
                tiles.add(coordinates[i][j]);
            }
        }
    }

    public void addEntity(Entity e){
        int x = e.getX();
        int y = e.getY();
        coordinates[x][y].addEntity(e);
    }
    public void setTileType(int x, int y, String type){
        coordinates[x][y].setType(type);
    }
    public List<Tile> getTiles(){
        return new List<>(tiles);
    }

    public List<Entity> getEntities(){
       List<Entity> entities = new ArrayList<>();
       for(Tile[] row: coordinates){
           for(Tile tile: row){
               entities.addAll(tile.entities);
           }
       }
    }
}

Then it would follow that your main method would look something like:

public static void main(String[] args) {
    // Creators
    World worldMap = new World(mapWidth, mapHeight);
    Character john = new Character("John", 0, 0);
    Character mary = new Character("Mary", 1, 4);
    worldMap.addEntity(john);
    worldMap.addEntity(mary);

    for (int x = 0; x < mapWidth; x++) {
        worldMap.setTileType(x, 5, "forest");
    }

    // Printing out info about character(s)
    //I think the world map should  have a list of characters.

    for (Character character : charList) {
        System.out.print(character+": " + character.getName() + "\n");
    }
    System.out.print("\n"+charList.size() + " characters in play\n\n");
    List<Tile> tileList = worldMap.getTiles(); 
    // Printing out info about tile(s)
    for (Tile tile : tileList) {
        System.out.print(tile + " type: " + tile.getType() + "\n");
    }
    System.out.print("\n"+tileList.size() + " tiles in play");
}

The reason why there are two #addEntity()s is because of how I think to answer the following predicament.

"I want to create a character john and add him to the world at position x,y."

Of course we will have

Character john = new Character("john", x, y);

Then, how do we add john to the World? I say, we just add him to the world, and let the world know what to do with the tiles and such.

world.addEntity(john);

John has a position, and the world can find the tile, and place john on the tile. The converse, which is more similar to what you have tried, would be to find the tile and add john directly.

world.coordinates[john.getX()][john.getY()].addEntity(john);

As you have shown in your example, this has some issues with index out of bounds exceptions, which you should handle. So the problem is, you need to know a lot about the structure of the tiles to add an Entity. Instead, let the world add the entity, because then it can handle all of the caveats one time and place the Entity at the correct tile.

like image 78
matt Avatar answered Mar 16 '23 18:03

matt


You are simply mistaking the tile map for the world. These are not identical concepts. The tile map describes the basic look of the world and maybe some basic properties (like walkable, impassable).

Its however not a complete description of the world. Anything that is not a tile needs to be modeled additionally. I can think of three workable concepts:

a.) Have an additional array for things occupying a tile location. This may work well if only one "thing" can occupy a specific location at any time.

b.) Instead of using a tile array use a location array. The difference is that you can model location to contain whatever you need, e.g. a tile plus a list of occupants for the location. Thats the OO variant of a.

c.) Have an independent data structure that keeps track of things existing in the world, e.g. a list of people. You need to model the location where something is as part of the state of the items that can populate the world, e.g. a person now has an additional x, y coordinate indicating their place in the world.

Whichever you chose, they all have their pros and cons, you can also use a hybrid, e.g. have a location map and a list of items. This combines the strengths of the two models (quick and simple checks of the surroundings of a location through the location map, as well as simple access to the entire world population through a list). Pick whatever fits your needs.

like image 39
Durandal Avatar answered Mar 16 '23 18:03

Durandal