【问题标题】:Godot 2D Top Down Tile Rendering in a Procedurally Generated World程序生成世界中的 Godot 2D 自上而下平铺渲染
【发布时间】:2021-06-12 20:20:34
【问题描述】:

我知道这个问题经常被问到。但是对于我的一生,我无法在互联网上找到答案。

到目前为止,我已经创建了一个带有 Player 节点(附加相机)和 TileMap 的场景。

TileMap 使用 OpenSimplexNoise 在玩家周围生成一个 32x32 的瓷砖网格,一个“块”。

我已经创建了一个脚本来不断地在 _process(Delta) 中生成新的图块,但是如果“块”太大并且我必须同时更新位掩码时,这会破坏帧速率。

通过我的研究,我了解到与其每 0.1 秒更新一次图块,不如在玩家通过“块”时将它们绘制成 9 个“块”会更快。

我隐约理解使用“块”作为实例并复制它的概念,但似乎这仅在 3D 场景中是必需的。

我的问题是: 我是否需要实例化一个 TileMap 块,或者我可以将 TileMap 保留在场景中并根据玩家块的位置绘制大块的图块。

我的最终游戏是创建一个程序生成的大型有限地图,但是当我使用位掩码和自动拼贴时,我无法超越绘制大量单元格以填充屏幕的阶段。

任何资源、链接、教程都会很有帮助,因为互联网上的知识太多了,以至于我在寻找正确答案时迷失了方向。

这是我的代码:

func _ready():
   randomize()
   noise = OpenSimplexNoise.new() # Makes the noise OpenSimplexNoise
   noise.seed = 123456#randi()
   print("seed: " + str(noise.seed))
   noise.octaves = 1.0
   noise.period = 12
   noise.persistence = 0.7
   screensize = get_viewport().get_visible_rect().size
   addChunk()



func addChunk():
   var chunkWidth = 32
   var chunkHeight = 32
   var player_pos = Vector2(0,0)
   var chunkCenter = ($Grid.world_to_map($Player.position)/32)*32
   var PlayerChunkPos = ($Grid.world_to_map($Player.position)/16)
   var columnStart: float = (chunkCenter.x/16 - (chunkWidth/2)+16)
   var columnEnd: float = (chunkCenter.x/16 + (chunkWidth/2)+16)
   var rowStart: float = (chunkCenter.y/16 - (chunkHeight/2)+16)
   var rowEnd: float = (chunkCenter.y/16 + (chunkHeight/2)+16)
      for x in range(columnStart,columnEnd):
        for y in range(rowStart,rowEnd):
           var a = noise.get_noise_2d(x,y)
              if  a < grass_cap:
                $Grass.set_cell(x,y,0)
                #$Grass.update_bitmask_region(Vector2(0.0, 0.0), Vector2(x,y))


func _process(delta):
   addChunk()
   print($Grid.world_to_map($Player.position))
   print(($Grid.world_to_map($Player.position)/32).floor())

【问题讨论】:

    标签: rendering godot procedural-generation chunking gdscript


    【解决方案1】:

    首先,TileMap 已经处理了用于内部渲染的图块块。您可以通过设置cell_quadrant_size 来配置这些块的大小。所以,是的,单个TileMap 应该适用于相当大尺寸的有限地图。


    为了生成块中的内容......好吧,一旦生成了块,您就不必再次生成它,对吗?因此,请跟踪您已经生成了哪些块(我建议使用字典的键作为集合)。

    您将使用相机的位置来计算附近块的坐标。对于每一个,您检查它们是否在生成的块集中。对于那些没有生成的块,你调用一个函数来生成块给定的坐标,然后将它们放到生成的块集合中。


    进一步优化的可能路径:您只能在相机从一个块移动到另一个块时生成块。此外,您只能考虑与相机移动的相机方向相同的块(假设相机没有跳过太多块)。


    如有更多问题,我建议姐妹网站gamedev.stackexchange.com。那里有很多关于块和世界生成的现有问题可能会对您有所帮助。

    【讨论】:

    • 感谢您的回复!我可能会让自己感到困惑,正如您从我的代码中看到的那样,我正在使用 TileSet $Grass 根据角色移动时的噪声级别来设置正确的单元格。每次角色移过一个新单元格时,它都会创建一组新单元格,但这会导致延迟,因为它每 0.1 秒调用很多单元格。 TileSets 是在地图上构建大块瓷砖的错误方法吗?我觉得我试图将这两件事结合起来是一个错误。谢谢你的链接,我去看看!
    • @FumbleTouch TileMap 可用于程序生成(您可以在 YouTube 中找到展示这一点的教程)。但是,您需要尽量减少对TileMap 的写入。正如我所看到的,您的代码正在对已设置的单元格进行大量额外的工作,并在_process 中每秒执行数十次。将细胞设置为它们已经存在的状态只是浪费精力。你已经知道这是有问题的,因为你越来越滞后了。
    • @FumbleTouch 还有其他解决方案,包括多个TileMap,或者自定义画布着色器,或者使用精灵而不是图块(通常是个坏主意)......也许你会发现其中一些工作更接近你想象的。例如,着色器将绘制每一帧。或者,如果您有多个TileMap,每个单元格写一次可能对您来说更容易,每个单元格都是一个块。但这并不意味着这不能用单个TileMap 来完成。也许我们甚至可以争论每个块的TileMap 或者着色器更好,因为它们可以处理无限映射,同时保持内存使用有限。
    • 感谢您的清晰解释。您的最后一条评论是我的理解,即使用 TileMaps 创建一个块。我已经设法从 4 个 TileMaps 创建了一个块,我的研究指向我将它实例化到我的场景中,但我无法理解如何将块实例化到网格坐标并让它工作(就像你在你的原始评论)我需要一个字典或数组来存储这些块。有很多东西要理解,我发现很难从 youtube 和论坛获得清晰的信息。再次感谢您。
    • @FumbleTouch“来自 4 个 TileMaps 的单个块”我会将其设为 1,也许更大的块。 “我无法理解如何将块实例化为网格坐标”实例化TileMap,设置其位置,然后将其添加到场景中。这可能会有所帮助:gamedev.stackexchange.com/a/187236/10408 - 您可以使用带有位置 (Vector2) 的 Dictionary 作为键,使用 has 检查它是否已经存在。对于单个TileMap,我只需添加true,并使用设置的密钥。对于多个TileMap,它们可以是值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多