【问题标题】:Use UIImageViews and frames or CALayers or something else?使用 UIImageViews 和框架或 CALayers 或其他东西?
【发布时间】:2014-03-09 21:46:37
【问题描述】:

所以我制作了一个非常简单的 iOS 游戏,它有多个在屏幕上滚动的对象,并在途中检查碰撞。目前要移动它们,我有一个 NSTimer,它每 0.01 秒左右触发一次,并将帧移动 2 个像素。然后它会检查玩家的位置是否有相交的帧并采取相应的行动。

这非常好用,我在我自己的设备上没有任何问题,但是我注意到当屏幕上有 20 多个对象在旧设备上同时移动时有时会出现延迟(例如例如 iPad 3)。


在分析应用程序后,似乎有大约 70% 的 CPU 流向了这个线程。这是正常的吗?如果我将每个对象添加到单个静止视图上的 CALayer 并更新该层上的位置,而不是在屏幕上同时移动 25-30 个单独的 UIImageView,它会减少 CPU 的负载吗?或者有更好的方法吗?

我想在我费尽心思将所有代码转换为与图层一起使用之前,我会先询问一下。有没有人有在旧设备上编写这样的游戏而没有任何延迟的经验?

我想支持尽可能多的设备,但较旧的设备似乎很难运行它(我觉得这很奇怪,因为与我制作的其他游戏相比,这款游戏非常简单)。

附加信息:

部署目标:5.0
iPad 设备 iOS:7.0.6
iPhone 5 设备 iOS:7.0.6
XCode 版本:5.0.2


这是在触发计时器时运行的代码。 CView 基本上是一个带有一些额外 int/bool 属性的 UIImageView。

for(CView* c in self.view.subviews)
{
    if(![c isKindOfClass: [CView class]])
    {
        continue;
    }
    
    [c setFrame:[CRect rect:c.frame withNewY:c.frame.origin.y+2]];
    
    if(fabsf(c.frame.origin.y + c.frame.size.height - (player.frame.origin.y+player.frame.size.height)) <= player.frame.size.height)
    {
        if([player collideWith:c.x])
            [self gameOver];
    }
    else if((c.frame.origin.y + c.frame.size.height) > (player.frame.origin.y + player.frame.size.height) && c.passed == NO)
    {
        c.passed = YES;
        score++;
    }
    
    if(c.frame.origin.y > [CRect height])
    {
        [self removeView:c];
    }
}

if(score != score2)
    [scoreLabel setText:[NSString stringWithFormat:@"%d",score]];

score2 = score;

reps++;
if(reps < 0)
    return;

NSArray* formation = [formations objectAtIndex:(int)[Global randomFloatBetween:0 andLarge:11.99]];

float max = 0;

for(int i = 0; i < formation.count; i++)
{
    if([[formation objectAtIndex:i] intValue] == -1)
        continue;
    
    if([[formation objectAtIndex:i] floatValue] > max)
        max = [[formation objectAtIndex:i] floatValue];
    
    float x = [CRect centerX:(player.laneWidth*5)+(player.lineWidth*4)] + ((i) * (player.xWidth+player.lineWidth)) + player.margin;
    float y = -101 + ([[formation objectAtIndex:i] floatValue] * (-130));
    
    CView* c = [[CView alloc] initWithFrame:CGRectMake(x, y, 49, 101)];
    [c setX:i+1];
    [c setImage:[images objectAtIndex:(int)[Global randomFloatBetween:0 andLarge:images.count-0.01]]];
    [self.view insertSubview:c belowSubview:adBanner];
}

reps = (-101 * (max+1)) - 202;
reps /= 1.75;

这是否与我以这种方式创建 CViews 并在它们离开屏幕时使它们无效有关?如果我使用一个固定的数字并重新使用旧的CViews(只需将它们放在屏幕的另一端并在它们完成交叉时重新运行它们)会提高性能吗?我不知道 ARC 多久收集一次垃圾。

【问题讨论】:

  • 嗯,可能是个愚蠢的问题。但这听起来像是 UIKit Dynamics 的工作。您不使用它有什么特别的原因吗?
  • @Murillo 我的无知...什么是 UIKit Dynamics?经过谷歌快速搜索,UIKit Dynamics 似乎适用于 7.0+;我想为 5.0+ 构建
  • 这是 iOS 7 的新物理引擎。它为您处理各种物理属性和行为,包括检测和处理碰撞。
  • @Murillo 听起来很棒!我将不得不为我的下一个项目检查它。不幸的是,我坚持使用 5.0 工具。

标签: ios performance memory-management core-animation


【解决方案1】:

您应该考虑使用现有的游戏引擎,例如 cocos-2d,或者花时间使用通用模式和最佳实践来改进您自己的引擎。如果您决定使用现有引擎,除了阅读他们的文档并在遇到困难时提出具体问题外,没有什么可说的。不要问关于使用什么引擎的问题。这种问题不适合 Stack Overflow。

如果您继续使用自己的引擎,那么我仍然建议您学习 cocos-2d 和 Sprite Kit 的文档和编程指南。这将帮助您构建自己的引擎。例如,这是 Sprite Kit Programming Guide 中解释游戏循环的图片。

如果您对使用 Core Animation 编写游戏引擎感兴趣,那么我建议您阅读 this series of blog posts by Matt Gallagher。它已经有几年的历史了,但应该仍然是最相关的。

当您将游戏引擎构建成这些步骤时

  1. 更新(移动东西)
  2. 动作(响应用户交互)
  3. 模拟(碰撞检测)
  4. 渲染

然后您可以开始测量不同步骤的性能和内存效率,并继续处理最重的部分,直到达到可接受的性能。

也许值得在视图移出屏幕时重用它们,也许您的碰撞检测过于昂贵并且应该进行优化,也许移动到层是值得的。您必须先衡量才能知道将时间和精力花在哪里。

不过,我会告诉你,你应该删除 NSTimer,并使用单个 CADisplayLink 进行游戏循环,以使更新与显示保持同步。


附注:

我不知道 ARC 多久收集一次垃圾。

这句话让我很担心。它表明你还没有理解 ARC 是什么以及它是如何工作的。 ARC 不是垃圾收集器。我建议你回去再看看 Objective-C 中的内存管理

【讨论】:

  • 内存管理是我在使用 Obj-C 时一直难以理解的一件事。我想我应该回到开始并重新学习它。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-22
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多