Tag Archives: iOS

Lua for scripting NPC behaviour

With character movement looking good, now it’s time to give the non-player-characters (NPCs in role-playing game parlance) some behaviour.

I have the idea that monkeys might chase after bananas, foxes after chickens, etc.  And what platform game would be complete without animals mindlessly going back and forth patrolling their platform?

After reading this post at Stoked Software, I like the idea of using Lua to script NPC behaviour, even though I’m sure the simple behaviours above could be much more easily done without it.  I downloaded Lua following the instructions in the second part of that post, and added it to my project by renaming the src folder lua, and dragging it into my XCode project. (Unlike the post, I downloaded Lua 5.2.1, not 5.1.)

Note this is the bare bones DIY approach, not using any existing wrappers like Wax or Corona, which are nicely described at Lua Nova. I’ll try it this way until I get frustrated.

Some initial set up decisions:

  • I decided to include the header files directly into the GameModel, since we only want one Lua state.  I was originally thinking of having one per animal.
  • Whereas the post adds an instance variable lua_State *l, I am adding a @property (readwrite) lua_State *luaState.
  • Also, to keep the NPC control separate from the rest of my code (in case I decide one day to use something other than Lua), I have added an NPC category to GameElement.

Some hurdles:

  • I get lots of “Undefined symbols for architecture i386:” errors, starting with one for luaL_error, the first Lua call I was trying to make. I posted a question on stack overflow which quickly sorted this out: it is because Box2D is in C++, but Lua is in C.  So you need to wrap the Lua includes with an extern "C" command. (See stack overflow for the precise solution.) In fact you’ll also need to wrap all the upcoming C code in this.
  • I get the error “Use of undeclared identifier ‘self‘” when the static C function which communicates with Lua tries to access the GameElement self. This is OK, the C code doesn’t have any concept of self; it means you have to pass the relevant object from Lua to C. Fortunately, the Stoked Software blog explains how to do this in Part 3, for enemy ships.
  • ARC – I have used __bridge everywhere so there is no transfer of ownership, would appreciate any thoughts on whether that’s correct.
  • Lua 5.2 does not use luaL_register, but instead luaL_setfuncs.  There’s a good discussion on the Lua users wiki, but in the end I could not make this work, so had to go back to Lua 5.1. Any advice on how to apply this to Lua 5.2 would be gratefully received.
  • The Stoked Software blog gives great examples of how to send position data from Objective C to the Lua script, and how to get the Lua script to trigger methods in Objective C so long as the only parameter is a single object.  However, I want to set a target point using Lua.  I have stumbled upon one way to do this, hinted at by the Lua users wiki, using luaL_checknumber, e.g.
    static int setTarget(lua_State *luaState) {
        //
        // Parameters: The GameElement whose target you want to set
        //             The x-coordinate of the target
        //             The y-coordinate of the target
        //
        // Returns: nothing
        //
        GameElement *element = (__bridge GameElement *)lua_touserdata(luaState, 1);
        float x = luaL_checknumber(luaState, 2);
        float y = luaL_checknumber(luaState, 3);
        NSLog(@"target (%6.2f, %6.2f) %@ %p",x,y, element.appearName, element);
        [element touchLocation:Point3DMake(x,y,0.)];
        return 0;
    }

    and then from the Lua script, it’s just:

    function process(gameElement)
      game.setTarget(gameElement, 1.1, 0.5)
    end

    I have no idea if this is a good way to do it, but it works.

     

With those hurdles surmounted, I can now use Lua to script my NPC behaviour.  I just need to think what that should be…

One last note – I see that the license for Lua requests that users give Lua credit (see the download page).

  

Saving objects as property lists

Previously I have saved objects in Cocoa using NSEncoding.  However, for my game I want to save the GameModel’s layout as an intelligible text file.

One way to do this is to save the object as a property list (or plist), which is simply an NSDictionary.  The result is an XML file.

My game has a GameModel class and this has an NSArray of GameElements. So to pull this off, I added two methods to each of these classes.  The first returns a dictionary which describes the layout of the object.  For GameElement, it looks like this:

-(NSDictionary*) layoutDictionary {
  //
  // Returns keys and values of all the parts of the object 
  //    that need to be saved to define this game layout.
  // This only needs to be overridden by subclasses 
  //    if special structs need to be added (e.g. Point3D).
  // Apart from this, instead, subclasses should add to layoutKeys.
  //
  NSDictionary* dict1 = [self dictionaryWithValuesForKeys:self.layoutKeys];
  NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:dict1];
  dict[@"where"] = NSStringFromPoint3D(self.where);
  dict[@"class"] = NSStringFromClass([self class]);
  return dict;
}

It uses the key-value coding (KVC) method dictionaryWithValuesForKeys, which returns the values of the object’s own methods or variables.  I declare which properties are important to save in the layoutKeys variable, which I set up in the GameElement initialisation.

However… you can see there is some special handling of the where struct above.  The reason is that while an NSDictionary can happily have any object in it, if you want to write it out as a plist file, you must only have “plist objects” – NSData, NSString, NSNumber, NSDate, NSArray, NSDictionary and the like. If “where” was in the layoutKeys, the first line above would happily add an NSValue object containing the where struct’s data.  But you could not write this out.

It would be great if you could add custom plist objects.  Please let me know if you know how to do this.  In the absence of this, I have written functions to convert the struct into a plist object (an NSString), and back again, instead. For CGPoint these functions already exist.

The second function then creates an object from a dictionary, for example:

+(GameElement*) elementWithLayoutDictionary:(NSDictionary*)dict inModel:(GameModel*)model {
    //
    // Creates an element, given the relevant piece of the game layout dictionary, and the model.
    // This needs to be overridden by subclasses
    //
    Point3D where = Point3DFromNSString([dict valueForKey:@"where"]);
    GameElement* element = [[self class] elementNamed:dict[@"name"] at:where inModel:model];
    element.scale = [[dict valueForKey:@"scale"] floatValue];
    return element;
}

The GameModel also has layoutDictionary and modelWithLayoutDictionary: functions, which loop through the array of GameElements, e.g.

+(GameModel*) modelWithLayoutDictionary:(NSDictionary*)dict {
    int elementNumber = 1;
    while (NSDictionary* elementDict = [dict valueForKey:
                [NSString stringWithFormat:@"Element-%d", elementNumber]]) {
        [self addElement:[NSClassFromString(elementDict[@"class"]) 
                elementWithLayoutDictionary:elementDict inModel:self]];
        elementNumber++;
    }
}

(You can see that this implementation allows for subclassing of the GameElements.)

That’s basically it.  I then write this out to a plist file using
[layoutDict writeToFile:path atomically:YES];
and read it in using
[NSDictionary dictionaryWithContentsOfFile:path].

I suspect this could be improved:

  • KVC allows for a one-to-many relationship.  Can I use this to remove my custom handling of the array?
  • Is there a way to remove the custom handling of non-plist-objects like the Point3D struct?
  • Perhaps this all comes for free if I used CoreData… but do you then lose control of the data format?

Any thoughts?

  

Unit testing private functions in Xcode 4

I have found myself in the uncomfortable position of declaring private methods in my .h files so that I can run tests on them, and have been looking for ways around this.

I’ve found discussions about handling this in C++ which have me thinking it is bad programming style to need to test private functions: instead, complex private functions should be moved to a new class where they are public. I like the intellectual purity of this approach, but I have to think about how to apply it in my case.

In the meantime, I would like to have two types of unit tests, those on private functions and those on public functions.  Only the public functions define what the class does, of course, but unexpected failure of tests on the private functions can help me quickly find and debug problems.

Fortunately, another Stack Overflow post pointed me to a solution for Objective C.  I declared a new category (“Private”), put the private methods in the classname+Private.h header file, and deleted the classname+Private.m file.  I then import this .h file in classname.m, as well as the unit tests.

[Note the first time I read that post, I misinterpreted it, and created a .h and a .m file for the new category, and tried to implement the private functions in this new .m file.  This approach doesn't solve the original problem at all.]

Using a “Private” category feels like a nice solution, since I could have declared those private functions in a class extension at the top of the classname.m file anyway.  Adding the Private category just allows the unit tests to access them too.

Nonetheless, I’d appreciate any comments on the benefits are of the purer approach of moving complex private functions into a new class…

  

Reloading table data in a UITableView

Work.

I have been using a UITableView and had quite a bit of trouble getting its entries to update.  Just calling the table view’s reloadData method didn’t seem change anything on-screen.  In the end I found it works fine to manually call tableView:cellForRowAtIndexPath: for each entry you want to update; the following sample code (placed in the relevant view controller) works for a table with only one section in it. myTableView is an IBOutlet.

-(void) entriesUpdated:(NSNotification*) notification {
    int numRows = [self.myTableView numberOfRowsInSection:0];
    [self.myTableView reloadData];
    for (int i=0; i < numRows; i++) {
        [self tableView:self.myTableView cellForRowAtIndexPath:
              [NSIndexPath indexPathForRow:i inSection:0]];
    }
    [self.myTableView reloadSections:
          [NSIndexSet indexSetWithIndex:0] withRowAnimation:
          UITableViewRowAnimationNone];
}

Note this code has (at least) one drawback – it can call tableView:cellForRowAtIndexPath: with a row beyond the table’s size, if rows have been deleted. As a result, that code must explicitly check that the row is valid.

Surely this is not the way you’re meant to do it though? Has anyone else had this problem, and can you point me to a cleaner solution?