Tag Archives: xcode

Chromodyne… HD!

Well, the iPad is out and Chromodyne was successfully ported after a marathon session of epic proportions. Amusingly, Chromodyne HD was submitted after Chromodyne v1.1 and was approved before. Some may say I amuse easily, but I was amused.

The Port

Thanks to some experience writing game engines for other platforms before, about 90-95% of Chromodyne’s graphics code was already resolution independent. After updating my XCode to the 3.2 Gold Master, I clicked the handy little “Convert this project to iPad” menu option and was playing Chromodyne in the simulator in mere minutes! Though everything else was really horrible looking because none of the 2D assets were scaled properly and some of the menus looked like crap on the huge screen.

So really, most of my time was spent creating high-res 2D graphics (even though the cutscenes are pixel art, for the most part, those are seriously high-def pixels!) and fiddling with the perspective/view on the gamefield because it was way too freaking big keeping the same perspective as the iPhone version.

I don’t know about the final build yet, but the simulator in the GM release of the SDK didn’t have 3D acceleration! I can understand why some devs were reluctant to release their apps sight-unseen to the App Store.

The iPad Only Version

If anyone actually wonders why I went with a stand-alone iPad version of Chromodyne, the biggest motivator is that the app bundle for the HD version with its 1024×768 graphics assets is larger than the 20 MB OTA limit. Basically I still want people to be able to get the iPhone version over 3G.

The Price

I’m also selling Chromodyne HD for $1.99 instead of 99 cents. I figure the larger, higher resolution game experience warrants a slightly higher price point. We’ll see how that plays out in the days to come anyway… at least I can have a sale at some point without going directly to free. Definitely something I regret when I priced Chromodyne originally.

The Numbers

I’m half-tempted to post sales numbers for Chromodyne HD as time wears on. If anything to see how things are going. I’ve seen that the game lists for the iPad don’t have any top lists for subcategories yet, which is pretty bad news for small devs such as myself. Sales for Chromodyne have not been anything to write home about, but they’ve been steady at least.

Anyway it’s been a fairly exciting few days, and at least I can say I was here from the start. Whatever that actually means, only time will tell.


Spinning Wheels

Much progress was to be had over the weekend, also much frustration… but my game code pretty much works on my iPod now! I’m so excited 😀

First of all, I’ve decided to create a new law. Let’s call this law Colin’s First Law of New Platform Development. It is thus: “When developing on a new platform and your code fails in a spectacular fashion, don’t assume it is the platform’s fault for being new and strange. It is in fact because you’re an idiot and didn’t initialize a variable properly.” I’ll just go ahead and leave this here.

In other news, I will now tell you how to make a fairly decent method to shuttle input from the main thread to your game thread when working on the iPhone OS. It took me a while to hunt it down, so I’m sure if this ever shows up in Teh Googles someone might find it useful.

First of all, I created a class which is basically a FIFO of “event” objects. It’s pretty basic, but it will do the trick.

Initially, I figured all I needed was a boolean variable in the FIFO to let the system know if the FIFO was busy. Boy howdy was I wrong. You see, I discovered that the variable itself was being accessed simultaneously by the view controller and the game code causing it to crash horribly. So I’m like… clearly people do this sort of thing all the time, I just need to keep searching until I find a mechanism that allows this sort of thing. After some searching I learned about atomic operations, or operations that are guaranteed to happen within one processor cycle. This guarantees that only one thread will be operating on the variable at one time, thus preventing Michael Bay levels of explosive action in your code.

So, where do we find these atomic operations? Thankfully Apple has thoughtfully included some in the OS. I’m sure there are more elsewhere, but for my code I decided to use the functions in the scarily located <libkern/OSAtomic.h>. Really though, it’s not so scary! What we’re going to do is use a spinlock to resolve resource contention (the resource being our FIFO). Basically we give our game code and the view controller a pointer to an OSSpinLock variable and they both use OSSpinLockLock(OSSpinLock *); to fight it out for who gets first crack at the buffer. The reason I chose OSAtomic functions is because they are relatively lightweight, and this sort of resource sharing is fairly simple.

Anyway! To get this to work, you need to declare an OSSpinLock variable (it’s basically an integer) somewhere and pass a pointer to it to your view controller and your game code. Also you have to do the same with your event queue object. Because your view controller will probably be trying to send touch events before your game code has fully initialized, it is best to have the view controller call the functions to init the spinlock and the event queue.

A word of warning, most of my game code is in C++, as I’m really not very comfortable with Obj-C atm, but C++ code will happily co-exist with your Obj-C code. The only major caveat is if you’re calling C++ inside your Obj-C objects, the implementation files have to be .mm, not just .m so they are compiled as Objective-C++. Otherwise the compiler will just sit there and stare at you funny. This spinlock method should work with straight Obj-C too though!

Okay so I’ve created a few simple functions (in C!) to initialize and pass around the spinlock and the event queue. They live in eventsync.cpp:

#include "eventsync.h" //This includes OSAtomic.h and the header for the event queue
 
static OSSpinLock *lock; //static so it never goes away
static CGEventQueue *uiEventQueue; //same here
 
CGEventQueue *getEventQueue()
{
  return uiEventQueue;
}
CGEventQueue *getEventQueueAndInit()
{
   uiEventQueue = new CGEventQueue;
   return uiEventQueue;
}
OSSpinLock *getSpinLockAndInit()
{
   lock = OS_SPINLOCK_INIT;
   return &lock;
}
OSSpinLock *getSpinLock()
{
   return &lock;
}

Now that that’s sorted out it’s pretty easy to get started. In your view’s interface add a pointer for an OSSpinLock and your queue object. Then in the view’s init code (in my case initWithCoder), call getSpinLockAndInit() and getEventQueueAndInit() to set up your view’s pointers (in this case, lock and eventQueue). In your game code you’ll want to call getSpinLock() and getEventQueue().

WARNING: Stargate references abound. Now that you’ve spanned your two threads with the code equivalent of a wormhole, just like in Stargate, they can only work in one direction. So your spinlock is going to act like a DHD and will activate the wormhole and send SG-1 in the right direction, hopefully avoiding killing some hapless team member in the process.

Basically what we will do is use OSSpinLockLock() to try and set the spinlock variable. If the spinlock is already locked, it is in use somewhere else, so OSSpinLockLock() will loop until it is no longer locked. It is our responsibility to unlock the spinlock in each thread when we’re done with it or everything will stop working.

So before this post gets even longer, here’s the upshot. When we overload touchesBegan, touchesMoved, and touchesEnded (or other input methods) we’re going to do something like this:

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
   UITouch *touch = [[event allTouches] anyObject];
   CGPoint touchLocation = [touch locationInView:touch.view];
 
   OSSpinLockLock(lock);
   //when the lock is free we can safely push events into the queue
   TouchEvent *ev = new TouchEvent;
   ev->type = CGE_TOUCHDOWN;
   ev->x = touchLocation.x;
   ev->y = touchLocation.y;
   eventQueue->pushEvent(ev);
   OSSpinLockUnlock(lock);//important to release the lock!
}

In our game code we’d have something like:

OSSpinLockLock(lock);
TouchEvent *ev;
while(eventQueue->getNumEvents())
{
   switch(eventQueue->topEvent()->type)
   {
      case CGE_TOUCHDOWN:
         ev = static_cast<TouchEvent *>(eventQueue->topEvent());
         //do stuff with the event
         break;
      }
      //Handle other events here
      eventQueue->delTopEvent();
   }
}
OSSpinLockUnlock(lock);

It’s as simple as that!

Til next time :)

Whee!

Well, I got my iPod Touch on Wednesday, so I spent about an hour to get a provisioning profile from Apple and to set up Xcode to work with that. I started an Open GL ES project and copied my 3D engine code into it and just kept beating it with a sledgehammer until it compiled. It was actually a fairly easy process overall.

I had already replaced all my immediate mode OpenGL calls with vertex arrays, but I discovered much to my horror that I was still using some unsupported calls. I cleaned that up and I figured out how to install GLU for the iPhone in the simulator and iPhone OS SDKs as well.

Then I realized that the iPhone’s GPU only supports power of two textures… oh great shades of 1998! I consulted the intertubes and found out how to use some GraphicsServices calls to scale my textures to a more appropriate size. This is in no way optimal mind you! Once everything is working properly as is, I’ll get a start on optimizing my textures and stuff like that, but this is a great start.

The next night I decided to start using a thread to run my game code instead of using the timer method as it creates a lot of overhead. If you end up having trouble with this, I have discovered for some reason you should initialize your GL buffers in the main thread instead of the game thread. I’m thinking it’s some sort of resource synchronization issue with the main thread and the forked thread.

So right now I sit with a working 3D engine and my next step is to capture touch input from the main thread and start pushing it into an event queue for my game thread to nom on. I suspect I will need a blocking mechanism while the game thread is doing it’s thing.