【问题标题】:JSTilemap - Loading only visible tilesJSTilemap - 仅加载可见图块
【发布时间】:2014-06-21 02:40:05
【问题描述】:

有没有人成功地使用 JSTilemap 仅加载可见图块?我问的原因是因为我的地图太大而无法一次加载,我想单独加载段或只动态加载当前在屏幕上可见的图块。

我不想使用 KoboldKit。

编辑:令人兴奋的更新。 Steffan 和 Marcus 正在 TilemapKit.com 上开发一个漂亮的工具包。迫不及待地想把钱扔给他们。

【问题讨论】:

  • 只是想知道您的平铺地图有多大?我正在运行一个 75 x 75 的 32 像素图块,没有任何问题。当我开始使用 Tiled 时,我尝试使用 JSTileMap,但发现使用导出的 JSON 文件滚动我自己的更好。可能不是很有帮助,但我的项目位于此处github.com/Urthstripe29/Old-Frank 它不会像 JSTileMap 那样易于使用,但您可能会在 Map.h/.m 文件中找到一些有用的东西。我将加载时间缩短到了 0.2 秒,这是在首次创建后添加 CoreData 来存储地图。
  • 当您说分段时,您的意思是要分块加载(一次 20 个图块 - 宽度),还是指每当一个图块进入视野时加载?
  • 感谢 cmets。当瓷砖进入视野时。地图约为。 32 像素的 400x300 平铺。我之前做过分段方法。只是看起来很草率,并且更喜欢在视图中节省内存。
  • 哇现在好大=)我尝试在每一侧都做一个公正的视图+1,但似乎我在弹出并将精灵推到场景中时遇到了太多问题。通过问题,我的意思是我得到了明显的 fps 损失。虽然这是在我正确重用纹理之前,所以这可能是原因。此外,我可能会创建新的并删除旧的,而不仅仅是重新定位和更改纹理。哦,过去的美好时光。祝我好运,希望你能找到一个好的解决方案。
  • @BigE 已经有一段时间了,但如果你还在研究这个,你可能会对这个及其剔除功能感兴趣。 github.com/SpriteKitAlliance/SKAToolKit我有另一个人的地图非常大,并从中获得了他想要的性能。如果您有机会尝试一下,请给我发一封电子邮件,让我知道您的想法。

标签: ios sprite-kit game-engine jstilemap


【解决方案1】:

这是以前做过的。在此处查看如何让 JSTileMap 执行您的要求。

https://github.com/fattjake/JSTileMap/commit/01b5bacc8c5ccc1099e020276d204ba439a6d06c

希望有帮助!

稍后更新:初步研究表明,这可能不是要走的路,让 spriteKit 为您处理优化。看到这个小讨论:https://github.com/slycrel/JSTileMap/issues/28

【讨论】:

  • 看起来 FattJake 的方向是正确的,但他的 mod 只显示最底层(最小的 z 值)。在您的原始课程中,我看到了所有三层,而在他的模组中,我只看到了最底层。我会继续查看它,看看我是否能找出原因。
  • 我和 Jake 谈过他的 JSTileMap 模组。他确认他的用例只有 1 个 tile 层,并且仅对其进行了测试。他确实计划很快看看它。使用示例项目,我已经测试了实现,它存在多个层的错误。
  • 感谢您的更新。它在我的列表中(但显然还没有进入顶部)检查并将其集成到主代码分支中。我对您在此处找到的结果非常感兴趣。
  • @slycrel - 在 JSTileMap.m +(id)layerWithTilesetInfo:(NSArray*)tilesets layerInfo:(TMXLayerInfo*)layerInfo mapInfo:(JSTileMap*)mapInfo 方法中,[layerNode addChild:sprite];添加实际的 SKSpriteNode。是否已经有一个 NSArray 类属性来访问这些单独的节点?
  • @sangony 看看 tileAt: 和 tileAtCoord: 获取单个图块的方法。
【解决方案2】:

我过去使用过分段地图方法。这适用于侧面滚动地图,您只需在侧面添加另一块。它也适用于需要侧面和底部或顶部部件的较大地图。

使用这种方法的另一个好处是,如果需要,可以在每次加载新地图时随机化地图部分。这消除了特定级别的“相同的旧地图”。

对于下面的代码示例,我使用相同大小的地图部分,宽度为 1280,并排放置。以下是涉及的步骤:

在 Tiled 应用中创建相同大小的地图部分。为每个地图部分指定一个以数字结尾的唯一名称。类似这样的东西:MyMap-0、MyMap-1、MyMap-2 等等。

创建一个可变数组来保存您的地图部分。我们就叫它mapSectionsArray吧。

创建一个名为 mapOffsetX 的浮点 ivar,并将其初始值设置为零。

如果您希望创建一个包含 10 个部分的静态地图,请使用以下代码:

for (int i = 0; i < 10; i++) {
    NSString *myString = [NSString stringWithFormat:@"MyMap-%d.tmx",i];
    JSTileMap *tiledMap = [JSTileMap mapNamed:myString];
    tiledMap.position = CGPointMake(mapOffsetX, 0);
    tiledMap.zPosition = 100;

    [worldNode addChild:tiledMap];
    [mapSectionsArray addObject:tiledMap];
    mapOffsetX += 1280;
}

如果您要创建一个包含 10 个部分的随机地图,请使用以下代码:

// create an array with the total number of sections created.
// in this example I have created 30 sections in total
// I make sure not to load the same section twice
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", @"13", @"14",@"15", @"16", @"17", @"18", @"19", @"20", @"21", @"22", @"23", @"24", @"25", @"26", @"27", @"28", @"29", nil];

for (int i = 0; i < 10; i++) {
    int r1 = arc4random() % [myArray count];

    NSString *myString = [NSString stringWithFormat:@"MyMap-%@.tmx",[myArray objectAtIndex:r1]];
    JSTileMap *tiledMap = [JSTileMap mapNamed:myString];
    tiledMap.position = CGPointMake(mapOffsetX, 0);
    tiledMap.zPosition = 100;

    [worldNode addChild:tiledMap];
    [mapSectionsArray addObject:tiledMap];
    mapOffsetX += 1280;

    [myArray removeObjectAtIndex:r1];
}

要在地图的对象层中加载项目,您可以这样做:

-(void)loadMapObjects {
    float xOffset;
    xOffset = 0;

    for (int i = 0; i < [mapSectionsArray count]; i++) {
        TMXObjectGroup *group = [[mapSectionsArray objectAtIndex:i] groupNamed:@"ObjectLayerName"];

        NSArray *arrayObjects = [group objectsNamed:@"objectName"];
        for (NSDictionary *dicObj in arrayObjects) {
            SKNode *myNode = [SKNode node.....];
            CGFloat x = [dicObj[@"x"] floatValue];
            CGFloat y = [dicObj[@"y"] floatValue];
            myNode.position = CGPointMake(x+xOffset, y);

            [worldNode addChild:myNode];
        }
    xOffset += 1280;
}

在更新方法中,您可以根据玩家的位置添加或删除选定的地图部分,如下所示:

// the exact values are determined by your view's size
// and map section's width
left = player.position.x - 1500;
right = player.position.x + 1500;
up = player.position.y + 1000;
down = player.position.y - 1000;

    for(JSTileMap *object in mapSectionsArray) {

        if((object.position.x > left) && (object.position.x < right) && (object.position.y > down) && (object.position.y < up)) {
            if(object.parent == nil) {
                [worldNode addChild:object];
            }
        } else {
            if(object.parent != nil) {
                [object removeFromParent];
            }
        }
    }

根据玩家的位置,地图部分被删除或添加到 worldNode 父级。

另一个优化是当它们不在视野中时,也可以(从父级)移除具有物理实体的对象。这可能可行,也可能不可行,具体取决于您游戏的设计和逻辑。

你可以在更新方法中处理这个:

left = player.position.x - 1500;
right = player.position.x + 1500;
up = player.position.y + 1000;
down = player.position.y - 1000;

for(SKSpriteNode *object in mapItemsArray) {
    if((object.position.x > left) && (object.position.x < right) && (object.position.y > down) && (object.position.y < up)) {
        if(object.parent == nil) {
            [worldNode addChild:object];
        }
    } else {
        if(object.parent != nil) {
            [object removeFromParent];
        }
    }
}

【讨论】:

  • 在这里颁发赏金,即使这不是我想要的。虽然我之前做过类似的实现,但目前没有可用的解决方案。至少这个答案可以帮助任何寻找一个好的权宜之计的人。感谢@sangony 的努力。
  • @BigE - 欣赏!我在 JSTileMap 类上花了几个小时,并试图从 Slycrel 获得一些额外的帮助,但我就是无法设置类属性数组。我看到在类中创建每个实际图块的位置,但我不知道有什么方法可以在该方法之外获取数据。我尝试了 github 项目,但它对我不起作用。分段地图加载帮助了我很多。如果将其与添加和删除的物理对象结合起来,您实际上可以获得显着的 FPS 速度提升。如果我遇到了按照您的要求做的方法,我会发布另一个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多