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.
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):
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.
I have three hazy ideas for solutions, but I could really use some help. Here’s my thought process so far:
- 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.
- 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.
- 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.