One of the reasons for posting progress updates here is to document the problems I encounter during development on the iPhone. By doing so I hope someone will find it useful when searching around for the same issue. Basically anything that stumps me for more than a couple hours is good to write down. Some of these may be "duh, what were you thinking" type of issues, but that's all part of the learning process.
First up is a problem I had most recently where a UITableView delegate wasn't responding to the didSelectRowAtIndexPath method (message, whatever). This would only happen when the table was placed in edit mode. My searches found this link that answered it nicely.
This is one of those "duh" moments since it was just a simple property change. Still, if you don't know about the existence of that property it leads to wasted time and frustration.
In addition to the technical aspects of my trials in iPhone programming I will also use blog this as a soap box to espouse my opinions about iPhone gaming in general.
First, I believe that having a "Lite" or "Free" version of your game is absolutely essential. Without it people will pass your game by unless it happens to have huge critical acclaim (Flight Control).
Apple changed this dynamic a bit in their latest update that allows in-game purchases from free apps. Now, rather than having two versions of your game (lite and normal), you can just have one. Allow the user to play some levels and then ask them to upgrade to unlock the rest. It remains to be seen if that strategy actually translates into a higher buy-in compared to the usual two-version method.
Another thing I've come across is that the lite version doesn't get to the interesting part of a game. You get to play the first few levels, which are usually the easiest and have the fewest features. When I'm trying out a game I want to see the full-spectrum of what I'd be buying. You don't have to show every single feature, but at least give me a challenge to let me know what I'll be up against.
As an example, the game MinMe does this. It's fun, but really easy to breeze through the levels offered in the base version before it asks you to unlock the rest. It would have been better to sprinkle in some harder challenges. I definitely liked the game, but wasn't willing to splash out for more when I don't know what I'd be getting.
On the other hand, the lite edition of Labyrinth recently added some levels from the sequel, Labyrinth 2. This was done very well as the levels chosen demonstrated some varied features from the full game. They didn't show all their hand, but still enough to whet your appetite.
With the launch of the iPad I have decided to change what I'm working on. My previous iPhone project was mostly just a vehicle for me to learn Objective C, get familiar with UI elements and become comfortable with the general Apple way of doing things. I believe it has served that purpose. It's a shame to leave the project unfinished, but I have learned that if I don't nip a project in a bud it can suck too much time. I'm sure I will return to it at some point.
My new app is a game (duh) that will target both iPhone and iPad. I haven't decided if they will be the same app or two separate ones. I suspect the latter as I want to get it done asap. Focusing on one platform (iPhone first) will help tremendously.
I'm not going to reveal a lot about the game yet. I started a design document, but a fair bit of it is still gestating in my head. What I will say is that it requires a lot of physics. As such I'm diving into Chipmunk Physics API, which seems ideal for what I am doing. I'm also considering the cocos2d engine since it has support for Chipmunk built in.
I have a hard deadline in mind. I've given myself eight months to get it done. I am currently working by myself, but will probably call upon others for help with the artwork and audio. I want to get a nice prototype up and running first, though.
Game Progress
Ah it's been a while since I've used that purple game progress indicator. It's nice to be doing something again.
I finally got things displaying with cocos2d. That was actually really easy. I can see myself liking this toolkit quite a bit. In fact I've been thinking about how I could use it for other games in my head (how about a Decaying Orbit port?).
What you see on the right is a pyramid of pegs. It was the first correct thing that I got showing (the very first thing had the pegs organized incorrectly).
My next task was to get some balls bouncing off those pegs using the Chipmunk physics engine. My first bug involved my pegs falling down off the screen just like the ball. Obviously they are supposed to be static so I changed my cpSpaceAddShape() call to cpSpaceAddStaticShape(). Still, that didn't fix it.
I finally found out the problem this morning. Chipmunk has two structures for each object. One describes the object's body (mass, etc) and the other describes its shape (for collision detection). Normal objects add both their body and shape to the simulation space that Chipmunk maintains. It turns out that for static shapes you only should add the shape.
With that fixed I now have multiple balls happily bouncing down my grid of pegs. The image to the left has tiny red pegs (obviously I couldn't keep them as large as in the other image) with purple balls ping-ponging their way to the bottom. A movie would be better to show what's going on. I'll have to figure out how to capture movies from the iPhone simulator. In the meantime you're stuck looking at static images and trust me it looks cool in motion.
I've been playing with different parameters. Peg size, ball size, number of balls, gravity, elasticity, friction, etc. I want to minimize the chances of balls getting stuck in the pegs, which requires some minimum distance between pegs. Also, I notice that sometimes balls will hit a peg just right and come to rest on top of it. That's definitely not acceptable. I'll probably add some slight sideways force (wind?) to avoid this.
As for the game itself, I'll get into that over time as I add more elements. Now that I have something working I'm going to clean up my code and structure it properly.
I nabbed the free trial of Snapz Pro to capture movies of my experiments in motion. Check out the first one (link here).
The movie doesn't do justice to how smooth the animation really is, unfortunately.
Here's what's happening in the video. So I have these balls falling into buckets at the bottom of the screen. As you can see the frame rate (bottom left corner) is fine as the balls fall, but once they start collecting in the buckets it drops to 30 fps. This is because of all the ball-to-ball interactions that the physics engine must compute.
To fix this I will convert the balls at the bottom of the piles into static objects once a sufficient number have accumulated on top. That way they will be removed from the calculations. The different colors are my way of knowing which balls are at the bottom of the piles.
Balls touching the bottom are solid red. The ones just above that are solid orange. And so forth through the rainbow. After purple it goes to red with a dot, orange with a dot, etc.
I will use this to compute the depth of the pile and once it is deep enough I will pick off the bottom most balls and remove them from the physics simulation (since they won't be moving that much anyway).
As I described last time, I have balls collecting in buckets at the bottom of the screen. The physics simulation proceeds at a good frame rate as the balls fall, but starts to slow down as they collect. This is due to the increased computation by the physics engine required since so many balls are touching.
To alleviate this I have implemented a system to convert the balls from dynamic objects to static objects. Static objects are handled differently by the physics simulator and are much faster (static objects don't move and don't collide with one another). The video below shows how balls are getting converted to static objects once they are no longer moving and are at the bottom of the pile. The gray balls are the static ones. Note that the frame rate remains around 60 instead of dipping to 30 like before.
There's still some work to be done on how balls are selected for conversion. You can see that the fourth bucket still ends up with quite a lot of normal balls. Ideally everything below the second or third layer will be converted to static. That way new balls that strike the top of a pile will still cause some bounce in the other balls in the pile, but the ones further down would be converted to take them out of the simulation.
It took a lot of experimentation to get to this point. I'll describe some of that here. More for my own sake than anything else. I want to be sure to document this process so I can remember later how I arrived at where I am. Unfortunately I've forgotten the details of some earlier experiments. Hopefully this process will jog my memory.
I knew from the beginning that I was going to implement the dynamic to static conversion. To do so I needed a way to keep track of the balls in each bucket. The Chipmunk physics engine has what are called sensor objects. Their purpose is to detect when objects collide with them without actually affecting their trajectory. Usually they are invisible (no sprite attached).
At first I used a sensor object in each bucket. The sensor was a rectangle that filled the entire space of the bucket. As balls enter, a callback is invoked and I can keep track of what balls are in what bucket.
Next I needed a method to determine when a ball should be converted from dynamic to static. The first criteria is that the ball needs to be still. Meaning its velocity is low enough that the user won't notice when it stops entirely.
The second criteria is that the ball must be in a bucket and at the bottom of the pile. We don't want to convert a ball that just happened to come to rest elsewhere on the board. Nor do we want to convert a ball at the top of the pile since it will look odd when it doesn't move as balls collide with it.
To accomplish this I tried using a second sensor object that started at the bottom of each bucket. It was a rectangle that was the width of the bucket, but the height started out at one ball diameter. That way only balls at the bottom would trigger the sensor. As balls are converted to static the sensor height is increased so that it is always just higher than the top-most static object in the pile.
A problem arose when I was seeing balls higher in the pile being converted before balls that are lower. This probably happened because the lower ball was still moving slightly at the time. This caused some bizarre behavior as I saw balls fly out at very fast velocities. I think balls were getting trapped between static objects. With no where else to go they were getting squeezed out at tremendous speed.
To avoid this I needed some way to determine a ball's distance from the bottom of the bucket. I got rid of the sensor objects and started tracking the contacts between the balls in the pile. This resulted in the colorful rainbow you saw in the last two videos.
With the new method for determining depth I needed a new method for determining when a ball should be converted to static. As it is now, whenever a ball strikes the pile I perform a check. To avoid the situation of higher balls being converted before lower ones I have the restriction that only the bottom-most ball may be converted. I also ensure the pile has a minimum depth, although that part still needs some tweaking.
So back to the prior observation about bucket #4. You'll note that I only perform the conversion check when a new ball strikes the top of the pile. I'm guessing that bucket #4 is flooded with so many balls that the conversion can't keep up. Now that I have the basic algorithm working I'll be playing with it to perform as desired.
Game Progress
Here's a video showing the latest algorithm for converting balls from dynamic objects to static objects. You can see that it always leaves a small layer at the top so that things look normal when a new ball strikes the pile.
With that out of the way I actually had to think about what to do next. Unfortunately I believe it is time to get some grunt work out of the way. I need a method for describing levels.
Levels will almost surely be defined by XML files. I need to make sure the definition is extensible enough to handle any additions I might make in the future.
So I might not post for a while as I do this required plumbing. Once I get it done it will be easy to create new objects and levels. I'll need to make a level editor at some point, but in the beginning I'll just create the XML files manually.
I have some of the XML parsing backbone complete. Just enough to get the app to the state it was at before. It isn't debugged yet - hopefully by the end of the week.
In the meantime I want to talk about startup times in iPhone apps. I probably wouldn't have even given it a second thought if I hadn't come across the game Hanto. It's an interesting tile-based strategy game. One of the things that really struck me about it is how quickly it loads. As soon as you tap the app icon the main menu appears. The buttons are not active immediately as it loads in the background, but that only takes 2-3 seconds. It's awesome and in stark contrast to some of the lengthy load times some games have. At least games like Peggle give you entertaining quips to read as it loads.
Another thing I've seen is the ability to turn off the opening splash screen. The Storm8 games allow this, which is great. (Too bad the rest of the load time is a hefty 7-8 seconds.)
As much as it is possible I am going to make my app load quickly. I might throw in an initial splash or title screen, but it won't last long and the user should be able to tap through it. In fact it would be great if the game restores itself to where it was when you left it, bypassing all loading screens.
I recently had a request to seed the NUON Tech Data file that's available as a torrent. Rather than doing that I just uploaded it here. I had to move the site to a different server to get enough space. I believe that went painlessly so I should be set for a while (it's cheaper too!).
Here's the first screen that greeted me once I got my XML parsing working somewhat correctly. It's a grid of (overly large) pegs. I quickly fixed their scale. In addition to being black and white you'll notice is that the pegs have random colors. I have a mechanism for explicitly assigning a particular peg image if necessary.
Next I got the first bucket displaying correctly (from XML instead of hard coding). Objects in the game can have multiple sprites and shapes attached to them. For now I made the bucket a normal rectangle, but there isn't any reason why it can't be a different shape. I'm trying to make it super easy to create new levels. I just don't have time to waste since I'm doing all of this by myself.
The second image is where things stand now. One bucket in the lower left corner and a grid of pegs. It should be trivial to add the remaining buckets now that I have one working. The main thing is to have the game automatically remove pegs that are overlapped by other objects (like buckets).
I placed my preorder for an iPad today. That's a lot of cash to splurge on an unproven piece of tech. Hopefully it was the right decision.
I think I have a nice, clean way of having the game support both iPhone/iTouch and iPad with the same build. There are two downsides to this approach. First, given the required increase in resolution on the iPad, the downloaded package will be larger than it ought to be for iPhone/iTouch users. There just isn't any way around that without compromising the iPad version. I don't expect the game to be huge anyway. Second, the aspect ratio is different between the two so it's not just a simple matter of scaling things up. I have some ideas, but haven't settled on what to do about that yet.
The next object to add to the XML is a ball launcher. I'll start with a simple one, but levels will potentially have different types of launchers. Once I get that then I should be at the same state I was a week or two ago with the last movie.
Nothing like a nice two-week long bug to make you appreciate how difficult it can be to learn new programming languages.
It wasn't until I stumbled on the right set of words to Google that I finally found my problem. I had some crashes related to some of my objects going invalid spontaneously. Turns out that the following two statements are not equivalent in ObjC.
myVar = newVal;
self.myVar = newVal;
The former assigns the new value directly, bypassing the object's setter. The latter does things the proper way. Guess which way I was doing up until yesterday?
I finally stumbled on this thread in the indubitably awesome Stack Overflow. In particular, the reply to the third answer made the light bulb finally go on. "properties don't retain/release unless you use self.property = foo instead of property = foo". Gah!
Why doesn't the compiler at least spit out a warning when you do it the wrong way?