Monday, December 03, 2012

Scripting iOS Games With Lua


A while back @celsiusgs published a blog entry discussing using C++ polymorphism for pluggable AI in his upcoming game Drifter. In a nutshell, each ship in the game is controlled by a ShipObject that has the ship’s state as well as methods (“inputs”) to control the ship (throttle, steering, etc.). This class provies a process method that updates ship state (presumably based on some sort of physical model and the current state and inputs). For player controlled ships, the ShipObject inputs are driven by touch controls. For instance, when the player touches the throttle control the throttleControl method(s) would be called (presumably).
This separation of the physical controls that respond to user touches from the ship controller makes it easy to plug in AI code to control NPC ships. For NPC ships, the ShipController object is assigned an AI object that accesses the ShipController to control the ship’s state. This AI object implements a process method that is called from the ShipObject’s update method once per game loop.
To make this as flexible as possible, @celsiusgs has created a generic AI class that provides a virtual process method that is implemented by classes inheriting from this base class. This allows him to simply attache different AI implementations to each NPC ship to get different behaviour.
The decoupled nature of this approach provides another benefit that @celsiusgs mentions: it provides an easy entry point for replacing C++ code with a scripting system.
I won’t get into a discussion here of the pros and cons of using an embedded scripting system. I like to think that there are more reasons supporting using one than reasons against it. For this appliction, however, there is one huge benefit that definitely makes it worth doing.
Implementing even simple AI is nontrivial and often involves a lot of iterations as you try to weed out “dumb” behavior. An NPC ship repeatedly bumping it’s “head” into an asteroid tends to spoil a games immersiveness. Executing test runs over and over again is particular painful on the iOS platform if the code under test needs to be compiled every run.
If the code is run from a script, however, these scripts can be read from a webserver every time they are executed, so the main program does not need to be rebuilt every run. In fact, if the code is written to support it, it may not even need to be restarted, but merely reset. This allows the AI coder to make changes to his/her scripts and rapidly test the effects.
By far the most popular embedded scripting language for game development is Lua. I won’t describe Lua in much detail here, instead I’ll refer the reader to the main Lua site. Suffice it to say, it has three properties that make it a good choice for embedding scripting in a game:
  • It was designed as an embedded language from the ground up
  • It is based on standard C/C++ code and is therefore runs on many platforms
  • It is lightweight and very fast
In this three part blog entry I am going to demonstrate how to embed Lua into an iOS app, with particular emphasis on a system like the one in Drifter, albeit using much simpler game mechanics. If you want to follow along in Xcode the project can be cloned from github at git@github.com:indiejames/TestLua.git.

First things first, we need a game platform in which to embed our lua interpreter. For this demonstration, I will create a very simple sample program using a single view. I want to keep the main program as simple as possible to focus on the lua portion, so this program won’t have any OpenGL or other graphics and only a rudimentary user interface.
I’ll skip using storyboards or generating tests as these are outside the scope of this discussion.
At this point we have a simple single view application with the standard boilerplate code. Aside from the startup code and support files, this consists of just two Objective C classes, AppDelegate and ViewController. These should be familar to anyone working in iOS, so I won’t discuss their core functionality here. If you don’t know how these work, check at one of the many resources related to iOS development.
I won’t be changing the AppDelegate class at all for this example so it is not shown here. All our changes to the boilerplate code will be done in ViewController. The bare bones code for this class is shown here:

ViewController.h
1
2
3
4
5
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end
ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#import "ViewController.h"

@implementation ViewController

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
  [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
  [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

@end

This is where we will load and invoke our Lua interpreter, but for now let’s set up our simple game mechanics. For this we will create a new class that we will call ShipController, which will manage the state of our ship and respond to inputs.
So now we have an empty class as shown here:

ShipController.h
1
2
3
4
5
#import <Foundation/Foundation.h>

@interface ShipController : NSObject

@end
ShipController.m
1
2
3
4
5
#import "ShipController.h"

@implementation ShipController

@end

I want to keep the game mechanics simple so I can focus on the scripting, so I am going to create a game in which ships move in two dimensions. We will use the OpenGL convention of the y-axis pointing “up”. All ships will have an intrinsic “speed” which determines how far they move in response to inputs. The player will have four buttons (Left, Right, Up, Down) that can be pressed to control the ship. When the player presses one of the buttons, the ship will move a certain number of units in that direction, where this number is given by the ship’s intrinsic speed. For instance, if the player’s ship has a speed of four, pressing the Up button twice will increase the y value of the ship’s postion by eight units. Note that we won’t be modeling velocity or accelaration here - the ship simply changes its position based on its inputs and its intrinsic speed.
We add the following code to the ShipController.h file to add instance variables to hold the state of ship, along with property declarations to make them available to other classes.

ShipController.h State Variables
1
2
3
4
5
6
7
8
9
10
@interface ShipController : NSObject {
    float x;
    float y;
    float speed;
    NSString *name;
}

@property (readonly) float x;
@property (readonly) float y;
@property (readonly) NSString *name;

We have variables x and y to store our ship’s position, speed which defines the instrinsic speed of the ship (NOT its velocity) and a name member by which we will distinguish different ships in our output.
Our property declarations will allow us to output the position of the ships by name periodically so we may observe their behaviour. We will not be generating any graphical output in this example.
In addition to the state for our ships, we need to provide methods to represent the “inputs” with which we can control it. We add the following to the header file:

ShipController.h Methods
1
2
3
4
5
-(id) initWithX:(float)x Y:(float)y Speed:(float)speed Name:(NSString *)name;
-(IBAction)pressLeftButton;
-(IBAction)pressRightButton;
-(IBAction)pressTopButton;
-(IBAction)pressBottomButton;

The first method is our init method and it sets the initial state (x,y) for a ship as well as it’s intrinsic speed and its name. The next four methods are the “input” methods that will be called whenever someone presses one of the buttons. Notice that there is no process method. Because we are using such a simple physics model, I am going to simply update the ships position directly every time one of the button press methods are called. A more sophisticated simulation would implement a processmethod ala Drifter to update the ships state once every game loop.
The implementation for these methods are shown here:

ShipController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#import "ShipController.h"

@implementation ShipController

@synthesize x, y, name;

-(id) initWithX:(float)_x Y:(float)_y Speed:(float)_s Name:(NSString *)_name{
    self = [super init];
    if (self) {
        x = _x;
        y = _y;
        speed = _s;
        name = _name;
        [name retain];
    }

    return self;
}

-(void) pressLeftButton {
    NSLog(@"Left button pressed for ship %@", self.name);
    x = x - speed;
}


-(void) pressRightButton {
    NSLog(@"Right button pressed for ship %@", self.name);
    x = x + speed;
}

-(void) pressTopButton {
    NSLog(@"Top button pressed for ship %@", self.name);
    y = y + speed;
}

-(void) pressBottomButton {
    NSLog(@"Bottom button pressed for ship %@", self.name);
    y = y - speed;
}

@end

The init method sets the initial state (x,y) the only model parameter, speed, and the name for the ship. The button press methods log the action and direcctly manipulate the ship’s state.
Now we modify our ViewController to instantiate a ShipController for the player’s ship. First we import the header for or ShipController class, then declare a global variable to hold a pointer to our player’s ship controller. Obviously using a global here is bad practice, but we do so now to keep things simple. Finally we instantiate the global in the viewDidLoad method of the ViewController.

ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "ShipController.h"

ShipController *playerShipController;

//////////////
//////////////
...

- (void)viewDidLoad
{
    [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

    // create the ship for the player
    playerShipController = [[ShipController alloc] initWithX:100 Y:100 Speed:2.0 Name:@"player_ship"];

}

Now that we have our ship’s controller we need to add a way for the user to manipulate it. To this end we add four simple buttons to our interface and wire them to our view controller. First we add four actions to the view controller (one for each button).

ViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController{
    NSTimer *timer;
}


-(IBAction)pressLeftButton:(id)sender;
-(IBAction)pressRightButton:(id)sender;
-(IBAction)pressTopButton:(id)sender;
-(IBAction)pressBottomButton:(id)sender;
@end
ViewController.m Actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# pragma mark - Button actions

-(void) pressLeftButton:(id) sender {
    [playerShipController pressLeftButton];
}

-(void) pressRightButton:(id) sender {
    [playerShipController pressRightButton];
}

-(void) pressTopButton:(id) sender {
    [playerShipController pressTopButton];
}

-(void) pressBottomButton:(id) sender {
    [playerShipController pressBottomButton];
}

These actions simply delegate to the ShipController class by calling the corresponding pressButton actions. We have also added an NSTimer to our ViewController. This will be used later to set up the game loop.
Now we use Interface Builder to add four buttons two our view and connect them to our actions.
We can test our game by executing it and pressing a few buttons. The output from this run is given here:
2012-02-04 22:27:46.348 TestLua[24376:f803] Top button pressed for ship player_ship
2012-02-04 22:27:47.028 TestLua[24376:f803] Right button pressed for ship player_ship
2012-02-04 22:27:47.676 TestLua[24376:f803] Bottom button pressed for ship player_ship
2012-02-04 22:27:48.260 TestLua[24376:f803] Left button pressed for ship player_ship
The last thing we’ll do before adding our Lua interpreter is to set up a game loop. We simply initialize the timer in the viewDidLoad method of our ViewController:

ViewController.m Game Loop
1
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(runLoop:) userInfo:nil repeats:YES];

This timer will execute the runLoop method every second. Not exactly blazing, but since we aren’t going to be doing graphics, this is more than enough.
The runLoop method is given here:

Game Run Loop
1
2
3
4
-(void)runLoop:(id)sender {

    NSLog(@"Player ship at (%f,%f)", playerShipController.x, playerShipController.y);
}

This simply writes out he position of the player’s ship every time it executes. So now if we run the game and press the up button a couple of times, we get the following:
2012-02-04 22:52:08.802 TestLua[25770:f803] Player ship at (100.000000,100.000000)
2012-02-04 22:52:09.508 TestLua[25770:f803] Top button pressed for ship player_ship
2012-02-04 22:52:09.801 TestLua[25770:f803] Player ship at (100.000000,102.000000)
2012-02-04 22:52:10.166 TestLua[25770:f803] Top button pressed for ship player_ship
2012-02-04 22:52:10.801 TestLua[25770:f803] Player ship at (100.000000,104.000000)
2012-02-04 22:52:11.801 TestLua[25770:f803] Player ship at (100.000000,104.000000)
2012-02-04 22:52:12.802 TestLua[25770:f803] Player ship at (100.000000,104.000000)
2012-02-04 22:52:13.801 TestLua[25770:f803] Player ship at (100.000000,104.000000)
Now we have our (very simple) game working to the point that we can steer our ship around using our buttons. In Part II we will get to the heart of the matter and add our Lua interpreter and some bindings that will allow us to use Lua scripts to interact with our game. Finally, in part III, we will wrap this up in a new Lua type that will allow us to easily control NPC ships in our scripts.


 | COMMENTS

In part I of this three part post, I introduced a simple game framework to which we are going to add Lua scripting. Now we are going to get right to it and cover all the steps necesary to get Lua scripting working. This will include embedding the Lua interpreter in the Xcode project, running Lua scripts from Objective C code, and accessing game state (ship position) in Lua scripts via a C function we will write and bind to Lua.

The first thing we need to do is grab a copy of the Lua source here. I’m using version 5.1. Version 5.2 was just released at the end of 2011, but the C binding system has changed somewhat so I am not using it here.
Once you have downloaded and untarred the archive, rename the src directory lua. Then drag the lua directory from Finder into your Xcode project. Be sure to uncheck the “create external build system box” and have Xcode copy the files and create a group:
Now open the lua group and delete the Makefile, lua.c, and luac.c files. We wont be using the Makefile to build the source and we don’t need lua.c or luac.c as these are the code for the standalone interpreter.
Now build the project using Xcode. It should build without issues. Congratulations! You’ve just embedded Lua in your iOS project! Of course, it isn’t actually doing anything yet, so let’s get to that.
One of the nice things about embedded Lua is that you can choose just how tightly you want to bind your code to Lua. Lua provides a C API that lets you control this. In the simplest case, you can call Lua scripts from C and get the results back. At the next level, you can have your Lua scripts invoke C functions that you bind to Lua. Finally, you can define new Lua types that not only invoke C functions, but instantiate C++/Objective C objects and delegate processing to them. We will look at each of these levels in turn.
First, let’s just invoke the embedded interpreter to execute a simple Lua script. I won’t cover Lua syntax here as it is oustide the scope of this blog post, but suffice it to say that its syntax is similar enough to C that the reader should have no problem following along. Please refer to The Lua Programming Language or another reference for a comprehensive introduction.
As I mentioned, Lua provides a C API for interacting with the interpreter. Actually, it provides two APIs, the basic API and the auxilary API. The auxilary API adds convenience methods to the basic API that make it a bit easier to use.
We need to add a few imports and a declaration to our ViewController.h file.

ViewController.h with Lua Support
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import <UIKit/UIKit.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

@interface ViewController : UIViewController{
    lua_State *L;
    NSTimer *timer;
}

-(IBAction)pressLeftButton:(id)sender;
-(IBAction)pressRightButton:(id)sender;
-(IBAction)pressTopButton:(id)sender;
-(IBAction)pressBottomButton:(id)sender;

@end

One of the nice things about the Lua code is that it’s designed to be reentrant. Therefore it maintains no internal state. Instead, the interpreter state is maintained externally in a C struct called, appropriately, lua_State. The main program creates these and passes them to the interpreter with every call in the APIs. For this application, we will only need one instance and we add it as an instance variable for our ViewController. Ideally we would probably create a separate class to handle all of our Lua interaction, but in this example we are simply going to do everything in the ViewController.
Add the following lines to the viewDidLoad method of ViewController.m before the call that creates the NSTimer:

ViewController.m Lua Init and Test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// initialize Lua and our load our lua file
L = luaL_newstate(); // create a new state structure for the interpreter
luaL_openlibs(L); // load all the basic libraries into the interpreter

lua_settop(L, 0);

int err;

err = luaL_loadstring(L, "print(\"Hello, world.\")");
if (0 != err) {
    luaL_error(L, "cannot compile lua file: %s",
               lua_tostring(L, -1));
  return;
}


err = lua_pcall(L, 0, 0, 0);
if (0 != err) {
  luaL_error(L, "cannot run lua file: %s",
               lua_tostring(L, -1));
  return;
}

All of the methods in the basic API have names that start with lua_, while all methods in the auxillary API have names that start with luaL_. The first thing we need to do is inovke luaL_newstate which instantiates a lua state structure for us and returns a pointer to it. The next call is to luaL_openlibs, which opens all the basic Lua libraries - we will use this to inject our own C methods into Lua later.
The next call to lua_settop brings up a very important point that needs to be made. All passing of data from C to Lua and from Lua to C is done via a stack. When C code invokes a Lua scripted function it passes the arguments to the Lua function on the stack. It also reads values returned by the function from the stack.
Similarly, when a Lua script invokes a bound C function, it passes its arguments on the stack and reads its return values from the stack. The call to lua_settop simply tells Lua that the stack contains zero values, i.e., it’s empty.
The next call to luaL_loadstring compiles our one line “Hello, world.” Lua script and returns a nonzero error code if something went wrong. We check this code and use luaL_error to get a more meaningful error message if something went wrong. For now we are just providing the script in a hard-coded string. Later we will read this script from a file.
Finally, we execute the Lua script using lua_pcall. The p in lua_pcall stands for protected, which essentially means that if something goes wrong the interpreter will trap the error and return an error code instead of propagating the error upwards.
After adding these lines, run the program and you should see output like this:
Hello, world.
2012-02-05 15:23:07.899 TestLua[29603:f803] Player ship at (100.000000,100.000000)
2012-02-05 15:23:08.899 TestLua[29603:f803] Player ship at (100.000000,100.000000)
More progress! We have just run our first Lua code from within our iOS project! Now let’s do something a bit more useful. We are going to demonstrate how to bind a C method to Lua so we can call it from our scripts.
Let’s extend Lua so that it knows where our player ship is. Add the following function to ViewController.m.

ViewController.m Binding C Function to Lua
1
2
3
4
5
6
static int player_ship_position(lua_State *L){
    lua_pushnumber(L, playerShipController.x);
    lua_pushnumber(L, playerShipController.y);

    return 2;
}

This C funciton is declared static so it cannot be used outside of our ViewController and therefore does not need to be declared in a header. Remember, this is NOT an instance method. It implements the basic prototype for C functions that are bound to Lua - it takes a single lua_Stateargument and returns an int. This method does two things; it pushes the ship’s x and y coordinates on the stack and returns the number of items it has placed on the stack, 2. Objective C 2.0 properties work even inside a C function, so we can access the ship’s position using its properties x and y.
Now we have a function that will return the ship’s position to Lua via the stack, but we must first bind it to Lua before we can use it in a script. There are a couple of different ways to do this, but the most useful one if you are going to bind many functions (and we will) is to put them in an array and pass this array to the luaL_register function. So we add the following code to ViewController.m.

ViewController.m Binding Code
1
2
3
4
5
6
7
8
9
10
11
static const struct luaL_Reg shiplib_f [] = {
    {"player_ship_position", player_ship_position},
    {NULL, NULL}
};

int luaopen_mylib (lua_State *L){

    luaL_register(L, "ship", shiplib_f);

    return 1;
}

We declare an array of struct luaL_Reg which are structures containing a function to be bound and a name to which to bind it. This array is terminated by an entry with NULL values. We pass this array to the luaL_register function (macro, really) along with a lua_State and a name for the table that will contain the functions in the array.
We need to call the luaopen_mylib function before we run our script. The easy way to do that is to add it to the list of libs that automatically get loaded when the Lua interpreter starts. This can be done by modifying the linit.c file in our lua directory like so:

linit.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#define linit_c
#define LUA_LIB

#include "lua.h"

#include "lualib.h"
#include "lauxlib.h"

extern int luaopen_mylib (lua_State *L);


static const luaL_Reg lualibs[] = {
  {"", luaopen_base},
  {LUA_LOADLIBNAME, luaopen_package},
  {LUA_TABLIBNAME, luaopen_table},
  {LUA_IOLIBNAME, luaopen_io},
  {LUA_OSLIBNAME, luaopen_os},
  {LUA_STRLIBNAME, luaopen_string},
  {LUA_MATHLIBNAME, luaopen_math},
  {LUA_DBLIBNAME, luaopen_debug},
  {"ship", luaopen_mylib},
  {NULL, NULL}
};


LUALIB_API void luaL_openlibs (lua_State *L) {
  const luaL_Reg *lib = lualibs;
  for (; lib->func; lib++) {
    lua_pushcfunction(L, lib->func);
    lua_pushstring(L, lib->name);
    lua_call(L, 1, 0);
  }
}

The only changes we have made here are to add {"ship", luaopen_mylib}, to the lualibs array and to add the extern int luaopen_mylib (lua_State *L) declaration so the linker can do its thing.
Now we are going to modify our Lua script to call our new method. At the same time, we will load our script from a file instead of a hard-coded string. First, let’s make the changes to ViewController.m. Replace the call to luaL_loadstring with the following.

ViewController.m Loading Lua Script From File
1
2
3
NSString *luaFilePath = [[NSBundle mainBundle] pathForResource:@"ship" ofType:@"lua"];

err = luaL_loadfile(L, [luaFilePath cStringUsingEncoding:[NSString defaultCStringEncoding]]);

This will load and execute the script in the file ship.lua. Now let’s create this file.

ship.lua
1
2
3
4
5
6
7
8
9
function print_player_ship_position()

    -- get the location of the player's ship
    player_x, player_y = ship.player_ship_position()

    -- print position to console
    print(string.format("player ship is at (%f, %f)", player_x, player_y))

end

This file defines a single lua function which will use our bound player_ship_position method to get the x,y position of the ship and print it out.
Now we need to execute this method in our run loop:

ViewController.m run loop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(void)runLoop:(id)sender {

    NSLog(@"Player ship at (%f,%f)", playerShipController.x, playerShipController.y);
    // put the pointer to the lua function we want on top of the stack
    lua_getglobal(L,"print_player_ship_position");

    // call the function on top of the stack
    int err = lua_pcall(L, 0, 0, 0);
  if (0 != err) {
      luaL_error(L, "cannot run lua file: %s",
                   lua_tostring(L, -1));
      return;
  }
}

Running the program and pushing the up button a couple of times produces the following:
2012-02-05 20:09:52.370 TestLua[32429:f803] Player ship at (100.000000,100.000000)
Lua says player ship is at (100.000000, 100.000000)
2012-02-05 20:09:52.892 TestLua[32429:f803] Top button pressed for ship player_ship
2012-02-05 20:09:53.310 TestLua[32429:f803] Top button pressed for ship player_ship
2012-02-05 20:09:53.370 TestLua[32429:f803] Player ship at (100.000000,104.000000)
Lua says player ship is at (100.000000, 104.000000)
2012-02-05 20:09:54.370 TestLua[32429:f803] Player ship at (100.000000,104.000000)
Lua says player ship is at (100.000000, 104.000000)
Now we’re getting somewhere! We can access our player ship’s state from within a Lua script, which opens up a lot of possibilities. We could create an entire C API that would let us manipulate our ship by calling methods on our ShipController instances. In fact, we will do something similar to this in Part III, but we will wrap it into a nice object oriented layer that will make our scripting cleaner.


In part I of this post, we created a simple iOS game in which to embed Lua scripting. In part II we embedded the Lua interpreter and demonstrated calling Lua scripts from our game. We also added some simple interaction by enabling our Lua scripts to access the state of our player ship (x,y position).
In this final part, we are going to build on this functionality to expose the entire ship control to Lua so that our scripts can control our NPC ships.

In part I of this post we created the ShipController class to allow our code access to the state of a ship (position) as well as to manipulate the ships controls. In part II we used a Lua script to access the ship’s state. Now we are going to make the full ShipController interface available to our Lua scripts.
We will begin by creating delagate functions for the rest of the methods in our ShipController. Add the following code to ViewController.m:

ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
static int press_right_button(lua_State *L){
    ShipController *sc = (ShipController *)lua_touserdata(L, 1);
    [sc pressRightButton];

    return 0;
}

static int press_left_button(lua_State *L){
    ShipController *sc = (ShipController *)lua_touserdata(L, 1);
    [sc pressLeftButton];

    return 0;
}

static int press_top_button(lua_State *L){
    ShipController *sc = (ShipController *)lua_touserdata(L, 1);
    [sc pressTopButton];

    return 0;
}

static int press_bottom_button(lua_State *L){
    ShipController *sc = (ShipController *)lua_touserdata(L, 1);
    [sc pressBottomButton];

    return 0;
}

static int get_ship_position(lua_State *L){
    ShipController *sc = (ShipController *)lua_touserdata(L, 1);

    // push x and y position on the stack
    lua_pushnumber(L, sc.x);
    lua_pushnumber(L, sc.y);

    // let the caller know how many results are available on the stack
    return 2;
}

These five functions are our delegates that implement the standard Lua C function prototype mentioned in part II. Each of these follows a standard format. First they pull a pointer off the stack and assign it to a local variable. This pointer is a ShipController pointer for the ship that is to be controlled. After that they use the local variable to perform an action, or, in the case of get_ship_position, to retrieve information. Finally, they push results on the stack where necessary and return the number of results pushed. The only really new thing here is the call to lua_touserdata at the beginning of each method. So what does this do?
There are essentially two different ways to pass non-primitive data to Lua. The first way lets Lua manage the memory for this data. We can define a struct to hold our data elements (including pointers) and ask Lua to allocate and manage the memory for instances of this struct, which we then fill in with our data. This approach is called user data. User data has the advantage of having Lua manage the memory, but its implementation is slightly more complicated.
The second approach is to simply pass pointers to Lua for the objects we create and manage in the main game code. This approach is known as light user data, and is the one we will use here.
Next we need to add these functions to our Lua library. This is simply a matter of adding entries for each to our library array.

ViewController.m
1
2
3
4
5
6
7
8
9
static const struct luaL_Reg shiplib_f [] = {
    {"player_ship_position", player_ship_position},
    {"press_right_button", press_right_button},
    {"press_left_button", press_left_button},
    {"press_top_button", press_top_button},
    {"press_bottom_button", press_bottom_button},
    {"get_ship_position", get_ship_position},
    {NULL, NULL}
};

Now all of these methods are available to our lua code. Before we can use them, we need to create another ship. Add the following code at the top of ViewController.m just below the allocation of our player ship:

ViewController.m Enemy Ship Declaration
1
ShipController *enemyShipController;

And add an allocation in viewDidLoad just below the one for the player ship:

ViewController.m Enemy Ship Allocation
1
enemyShipController = [[ShipController alloc] initWithX:105 Y:102 Speed:1.0 Name:@"enemy_ship"];

Our enemy ship will originate at (x,y) = (105, 102), or slightly offset from our player ship.
Next we need to create a simple AI script for our enemy ship. Create a new file called enemy_ship.lua and add the following:

enemy_ship.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function process(npc_ship)

 -- get the location of the player's ship
    player_x, player_y = ship.player_ship_position()

    -- get the location npc ship
    x, y = ship.get_ship_position(npc_ship)

    -- move this ship toward the player
    if player_x < x then
          ship.press_left_button(npc_ship)
    elseif player_x > x then
    ship.press_right_button(npc_ship)
    end

    if player_y < y then
        ship.press_bottom_button(npc_ship)
    elseif player_y > y then
        ship.press_top_button(npc_ship)
    end

end

This script declares a sigle function, process, which takes a single argument, a pointer to a ShipController. The function does nothing with this pointer directly, it simply passes it to the functions we bound to our ship library. The “AI” here is about as primitive as can be; it simply causes the enemy ship to move a bit closer to the player ship by calling the appropriate “press_*_button” functions.
The only things left to do are to load the new script and modify our game loop to call this lua function. The first is simply a matter of changing the name of the loaded file.

ViewController.m Loading Enemy Ship Lua Script
1
NSString *luaFilePath = [[NSBundle mainBundle] pathForResource:@"enemy_ship" ofType:@"lua"];

`
While we are at it, lets modify our output to make use of the name property we added to ShipController.

ViewController.m Adding output to run loop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-(void)runLoop:(id)sender {


    // put the pointer to the lua function we want on top of the stack
    lua_getglobal(L,"process");

    lua_pushlightuserdata(L, enemyShipController);

    // call the function on the stack
    int err = lua_pcall(L, 1, 0, 0);
  if (0 != err) {
      luaL_error(L, "cannot run lua file: %s",
                   lua_tostring(L, -1));
      return;
  }

    NSLog(@"%@ at (%f,%f)", playerShipController.name, playerShipController.x, playerShipController.y);
    NSLog(@"%@ ship at (%f,%f)", enemyShipController.name, enemyShipController.x, enemyShipController.y);
}

This method uses the lua_getglobal function, which simply retrieves the address for the processsymbol (our Lua function name) and puts it on the stack. Then it pushes our pointer to our ShipController for our enemy ship on the stack. Finally, it tells lua to call the function on the stack, using one argument - the pointer we pushed on the stack.
Now if we run our game we get the following output:
2012-02-06 20:57:30.609 TestLua[37090:f803] Left button pressed for ship enemy_ship
2012-02-06 20:57:30.609 TestLua[37090:f803] Bottom button pressed for ship enemy_ship
2012-02-06 20:57:30.610 TestLua[37090:f803] player_ship at (100.000000,100.000000)
2012-02-06 20:57:30.610 TestLua[37090:f803] enemy_ship ship at (104.000000,101.000000)
2012-02-06 20:57:31.608 TestLua[37090:f803] Left button pressed for ship enemy_ship
2012-02-06 20:57:31.609 TestLua[37090:f803] Bottom button pressed for ship enemy_ship
2012-02-06 20:57:31.609 TestLua[37090:f803] player_ship at (100.000000,100.000000)
2012-02-06 20:57:31.609 TestLua[37090:f803] enemy_ship ship at (103.000000,100.000000)
2012-02-06 20:57:32.608 TestLua[37090:f803] Left button pressed for ship enemy_ship
2012-02-06 20:57:32.609 TestLua[37090:f803] player_ship at (100.000000,100.000000)
2012-02-06 20:57:32.609 TestLua[37090:f803] enemy_ship ship at (102.000000,100.000000)
2012-02-06 20:57:33.608 TestLua[37090:f803] Left button pressed for ship enemy_ship
2012-02-06 20:57:33.609 TestLua[37090:f803] player_ship at (100.000000,100.000000)
2012-02-06 20:57:33.609 TestLua[37090:f803] enemy_ship ship at (101.000000,100.000000)
2012-02-06 20:57:34.608 TestLua[37090:f803] Left button pressed for ship enemy_ship
2012-02-06 20:57:34.609 TestLua[37090:f803] player_ship at (100.000000,100.000000)
2012-02-06 20:57:34.609 TestLua[37090:f803] enemy_ship ship at (100.000000,100.000000)
2012-02-06 20:57:35.609 TestLua[37090:f803] player_ship at (100.000000,100.000000)
2012-02-06 20:57:35.609 TestLua[37090:f803] enemy_ship ship at (100.000000,100.000000)
So there you have it. Our enemy ship controlled by a Lua script. We see the enemy ship script frantically pressing buttons to try to move closer to our ship. Not exactly the brightest AI in the world, but enough to get started. Along with better AI, there are some refinements that could be added. For one thing, constantly passing in the pointer to our enemy ship’s ShipController seems a bit cheesy. It would be better if we could wrap it up in a nice Lua object that our scripts could use, and we can. But that is the subject for another post.