My Codea Addons - logging to console and setting fps

Hi everybody!

So I have nearly finished my first official game and now I want to release it to App Store. Thanks to the awesome runtime and it’s add-on mechanism I was able to implement two features that I found quite useful for a standalone app: Logging to the console in Xcode and setting the fps manually to something lower than the default 60. This saves processing time and thus battery life when your app does not need such a high frame rate. Here’s the code, I’ll release it under the BSD two clause license.

By the way I also like to thank Reefwing for his great tutorials that got me started when it came to Codea add-ons.

  • NsLogAddOn.h
#import <Foundation/Foundation.h>
#import "CodeaAddon.h"

@interface NsLogAddOn : NSObject<CodeaAddon>
@property (strong, nonatomic) NSString *logPrefix;
@property (assign, nonatomic) int fps;

+ (NsLogAddOn*) sharedInstance;

static int nslog (struct lua_State *state);
static int fps (struct lua_State *state);
@end
  • NsLogAddOn.mm
#import "lua.h"
#import "NsLogAddOn.h"
#import <GLKit/GLKit.h>

@interface NsLogAddOn ()
@property (weak, nonatomic) GLKViewController *glkViewController;
@end

@implementation NsLogAddOn
- (id) init {
    if ((self = [super init])) {
        self.logPrefix = @"LUA: ";
    }
    return self;
}

+ (NsLogAddOn*) sharedInstance {
    static NsLogAddOn *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once (&onceToken, ^{
        sharedInstance = [[NsLogAddOn alloc] init];
    });
    return sharedInstance;
}

- (void)codea:(CodeaViewController *)controller didCreateLuaState:(struct lua_State *)L {
    self.glkViewController = (GLKViewController*)[controller.childViewControllers objectAtIndex:1];
    
    NSLog(@"NsLogAddOn Registering Functions");
    lua_register(L, "nslog", nslog);
    lua_register(L, "fps", fps);
 }

- (void) nslog:(NSString*)format arguments:(NSArray*)arguments {
    NSMutableData* data = [NSMutableData dataWithLength: sizeof(id) * [arguments count]];
    [arguments getObjects: (__unsafe_unretained id *)data.mutableBytes range:NSMakeRange(0, [arguments count])];
    NSString* message = [[NSString alloc] initWithFormat:format arguments:data.mutableBytes];
    NSLog(@"%@%@", self.logPrefix, message);
}

- (void) setFps:(int)fps {
    NSLog(@"Setting framerate to %d fps", fps);
    [self.glkViewController setPreferredFramesPerSecond:fps];
}

- (int) fps {
    return [self.glkViewController preferredFramesPerSecond];
}

static int nslog (struct lua_State *state) {
    int argc = lua_gettop(state);
    NSString *format = [NSString stringWithCString:lua_tostring(state, 1) encoding:NSUTF8StringEncoding];
    NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:argc - 1];
    for (int i = 2; i <= argc; i++) {
        if (lua_isnumber(state, i))
            arguments[i - 2] = [NSNumber numberWithDouble:[[NSString stringWithCString:lua_tostring(state, i) encoding:NSUTF8StringEncoding] doubleValue]];
        else if (lua_isstring(state, i))
            arguments[i - 2] = [NSString stringWithCString:lua_tostring(state, i) encoding:NSUTF8StringEncoding];
        else if (lua_isnil(state, i))
            arguments[i - 2] = [NSNull null];
    }
    [[NsLogAddOn sharedInstance] nslog:format arguments:arguments];
    return 0;
}

static int fps (struct lua_State *state) {
    if (lua_gettop(state) == 1) {
        [NsLogAddOn sharedInstance].fps = MAX(30.0f, MIN((float)lua_tonumber(state, 1), 60.0f));
        return 0;
    } else {
        lua_pushinteger(state, [NsLogAddOn sharedInstance].fps);
        return 1;
    }
}
@end
  • In your AppDelegate.mm, you register the add-on with
[self.viewController registerAddon:[NsLogAddOn sharedInstance]];

This gives you two handy new functions, namely nslog and fps.

  • nslog Example:
function setup () 
    -- Always use a %@ to denote a parameter
    nslog("Hello World!") -- "Hello World!"
    nslog("Hello %@!", "World") -- "Hello World!" 
    nslog("Hello %@ number %@!", "World", 42) -- "Hello World number 42!"
end
  • fps Example:
function setup ()
    print("FPS: " .. fps()) -- "FPS: 60"
    fps(30)
    print("FPS: " .. fps()) -- "FPS: 30"
end

I hope you find this useful and I’ll let you know when my game is ready.

CU Jegge

EDIT: Changed NSASCIIStringEncoding to NSUTF8StringEncoding. Silly me.

Hey thats brilliant thanks! When dropping the fps, are touches affected?

Not that I am aware of. Touches should work as expected, since they are events generated by the underlying uikit framework. What the code really does is limiting how often the draw() method is called per second, effectively giving you double draw time per frame. I haven’t tried this with the physics stuff however, maybe there are some caveats.

I have a use for it then, great :slight_smile:

Brilliant! Thank you.