Monday, January 28, 2013

Game Music



Wow - nearly the end of January and I haven't posted here for a week!  Time flies when you're hacking.

This is a really quick post just to frame a quick recording I made of some basic video game music.

I didn't want to just post the music as a raw sound file so I dropped it into a quick video format so I could put it on YouTube, and that also gave me a bit of an opportunity to mention the technologies I used to make the music.

I have a Yamaha PSR-E413 Keyboard, which is a very basic guy - just fine for what I need.  I can play it stand alone as a keyboard but I mostly use it as a midi to drive Garageband.  Because I am very low on the skill level - I can do a few basic chords & scales, that is it - I love the GarageBand ability to do multiple takes until you get something you like.

For this I chose a basic scale and just fiddled about until I found some notes I liked, then worked out a rhythm to suit.  I used GarageBands metronome to get things in time, and then turned that off when I exported the recording.

As I mention in the video to get the atmospheric and futuristic feel I wanted, I used a synth pad.  GarageBand comes with a few but I wanted to be able to tweak it a bit so I picked up NLog Poly Synth from http://www.temporubato.com/

The result is pretty average but good enough to use as a place holder for the early stages of the game, and to give a pro musician an idea of the sort of thing I want if I get funds for a bit of polish on the game.

Thursday, January 17, 2013

A couple of notes about stores

A few posts ago I talked about how you can use Apple's core data in games by employing the techniques shown in the XCode Core-Data command line example.

That example works well because it doesn't assume any code templates - and if you're coding a game you're probably not using a core data template - and also it doesn't assume using utility classes like NSPersistentDocument.

However some of the file saving semantics of Core Data stores are pretty weird, so I thought I would document my current findings here.  The relationship between the NSPersistentStore object, and the on-disk file are also a bit obscure in the documentation.  So call this the "what they don't tell you in the Apple documentation" article.

Stores and Coordinators

All the three functions I discuss below are on NSPersistentStoreCoordinator.  I suggest never saving a reference to your store object.  The action of saving or moving a store will likely invalidate any instance of NSPersistentStore you have saved.  Instead do something like this:

- (NSPersistentStore *)store
{
    NSArray *stores = [[m_managedObjectContext persistentStoreCoordinator] persistentStores];
    
    NSAssert([stores count] <= 1, @"Each world can have (at most) one backing store!");
    return [stores lastObject];
}


In other words, use the coordinator as the place for all your store operations - not the instances of the stores themselves.  Weird - maybe but that is how Cocoa does it.

Who ya Gonna Call?

The documentation says: Adds a new persistent store of a specified type at a given location, and returns the new store.

What the documentation doesn't make specifically clear is that this function will create the on-disk file, in this case an SQLite data store if required - but it will also just transparently open the existing on-disk file if there is one there.  Nice.

Here the relation with the store object is clear: it creates the on-disk file (or opens an existing one) and returns a new store object.  You can use the returned store object for checking success, but as mentioned above I suggest not saving a reference to it.

This is your go-to function for opening a data store file, existent or not, given its location.  In the simple case you know your type and can simply specify it - eg NSSQLiteStoreType, and you don't have any configuration or options.

There's no need to use NSFileManager's exists functions or anything like that, to check for existence of the file first.  Of course you will need to make sure that any intermediate directories in the path for the URL do exist.

If you want to do basic error checking just test the returned value for nil - there's no need to get the error argument unless you want verbose error reporting.  To understand how this works simply doing the two modes (initial creation versus subsequent re-opening) checkout the main.cpp of the XCode Core-Data command line example.  Might not seem like a big deal, but as these are databases which normally require a bunch of setup, its nice to have a one-stop-shop for opening like this.

The Mad and the Bad

The documentation says: Sets the URL for a given persistent store.

No shit, Sherlock!  This is one of the least useful functions, and most poorly documented, on NSPersistentStoreCoordinator.  Basically the intent of it seems to be a very cheap way to open already existing data store files, where you absolutely know your existing store object has the right setup, and you know for sure you have an existing store file.  The fact it has a BOOL return looks promising for light-weight error detection (but it turns out not to be).

Here you must already have a store object.  Even though these calls are on NSPersistentStoreCoordinator, which can make new store objects, this call is not going to do that - you must have an existing store.  What if you don't save before calling this?  Changes to the store might get lost - in some cases.  See the documentation but its got to do with whether or not you have an atomic store - basically SQLite is non-atomic.

The arguments are the URL to open, and an existing store object - that is an instance of NSPersistentStore.  But what beats me is in what circumstances would you have a valid instance of a store object, but either not have it opened to a backing store URL, or want to just cut that store file loose?

Another problem is you must have an existing backing file - which the documentation says.  What it doesn't say is what happens if you don't?  Well, the function quite happily returns true if the file doesn't exist - huh??? - and then when you try to call save on your NSManagedObjectContext at a later point you get an exception.  Joy.

If anyone can find a great use for this function tell me - because as far as I can tell its mad, bad and dangerous to know.

Saving As

The documentation says: Moves a persistent store to a new location, changing the storage type if necessary.

This call is basically a addPersistentStoreWithType:configuration:URL:options:error: call using your old stores type, followed by a removePersistentStore:error: call on the old store (assuming you don't change the store type).

What I mean by that is if you have a store saved at URL A and  you want to make a copy of it at URL B, and do subsequent saves and operations on that new URL B, then this call will do what you need.

Here you are going to lose the store you pass in - but if you follow the idiom above of not saving a reference to your stores that is no problem.  Rather than BOOL this returns a new store which you can check against nil if you want to determine success.

Obviously its also the go to function if you need to migrate between store types for some reason - though I'm not really sure why you'd want to do that so much.  In most applications you decide on say SQLite and stay with it.

Conclusions

  • Use addPersistentStoreWithType:configuration:URL:options:error: to open all your data files, and also to create them the first time.  Don't keep a member variable of the store it returns.
  • Once a file is open, you can save the data to it by calling save: on your NSManagedObjectContext.  That will cause the attached stores to save to whatever URL's they're opened onto.
  • To do a save as use migratePersistentStore:toURL:options:withType:error: and pass in your existing store object, obtained from the - (NSPersistentStore *)store function listed above.
  • Closing files is not necessary - just let the objects go out of scope and ARC plus their destructors will clean everything up.  Make sure you save first obviously.
  • I suggest hiding all references to stores inside a class, and doing everything through NSPersistentStoreCoordinator.
Farewell and may all your data persist!

Tuesday, January 15, 2013

The Solo Gig


Last week or so I've been finishing up at my last full-time paying work, and now I embark on the solo gig.

Today was my first day where my time was not dictated by a clock and a timesheet.

I want to do some drawing every day, doesn't matter how much of it is teh sux - it just gots ta be done.  Here's some rushes.

Its the only way to free up the hands, and get the mind & eye really looking and seeing.  So as painful as it is getting back into it - has to be done.

Between doing some grocery shopping and checking the mail I stopped in at a local cafe for a coffee and BLT.  I sketched a couple of things around the coffee shop.

Now back at home, I had this old shot of me (from just outside the coffee shop a few evenings ago) shot at a funny angle with my cell-phone, and I thought I'd try doing a freehand sketch loosely based off it.

Drawing faces and heads usually follows a formula but for games and comics often the characters are in a strange perspective with the camera or eye positioned underneath (as in this picture) or above - with the character jumping or flying toward it.

When this happens instead of the eyes being positioned exactly half-way down the oval of the face as is usual for a front-on depiction, you get the eyes right up around a 1/3 or so from the top of the head.  That's where you have to use extra care to make sure the perspective and proportions are right.

I didn't like my real hair in this photo so I have gone for a more manga sort of thing, and the result is that the line-work for the hair doesn't look right.  Even though I wanted a "hair falling in my eyes" look, its too heavy over the forehead.  I think from this angle you'd kind of see up under the fringe: and that's quite hard to do.

Also in the under shot like this the tendons and muscles of the neck are more prominent and occupy much more real-estate in the panel.  The jaw & mouth is also more prominent, while the eyes - usually a focus - are smaller and further away.  Here I've made the eyes a bit too small and close together tho' that may be because the hair is framing the top of the head as being too wide.  For the from down-under perspective the head winds up being more egg-shaped: getting narrower at the top, and I haven't really done that here again because of the hair.

I'm using Manga Studio here so I could easily do some work to improve the proportions by grabbing chunks of the line work and moving it round, but as its just a drawing exercise for throwaway purposes there is no point in putting that time in.

I'm hoping this will be a baseline and future posts will show some improvement in my drawing.

Oh, and welcome to 2013.  :-)