简体   繁体   中英

skSpriteKit improve Performance

Im writing a top-down racing game. It's something like "open world" game, no laps but free roaming. For many reasons i have not used a tiled map, so i have a big background image of 2048x2048. Moving this image isn't the cause of the slow performance. Over this image i have inserted some physic objects to create walls. Now i have inserted others cars to simulate traffic, each car is moving on a cgpath by an skaction that repeat itself forever. Each car respond to traffic light and stops by a system of invisible active area and cycling cgrectintersect check. The cars don't have physics body because add physics body to each car make the game performance poor after only 3 or 4 cars... So i have write a method that take care of contacts, traffic light,stops ,etc... It works fine but on iphone 4 i can manage only 15 cars before get poor perfomance. The first cause of this performance issue is the method that i have wrote. I'm trying an optimization and in my method i have some recursive loop (for example: for each update i check each car in for that have inside another loop to check contacts beetween others cars...)

for (int i=0; i<[ArrayCars count]; i++) {   

  CGRect Frame=[[ArrayCars objectAtIndex:i] frame];

  for (int z=0; z<[ArrayCars count]; z++) {

        CGRect Frame1=[[ArrayCars objectAtIndex:z] frame];
        SKSpriteNode *Car=[ArrayCars objectAtIndex:z];


        if (CGRectEqualToRect(Frame,Frame1)==NO && [Car speed]==0) {

            if ([self CheckIntersection:Car.frame :Frame]) {

              //set some flags that identifies the contact


            }



        }



    }
}

How i can do an optimization on something recursive like this? My method is launched by update method , but i have already tried to move it in didEvaluateActions without sensible gain.

There are a number of "optimizations" you can make, beginning with using fast enumeration:

for (SKSpriteNode* car1 in ArrayCars) 
{   
  CGRect Frame1 = car1.frame;

  for (SKSpriteNode* car2 in ArrayCars) 
  {
        CGRect Frame2 = car2.frame;

        if (CGRectEqualToRect(Frame1, Frame2) == NO && [car2 speed] == 0)
        {
            if ([self CheckIntersection:Frame2 :Frame1]) 
            {
              //set some flags that identifies the contact
            }
        }
    }
}

I bet this will already give you some improvement.

The next optimization steps would be to consider that not ever car1 needs to be checked against every car2. Basically if you checked whether car1 and car2 collided, the inverse check for car2 vs car1 is superfluous.

This variation checks each car1 against all car2. It skips the check against itself and against any previous cars because they have already been checked. Thus the inner loop has fewer and fewer iterations every time the outer loop has completed an iteration. Not too good at math but I believe this halves the number of total iterations. Unfortunately you can't use fast enumeration for the inner loop.

NSUInteger numCars = ArrayCars.count;
int otherCarsStartIndex = 0;

for (SKSpriteNode* car1 in ArrayCars) 
{   
  CGRect Frame1 = car1.frame;
  otherCarsStartIndex++;

  for (int i = otherCarsStartIndex; i < numCars; i++) 
  {
      SKSpriteNode* car2 = [ArrayCars objectAtIndex:i];

      // previous code omitted...
  }
}

One more optimization would be to inline the CheckIntersection code or to rewrite it as a C function to avoid the ObjC messaging overhead.

Also, if most of your cars happen to have speed == 0 most of the time it may improve performance if you first enumerate ArrayCars to build a new array containing only cars whose speed is non-zero. The new array probably needs to have about half or fewer than the original number of cars, otherwise the overhead of populating the new array may be too high to see a benefit.

Lastly you can squeeze out more performance by using a C style array to store your cars in, but this requires manual memory management and there is no protection against buffer over/underflow as in NSArray.

PS: Keep in mind the iPhone 4 is very slow compared to its successor, the iPhone 4S. The iPhone 4 is basically a iPhone 3GS with a 33% speed bump that is overly taxed by having to draw four times as many pixels to its Retina display.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM