2014-10-11 91 views
1

我正在開發一款可產生大塊2d瓷磚的iOS遊戲,用戶可以「無限」地移動。將NSCoding對象寫入磁盤時性能下降

僅適用於上下文:每個圖塊都是32x32px,每個「塊」包含4x4圖塊(共16個)。大多數瓷磚都是空的,但是當某些東西被放置在瓷磚上時,並且如果用戶移動太遠並且該塊「卸載」 - 我將塊和瓷磚數據保存到磁盤。

現在,大塊和小塊都使用NSCoding協議。塊保存瓷磚和一些布爾值的NSArray,並且每個瓷磚節省幾個數字/布爾值。

這個效果非常好 - 當大塊卸載時它會保存,當塊再次被加載時,它會被恢復。

但是,我注意到寫入磁盤方法極其簡單地殺死了我的FPS。由於隨着玩家的移動,通常會有幾個塊被卸載在一起,當他們被卸載時,玩家已經進一步移動並卸載 - 這加起來了。

我已經盡我所能確保只保存實際更改的塊,並且我最好組織保存代碼以避免每次保存調用都實例化對象。

有沒有更好的方式可以保存數據而不影響FPS?

  • 因爲我通常保存屏幕上不可見的數據,我可以做這個異步嗎?
  • 是否有比NSCoding更快的方法,因爲它只是每個類的一些float/bool值?

這裏的組塊保存代碼:

-(void)saveToDisk { 
    if(!self.hasUnsavedChanges){ 
     NSLog(@"skipping saving chunk that has not changed"); 
     return; 
    } 
    [self.saveFile writeData:self withKey:self.savefileKey]; 
    self.hasUnsavedChanges = false; 
} 

-(void)encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeObject:[NSNumber numberWithFloat:self.position.x] forKey:@"chunk.x"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:self.position.y] forKey:@"chunk.y"]; 
    [encoder encodeObject:tiles forKey:@"chunk.tiles"]; 
} 

-(id)initWithCoder:(NSCoder *)decoder { 

    Chunk *restore = [self init]; 

    NSNumber *xChunkNum = [decoder decodeObjectForKey:@"chunk.x"]; 
    NSNumber *yChunkNum = [decoder decodeObjectForKey:@"chunk.y"]; 
    restore.position = [Coord coordWithX:[xChunkNum intValue] Y:[yChunkNum intValue]]; 

    tiles = [decoder decodeObjectForKey:@"chunk.tiles"]; 

    return restore; 
} 

而且瓷磚代碼:

-(void)encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeObject:[NSNumber numberWithFloat:self.worldContextCoordinate.x] forKey:@"tile.world.x"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:self.worldContextCoordinate.y] forKey:@"tile.world.y"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:self.color.red] forKey:@"tile.color.red"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:self.color.green] forKey:@"tile.color.green"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:self.color.blue] forKey:@"tile.color.blue"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:self.isSourceTile] forKey:@"tile.isSource"];forKey:@"tile.hasBlackNeighbor"]; 
} 

-(id)initWithCoder:(NSCoder *)decoder { 

    Tile *restore = [self init]; 

    NSNumber *xNum = [decoder decodeObjectForKey:@"tile.world.x"]; 
    NSNumber *yNum = [decoder decodeObjectForKey:@"tile.world.y"]; 
    [restore setWorldContextCoordinate:b2Vec2([xNum floatValue], [yNum floatValue])]; 

    NSNumber *red = [decoder decodeObjectForKey:@"tile.color.red"]; 
    NSNumber *green = [decoder decodeObjectForKey:@"tile.color.green"]; 
    NSNumber *blue = [decoder decodeObjectForKey:@"tile.color.blue"]; 

    restore.color = [CCColor colorWithRed:[red floatValue] green:[green floatValue] blue:[blue floatValue]]; 

    restore.isSourceTile = [decoder decodeObjectForKey:@"tile.isSource"]; 

    return restore; 
} 
+0

您是否完全保存這些?如在其中,是否可能發生了一件事情,要求在它開始之前將它們保存到磁盤中?如果是這樣,那麼異步可能會成爲一個噩夢,即使完成塊。除了CoreData之外,你可能在NSCoding的正確軌道上。 – brandonscript 2014-10-11 16:36:13

+0

不是。這些通常在我「卸載」它們時保存 - 當用戶離開時不再需要這個「土地」。所有需要最終結果的是數據再次加載時,當用戶回到這個位置並加載塊數據時。 – helion3 2014-10-11 16:50:44

+0

使用分析器和/或時間記錄來確定時間。然後你可以決定加速什麼。你會知道NSCoding花費的時間和磁盤寫入時間。 – zaph 2014-10-11 17:11:37

回答

0

鑑於這一事實,你並不需要擔心影響UI或UX完成事件,你應該能夠異步運行它們。如果需要也可以使用完成塊來完成此操作,以便在必要時處理完成事件。

- (void)saveToDiskAsyncWithCompletion:(void(^)(BOOL finished))completion 
{  
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NO), ^{ 
     [self saveToDisk]; 
     // or you could run any of your other operations here too. 
     dispatch_async(dispatch_get_main_queue(), ^(void){ 
      completion(YES); 
     }); 
    }); 
} 
+0

你認爲有什麼可能的方式來加載數據異步嗎?查看新的性能分析數據和我的Tile對象的initWithCoder仍然是一個相當大的時間,仍然影響fps。 – helion3 2014-10-11 23:16:36

+0

有 - 您需要使用類似於您的方法的完成塊,以便在系統完成時通知系統。調用方法時,將UI更新放入完成塊中。 – brandonscript 2014-10-11 23:18:34