0

Apple Review Times

Posted by lorenb on Aug 11, 2009 in business, iphone

Still no word from Apple about the latest MMATracker release. Used to only take around 6/7 days to get an approval for app updates, but that seems to be rising.

I’ve talked to other developers and they have noticed the same thing. Perhaps Apple is having trouble keeping up with demand.

 
1

Porting from iPhone to Windows Mobile

Posted by lorenb on Aug 5, 2009 in iphone, windows

Saw a Microsoft case study on Porting the Amplitude Application from the iPhone to a Windows Mobile Device. I’ll have to read that in more detail later on.

 
0

High Scores

Posted by lorenb on Aug 5, 2009 in game development, iphone

I’ve been thinking about high scores and how that should be implemented in a game. If you are only concerned about local scores that can be done using NSUserDefaults or you could use a sqlite database. Those are fairly easy to implement.

Local scores though are limited in use. They are good if you want track your personal best effort in a given game. How many other people use your iPhone/iPod and would play a given game? Probably not many; maybe none.

Global/Internet based scores are more interesting. I think it encourages people to play games more due to competition with other players. That can help word of mouth sales, if someone likes your game(s) and they get their friends to buy it and see who is the best.

The more people playing your games can create more opportunities to sell in app purchases. You can obtain better metrics of who is playing your games and how they are doing (Is it too easy? Too hard? etc.),

Long term it’s not hard to see Apple putting something together like XBox Live that developers could plug into for these purposes.

Today you are on your own. I did see one open source system called iGetScores. The server side is written in PHP with a MySQL backend. It uses OAuth. The client code is not small and you’d be adding around 40 files to your project. It seemed to be more complicated that it should be.

I wanted something simple and am looking to writing my own.The basic requirements would be to accept new high scores and to be able to get a list of them for a given game. From a security point of view, accepting data from random users into your database can be an issue. You need to consider people trying to use SQL Injections or denial of service attacks. You have to deal with people who might try to cheat and put in false scores.

I was thinking about having a shared secret where by the iPhone/iPod that wants to submit a score, encrypts the data with a shared secret and sends to server. The server then decrypts the data and inserts into the database after some validation. Depending on encryption used that might cause export issues for some countries.

You could use the UUID of the iPhone/iPod to keep track of submissions from people and use the date/time of the request to see if that person has submitted anything before. If someone tries to post multiple scores within a few minutes and you know your game would take at least X number of minutes to complete, you could throw that out as a fake.

I’m still thinking it through and I don’t have a full design yet. I’m still flushing things out. I’ll have more to say about this later and maybe some code too.

To be continued…

 
1

More on code sharing

Posted by lorenb on Aug 4, 2009 in game development, iphone

I wrote the other day about Sharing code in iPhone applications which was about using static libraries. I ran into an interesting problem on the weekend where by my code was working on the simulator but not on real hardware.

In my static library I was using kissxml to parse a tile map from Tiled. The TiledMap code was from the guys at 71Squared.

In the simulator things worked as expected. On an iPhone/iPod the program would always crash trying to parse the XML. The program was aborting because NSStringAdditions were not taking effect. The specific error was [NSCFString xmlChar]: unrecognized selector sent to instance

If I had all the code in a single program it worked and as I mentiond there were no problems with library + app in the simulator. It was very odd and unfortunately I was unable to determine how to fix this.

As a workaround, I re-wrote the TiledMap class to use NSXMLParser instead of kissxml. It’s a bit slower than kissxml but at least it works in a static library on the simulator and devices. Only difference from original code is that it doesn’t support layer properties yet.

The original code from 71Squared was released under the MIT license. Here are my changes under the same license.

Long term, the ideal situation would be for Apple to add some XML APIs that can handle XPath in a future OS release.

TiledMap.h

- (id)initWithTMXFile:(NSString *)tmxFile;

TiledMap.m

- (id)initWithTMXFile:(NSString *)tmxFile {
	if ((self = [super init])) {

		// Shared game state
		sharedDirector = [Director sharedDirector];

	        // Set up the default colour filter
	        colourFilter = Color4fInit;

		// Set up the arrays and default values for layers and tilesets
		tileSets = [[NSMutableArray alloc] init];
		layers = [[NSMutableArray alloc] init];

		// Allocate and init the properties dictionary for the map
		mapProperties = [[NSMutableDictionary alloc] init];

		// Init the current layer, tileset and tile x and y
		currentLayerID = 0;
		currentTileSetID = 0;
		tileX = 0;
		tileY = 0;

		NSURL *url = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:tmxFile ofType:@"tmx"]];
		NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

		[parser setDelegate:self];
		[parser setShouldProcessNamespaces:NO];
		[parser setShouldReportNamespacePrefixes:NO];
		[parser setShouldResolveExternalEntities:NO];
		[parser parse];

		NSError *error = [parser parserError];
		if (error) {
			NSLog(@"Error parsing TMX file: %@", error);
		}

		[parser release];

		// Calculate the total number of tiles it would take to fill the visible screen.  The values below which define the screen
		// size would need to be changed based on the size of the area you need the tilemap to fill.  I am adding a couple of tiles
		// to the total to cover fractions of a tile which may have resulted in the calculation.  I am then multuplying the result
		// by two as there are two triangles per tile
		int totalTriangles = ((320 / tileWidth) + 2) * ((480 / tileHeight) + 2) * 12 ;
		if(DEBUG) NSLog(@"--> Initializing vertex arrays for '%d' triangles.", totalTriangles);

		// Set up the vertex arrays
		tileVerts = calloc(totalTriangles, sizeof(TileVert));

		// If one of the arrays cannot be allocated, then report a warning and return nil
		if(!tileVerts) {
			if(DEBUG) NSLog(@"WARNING: Tiled - Not enough memory to allocate vertex arrays");
			return nil;
		}
	}

	return self;
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {	

	if([elementName isEqualToString:@"map"]) {
		mapWidth = [[attributeDict valueForKey:@"width"] intValue];
		mapHeight = [[attributeDict valueForKey:@"height"] intValue];
		tileWidth = [[attributeDict valueForKey:@"tilewidth"] intValue];
		tileHeight = [[attributeDict valueForKey:@"tileheight"] intValue];

	} else if([elementName isEqualToString:@"tileset"]) {

		tileSetName = [[attributeDict valueForKey:@"name"] retain];
		tileSetFirstGID = [[attributeDict valueForKey:@"firstgid"] intValue];
		tileSetSpacing = [[attributeDict valueForKey:@"spacing"] intValue];
//		tileset->margin = [[attributeDict valueForKey:@"margin"] intValue];
		tileSetWidth = [[attributeDict valueForKey:@"tilewidth"] intValue];
		tileSetHeight = [[attributeDict valueForKey:@"tileheight"] intValue];

		tileSetProperties = [[NSMutableDictionary alloc] init];

	} else if([elementName isEqualToString:@"layer"]) {

		layerName = [[attributeDict valueForKey:@"name"] retain];
		layerWidth = [[attributeDict valueForKey:@"width"] intValue];
		layerHeight = [[attributeDict valueForKey:@"height"] intValue];

		currentLayer = [[Layer alloc] initWithName:layerName layerID:currentLayerID layerWidth:layerWidth layerHeight:layerHeight];
		if(DEBUG) NSLog(@"--> LAYER found called: %@, width=%d, height=%d", layerName, layerWidth, layerHeight);

		[layers addObject:currentLayer];
		[currentLayer release];
		currentLayerID++;

	} else if([elementName isEqualToString:@"image"]) {

		NSString *source = [[attributeDict valueForKey:@"source"] retain];

		// Create a tileset instance based on the retrieved information
		currentTileSet = [[TileSet alloc] initWithImageNamed:source
														name:tileSetName
												   tileSetID:currentTileSetID
													firstGID:tileSetFirstGID
												   tileWidth:tileSetWidth
												  tileHeight:tileSetHeight
													 spacing:tileSetSpacing];

		// Add the tileset instance we have just created to the array of tilesets
		[tileSets addObject:currentTileSet];

		// Release the current tileset instance as its been added to the array and we do not need it now
		[currentTileSet release];

		// Increment the current tileset id
		currentTileSetID++;

	} else if([elementName isEqualToString:@"tile"]) {

		if ([attributeDict valueForKey:@"id"] != nil) {
			currentTileID = [[attributeDict valueForKey:@"id"] intValue] + tileSetFirstGID;
		} else {

			Layer *layer = [layers lastObject];
			int globalID = [[attributeDict valueForKey:@"gid"] intValue];

			// If the globalID is 0 then this is an empty tile else populate the tile array with the
			// retrieved tile information
			if(globalID == 0) {
				[layer addTileAtX:tileX y:tileY tileSetID:-1 tileID:0 globalID:0];
			} else {
				TileSet *tileSet = [self findTileSetWithGlobalID:globalID];
				[layer addTileAtX:tileX
								y:tileY
						   tileSetID:[tileSet tileSetID]
							  tileID:globalID - [tileSet firstGID]
							globalID:globalID];
			}

			// Calculate the next coord within the tiledata array
			tileX++;
			if(tileX > layerWidth - 1) {
				tileX = 0;
				tileY++;
			}
		}
	} else if([elementName isEqualToString:@"property"]) {

		NSString *tileIDKey = [NSString stringWithFormat:@"%d", currentTileID];
		NSMutableDictionary *tileProperties = [[NSMutableDictionary alloc] init];

		NSString *name = [attributeDict valueForKey:@"name"];
		NSString *value = [attributeDict valueForKey:@"value"];
		if(DEBUG) NSLog(@"----> Property '%@' found with value '%@' for global tile id '%@'", name, value, tileIDKey);

		[tileProperties setObject:value forKey:name];
		[tileSetProperties setObject:tileProperties forKey:tileIDKey];

		// Release the tileProperties now they have been added to tileSetProperties
		[tileProperties release];
	}
}

 
1

MonoTouch Preview

Posted by lorenb on Aug 3, 2009 in iphone, mono

MonoTouch is now feature complete and the developers are looking for testers for a closed preview.

MonoTouch is a static compiler for C# and other static CIL languages that allows developers to use C# for developing iPhone applications while taking advantage of Apple’s native APIs for developing iPhone applications.

It’s supposed to released the first week of September. MonoTouch is a commercial product and will be licensed on a per-developer basis.

I’ll be watching to see what Novell is charging as I’m still interested in this project.

 
1

MMATracker 2.3

Posted by lorenb on Aug 3, 2009 in business, iphone

MMATracker v2.3 has been submitted to Apple. New in this release: when showing a fight card, it’s now broken into sections for the main/under card. You can see a screenshot of that below.

When clicking on “More” information about a figther, the app now slides over and shows that content in a web view. It no longer closes the program and launches Safari.

We were planning to update the titles view and drop WAMMA and insert Strikeforce but it slipped my mind. We’ll do that in 2.3.1 or whatever the next release ends up being.

Showing main/under card breakdown in MMATracker

MMATracker v2.3

 
1

Sharing code in iPhone applications

Posted by lorenb on Jul 16, 2009 in game development, iphone

There are two schools of though on iPhone application development.

Some people spend a lot of time/money on developing an iPhone application. I’ve posted articles about that before, people spending upwards of $100,000 on an app and making back a fraction of that.

Going away for 1-2 years and developing something in secret is a dead development model in my opinion. Coming from an Open Source background I prefer release early/often.

On the iPhone, rather than put 100% of all our effort/resources into a single app, we are planning to release multiple titles. The purpose to keep developing/learning, get feedback from users and act upon it.

For a specific app this will come in the form of updates. If you bought MMATracker 1.0 for example, you’ve seen numerous revisions and increased functionality. A lot that was driven by user feedback.

If an application completely bombs, we take the lessons learned and incorporate into the next app. We keep developing and pushing forward. We can do this because we are not spending tens of thousands on each application.

Writing multiple applications can be difficult and it’s in your interests to re-use code where possible. Otherwise you’ll never be able to manage all the code.

Normally this is done via a shared library. This would allow multiple apps to use the same code. Problem is that Apple doesn’t allow custom shared libraries on the iPhone.

The only way around this is to use a static library. For some reason, Apple/XCode makes this more difficult than it really has to be. I was having some trouble yesterday with one project and found this great article, Easy, Modular Code Sharing Across iPhone Apps: Static Libraries and Cross-Project References

Copyright © 2010 LB Technology Services Blog All rights reserved.