在Java中,创建可放置对象的2D地图并移动

时间:2015-11-12 16:45:16

标签: java arrays multidimensional-array

我是Java的新手,我正在尝试创建一个基于2D文本的游戏,内部由一个世界地图组成,一个类的实例可以在其上进行交互和移动。但是,我一开始就很困惑。假设我想要一张3x3地图。然后,每个图块是多维数组中的值(例如坐标[0] [2]上的图块)。但是,每个图块(即地图上的坐标)必须是类的实例化数组(例如,tile对象(Forest,Ground,Desert)或实体(Person,Rock,Duck)。一个数组,因为每个坐标必须至少包含一个元素(tile对象(Forest,Ground,Desert),但可以包含理论上无限数量的实体。

我在这里尝试并结合了一些答案。目前的想法是创建一个除了坐标之外什么都没有的超类实体。创建实体时(给定一些坐标),对象将链接到该位置上的世界地图(似乎不起作用)。世界地图是一个可以容纳实体的多维数组。

正如您所看到的,该实体尚未与世界地图相关联,我无法弄清楚为什么不这样做。在Entity.java和World.java文件中肯定出错,但我仍然不确定如何将位置设置为世界地图。 请注意,我需要设置,稍后从地图中更改实体的位置,或整体删除实体(包括其在地图上的位置)。

4 个答案:

答案 0 :(得分:5)

我认为你的瓷砖不应该是一个实体。我认为tile应该封装实体.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);
    }
}

然后世界级将包含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);
           }
       }
    }
}

然后它会跟随你的主要方法看起来像:

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.add(john);
    worldMap.add(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");
}

有两个#addEntity()的原因是认为如何回答以下困境。

“我想创建一个角色john并将它们添加到位置x,y的世界。”

当然我们会有

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

然后,我们如何与世界结合?我说,我们只是将他加入世界,让世界知道如何处理瓷砖等。

world.addEntity(john);

约翰有一个位置,世界可以找到瓷砖,并将约翰放在瓷砖上。反之,更类似于你所尝试的,将是找到瓷砖并直接添加约翰。

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

正如您在示例中所示,这存在索引越界异常的一些问题,您应该处理这些异常。所以问题是,你需要了解很多关于添加实体的tile的结构。相反,让世界在实体,因为它可以一次处理所有警告,并将实体放在正确的瓷砖上。

答案 1 :(得分:1)

您只是误认为世界图块地图。这些不是相同的概念。瓦片地图描述了世界的基本外观,也许还有一些基本属性(如步行,无法通行)。

但它不是完整的世界描述。任何不是瓷砖的东西都需要另外建模。我可以想到三个可行的概念:

a。)为占据磁贴位置的东西增加一个数组。如果只有一个“东西”可以随时占据一个特定的位置,这可能会很好。

b。)使用位置数组而不是使用 tile数组。不同之处在于您可以对位置进行建模以包含您需要的任何内容,例如瓷砖加上该位置的占用者列表。这是a的OO变体。

c。)拥有独立的数据结构,可以跟踪世界上存在的事物,例如:一份人的名单。您需要对某些内容的位置进行建模,其中某些内容是可以填充世界的项目状态的一部分,例如一个人现在有一个额外的x,y坐标表示他们在世界上的位置。

无论你选择哪一种,它们都有其优点和缺点,你也可以使用混合物,例如有一个位置图一个项目列表。这结合了两种模型的优势(通过位置图快速简单地检查位置周围环境,以及通过列表简单访问整个世界人口)。选择适合您需求的任何东西。

答案 2 :(得分:0)


我不是100%肯定你想要实现的目标,但让我回答你的直接问题,然后给你一些提示。 因此,如果您想将实体John分配到左上角,则可以通过以下方式执行:ProvedorImagem.carregaImagem(processaImagem.carregaImagem()); 无论如何,为imagemPreview.source = "image://provedor/imagemEditada_" + camera.numeroImagem.toString(); 设置accessor和mutator方法是一种很好的做法。话虽如此,我建议你把所有字段都设为私有。在这种情况下,您的代码将如下所示:

world.mapArray[0][0] = john;

我建议您不要将实体的位置保留为其上下文的一部分,否则您每次移动时都必须更新它。这样你可以得到类似的东西:

Java beans/POJOs

最后,但并非最不重要的是,如果您尝试编译代码,您必须知道Java文件中不能有超过1个公共类。 附:您可以使用public class Map { private Entity[][] mapArray; // Creates an istance of a map with a user-defined size public Map(int width, int height) { mapArray = new Entity[width][height]; } public void setEntityAt(Entity entity, int x, int y) { if (x < 0 || x > mapArray.length || y < 0 || y > mapArray[x].length) { throw new IllegalArgumentException("Incorrect X or Y parameters"); } mapArray[x][y] = entity; } } 进行测试。

答案 3 :(得分:0)

我尽量不通过告诉他们思考方式来帮助别人。走直觉引导你的地方往往更好。话虽这么说,我仍然会说你应该重构你的Map类,因为你并不是真的想要一个java Map,并给它一个不同的名字,在这里我建议你把World作为你的类来包含你的tile。你的主类应该是游戏,主要方法。我建议这些更改只是因为Map和main在java中有自己的含义。

您还需要将类分开,以便每个类都在自己的.java文件中。所以你开始使用,再加上上面提到的重构就留下了三个文件:

    Entity.java
package stackoverflow;

public class Entity {
    String name;
    int xPosition, yPosition;

    // Creates an entity with a name, and an x/y-position on a maps
    public Entity(String name, int xPosition, int yPosition) {
        this.name = name;
        this.xPosition = xPosition;
        this.yPosition = yPosition;
    }
}

World.java
package stackoverflow;

public class World {

    Entity[][] mapArray;

    // Creates an istance of a map with a user-defined size
    public World(int width, int height) {
        mapArray = new Entity[width][height];
    }
}

Game.java
package stackoverflow;

public class Game {
    static int mapWidth = 8;
    static int mapHeight = 8;

    public static void main(String[] args) {
        World world = new World(mapWidth, mapHeight);
        Entity john = new Entity("John", 0, 0);
        for (int x = 0; x < mapWidth; x++) {
            for (int y = 0; y < mapHeight; y++) {
                Entity tile = new Entity("Tile", x, y);
            }
        }
    }
}

多维数组可以工作,但有一些缺点。您也可以使您的世界成为可以添加,删除,遍历等的实体列表,可能比阵列更容易。但是你现在可以用你所知道的来弄湿你的脚。为了测试,我建议你将JUnit添加到你的项目中。我也喜欢传播测试驱动的开发,但这可能是一个完全不同的问题。

要使实体移动,请将移动(x,y)方法或moveTo(x,y)方法添加到Entity对象,并将距离移动(或新坐标)作为参数。