【发布时间】:2016-01-02 04:38:50
【问题描述】:
我正在使用 swift 和 Firebase 为 iOS 构建一个基于图块的 2d 游戏。因为世界很大,所以我将其设计为只订阅屏幕上的图块。也就是说,我没有为所有 10,000x10,000 块添加侦听器,而是将它们添加到屏幕上的块中。随着玩家的移动,我取消注册旧听众并注册新听众。我在屏幕边缘添加了一些缓冲区,希望在屏幕上移动时所有内容都能充分加载。不幸的是,Firebase 通常存在足够大的延迟,以至于这种策略根本行不通。在次优的互联网连接上,有可能继续走进“未加载的世界”,有时需要几秒钟来加载丢失的图块。
问题是这样的:同一连接和同一设备上的其他 MMO iOS 游戏运行良好。这不是一个可怕的联系。这让我怀疑我的实现,或者 Firebase 本身有问题。
基本上,每次我迈出一步时,我都会等待大约 20 个图块的“加载一次”事件。一个步骤大约需要 1/4 秒,所以我每秒从 Firebase 请求大约 100 个项目。不过,我想不出更好的方法。 Firebase 文档表明这应该不是问题,因为它都是一个套接字连接。我可以将对象“存储”到 10x10 块中,这意味着我将订阅更少的对象,但这在总数据传输方面也会更加浪费。如果套接字连接真的优化了,总的数据传输应该是唯一的瓶颈,这意味着这个策略是错误的。
编辑
这是一个展示其工作原理的视频。缓冲区大小已减小到-1,因此您可以轻松查看屏幕边缘以及加载和卸载的瓷砖。在视频快结束时,滞后来袭,我徘徊在空虚中。我打开了另一个游戏,它几乎立即加载。 http://forevermaze.inzania.com/videos/FirebaseLag.mov(n.b.,我在屏幕再次加载之前结束了录制。它永远不会加载失败,所以并不是代码无法工作。这纯粹是延迟。)
这是我用来加载图块的代码。它为每个图块调用一次。正如我所说,这意味着该代码每步被并行调用大约 20 次。所有其他应用程序都以良好的速度运行,没有延迟。我在东京使用具有 LTE 连接的 MiFi,因此连接稳定。
/**
* Given a path to a firebase object, get the snapshot with a timeout.
*/
static func loadSnapshot(firebasePath: String!) -> Promise<FDataSnapshot?> {
let (promise, fulfill, _) = Promise<FDataSnapshot?>.pendingPromise()
let connection = Firebase(url: Config.firebaseUrl + firebasePath)
connection.observeSingleEventOfType(.Value, withBlock: { snapshot in
if !promise.resolved {
fulfill(snapshot)
}
})
after(Config.timeout).then { () -> Void in
if !promise.resolved {
DDLogWarn("[TIMEOUT] [FIREBASE-READ] \(firebasePath)")
fulfill(nil)
//reject(Errors.network)
}
}
return promise
}
图块位于[ROOT]/tiles/[X]x[Y]。大多数图块包含非常少的数据,但如果该图块上有对象(即其他玩家),则会存储这些对象。这是 Firebase 的屏幕截图:
edit2
根据要求,我非常简单地重新创建了这个问题。这是一个 100 行的 XCTestCase 类:http://forevermaze.com/code/LagTests.swift
用法:
- 将文件拖放到您的 Swift 项目中(它应该是独立的,只需要 Firebase)
- 将
firebaseUrl的值更改为您的根 URL(即https://MyProject.firebaseio.com) - 运行一次
testSetupDatabase()函数测试以设置数据库的初始状态 - 运行
testWalking()函数来测试延迟。这是主要测试。如果任何图块的加载时间超过 2 秒,它将失败。
我已经在几个不同的连接上尝试过这个测试。一流的办公室连接没有问题,但即使是高端 LTE 或 MiFi 连接也会失败。 2 seconds 已经是一个 非常 长的超时时间,因为这意味着我需要有一个 10 tile 缓冲区(0.2 秒 * 10 块 = 2 秒)。这是我连接到 LTE 连接时的一些输出,显示加载磁贴花了将近 10 秒(!!):
error: -[ForeverMazeTests.LagTests testWalking] : XCTAssertTrue failed - Tile 2x20 took 9.50058007240295
【问题讨论】:
-
感谢您对目标的清晰描述。但这是一个相当广泛的话题。如果不把它煮沸一点,就很难有多大帮助。您能否将问题简化为特定的 sn-p 代码、数据结构示例以及关于两者的问题?
-
@FrankvanPuffelen 谢谢。我添加了一堆附加信息,包括视频、代码 sn-ps 和我的 Firebase 数据树的屏幕截图。
-
仅供参考 该视频无法为我播放;也许它已损坏。
-
@jtbandes 抱歉,我在
save edit按钮上有点快。现在刚刚上传完毕,请重试(我测试过,对我有用)。 -
该代码看起来不错,数据结构看起来也足够小。因此,在这个 sn-p 的背景下,更有可能是其他原因导致了减速。您能否将重现问题的程序减少到最小(但完整),以便有人可以在本地运行和重现问题?在这种情况下,如果您将 JSON 作为文本而不是屏幕截图包含在内,也会有所帮助。