Finding My App’s Memory Leak

My plan was to write a quick post explaining how I figured out the source of my app’s memory leak; however, I’ve run into two problems: 1) I think my app actually has a few other minor leaks, so I didn’t fix it completely and 2) the “Allocations” instrument in the latest Xcode beta is absolutely refusing to work now, so I can’t recreate what I saw the other day and take screenshots. As soon as I’m done writing this, I’m going to file a radar because I was able to reproduce the crash using Apple’s own sample game, DemoBots.

Anyway, there are still a couple things I can show you. First, I ran Corgi Corral on my iPhone 6S and played the same level twice. In between levels, the app transitions to another view controller that gives a summary of your score. As you can see, the second time I played the level the app used more memory than before. Each time I hit “retry,” it increased ever so slightly.

Debug navigator

If I hit the “Profile in Instruments” button during gameplay, my app would immediately crash (which is why I’m filing a radar). However, for awhile I was able to get the “Allocations” tool to collect data on the score summary screen. Now, I can only get it to run on the main menu without crashing.

Transfer to Allocations

For what it’s worth, it doesn’t matter whether I select “transfer” or “restart” — the app still crashes, except on the main menu, where I can at least show you what the memory-analyzing tool looks like when it’s running:

Allocations and leaks

See those little green checkmarks next to “Leak Checks”? When I reached my score summary screen, those were showing up as red icons with an “x” in the middle. When I clicked the red icon, it showed me a list of objects that weren’t being deallocated. The list included many instances of “GKAgent2D,” “GKGoal,” “GKBehavior,” “GKComponentSystem”—enough instances to cover the number of sheep in the level. Evidently, even though the SKSpriteNodes were being removed from the scene (and their agents from the scene’s agent system) when the sheep entered the pen, their GameplayKit agents were refusing to die.

I’m hoping that the next beta of Xcode 7.3 will fix my profiling problem, because I’ve become really interested in learning how to analyze my game’s performance! I’m sure there are many more problems to be found and optimizations to be made. For now, I’m off to file a bug report!

February 15th – Progress Update

Corgi Corral iconYikes, I can’t believe it’s already been nearly two weeks since I’ve done this! I admit that I haven’t spent much time working on the game lately, mostly because I just haven’t felt very good. Besides the ever-increasing pregnancy discomforts, I’ve just been feeling sort of discouraged. However, I’m still determined to push through and release the game—no matter what!

Accomplishments

As you can see, I made an icon for the game along with a main menu screen:

Corgi Corral Menu Screen

The title falls from the top of the screen and does a little “bounce” when the app is first launched. As I was setting up the menu, I realized that if I used less text, it would be easier to localize the app into different languages. I switched “Options” to a little gear icon and “Leaderboards” to a simplified Game Center logo. I also changed the “Tap to Start” text to a tapping finger icon:

Screenshot 2-15-16

After that, I shifted my focus to finding the source of a small memory leak. According to Xcode’s debug panel, every time I restarted a level, the app would use about 1 megabyte more memory than it did the previous time. Eventually, I figured out that the app was holding on to a bunch of GameplayKit-related objects for no apparent reason. Like, all of the GKAgent instances should be owned by the sheep SKSpriteNodes, which should have been wiped out when the scene was set to nil. Instead, the game was holding on to their agents, their agents’ behaviors, and all of the GKGoal objects indefinitely.

Now, whenever the game enters its “Game Over” state, I explicitly remove all the GameplayKit-related objects. I think that fixed the problem…or at least, the Allocations instrument isn’t reporting leaks anymore.

What’s Next

Art, art, and more art! Probably going to work on Level 3 scenery, and maybe figure out how to draw a top-down view of a pig. :-)

That’s all for now…thanks for reading!

Herding Success

I finally found a decent fix for the GameplayKit/physics problem I’ve been fussing over for months (and that I wrote about yesterday). The good news is that it’s simple. The bad news is that it’s really only applicable to my particular game and probably won’t help anyone else that is looking for a way to get GKAgents to avoid the edges of the screen. Sorry! If it helps, I filed a radar about it.

Prior to figuring this out, I had just set my sheep to wander at a slow speed when they spawned. I set a low weight for the wandering goal because I mostly wanted them to flee from the corgi. I set the weight of each sheep’s fleeing goal high when the corgi approached, and back to zero when the corgi was farther away. I never changed the wandering goal.

The solution was to switch between the fleeing goal and the wandering goal, turning each completely on or off depending on the distance between sheep and corgi. I also assigned a higher weight to the wandering goal and increased the speed. Here’s the function that handles that logic:

func checkDistanceBetweenCorgiAndCritters() {
        enumerateChildNodesWithName("critter", usingBlock: { node, _ in
            let critter = node as! Critter
            let playerVector = CGPointMake(CGFloat(self.player.agent.position.x), CGFloat(self.player.agent.position.y))
            let critterVector = CGPointMake(CGFloat(critter.agent.position.x), CGFloat(critter.agent.position.y))
            let distance = self.distanceFromCGPoints(playerVector, b: critterVector)
            let maxDistance:CGFloat = 200.0
            
            if distance < maxDistance {
                critter.agent.behavior?.setWeight(100, forGoal: self.fleeGoal)
                critter.agent.behavior?.setWeight(0, forGoal: self.wanderGoal)
            } else {
                critter.agent.behavior?.setWeight(0, forGoal: self.fleeGoal)
                critter.agent.behavior?.setWeight(100, forGoal: self.wanderGoal)
            }
        })
    }

I call them critters instead of sheep so that I have some species-flexibility. ;) The above function borrows a method from Apple’s “AgentCatalog” demo project that calculates the distance between two positions. Now when the sheep get “stuck” along the edges, it’s only momentary because as soon as the corgi moves away, they’re super focused on wandering around.

https://www.youtube.com/watch?v=Grdr028WZFk

What’s Next
Here’s my short list of things to work on next:

  • Add some “flocking” behavior so the sheep tend to travel in cohesive groups.
  • Add a “run” animation for the corgi so it’s not just a legless blob.
  • Animate a little “+1” whenever a sheep enters the pen.
  • Add a pause menu with “resume” and “retry” options (and later an option to quit and return to the main menu).
  • Work on background art.

Spinning in Circles

I spent a long time messing with Corgi Corral yesterday. Too long, probably, because now I can hardly stand to look at it. I hear this is normal though, so I figured I’d take a break today and blog about it instead!

Awhile ago I wrote about the disconnect between GameplayKit’s agent system and SpriteKit’s physics world. I’m still working my way through these issues and have only managed to come up with partial, half-baked solutions. Specifically, I’m struggling with how to handle collisions between the sheep and the edge of the screen.

What Happens
When the sheep, who are part of the GameplayKit agent system, collide with the edges of the screen (an edge chain physics body), they “stick” to the edge and slide along it. Eventually, they all end up huddled against the edges of the screen.

What I’d Like to Happen
When the sheep collide with the edge of the screen, they should turn around and go the other direction.

My Failed Solution
I came up with something that almost works. When I detect a physics collision between the sheep and the edge chain, I run an SKAction that rotates the sheep in the other direction, like so:

sheep.runAction(SKAction.rotateByAngle(CGFloat(-M_PI), duration: 1))

That actually works really well in most cases. The sheep hit the edge of the screen, turn around, and go the other way. The problem is that when they hit the corners, or get pinned between the wall and other sheep, then they spin pretty much indefinitely, like so (tap/click to play the GIF, note bottom left corner):

spinning sheep

They currently have circular physics bodies, but I’ve tried a variety of other shapes and they still get caught in the Spin Cycle of Doom.

Why This Problem Even Exists
In essence, GameplayKit’s agent system and SpriteKit’s physics system are in constant conflict. In the “agentDidUpdate” method, the position of the sprite is always reset to match that of its agent after the agent carries out its goals for that frame. Therefore, the agent system essentially overrides the physics system. So what’s the point of giving sprites with GKAgents physics bodies at all? Well, mostly to prevent them from passing through other sprites and to be able to be notified of collisions.

What Now?
I have three hazy ideas for solutions, but I could really use some help. Here’s my thought process so far:

  1. Maybe there’s something I could do in the agent delegate methods? There’s got to be a use case for those besides just setting the position of the agent and the sprite.
  2. Another idea was that after rotating the sheep, I could apply an impulse to propel it away from the wall. The problem is, I need to know which direction to propel it, and I don’t know how to figure out which edge of the screen it hit. I’m also wondering if this could cause a similar problem with the sheep bouncing around the corners, unable to break out of the back-and-forth pattern.
  3. I could find some way to use the agent system itself to keep the sheep away from the walls. So far, adding the edge chain as an “obstacle” and ordering the agents to avoid it doesn’t work—I suspect because the edge chain is just a line instead of something with actual volume. I could add some large, clear rectangular sprites along (but mostly outside) the bounds of the screen and add those as obstacles maybe?

So yeah, I don’t know. The documentation on GameplayKit is still lacking and the dev forums are pretty much dead. I’m hoping this year’s WWDC will bring some clarity and new features to this otherwise nifty framework.

Got an idea for me? Tweet at me: @bhansmeyer.