Skip to content

Commit

Permalink
Adding in-memory TMX map creation
Browse files Browse the repository at this point in the history
Added convenience methods to take an XML string and create an in-memory
TMX map from it.  Also added a test for this.
  • Loading branch information
slycrel committed Sep 4, 2011
1 parent 722c6dd commit ab91c1b
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 51 deletions.
6 changes: 6 additions & 0 deletions cocos2d/CCTMXTiledMap.h
Expand Up @@ -122,9 +122,15 @@ enum
/** creates a TMX Tiled Map with a TMX file.*/
+(id) tiledMapWithTMXFile:(NSString*)tmxFile;

/** initializes a TMX Tiled Map with a TMX formatted XML string and a path to TMX resources */
+(id) tiledMapWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath;

/** initializes a TMX Tiled Map with a TMX file */
-(id) initWithTMXFile:(NSString*)tmxFile;

/** initializes a TMX Tiled Map with a TMX formatted XML string and a path to TMX resources */
-(id) initWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath;

/** return the TMXLayer for the specific layer */
-(CCTMXLayer*) layerNamed:(NSString *)layerName;

Expand Down
77 changes: 51 additions & 26 deletions cocos2d/CCTMXTiledMap.m
Expand Up @@ -43,6 +43,7 @@
@interface CCTMXTiledMap (Private)
-(id) parseLayer:(CCTMXLayerInfo*)layer map:(CCTMXMapInfo*)mapInfo;
-(CCTMXTilesetInfo*) tilesetForLayer:(CCTMXLayerInfo*)layerInfo map:(CCTMXMapInfo*)mapInfo;
-(void) buildWithMapInfo:(CCTMXMapInfo*)mapInfo;
@end

@implementation CCTMXTiledMap
Expand All @@ -57,6 +58,55 @@ +(id) tiledMapWithTMXFile:(NSString*)tmxFile
return [[[self alloc] initWithTMXFile:tmxFile] autorelease];
}

+(id) tiledMapWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath
{
return [[[self alloc] initWithXML:tmxString resourcePath:resourcePath] autorelease];
}

-(void) buildWithMapInfo:(CCTMXMapInfo*)mapInfo
{
mapSize_ = mapInfo.mapSize;
tileSize_ = mapInfo.tileSize;
mapOrientation_ = mapInfo.orientation;
objectGroups_ = [mapInfo.objectGroups retain];
properties_ = [mapInfo.properties retain];
tileProperties_ = [mapInfo.tileProperties retain];

int idx=0;

for( CCTMXLayerInfo *layerInfo in mapInfo.layers ) {

if( layerInfo.visible ) {
CCNode *child = [self parseLayer:layerInfo map:mapInfo];
[self addChild:child z:idx tag:idx];

// update content size with the max size
CGSize childSize = [child contentSize];
CGSize currentSize = [self contentSize];
currentSize.width = MAX( currentSize.width, childSize.width );
currentSize.height = MAX( currentSize.height, childSize.height );
[self setContentSize:currentSize];

idx++;
}
}
}

-(id) initWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath
{
if ((self=[super init])) {

[self setContentSize:CGSizeZero];

CCTMXMapInfo *mapInfo = [CCTMXMapInfo formatWithXML:tmxString resourcePath:resourcePath];

NSAssert( [mapInfo.tilesets count] != 0, @"TMXTiledMap: Map not found. Please check the filename.");
[self buildWithMapInfo:mapInfo];
}

return self;
}

-(id) initWithTMXFile:(NSString*)tmxFile
{
NSAssert(tmxFile != nil, @"TMXTiledMap: tmx file should not bi nil");
Expand All @@ -68,32 +118,7 @@ -(id) initWithTMXFile:(NSString*)tmxFile
CCTMXMapInfo *mapInfo = [CCTMXMapInfo formatWithTMXFile:tmxFile];

NSAssert( [mapInfo.tilesets count] != 0, @"TMXTiledMap: Map not found. Please check the filename.");

mapSize_ = mapInfo.mapSize;
tileSize_ = mapInfo.tileSize;
mapOrientation_ = mapInfo.orientation;
objectGroups_ = [mapInfo.objectGroups retain];
properties_ = [mapInfo.properties retain];
tileProperties_ = [mapInfo.tileProperties retain];

int idx=0;

for( CCTMXLayerInfo *layerInfo in mapInfo.layers ) {

if( layerInfo.visible ) {
CCNode *child = [self parseLayer:layerInfo map:mapInfo];
[self addChild:child z:idx tag:idx];

// update content size with the max size
CGSize childSize = [child contentSize];
CGSize currentSize = [self contentSize];
currentSize.width = MAX( currentSize.width, childSize.width );
currentSize.height = MAX( currentSize.height, childSize.height );
[self setContentSize:currentSize];

idx++;
}
}
[self buildWithMapInfo:mapInfo];
}

return self;
Expand Down
14 changes: 13 additions & 1 deletion cocos2d/CCTMXXMLParser.h
Expand Up @@ -164,6 +164,9 @@ enum {
// tmx filename
NSString *filename_;

// tmx resource path
NSString *resources_;

// map orientation
int orientation_;

Expand Down Expand Up @@ -195,13 +198,22 @@ enum {
@property (nonatomic,readwrite,retain) NSMutableArray *layers;
@property (nonatomic,readwrite,retain) NSMutableArray *tilesets;
@property (nonatomic,readwrite,retain) NSString *filename;
@property (nonatomic,readwrite,retain) NSString *resources;
@property (nonatomic,readwrite,retain) NSMutableArray *objectGroups;
@property (nonatomic,readwrite,retain) NSMutableDictionary *properties;
@property (nonatomic,readwrite,retain) NSMutableDictionary *tileProperties;

/** creates a TMX Format with a tmx file */
+(id) formatWithTMXFile:(NSString*)tmxFile;
/** initializes a TMX format witha tmx file */

/** creates a TMX Format with an XML string and a TMX resource path */
+(id) formatWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath;

/** initializes a TMX format with a tmx file */
-(id) initWithTMXFile:(NSString*)tmxFile;

/** initializes a TMX format with an XML string and a TMX resource path */
-(id) initWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath;

@end

86 changes: 62 additions & 24 deletions cocos2d/CCTMXXMLParser.m
Expand Up @@ -116,69 +116,103 @@ -(CGRect) rectForGID:(unsigned int)gid
@interface CCTMXMapInfo (Private)
/* initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file */
-(void) parseXMLFile:(NSString *)xmlFilename;
/* initalises parsing of an XML string, either a tmx (Map) string or tsx (Tileset) string */
- (void) parseXMLString:(NSString *)xmlString;
/* handles the work of parsing for parseXMLFile: and parseXMLString: */
- (NSError*) parseXMLData:(NSData*)data;
@end


@implementation CCTMXMapInfo

@synthesize orientation = orientation_, mapSize = mapSize_, layers = layers_, tilesets = tilesets_, tileSize = tileSize_, filename = filename_, objectGroups = objectGroups_, properties = properties_;
@synthesize orientation = orientation_, mapSize = mapSize_, layers = layers_, tilesets = tilesets_, tileSize = tileSize_, filename = filename_, resources = resources_, objectGroups = objectGroups_, properties = properties_;
@synthesize tileProperties = tileProperties_;

+(id) formatWithTMXFile:(NSString*)tmxFile
{
return [[[self alloc] initWithTMXFile:tmxFile] autorelease];
}

+(id) formatWithXML:(NSString*)tmxString resourcePath:(NSString*)resourcePath
{
return [[[self alloc] initWithXML:tmxString resourcePath:resourcePath] autorelease];
}

- (void) internalInit:(NSString*)tmxFileName resourcePath:(NSString*)resourcePath
{
self.tilesets = [NSMutableArray arrayWithCapacity:4];
self.layers = [NSMutableArray arrayWithCapacity:4];
self.filename = tmxFileName;
self.resources = resourcePath;
self.objectGroups = [NSMutableArray arrayWithCapacity:4];
self.properties = [NSMutableDictionary dictionaryWithCapacity:5];
self.tileProperties = [NSMutableDictionary dictionaryWithCapacity:5];

// tmp vars
currentString = [[NSMutableString alloc] initWithCapacity:1024];
storingCharacters = NO;
layerAttribs = TMXLayerAttribNone;
parentElement = TMXPropertyNone;
}

-(id) initWithXML:(NSString *)tmxString resourcePath:(NSString*)resourcePath
{
if( (self=[super init])) {
[self internalInit:nil resourcePath:resourcePath];
[self parseXMLString:tmxString];
}
return self;
}

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

self.tilesets = [NSMutableArray arrayWithCapacity:4];
self.layers = [NSMutableArray arrayWithCapacity:4];
self.filename = tmxFile;
self.objectGroups = [NSMutableArray arrayWithCapacity:4];
self.properties = [NSMutableDictionary dictionaryWithCapacity:5];
self.tileProperties = [NSMutableDictionary dictionaryWithCapacity:5];

// tmp vars
currentString = [[NSMutableString alloc] initWithCapacity:1024];
storingCharacters = NO;
layerAttribs = TMXLayerAttribNone;
parentElement = TMXPropertyNone;

[self internalInit:tmxFile resourcePath:nil];
[self parseXMLFile:filename_];
}
return self;
}

- (void) dealloc
{
CCLOGINFO(@"cocos2d: deallocing %@", self);
[tilesets_ release];
[layers_ release];
[filename_ release];
[resources_ release];
[currentString release];
[objectGroups_ release];
[properties_ release];
[tileProperties_ release];
[super dealloc];
}

- (void) parseXMLFile:(NSString *)xmlFilename
- (NSError*) parseXMLData:(NSData*)data
{
NSURL *url = [NSURL fileURLWithPath:[CCFileUtils fullPathFromRelativePath:xmlFilename] ];
NSData *data = [NSData dataWithContentsOfURL:url];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:data] autorelease];

// we'll do the parsing
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];

return [parser parserError];
}

NSAssert1( ! [parser parserError], @"Error parsing file: %@.", xmlFilename );
- (void) parseXMLString:(NSString *)xmlString
{
NSData* data = [xmlString dataUsingEncoding:NSUTF8StringEncoding];
NSError* err = [self parseXMLData:data];
NSAssert1( !err, @"Error parsing TMX data: %@.", [NSString stringWithCharacters:[data bytes] length:[data length]] );
}

[parser release];
- (void) parseXMLFile:(NSString *)xmlFilename
{
NSURL *url = [NSURL fileURLWithPath:[CCFileUtils fullPathFromRelativePath:xmlFilename] ];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError* err = [self parseXMLData:data];
NSAssert3(!err, @"Error parsing TMX file: %@, %@ (%d).", xmlFilename, [err localizedDescription], [err code]);
}

// the XML parser calls here with all the elements
Expand Down Expand Up @@ -212,6 +246,8 @@ -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName name
if (externalTilesetFilename) {
// Tileset file will be relative to the map file. So we need to convert it to an absolute path
NSString *dir = [filename_ stringByDeletingLastPathComponent]; // Directory of map file
if (!dir)
dir = resources_;
externalTilesetFilename = [dir stringByAppendingPathComponent:externalTilesetFilename]; // Append path to tileset file

[self parseXMLFile:externalTilesetFilename];
Expand Down Expand Up @@ -286,7 +322,9 @@ -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName name

// build full path
NSString *imagename = [attributeDict valueForKey:@"source"];
NSString *path = [filename_ stringByDeletingLastPathComponent];
NSString *path = [filename_ stringByDeletingLastPathComponent];
if (!path)
path = resources_;
tileset.sourceImage = [path stringByAppendingPathComponent:imagename];

} else if([elementName isEqualToString:@"data"]) {
Expand Down
4 changes: 4 additions & 0 deletions tests/TileMapTest.h
Expand Up @@ -143,6 +143,10 @@
{}
@end

@interface TMXOrthoFromXMLTest : TileDemo
{}
@end

@interface TMXBug987 : TileDemo
{}
@end
Expand Down
37 changes: 37 additions & 0 deletions tests/TileMapTest.m
Expand Up @@ -38,6 +38,7 @@
@"TMXIsoMoveLayer",
@"TMXOrthoMoveLayer",
@"TMXOrthoFlipTest",
@"TMXOrthoFromXMLTest",
@"TMXBug987",
@"TMXBug787",

Expand Down Expand Up @@ -1394,6 +1395,42 @@ -(NSString *) title
@end


#pragma mark -
#pragma mark TMXOrthoFromXMLTest

@implementation TMXOrthoFromXMLTest
-(id) init
{
if( (self=[super init]) ) {
NSString* resources = @"TileMaps"; // partial paths are OK as resource paths.
NSString* file = [resources stringByAppendingPathComponent:@"orthogonal-test1.tmx"];
NSError* error = nil;
NSString* str = [NSString stringWithContentsOfFile:[CCFileUtils fullPathFromRelativePath:file] encoding:NSUTF8StringEncoding error:&error];
NSAssert3(!error, @"Unable to open file %@, %@ (%d)", file, [error localizedDescription], [error code]);

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithXML:str resourcePath:resources];
[self addChild:map z:0 tag:kTagTileMap];

CGSize s = map.contentSize;
NSLog(@"ContentSize: %f, %f", s.width,s.height);

for( CCSpriteBatchNode* child in [map children] ) {
[[child texture] setAntiAliasTexParameters];
}

id action = [CCScaleBy actionWithDuration:2 scale:0.5f];
[map runAction:action];
}
return self;
}

-(NSString *) title
{
return @"TMX created from XML test";
}
@end


#pragma mark -
#pragma mark TMXBug987

Expand Down

0 comments on commit ab91c1b

Please sign in to comment.