创建可以放置和移动对象的 2D 地图 Java
Create 2D map on which objects can be placed and move in Java
我是 Java 的新手,我正在尝试制作一个基于文本的 2D 游戏,该游戏内部包含一个世界地图,对象可以在该地图上进行交互和移动。但是,我一开始就很困惑。假设我有一张 3x3 的地图。然后,每个图块都是多维数组中的一个值(例如,坐标 [0][2] 上的图块)。但是,每个图块必须是对象数组(例如,图块对象(森林、地面、沙漠)或实体(人、岩石、鸭子))。它应该是一个数组,因为每个图块必须至少包含一个图块对象(森林、地面、沙漠),但理论上可以包含无限数量的实体。
我尝试并结合了这里的一些答案。目前的想法是制作一个只有坐标的超类实体。创建实体时(给定一些坐标),该对象将链接到该位置的世界地图(似乎不起作用)。世界地图是一个可以容纳实体的多维数组。
该实体未链接到世界地图,我不明白为什么。在Entity.java和World.java文件中肯定是出错了,但我仍然不确定如何将位置设置到世界地图。 请注意,稍后我需要在地图上设置或更改实体的位置,或者将实体作为一个整体(包括它在地图上的位置)移除。
我不是 100% 确定你想要实现什么,但让我回答你的直接问题,然后可能会给你一些提示。
因此,如果您想将实体 John 分配到您的左上角,您可以通过以下方式完成:world.mapArray[0][0] = john;
无论如何,为您的 Java beans/POJOs
使用访问器和修改器方法是一个好习惯。话虽如此,我建议您将所有字段设为私有然后。在这种情况下,您的代码将如下所示:
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;
}
}
我建议您不要将实体的位置作为其上下文的一部分,否则每次移动它时都必须更新它。这样你就可以得到类似的东西:
Map world = new Map(mapWidth, mapHeight);
Entity john = new Entity("John");
world.setEntityAt(john, 0, 0);
最后但同样重要的是,如果您尝试编译您的代码,您必须知道在一个 Java 文件中不能有超过 1 个 public class。
P.S。您可以使用 JUnit
进行测试。
我尽量不通过告诉人们以我的方式思考来帮助他们。去你的直觉引导你的地方往往更好。话虽这么说,我仍然会说你应该重构你的地图 class,因为你并不是真的想要一个 java 地图,并给它一个不同的名字,在这里我建议世界作为你的 [=22] =] 来包含你的瓷砖。此外,您的 Main class 应该是 Game,具有 main 方法。我建议这些更改只是因为 Map 和 main 在 java.
中有它们自己的含义
您还需要将 class 分开,以便每个都在自己的 .java 文件中。所以你从什么开始,加上上面提到的重构留下三个文件:
Entity.java
package Whosebug;
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 Whosebug;
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 Whosebug;
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 添加到您的项目中。我也喜欢宣传测试驱动开发,但这可能是一个完全不同的问题。
要使您的实体移动,请将 move(x, y) 方法或 moveTo(x, y) 方法添加到您的实体对象,并将要移动的距离(或新坐标)作为参数。
您只是将 瓦片地图 误认为是 世界 。这些不是相同的概念。瓷砖地图描述了世界的基本外观以及一些基本属性(例如可步行、不可通行)。
然而,它并不是对世界的完整描述。任何不是瓷砖的东西都需要另外建模。我可以想到三个可行的概念:
a.) 有一个额外的阵列用于占据一个瓷砖位置的东西。如果任何时候只有一个 "thing" 可以占据特定位置,这可能会很有效。
b.) 不要使用 tile 数组,而是使用 location 数组。不同之处在于您可以对位置进行建模以包含您需要的任何内容,例如瓷砖加上该位置的占用者列表。那是 a.
的 OO 变体
c.) 拥有一个独立的数据结构来跟踪世界上存在的事物,例如人员名单。您需要将某物所在的位置建模为可以填充世界的物品状态的一部分,例如一个人现在有一个额外的 x、y 坐标来指示他们在世界上的位置。
无论你选择哪个,它们都各有利弊,你也可以混合使用,例如有位置图 和 项目列表。这结合了两种模型的优势(通过位置地图快速简单地检查某个位置的周围环境,以及通过列表简单地访问整个世界的人口)。选择适合您的需求。
我认为您的磁贴不应该是一个实体。我认为 tile 应该封装 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);
}
}
然后世界class将包含实体:
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.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");
}
之所以有两个#addEntity()是因为我想如何回答下面的困境。
"I want to create a character john and add him to the world at position x,y."
当然会有
Character john = new Character("john", x, y);
那么,我们如何将 john 添加到 World 中呢?我说,我们只是把他添加到世界中,让世界知道如何处理瓷砖之类的。
world.addEntity(john);
约翰有一个位置,世界可以找到瓷砖,并将约翰放在瓷砖上。相反,这与您尝试过的更相似,就是找到磁贴并直接添加 john。
world.coordinates[john.getX()][john.getY()].addEntity(john);
如您在示例中所示,索引越界异常存在一些问题,您应该处理这些问题。所以问题是,您需要了解很多有关图块结构的信息才能添加实体。相反,让世界添加实体,因为这样它就可以一次处理所有警告并将实体放置在正确的图块上。
我是 Java 的新手,我正在尝试制作一个基于文本的 2D 游戏,该游戏内部包含一个世界地图,对象可以在该地图上进行交互和移动。但是,我一开始就很困惑。假设我有一张 3x3 的地图。然后,每个图块都是多维数组中的一个值(例如,坐标 [0][2] 上的图块)。但是,每个图块必须是对象数组(例如,图块对象(森林、地面、沙漠)或实体(人、岩石、鸭子))。它应该是一个数组,因为每个图块必须至少包含一个图块对象(森林、地面、沙漠),但理论上可以包含无限数量的实体。
我尝试并结合了这里的一些答案。目前的想法是制作一个只有坐标的超类实体。创建实体时(给定一些坐标),该对象将链接到该位置的世界地图(似乎不起作用)。世界地图是一个可以容纳实体的多维数组。
该实体未链接到世界地图,我不明白为什么。在Entity.java和World.java文件中肯定是出错了,但我仍然不确定如何将位置设置到世界地图。 请注意,稍后我需要在地图上设置或更改实体的位置,或者将实体作为一个整体(包括它在地图上的位置)移除。
我不是 100% 确定你想要实现什么,但让我回答你的直接问题,然后可能会给你一些提示。
因此,如果您想将实体 John 分配到您的左上角,您可以通过以下方式完成:world.mapArray[0][0] = john;
无论如何,为您的 Java beans/POJOs
使用访问器和修改器方法是一个好习惯。话虽如此,我建议您将所有字段设为私有然后。在这种情况下,您的代码将如下所示:
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;
}
}
我建议您不要将实体的位置作为其上下文的一部分,否则每次移动它时都必须更新它。这样你就可以得到类似的东西:
Map world = new Map(mapWidth, mapHeight);
Entity john = new Entity("John");
world.setEntityAt(john, 0, 0);
最后但同样重要的是,如果您尝试编译您的代码,您必须知道在一个 Java 文件中不能有超过 1 个 public class。
P.S。您可以使用 JUnit
进行测试。
我尽量不通过告诉人们以我的方式思考来帮助他们。去你的直觉引导你的地方往往更好。话虽这么说,我仍然会说你应该重构你的地图 class,因为你并不是真的想要一个 java 地图,并给它一个不同的名字,在这里我建议世界作为你的 [=22] =] 来包含你的瓷砖。此外,您的 Main class 应该是 Game,具有 main 方法。我建议这些更改只是因为 Map 和 main 在 java.
中有它们自己的含义您还需要将 class 分开,以便每个都在自己的 .java 文件中。所以你从什么开始,加上上面提到的重构留下三个文件:
Entity.java
package Whosebug;
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 Whosebug;
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 Whosebug;
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 添加到您的项目中。我也喜欢宣传测试驱动开发,但这可能是一个完全不同的问题。
要使您的实体移动,请将 move(x, y) 方法或 moveTo(x, y) 方法添加到您的实体对象,并将要移动的距离(或新坐标)作为参数。
您只是将 瓦片地图 误认为是 世界 。这些不是相同的概念。瓷砖地图描述了世界的基本外观以及一些基本属性(例如可步行、不可通行)。
然而,它并不是对世界的完整描述。任何不是瓷砖的东西都需要另外建模。我可以想到三个可行的概念:
a.) 有一个额外的阵列用于占据一个瓷砖位置的东西。如果任何时候只有一个 "thing" 可以占据特定位置,这可能会很有效。
b.) 不要使用 tile 数组,而是使用 location 数组。不同之处在于您可以对位置进行建模以包含您需要的任何内容,例如瓷砖加上该位置的占用者列表。那是 a.
的 OO 变体c.) 拥有一个独立的数据结构来跟踪世界上存在的事物,例如人员名单。您需要将某物所在的位置建模为可以填充世界的物品状态的一部分,例如一个人现在有一个额外的 x、y 坐标来指示他们在世界上的位置。
无论你选择哪个,它们都各有利弊,你也可以混合使用,例如有位置图 和 项目列表。这结合了两种模型的优势(通过位置地图快速简单地检查某个位置的周围环境,以及通过列表简单地访问整个世界的人口)。选择适合您的需求。
我认为您的磁贴不应该是一个实体。我认为 tile 应该封装 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);
}
}
然后世界class将包含实体:
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.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");
}
之所以有两个#addEntity()是因为我想如何回答下面的困境。
"I want to create a character john and add him to the world at position x,y."
当然会有
Character john = new Character("john", x, y);
那么,我们如何将 john 添加到 World 中呢?我说,我们只是把他添加到世界中,让世界知道如何处理瓷砖之类的。
world.addEntity(john);
约翰有一个位置,世界可以找到瓷砖,并将约翰放在瓷砖上。相反,这与您尝试过的更相似,就是找到磁贴并直接添加 john。
world.coordinates[john.getX()][john.getY()].addEntity(john);
如您在示例中所示,索引越界异常存在一些问题,您应该处理这些问题。所以问题是,您需要了解很多有关图块结构的信息才能添加实体。相反,让世界添加实体,因为这样它就可以一次处理所有警告并将实体放置在正确的图块上。