Parsing Multiple Attributes with GDataXML

Forums Programming Programming – Everything else Parsing Multiple Attributes with GDataXML

This topic contains 10 replies, has 5 voices, and was last updated by  mavrik5150 1 year, 10 months ago.

Viewing 11 posts - 1 through 11 (of 11 total)
Author Posts
Author Posts
January 22, 2012 at 5:14 pm #238602

mavrik5150
Participant
@mavrik5150

Hey everyone, I’m a bit stumped on how to to something in my game prototype. So far I’ve been able to get everything working the way I want and have put most of the game data in XML files that are then loaded into a scene so I have fewer scenes to manage than before but now I’ve hit a road bump in dealing with the objects for a set of levels. What I want to do is have an XML file that loads all the specific information for each level when that level is selected, such as what types of enemies the player will face and the frequency of those enemies. Following a few examples and books I’ve got the XML file below for my levels:

<!-- Objects: Heart = 1, GreenObject = 2, BlueObject = 3 -->

<Levels>
<Level>
<Name>Chapter1Level1</Name>
<Number>1</Number>
<Unlocked>1</Unlocked>
<Stars>3</Stars>
<Data>Some Chapter 1 Level 1 Data</Data>
<Object type="1" spawnProbability="15"/>
<Object type="2" spawnProbability="25"/>
</Level>
<Level>
<Name>Chapter1Level2</Name>
<Number>2</Number>
<Unlocked>1</Unlocked>
<Stars>2</Stars>
<Data>Some Chapter 1 Level 2 Data</Data>
<Object type="1" spawnProbability="15"/>
<Object type="3" spawnProbability="35"/>
</Level>
<Level>
<Name>Chapter1Level3</Name>
<Number>3</Number>
<Unlocked>1</Unlocked>
<Stars>1</Stars>
<Data>Some Chapter 1 Level 3 Data</Data>
<Object type="1" spawnProbability="15"/>
<Object type="2" spawnProbability="25"/>
<Object type="3" spawnProbability="35"/>
</Level>
<Level>
<Name>Chapter1Level4</Name>
<Number>4</Number>
<Unlocked>1</Unlocked>
<Stars>0</Stars>
<Data>Some Chapter 1 Level 4 Data</Data>
<Object type="1" spawnProbability="15"/>
<Object type="2" spawnProbability="45"/>
<Object type="3" spawnProbability="35"/>
</Level>
</Levels>

This is just some sample data that I’m using for testing, other fields will be added and/or changed once I get further into the prototype. In my Parser, what I need to do is have all the Object Types and their Probability added to the array that holds all of the level information for each level and below is what I’m doing for the object part specifically

NSArray *dataArray = [doc nodesForXPath:@"//Levels/Level" error:nil];
//NSLog(@"Array Contents = %@", dataArray);

NSMutableArray *levelObjects = [[NSMutableArray alloc] init];

for (GDataXMLElement *element in dataArray) {

NSArray *nameArray = [element elementsForName:@"Name"];
NSArray *numberArray = [element elementsForName:@"Number"];
NSArray *unlockedArray = [element elementsForName:@"Unlocked"];
NSArray *starsArray = [element elementsForName:@"Stars"];
NSArray *dataArray= [element elementsForName:@"Data"];
NSArray *objectArray = [element elementsForName:@"Object"];
// Get Level Name
if (nameArray.count > 0) {
GDataXMLElement *nameElement = (GDataXMLElement *) [nameArray objectAtIndex:0];
name = [nameElement stringValue];
}

// Get Level Number
if (numberArray.count > 0) {
GDataXMLElement *numberElement = (GDataXMLElement *) [numberArray objectAtIndex:0];
number = [[numberElement stringValue] intValue];
}
//For the Level Objects, find each object and spawn probability for that level and add those items to an NSArray
if (objectArray.count > 0) {
for (int i = 0; i < objectArray.count; i++) {
NSMutableDictionary *objectDict = [NSMutableDictionary dictionary];
objectType = [[(GDataXMLNode *)[[objectArray objectAtIndex:i] attributeForName:@"type"] stringValue] intValue];
objectSpawn = [[(GDataXMLNode *)[[objectArray objectAtIndex:i] attributeForName:@"spawnProbability"] stringValue] intValue];
[objectDict setObject:[NSNumber numberWithInt:objectType] forKey:@"ObjectType"];
[objectDict setObject:[NSNumber numberWithInt:objectSpawn] forKey:@"ObjectSpawn"];
[levelObjects addObject:objectDict];
}
}

//CCLOG(@"the new level object array contains: %@", levelObjects);

Level *level = [[Level alloc] initWithName:name number:number locked:locked stars:stars data:data objects:levelObjects];

[levels.levelArray addObject:level];
}

At first I thought this would work, since when I tested on the first level and called

Levels *levels = [LevelParser loadLevelsForChapter:selectedChapter];

for (Level *level in levels.levelArray) {
if (level.levelNumber == selectedLevel) {

NSArray *objectArray = [[NSArray alloc] init];
objectArray = level.levelObjects;
CCLOG(@"the object array for this level contains: %@", objectArray);
}

The log was showing just the items for the first level, but when I tried loading a later level, like Level 4 the Log showed that my array for level 4 not only contained the objects for level 4 but all of the previous levels as well. I feel like I’m getting close and I know I’m missing something somewhere but I just can’t seem to figure out why the array is storing all objects continuously instead of a new array each time. If anyone has had some experience in loading level items through XML can point me in the right direction that would be great. I’ve searched Google and through the forum for a couple of days now but so far I’m not coming up with anything that addresses my specific scenario, which makes me think I’m also going about this the wrong way but so far this method has been working for the rest of the game (such as loading the different Stages and Level scenes). Thanks.

January 24, 2012 at 2:58 am #362950

mavrik5150
Participant
@mavrik5150

bump please. I know that this may be trivial, but I just can’t seem to figure out why the Array in the later stages is pulling all of the objects from every level in the XML list. Thanks.

January 24, 2012 at 7:50 am #362951

mavrik5150
Participant
@mavrik5150

Actually never mind the bump, I just realized that since I’m putting all of my objects into a dictionary and then adding it to an array I could just use NSPredicate to filter out the dictionary items for that specific level by adding the level number to the dictionary as well. So far it works, may not be the best approach or even cleanest, but so far it’s working for my prototype and that’s enough to keep me moving to the next step.

March 2, 2012 at 9:15 am #362952

elsevero
Participant
@elsevero-1

@mavrik5150: Almost the same issue that you had but in my case its a little bit different; In my case a level will have an amount of games and each game will have some item sprites to it.

For that I’ve created separate classes for games and item sprites.

In ItemSprite XML file

<ItemSprite>
<IsEnabled>0</IsEnabled>
<IncludedInGameNumber>2</IncludedInGameNumber>
<Picture>image.png</Picture>
<Text>Text</Text>
<xCoordonate>500</xCoordonate>
<yCoordonate>500</yCoordonate>
<tag>1</tag>
<zOrder>2</zOrder>
</ItemSprite>

How should I proceed in order that for my each level to manage the games dynamically (also each itemSprite to added to its game)? Thanks!

March 2, 2012 at 11:48 am #362953

mavrik5150
Participant
@mavrik5150

It all depends on how you are parsing the XML file, the structure of your XML file and what you are parsing it into. In my case I was adding each item that was parsed into a NSMutableDictionary so that I can add a “Key” value for each item and then add the end of the parsing each “group” of items was added to a NSMutableArray so when needed I can use both “ValueForKey” and “ObjectAtIndex” to get the exact information I needed based on the Chapter and Level selected.

You may want to look at this tutorial http://timroadley.com/2011/07/08/game-template-part-1-universal-support/ , when I was struggling I read his examples on the level parsing and it helped me figure out what I needed to do to get my setup to work. Depending again on how you are setting up your XML file you could do something like what I did in what file that breaks down the objects needed for each stage by using a counter to make sure the element being parsed belongs to the same level you want to play

for (GDataXMLElement *element in dataArray) {

count++;
NSArray *objectTypeArray = [element elementsForName:@"Object"];

if (count == levelNumber) {
if (objectTypeArray.count > 0) {
for (int i = 0; i < objectTypeArray.count; i++) {
//start adding items to the NSMutableDictionary then add the Dictionary to the NSMutableArray
}}}

March 2, 2012 at 1:16 pm #362954

elsevero
Participant
@elsevero-1

@mavrik5150: So I should add the items when I’m parsing Games, in GameParser class?

From that tutorial in the GameScene class I have:

Levels *levels = [LevelParser loadLevelsForChapter:selectedLevel];
Games *games = [GameParser loadGamesForLevel:selectedLevel fromChapter:selectedChapter];
SpriteItems *spriteItems = [SpriteItemParser loadISpritetemsForLevel:selectedLevel fromChapter:selectedChapter];

and over there I create the for loops:

for (Level *level in levels.levels) {
if (chapter.number == selectedChapter) {
//do stuff here
}
}

Should I do also for spriteItems like this?

for (SpriteItem *spriteItem in SpriteItems.spriteItems) {
if (SpriteItem.includedInGameNumber-1 == [games.games indexOfObject:game]) {
}
}

March 6, 2012 at 8:36 am #362955

HHG
@hhg

Hey everyone… This looks like some very cool code. I have a tool I designed & directed the development of back in 2009/2010 called the Layout Editor. It handles object placement, movement on a timeline, alignment, centering, asset labels, custom fonts. etc.. and it exports in XML and Binary. The data structures between my back end and Cocos are very similar and could be easily hooked up to nodes and actions… Here’s a sample of the code the system outputs and a couple screenshots.

Thx,

Thomas

<ACTOR2D_TEXT>

<STRING>OPTIONS</STRING>

<FONT_SIZE>24</FONT_SIZE>

<FONT_NAME>SF Collegiate Solid Italic</FONT_NAME>

<FONT_DIMENSIONS>96 64</FONT_DIMENSIONS>

<FONT_ALIGNMENT>-1</FONT_ALIGNMENT>

<FONT_RGBA>0.509804 0.4745098 0.2196078 1</FONT_RGBA>

<DROP_SHADOW>YES</DROP_SHADOW>

<DROP_COLOR>0 0 0 1</DROP_COLOR>

<DROP_OFFSET>2 2</DROP_OFFSET>

<POSITION>-190 -64 0</POSITION>

<SCALE>1 1 1</SCALE>

<FADING>0 0 1 1.21 SIMPLE</FADING>

<ROTATION>0 0 0</ROTATION>

<ACTION>BUTTON_OPTIONS</ACTION>

<REGION>-344 -59 87 32</REGION>

<MOVEMENT>0 -339 -79 0 -186 -80 0 1.21 SIMPLE</MOVEMENT>

</ACTOR2D_TEXT>

<ACTOR2D>

<POSITION>-83 -116 0</POSITION>

<SCALE>1 1 1</SCALE>

<SCALING>0 1 1 1 1 1 1 0.5 SIMPLE</SCALING>

<FADING>0 1 1 0.5 SIMPLE</FADING>

<ROTATION>0 0 0</ROTATION>

<FILE>UI_bar_tabs.png</FILE>

<ACTION>TAB_QP_SETTINGS</ACTION>

<REGION>-83 -181 156 34</REGION>

<MOVEMENT>0 -83 -181 0 -83 -116 0 0.5 SIMPLE</MOVEMENT>

</ACTOR2D>

April 25, 2012 at 11:05 am #362956

akrant06
Participant
@akrant06

Hi Everyone ,

I am using GDataXml for parsing XMl .

How can I update a perticular nod in my xml file. ?

Any help appreciated.

June 19, 2012 at 12:22 am #362957

kingappdesigns
@kingappdesigns

How would i add a int value to the scene like how many monster i spawn from the xml file and actually put the int value into the scene

June 19, 2012 at 11:33 pm #362958

kingappdesigns
@kingappdesigns

I Have This Actually In My Game Play Layer

GameData *gameData = [GameDataParser loadData];

int selectedChapter = gameData.selectedChapter;
int selectedLevel = gameData.selectedLevel;

NSMutableArray *levels = [LevelParser loadLevelsForChapter:selectedChapter];

for (Level *level in levels) {
if (level.number == selectedLevel) {

currentNumberOfDucks = level.maxducks;

maxNumberOfDucks = level.currentducks;

}
}

The Reason They Need To Be In My Gameplaylayer is Because of This

-(void)gameLogic:(ccTime)dt {

if (currentNumberOfDucks < maxNumberOfDucks)
{
[self addTarget];
currentNumberOfDucks++;
}

But It Evidently Not Passing The Int Values From The Xml File

Will Please Help Me

June 20, 2012 at 4:25 pm #362959

mavrik5150
Participant
@mavrik5150

Although I have moved on to a different route for my prototype, I still have the code for the first prototype and below is what I did to pass an int value to the game from the XML file.

//LevelParser file
+(NSMutableArray *) loadLevelDataForLevelNumber:(int)levelNumber {

NSMutableArray *objectArray = [[[NSMutableArray alloc] init] autorelease];

//Create File Path for XML Document
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc == nil) {
return nil;
}

//Create Array with contents of XPath Query
NSArray *dataArray = [doc nodesForXPath:@"//Objects/Level" error:nil];

//to help find only the level items we want from the request we will use a counter to match the items in the array to the level selected
int count = 0;

for (GDataXMLElement *element in dataArray) {

count++;
NSArray *objectTypeArray = [element elementsForName:@"Object"];

if (count == levelNumber) {
if (objectTypeArray.count > 0) {
for (int i = 0; i < objectTypeArray.count; i++) {
//Since there are multiple items for each stage first add each item individually to a temporary dictionary then add to the array
NSMutableDictionary *tempDict = [NSMutableDictionary dictionary];
int typeNumber = [[(GDataXMLNode *)[[objectTypeArray objectAtIndex:i] attributeForName:@"type"] stringValue] intValue];
int spawnNumber = [[(GDataXMLNode *)[[objectTypeArray objectAtIndex:i] attributeForName:@"spawnProbability"] stringValue] intValue];
float fallFloat = [[(GDataXMLNode *)[[objectTypeArray objectAtIndex:i] attributeForName:@"fallSpeed"] stringValue] floatValue];
[tempDict setObject:[NSNumber numberWithInt:typeNumber] forKey:@"ObjectType"];
[tempDict setObject:[NSNumber numberWithInt:spawnNumber] forKey:@"ObjectSpawn"];
[tempDict setObject:[NSNumber numberWithFloat:fallFloat] forKey:@"ObjectFall"];
[objectArray addObject:tempDict];
}
}
}
}

return objectArray;
}

//First in my init method I fill an array with all the items from the XML File for this specific level
self.levelObjects = [PoxLevelParser loadLevelDataForLevelNumber:selectedLevel];

//Then later when I need one of the values I just use:
int number = [[[levelObjects valueForKey:@"ObjectType"] objectAtIndex:i] intValue];

Hope that helps a little. But as I said that example from Tim was very helpful in getting me to understand this entire process, so I’m not sure why you are having so much trouble with it but maybe you can post your Parser code as well to see if maybe it’s something in there that is causing this.

Viewing 11 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic.