如何构建游戏地图的有向图(Python)

178 阅读2分钟

在开发一个使用 Python 创建的程序生成的游戏世界时,游戏世界的结构将类似于 MUD/MUSH 的范式,即房间和出口被安排为有向图(房间是节点,出口是边)。为了构建一个连通且符合特定规则的游戏地图,需要一些策略来实例化和安排这些房间。

  1. 解决方案 a. 建立位置概念: 首先,需要定义一个位置的概念,即游戏中的各种对象占据一定的坐标空间。可以将位置定义为简单的矩形或矩形实体,以便于规划。

b. 创建地图对象: 定义一个地图对象来包含位置信息。每个位置都有一个坐标跨度,使用简单的矩形时,每个位置可以有一个(左、上、右、下)元组。地图对象需要一些方法来确定位置中包含哪些对象,以及位置的邻近关系等。

c. 设计迷宫生成器: 其次,需要一个迷宫生成器。一个简单连通的迷宫可以很容易地生成一个以树结构表示的结构,然后将其折叠到给定的空间中。迷宫或树有一个“根”节点,作为迷宫的中心。可以选择一个根节点的空间,并将其放入地图空间中。根节点有 1 到 n 个入口,每个入口都是一个包含根节点和 1 到 n 个入口的子树。从根节点开始,递归地选取位置并将其放入可用空间中。

d. 微调迷宫生成器: 规则微调了迷宫生成器选择位置的方式。最简单的方法是使用权重表和随机选择。生成一个随机数,与权重进行比较,以确定生成哪种位置。

e. 扩展性: 可以定义空间为 2D 或 3D,这都是合理的。对于额外的扩展,可以考虑如何使用六边形而不是正方形来实现 2D 空间。这种“几何”可以作为迷宫生成器的策略插件。

代码示例:

class Location:
    def __init__(self, left, top, right, bottom):
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom

    def contains(self, x, y):
        return self.left <= x <= self.right and self.top <= y <= self.bottom


class Map:
    def __init__(self):
        self.locations = []

    def add_location(self, location):
        self.locations.append(location)

    def get_neighbors(self, location):
        neighbors = []
        for other_location in self.locations:
            if location.right == other_location.left and location.top <= other_location.bottom and location.bottom >= other_location.top:
                neighbors.append(other_location)
            if location.left == other_location.right and location.top <= other_location.bottom and location.bottom >= other_location.top:
                neighbors.append(other_location)
            if location.top == other_location.bottom and location.left <= other_location.right and location.right >= other_location.left:
                neighbors.append(other_location)
            if location.bottom == other_location.top and location.left <= other_location.right and location.right >= other_location.left:
                neighbors.append(other_location)
        return neighbors


class MazeGenerator:
    def __init__(self, map):
        self.map = map

    def generate(self):
        # Generate a random root node
        root_node = Location(0, 0, 1, 1)
        self.map.add_location(root_node)

        # Recursively generate child nodes
        self.generate_child_nodes(root_node)

    def generate_child_nodes(self, parent_node):
        # Generate a random number of child nodes
        num_child_nodes = random.randint(1, 3)

        # Generate each child node
        for i in range(num_child_nodes):
            # Generate a random location for the child node
            child_node = Location(
                random.randint(parent_node.left, parent_node.right - 1),
                random.randint(parent_node.top, parent_node.bottom - 1),
                random.randint(parent_node.left + 1, parent_node.right),
                random.randint(parent_node.top + 1, parent_node.bottom),
            )

            # Add the child node to the map
            self.map.add_location(child_node)

            # Connect the child node to the parent node
            parent_node.neighbors.append(child_node)
            child_node.neighbors.append(parent_node)

            # Recursively generate child nodes for the child node
            self.generate_child_nodes(child_node)


# Create a map
map = Map()

# Create a maze generator
maze_generator = MazeGenerator(map)

# Generate a maze
maze_generator.generate()

# Print the map
for location in map.locations:
    print(location)