使用UIImageViews和框架或CALayers或其他?

时间:2014-03-09 21:46:38

标签: ios performance memory-management core-animation

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

这非常有效,我在自己的设备上没有任何问题,但是我注意到,当屏幕上有超过20个对象在旧设备上同时移动时(例如例如iPad 3。


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

我认为在解决所有代码转换为图层之前我会遇到麻烦。有没有人有过编写这样的游戏的经验而没有任何旧设备上的延迟?

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

其他信息:

  

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


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

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收集垃圾的频率。

1 个答案:

答案 0 :(得分:2)

您应该考虑使用现有的游戏引擎,例如cocos-2d,或者花些时间使用常见模式和最佳实践来优化自己的引擎。如果您决定使用现有的引擎,除了阅读他们的文档之外没什么好说的,如果您遇到问题就会询问具体问题。不要问有关使用什么引擎的问题。这种问题不适合Stack Overflow。

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

enter image description here

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

将游戏引擎结构化为这些步骤

  1. 更新(移动物品)
  2. 操作(响应用户交互)
  3. 模拟(碰撞检测)
  4. 渲染
  5. 然后,您可以开始测量不同步骤的性能和内存效率,并继续处理最重的部分,直到达到可接受的性能。

    当他们离开屏幕时,也许值得重新使用视图,也许你的碰撞检测太昂贵而且应该进行优化,也许移动到图层是值得的。你必须先测量一下,知道在哪里花费你的时间和精力。

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


    作为旁注:

      

    我不知道ARC收集垃圾的频率。

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