如何用Java生成地图?

时间:2022-11-23 09:59:44

I trying to complete a RPG game for a project, but have no idea on how to make the game map. It doesn't need to be graphical, but the code for the whole map and each tile must be correct.

我试图完成一个项目的RPG游戏,但不知道如何制作游戏地图。它不需要是图形的,但整个地图和每个图块的代码必须是正确的。

So far, I thought about making a non-matricial map (as request by the professor) by using an ArrayList which contain all the linked tiles.

到目前为止,我想通过使用包含所有链接的tile的ArrayList来制作非matricial地图(作为教授的请求)。

public abstract class Casella {
/** 
 * @uml.property name="tabellone"
 * @uml.associationEnd multiplicity="(1 1)" inverse="casella:Tabellone"
 * @uml.association name="contains"
 */

private int id;
private boolean free = true;
private List adjacent;
private List items;
private Tabellone tabellone = null;

public void in(){
    free = false;
}

public void out(){
    free = true;
}

}

This was the code for a single tile (which has 3 classes that extends it). I still have no idea on how to put together and generate a map.

这是单个图块的代码(有3个类扩展它)。我仍然不知道如何组合并生成地图。

Thank you for your time.

感谢您的时间。

8 个解决方案

#1


Don't start with the implementation, start with how you would like to use the map. That will give you some constraints how to implement it. For example:

不要从实现开始,从您希望如何使用地图开始。这将为您提供一些约束如何实现它。例如:

When drawing the map, how do you access it? By coordinate? Or by "go west from tile X"?

绘制地图时,如何访问它?通过协调?或者“从X向西走”?

[EDIT] I suggest to start with the main loop of the RPG game. You'll need to place the character/token somewhere (i.e. it needs some kind of relation to a tile).

[编辑]我建议从RPG游戏的主循环开始。你需要将字符/标记放在某处(即它需要与图块有某种关系)。

Then you need to move the character. A character must be able to examine the current tile (opponents, items, type). It needs a way to know how it can move (i.e. is there a wall to the right?)

然后你需要移动角色。角色必须能够检查当前的牌(对手,物品,类型)。它需要一种方法来知道它是如何移动的(即右边有一堵墙吗?)

This gives you an interface for your map: Services which it renders for other objects in the game. When you have an idea of what the interface needs to provide, that should give you an idea how to implement the map (the data structure).

这为您提供了一个地图界面:它为游戏中的其他对象渲染的服务。当您了解接口需要提供的内容时,应该可以了解如何实现映射(数据结构)。

As for generating a map, use a random number generator plus some "common sense". Have a look at the adjacent tiles: When they are all city, this tile is probably city, too. Same for plains. Hills are singular items, and they are least frequent.

至于生成地图,使用随机数生成器加上一些“常识”。看看相邻的瓷砖:当它们都是城市时,这个瓷砖也可能是城市。平原也一样。丘陵是单一的物品,它们是最不常见的。

Run this code, print the map as ASCII ("C"ity, "P"lain, "H"ill) to see if it works.

运行此代码,将地图打印为ASCII(“C”ity,“P”lain,“H”ill)以查看是否有效。

#2


To generate a map like this without using a matrix, I recommend starting with a center tile and then populating the map outwards by using a modified breadth first search algorithm. First of all, we'll need something a little better than a list of adjacent tiles. You could simply have four variables, one for each direction that stores the next tile, as such:

要在不使用矩阵的情况下生成这样的地图,我建议从中心区块开始,然后使用修改后的广度优先搜索算法向外填充地图。首先,我们需要比相邻瓷砖列表更好的东西。您可以简单地使用四个变量,每个变量用于存储下一个磁贴的每个方向,如下所示:

private Tabellone up = null;
private Tabellone down = null;
private Tabellone left = null;
private Tabellone right = null;

Say we start with the center-most tile. All you have to do now is figure out how many of the directions are null, and create a new Tablellone object for each direction, making sure to set each of the variables in this current object and to set the appropriate opposite variable in the object created.

假设我们从最中心的瓷砖开始。您现在要做的就是弄清楚有多少方向是null,并为每个方向创建一个新的Tablellone对象,确保在当前对象中设置每个变量并在创建的对象中设置相应的相反变量。

Tabellone adj = new Tabellone();
up = adj;
adj.setDown(this);

Once you've filled out all of the directions on this tile, you then choose one of the other tiles you've created and perform the same operation. This is where the breadth-first search algorithm comes in. You can use a queue to go through each tile you've created and fill out the directions. To make the algorithm stop, simply set a limit on the number of tiles you want to create and use a counter to keep track of how many have been created.

一旦您填写了此图块上的所有方向,您就可以选择已创建的其他图块之一并执行相同的操作。这是广度优先搜索算法的用武之地。您可以使用队列浏览您创建的每个图块并填写指示。要使算法停止,只需设置要创建的切片数量限制,并使用计数器跟踪已创建的切片数量。

int count = 0;
ArrayList<Tabellone> queue = new ArrayList<Tabellone>()
queue.add(/*center tile*/);
while (count < 100) { //if we want 100 tiles
  //take out the center tile from the beginning of the array list, create a tile for each direction and add those tiles to the array list, then increment count by 1.
}

Note: This algorithm as it stands will create a diamond shaped map, if you want a square, you'd need to have a variable for each diagonal direction as well.

注意:此算法原样会创建一个菱形地图,如果你想要一个正方形,你也需要为每个对角线方向都有一个变量。

Of course, if this seems a little more complicated than you'd like, I'd recommend a coordinate system.

当然,如果这看起来比你想要的复杂一点,我建议使用坐标系。

#3


The walls, baggs and areas are special containers, which will hold all the walls, baggs and areas of the game.

墙壁,袋子和区域是特殊的容器,可以容纳游戏的所有墙壁,袋子和区域。

private String level =
          "    ######\n"
        + "    ##   #\n"
        + "    ##$  #\n"
        + "  ####  $##\n"
        + "  ##  $ $ #\n"
        + "#### # ## #   ######\n"
        + "##   # ## #####  ..#\n"
        + "## $  $          ..#\n"
        + "###### ### #@##  ..#\n"
        + "    ##     #########\n"
        + "    ########\n";

This is the level of the game. Except for the space, there are five characters. The hash (#) stands for a wall. The dollar ($) represents the box to move. The dot (.) character represents the place where we must move the box. The at character (@) is the sokoban. And finally the new line character (\n) starts a new row of the world.

这是游戏的水平。除了空间,有五个字符。哈希(#)代表墙。美元($)代表要移动的方框。点(。)字符代表我们必须移动框的位置。 at字符(@)是推箱子。最后,新行字符(\ n)开始了一个新的世界行。

#4


Is speed or memory a huge concern for this project? If not, why don't you use a 2d array?

速度或记忆是这个项目的一大问题吗?如果没有,为什么不使用二维阵列?

Something like

Casella map [][] = new Casella[xSize][ySize];

From here it is easy to conceptualize, just picture it as an excel spreadsheet where each cell is a tile on the map.

从这里可以很容易地进行概念化,只需将其描绘为excel电子表格,其中每个单元格都是地图上的图块。

The way you are going is fine though, just a little hard to conceptualize sometimes. You have a List of adjacent tiles. So, when creating your map you start somewhere, possibly top left, and go from there.

你的方式很好,但有时候有点难以概念化。你有一个相邻的瓷砖列表。因此,在创建地图时,您可以从某处开始,可能是左上角,然后从那里开始。

You could use nested for loops in order to set up the map, and to help determine the edge items.

您可以使用嵌套for循环来设置地图,并帮助确定边缘项。

for(int i = 0; i < XSIZE ; ++i)
    for(int j = 0; j < YSIZE ; ++j)
        if(j==0) //found left edge (i.e. no adjacent ones to the left)
        if(j==(YSIZE)) //found right edge (you get the picture) 

The point of using the loops, and checking the edges, is that you are going to need to link backwards and forward, up and down for each tile except at the edges, where you will have either 2 or 3 links instead of 4.

使用循环和检查边缘的关键是,除了边缘之外,您将需要为每个图块向后和向前,向上和向下链接,在那里您将有2个或3个链接而不是4个。

#5


The code needs to be correct really isn't a functional requirement, so its hard to say exactly what is correct without knowing more about your game/map.

代码需要是正确的,实际上并不是一个功能要求,因此很难在不了解更多关于游戏/地图的情况下确切地说出正确的内容。

Assuming you have a map that has X tiles and no ordered adjacency a non-matricial solution is best, a common solution is to just model it like a graph using either adjacency list for non-symmetric adjacency or incidence list for symmetric adjacency. If youre using an incidence list you need an edge object that contain the vertices the edge is connecting, if youre using adjacency list a multimap might be cool to use.

假设您有一个具有X个图块且没有有序邻接的地图,非基本解决方案是最好的,一个常见的解决方案就是使用非对称邻接的邻接列表或对称邻接的入射列表将其建模为图形。如果您使用入射列表,则需要包含边连接的顶点的边对象,如果使用邻接列表,则可能很难使用多图。

If you want a non-matricial solution with ordered adjacency AlbertoPL has the solution for that.

如果你想要一个具有有序邻接的非矩阵解决方案,AlbertoPL就能为你提供解决方案。

Assuming you have a map thats X tiles wide and Y tiles tall and the tiles that are next to each other are adjacent, so that each tile has at max 4 and min 2 adjacent tiles you could use a matrix to access the tiles and also represent adjacency by matricial adjacency. The idea is that map[Y][X] is adjacent to map[Y+1][X] and map[Y][X+1] and reversely. This solution could also fit max 6 and min 3 tile adjacency if tile [Y+1][X+1] is adjacent to tile [Y][X]. Upside to this is that you can easily parse the map, and since it has 2 dimensions its natural to model it like this. Downside is that once a tile is set, you cant change its adjacency without changing the matrix. As this isnt what you professor suggested you might not want to do it, but if you have (static) ordered adjacency this might be easiest way to do it.

假设您有一个X图块宽且Y图块高的地图,并且彼此相邻的图块是相邻的,因此每个图块具有最多4个和最少2个相邻图块,您可以使用矩阵来访问图块并且还表示通过matricial adjacency邻接。想法是地图[Y] [X]与地图[Y + 1] [X]和地图[Y] [X + 1]相反并且相反。如果tile [Y + 1] [X + 1]与tile [Y] [X]相邻,则该解决方案还可以适合max 6和min 3 tile邻接。这样做的好处是你可以轻松地解析地图,因为它有2个维度,所以很自然地像这样建模。缺点是,一旦设置了瓷砖,您就无法在不更改矩阵的情况下更改其邻接关系。因为这不是你教授建议你可能不想这样做的,但如果你有(静态)有序邻接,这可能是最简单的方法。

#6


I managed this by using adjacency lists. Each cell will have an ArrayList containing the indexes of the adjacent cells. Those indexes are the ones that the said cell have in the map ArrayList of cells.

我通过使用邻接列表来管理这个。每个单元格都有一个包含相邻单元格索引的ArrayList。那些索引是所述单元格在单元格的映射ArrayList中具有的索引。

http://en.wikipedia.org/wiki/Adjacency_list

#7


If it's a tile-based map, then each room has a fixed relationship with its adjacent rooms. You may not need to worry about co-ordinates (although it might be simpler if the tiles are square), but you will need to worry about directions.

如果它是基于图块的地图,则每个房间与其相邻房间具有固定关系。您可能不需要担心坐标(尽管如果瓷砖是正方形可能更简单),但您需要担心方向。

If the tiles are square, cardinal directions (n, s, e, w) may be all you need care about. If they're hex tiles, you can number your exits 1-6 (perhaps with static final constants). Then each adjacent tile may be linked to this one along with its exit.

如果瓷砖是方形的,则可能需要关注基本方向(n,s,e,w)。如果它们是十六进制图块,则可以将出口编号为1-6(可能具有静态最终常量)。然后,每个相邻的区块可以与其出口连接。

#8


As said by Aaron, you need to decide first how the maping coordinates will be.

正如Aaron所说,你需要先确定maping坐标是怎样的。

But you are not constrained by an X-Y-Z coordinate system. For instance, each tile could be linked to any other tile on your map. It all depends on how you want to build it.

但是你不受X-Y-Z坐标系的限制。例如,每个图块可以链接到地图上的任何其他图块。这一切都取决于你想要如何构建它。

You say that you're building an RPG game, then you need to have a good view of the terrain surround your character. Is it multi-level? How does the character move from one tile to another? Is the movement one way?

你说你正在构建一个RPG游戏,那么你需要很好地了解角色周围的地形。这是多层次的吗?角色如何从一个瓷砖移动到另一个瓷砖?运动是单向的吗?

There are, literally, dozens of question to be asked when designing a map for a game.

从字面上看,在设计游戏地图时会有几十个问题要问。

You need to plan it very well first, before starting coding.

在开始编码之前,您需要先做好计划。

#1


Don't start with the implementation, start with how you would like to use the map. That will give you some constraints how to implement it. For example:

不要从实现开始,从您希望如何使用地图开始。这将为您提供一些约束如何实现它。例如:

When drawing the map, how do you access it? By coordinate? Or by "go west from tile X"?

绘制地图时,如何访问它?通过协调?或者“从X向西走”?

[EDIT] I suggest to start with the main loop of the RPG game. You'll need to place the character/token somewhere (i.e. it needs some kind of relation to a tile).

[编辑]我建议从RPG游戏的主循环开始。你需要将字符/标记放在某处(即它需要与图块有某种关系)。

Then you need to move the character. A character must be able to examine the current tile (opponents, items, type). It needs a way to know how it can move (i.e. is there a wall to the right?)

然后你需要移动角色。角色必须能够检查当前的牌(对手,物品,类型)。它需要一种方法来知道它是如何移动的(即右边有一堵墙吗?)

This gives you an interface for your map: Services which it renders for other objects in the game. When you have an idea of what the interface needs to provide, that should give you an idea how to implement the map (the data structure).

这为您提供了一个地图界面:它为游戏中的其他对象渲染的服务。当您了解接口需要提供的内容时,应该可以了解如何实现映射(数据结构)。

As for generating a map, use a random number generator plus some "common sense". Have a look at the adjacent tiles: When they are all city, this tile is probably city, too. Same for plains. Hills are singular items, and they are least frequent.

至于生成地图,使用随机数生成器加上一些“常识”。看看相邻的瓷砖:当它们都是城市时,这个瓷砖也可能是城市。平原也一样。丘陵是单一的物品,它们是最不常见的。

Run this code, print the map as ASCII ("C"ity, "P"lain, "H"ill) to see if it works.

运行此代码,将地图打印为ASCII(“C”ity,“P”lain,“H”ill)以查看是否有效。

#2


To generate a map like this without using a matrix, I recommend starting with a center tile and then populating the map outwards by using a modified breadth first search algorithm. First of all, we'll need something a little better than a list of adjacent tiles. You could simply have four variables, one for each direction that stores the next tile, as such:

要在不使用矩阵的情况下生成这样的地图,我建议从中心区块开始,然后使用修改后的广度优先搜索算法向外填充地图。首先,我们需要比相邻瓷砖列表更好的东西。您可以简单地使用四个变量,每个变量用于存储下一个磁贴的每个方向,如下所示:

private Tabellone up = null;
private Tabellone down = null;
private Tabellone left = null;
private Tabellone right = null;

Say we start with the center-most tile. All you have to do now is figure out how many of the directions are null, and create a new Tablellone object for each direction, making sure to set each of the variables in this current object and to set the appropriate opposite variable in the object created.

假设我们从最中心的瓷砖开始。您现在要做的就是弄清楚有多少方向是null,并为每个方向创建一个新的Tablellone对象,确保在当前对象中设置每个变量并在创建的对象中设置相应的相反变量。

Tabellone adj = new Tabellone();
up = adj;
adj.setDown(this);

Once you've filled out all of the directions on this tile, you then choose one of the other tiles you've created and perform the same operation. This is where the breadth-first search algorithm comes in. You can use a queue to go through each tile you've created and fill out the directions. To make the algorithm stop, simply set a limit on the number of tiles you want to create and use a counter to keep track of how many have been created.

一旦您填写了此图块上的所有方向,您就可以选择已创建的其他图块之一并执行相同的操作。这是广度优先搜索算法的用武之地。您可以使用队列浏览您创建的每个图块并填写指示。要使算法停止,只需设置要创建的切片数量限制,并使用计数器跟踪已创建的切片数量。

int count = 0;
ArrayList<Tabellone> queue = new ArrayList<Tabellone>()
queue.add(/*center tile*/);
while (count < 100) { //if we want 100 tiles
  //take out the center tile from the beginning of the array list, create a tile for each direction and add those tiles to the array list, then increment count by 1.
}

Note: This algorithm as it stands will create a diamond shaped map, if you want a square, you'd need to have a variable for each diagonal direction as well.

注意:此算法原样会创建一个菱形地图,如果你想要一个正方形,你也需要为每个对角线方向都有一个变量。

Of course, if this seems a little more complicated than you'd like, I'd recommend a coordinate system.

当然,如果这看起来比你想要的复杂一点,我建议使用坐标系。

#3


The walls, baggs and areas are special containers, which will hold all the walls, baggs and areas of the game.

墙壁,袋子和区域是特殊的容器,可以容纳游戏的所有墙壁,袋子和区域。

private String level =
          "    ######\n"
        + "    ##   #\n"
        + "    ##$  #\n"
        + "  ####  $##\n"
        + "  ##  $ $ #\n"
        + "#### # ## #   ######\n"
        + "##   # ## #####  ..#\n"
        + "## $  $          ..#\n"
        + "###### ### #@##  ..#\n"
        + "    ##     #########\n"
        + "    ########\n";

This is the level of the game. Except for the space, there are five characters. The hash (#) stands for a wall. The dollar ($) represents the box to move. The dot (.) character represents the place where we must move the box. The at character (@) is the sokoban. And finally the new line character (\n) starts a new row of the world.

这是游戏的水平。除了空间,有五个字符。哈希(#)代表墙。美元($)代表要移动的方框。点(。)字符代表我们必须移动框的位置。 at字符(@)是推箱子。最后,新行字符(\ n)开始了一个新的世界行。

#4


Is speed or memory a huge concern for this project? If not, why don't you use a 2d array?

速度或记忆是这个项目的一大问题吗?如果没有,为什么不使用二维阵列?

Something like

Casella map [][] = new Casella[xSize][ySize];

From here it is easy to conceptualize, just picture it as an excel spreadsheet where each cell is a tile on the map.

从这里可以很容易地进行概念化,只需将其描绘为excel电子表格,其中每个单元格都是地图上的图块。

The way you are going is fine though, just a little hard to conceptualize sometimes. You have a List of adjacent tiles. So, when creating your map you start somewhere, possibly top left, and go from there.

你的方式很好,但有时候有点难以概念化。你有一个相邻的瓷砖列表。因此,在创建地图时,您可以从某处开始,可能是左上角,然后从那里开始。

You could use nested for loops in order to set up the map, and to help determine the edge items.

您可以使用嵌套for循环来设置地图,并帮助确定边缘项。

for(int i = 0; i < XSIZE ; ++i)
    for(int j = 0; j < YSIZE ; ++j)
        if(j==0) //found left edge (i.e. no adjacent ones to the left)
        if(j==(YSIZE)) //found right edge (you get the picture) 

The point of using the loops, and checking the edges, is that you are going to need to link backwards and forward, up and down for each tile except at the edges, where you will have either 2 or 3 links instead of 4.

使用循环和检查边缘的关键是,除了边缘之外,您将需要为每个图块向后和向前,向上和向下链接,在那里您将有2个或3个链接而不是4个。

#5


The code needs to be correct really isn't a functional requirement, so its hard to say exactly what is correct without knowing more about your game/map.

代码需要是正确的,实际上并不是一个功能要求,因此很难在不了解更多关于游戏/地图的情况下确切地说出正确的内容。

Assuming you have a map that has X tiles and no ordered adjacency a non-matricial solution is best, a common solution is to just model it like a graph using either adjacency list for non-symmetric adjacency or incidence list for symmetric adjacency. If youre using an incidence list you need an edge object that contain the vertices the edge is connecting, if youre using adjacency list a multimap might be cool to use.

假设您有一个具有X个图块且没有有序邻接的地图,非基本解决方案是最好的,一个常见的解决方案就是使用非对称邻接的邻接列表或对称邻接的入射列表将其建模为图形。如果您使用入射列表,则需要包含边连接的顶点的边对象,如果使用邻接列表,则可能很难使用多图。

If you want a non-matricial solution with ordered adjacency AlbertoPL has the solution for that.

如果你想要一个具有有序邻接的非矩阵解决方案,AlbertoPL就能为你提供解决方案。

Assuming you have a map thats X tiles wide and Y tiles tall and the tiles that are next to each other are adjacent, so that each tile has at max 4 and min 2 adjacent tiles you could use a matrix to access the tiles and also represent adjacency by matricial adjacency. The idea is that map[Y][X] is adjacent to map[Y+1][X] and map[Y][X+1] and reversely. This solution could also fit max 6 and min 3 tile adjacency if tile [Y+1][X+1] is adjacent to tile [Y][X]. Upside to this is that you can easily parse the map, and since it has 2 dimensions its natural to model it like this. Downside is that once a tile is set, you cant change its adjacency without changing the matrix. As this isnt what you professor suggested you might not want to do it, but if you have (static) ordered adjacency this might be easiest way to do it.

假设您有一个X图块宽且Y图块高的地图,并且彼此相邻的图块是相邻的,因此每个图块具有最多4个和最少2个相邻图块,您可以使用矩阵来访问图块并且还表示通过matricial adjacency邻接。想法是地图[Y] [X]与地图[Y + 1] [X]和地图[Y] [X + 1]相反并且相反。如果tile [Y + 1] [X + 1]与tile [Y] [X]相邻,则该解决方案还可以适合max 6和min 3 tile邻接。这样做的好处是你可以轻松地解析地图,因为它有2个维度,所以很自然地像这样建模。缺点是,一旦设置了瓷砖,您就无法在不更改矩阵的情况下更改其邻接关系。因为这不是你教授建议你可能不想这样做的,但如果你有(静态)有序邻接,这可能是最简单的方法。

#6


I managed this by using adjacency lists. Each cell will have an ArrayList containing the indexes of the adjacent cells. Those indexes are the ones that the said cell have in the map ArrayList of cells.

我通过使用邻接列表来管理这个。每个单元格都有一个包含相邻单元格索引的ArrayList。那些索引是所述单元格在单元格的映射ArrayList中具有的索引。

http://en.wikipedia.org/wiki/Adjacency_list

#7


If it's a tile-based map, then each room has a fixed relationship with its adjacent rooms. You may not need to worry about co-ordinates (although it might be simpler if the tiles are square), but you will need to worry about directions.

如果它是基于图块的地图,则每个房间与其相邻房间具有固定关系。您可能不需要担心坐标(尽管如果瓷砖是正方形可能更简单),但您需要担心方向。

If the tiles are square, cardinal directions (n, s, e, w) may be all you need care about. If they're hex tiles, you can number your exits 1-6 (perhaps with static final constants). Then each adjacent tile may be linked to this one along with its exit.

如果瓷砖是方形的,则可能需要关注基本方向(n,s,e,w)。如果它们是十六进制图块,则可以将出口编号为1-6(可能具有静态最终常量)。然后,每个相邻的区块可以与其出口连接。

#8


As said by Aaron, you need to decide first how the maping coordinates will be.

正如Aaron所说,你需要先确定maping坐标是怎样的。

But you are not constrained by an X-Y-Z coordinate system. For instance, each tile could be linked to any other tile on your map. It all depends on how you want to build it.

但是你不受X-Y-Z坐标系的限制。例如,每个图块可以链接到地图上的任何其他图块。这一切都取决于你想要如何构建它。

You say that you're building an RPG game, then you need to have a good view of the terrain surround your character. Is it multi-level? How does the character move from one tile to another? Is the movement one way?

你说你正在构建一个RPG游戏,那么你需要很好地了解角色周围的地形。这是多层次的吗?角色如何从一个瓷砖移动到另一个瓷砖?运动是单向的吗?

There are, literally, dozens of question to be asked when designing a map for a game.

从字面上看,在设计游戏地图时会有几十个问题要问。

You need to plan it very well first, before starting coding.

在开始编码之前,您需要先做好计划。