0

所以我目前有一种为我的 Cocos2d 游戏保存设置的有效方法,我使用的方法是 XML 解析器。

首先,将 NSUserDefaults 用于这样的事情会更好吗?

编辑:如果您已经知道 XML 解析器的工作原理,请跳到最后。

这是我的 GlobalSettings.h:

#import <Foundation/Foundation.h>

@interface GlobalSettings : NSObject {

// Declare variables with an underscore in front, for example:
int _currency;
BOOL _BankerBossDefeated;
BOOL _BabyBossDefeated;
BOOL _DuckBossDefeated;
BOOL _BaseBallBossDefeated;
BOOL _NewtonBossDefeated;

BOOL _CatchExtender;
BOOL _CatchExtenderEnabled;
BOOL _SpeedBoost;
BOOL _SpeedBoostEnabled;
}

// Declare your variable properties without an underscore, for example:
@property (nonatomic, assign) int currency;
@property (nonatomic, assign) BOOL BankerBossDefeated;
@property (nonatomic, assign) BOOL BabyBossDefeated;
@property (nonatomic, assign) BOOL DuckBossDefeated;
@property (nonatomic, assign) BOOL BaseBallBossDefeated;
@property (nonatomic, assign) BOOL NewtonBossDefeated;
@property (nonatomic, assign) BOOL SpeedBoost;
@property (nonatomic, assign) BOOL CatchExtender;
@property (nonatomic, assign) BOOL SpeedBoostEnabled;
@property (nonatomic, assign) BOOL CatchExtenderEnabled;

// Put your custom init method interface here:
-(id)initWithcurrency:(int)currency 
BankerBossDefeated:(BOOL)BankerBossDefeated
BabyBossDefeated:(BOOL)BabyBossDefeated
DuckBossDefeated:(BOOL)DuckBossDefeated
BaseBallBossDefeated:(BOOL)BaseBallBossDefeated
NewtonBossDefeated:(BOOL)NewtonBossDefeated
CatchExtender:(BOOL)CatchExtender
       SpeedBoost:(BOOL)SpeedBoost
 CatchExtenderEnabled:(BOOL)CatchExtenderEnabled
       SpeedBoostEnabled:(BOOL)SpeedBoostEnabled;

@end

我的 GlobalSettings.m 是:

#import "GlobalSettings.h"

@implementation GlobalSettings

// Synthesize your variables here, for example: 
@synthesize currency = _currency;
@synthesize BankerBossDefeated = _BankerBossDefeated;
@synthesize BabyBossDefeated = _BabyBossDefeated;
@synthesize DuckBossDefeated = _DuckBossDefeated;
@synthesize BaseBallBossDefeated = _BaseBallBossDefeated;
@synthesize NewtonBossDefeated = _NewtonBossDefeated;
@synthesize SpeedBoost = _SpeedBoost;
@synthesize CatchExtender = _CatchExtender;
@synthesize SpeedBoostEnabled = _SpeedBoostEnabled;
@synthesize CatchExtenderEnabled = _CatchExtenderEnabled;

// put your custom init method here which takes a variable 
// for each class instance variable
-(id)initWithcurrency:(int)currency
BankerBossDefeated:(BOOL)BankerBossDefeated
 BabyBossDefeated:(BOOL)BabyBossDefeated
 DuckBossDefeated:(BOOL)DuckBossDefeated
 BaseBallBossDefeated:(BOOL)BaseBallBossDefeated
NewtonBossDefeated:(BOOL)NewtonBossDefeated
    CatchExtender:(BOOL)CatchExtender
       SpeedBoost:(BOOL)SpeedBoost
    CatchExtenderEnabled:(BOOL)CatchExtenderEnabled
       SpeedBoostEnabled:(BOOL)SpeedBoostEnabled;{

if ((self = [super init])) {

    // Set class instance variables based on values 
    // given to this method
    self.currency = currency; 
    self.BankerBossDefeated = BankerBossDefeated;  
    self.BabyBossDefeated = BabyBossDefeated;
    self.DuckBossDefeated = DuckBossDefeated;
    self.BaseBallBossDefeated = BaseBallBossDefeated;
    self.NewtonBossDefeated = NewtonBossDefeated;
    self.CatchExtender = CatchExtender;
    self.SpeedBoost = SpeedBoost;
    self.CatchExtenderEnabled = CatchExtenderEnabled;
    self.SpeedBoostEnabled = SpeedBoostEnabled;
}
return self;
}

- (void) dealloc {
[super dealloc];
}

@end

然后我用 SettingsParser.h 解析 XML:

#import <Foundation/Foundation.h>

@class GlobalSettings;

@interface SettingsParser : NSObject {} 

+ (GlobalSettings *)loadData;
+ (void)saveData:(GlobalSettings *)saveData;

@end

和 SettingsParser.m:

#import "SettingsParser.h"  
#import "GlobalSettings.h"  
#import "GDataXMLNode.h"

@implementation SettingsParser

+ (NSString *)dataFilePath:(BOOL)forSave {

NSString *xmlFileName = @"GlobalSettings";

/***************************************************************************
 This method is used to set up the specified xml for reading/writing.
 Specify the name of the XML file you want to work with above.
 You don't have to worry about the rest of the code in this method.
 ***************************************************************************/

NSString *xmlFileNameWithExtension = [NSString stringWithFormat:@"%@.xml",xmlFileName];    
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,     NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentsPath = [documentsDirectory     stringByAppendingPathComponent:xmlFileNameWithExtension];
if (forSave || [[NSFileManager defaultManager] fileExistsAtPath:documentsPath]) {
    return documentsPath;   
    NSLog(@"%@ opened for read/write",documentsPath);
} else {
    NSLog(@"Created/copied in default %@",xmlFileNameWithExtension);
    return [[NSBundle mainBundle] pathForResource:xmlFileName ofType:@"xml"];
}    
}

+ (GlobalSettings *)loadData {

/*************************************************************************** 
 This loadData method is used to load data from the xml file 
 specified in the dataFilePath method above.  

 MODIFY the list of variables below which will be used to create
 and return an instance of TemplateData at the end of this method.
 ***************************************************************************/

int currency;
BOOL BankerBossDefeated;
BOOL BabyBossDefeated;
BOOL DuckBossDefeated;
BOOL BaseBallBossDefeated;
BOOL NewtonBossDefeated;
BOOL CatchExtender;
BOOL SpeedBoost;
BOOL CatchExtenderEnabled;
BOOL SpeedBoostEnabled;


// Create NSData instance from xml in filePath
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; NSLog(@"xml file is empty!");}
NSLog(@"Loading %@", filePath);

/*************************************************************************** 
 This next line will usually have the most customisation applied because 
 it will be a direct reflection of what you want out of the XML file.
 ***************************************************************************/

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

/*************************************************************************** 
 We use dataArray to populate variables created at the start of this 
 method. For each variable you will need to:
    1. Create an array based on the elements in the xml
    2. Assign the variable a value based on data in elements in the xml
 ***************************************************************************/

for (GDataXMLElement *element in dataArray) {

    NSArray *currencyArray = [element elementsForName:@"currency"];       
    NSArray *BankerBossDefeatedArray = [element elementsForName:@"BankerBossDefeated"];   
    NSArray *BabyBossDefeatedArray = [element elementsForName:@"BabyBossDefeated"]; 
    NSArray *DuckBossDefeatedArray = [element elementsForName:@"DuckBossDefeated"]; 
    NSArray *BaseBallBossDefeatedArray = [element     elementsForName:@"BaseBallBossDefeated"]; 
    NSArray *NewtonBossDefeatedArray = [element elementsForName:@"NewtonBossDefeated"];
    NSArray *CatchExtenderArray = [element elementsForName:@"CatchExtender"];
    NSArray *SpeedBoostArray = [element elementsForName:@"SpeedBoost"];
    NSArray *CatchExtenderEnabledArray = [element elementsForName:@"CatchExtenderEnabled"];
    NSArray *SpeedBoostEnabledArray = [element elementsForName:@"SpeedBoostEnabled"];

    // currency
    if (currencyArray.count > 0) {
        GDataXMLElement *currencyElement = (GDataXMLElement *) [currencyArray objectAtIndex:0];
        currency = [[currencyElement stringValue] intValue];
    } 

    // BankerBossDefeated    
    if (BankerBossDefeatedArray.count > 0) {
        GDataXMLElement *BankerBossDefeatedElement = (GDataXMLElement *) [BankerBossDefeatedArray objectAtIndex:0];
        BankerBossDefeated = [[BankerBossDefeatedElement stringValue] boolValue];
    }

    // DuckBossDefeated    
    if (DuckBossDefeatedArray.count > 0) {
        GDataXMLElement *DuckBossDefeatedElement = (GDataXMLElement *) [DuckBossDefeatedArray objectAtIndex:0];
        DuckBossDefeated = [[DuckBossDefeatedElement stringValue] boolValue];
    }

    // BabyBossDefeated    
    if (BabyBossDefeatedArray.count > 0) {
        GDataXMLElement *BabyBossDefeatedElement = (GDataXMLElement *) [BabyBossDefeatedArray objectAtIndex:0];
        BabyBossDefeated = [[BabyBossDefeatedElement stringValue] boolValue];
    }

    // BaseBallBossDefeated    
    if (BaseBallBossDefeatedArray.count > 0) {
        GDataXMLElement *BaseBallBossDefeatedElement = (GDataXMLElement *) [BaseBallBossDefeatedArray objectAtIndex:0];
        BaseBallBossDefeated = [[BaseBallBossDefeatedElement stringValue] boolValue];
    }

    // NewtonBossDefeated    
    if (NewtonBossDefeatedArray.count > 0) {
        GDataXMLElement *NewtonBossDefeatedElement = (GDataXMLElement *) [NewtonBossDefeatedArray objectAtIndex:0];
        NewtonBossDefeated = [[NewtonBossDefeatedElement stringValue] boolValue];
    }
    // CatchExtender
    if (CatchExtenderArray.count > 0) {
        GDataXMLElement *CatchExtenderElement = (GDataXMLElement *) [CatchExtenderArray objectAtIndex:0];
        CatchExtender = [[CatchExtenderElement stringValue] boolValue];
    }
    // SpeedBoost
    if (SpeedBoostArray.count > 0) {
        GDataXMLElement *SpeedBoostElement = (GDataXMLElement *) [SpeedBoostArray objectAtIndex:0];
        SpeedBoost = [[SpeedBoostElement stringValue] boolValue];
    }

    // CatchExtenderEnabled
    if (CatchExtenderEnabledArray.count > 0) {
        GDataXMLElement *CatchExtenderEnabledElement = (GDataXMLElement *) [CatchExtenderEnabledArray objectAtIndex:0];
        CatchExtenderEnabled = [[CatchExtenderEnabledElement stringValue] boolValue];
    }
    // SpeedBoost
    if (SpeedBoostEnabledArray.count > 0) {
        GDataXMLElement *SpeedBoostEnabledElement = (GDataXMLElement *) [SpeedBoostEnabledArray objectAtIndex:0];
        SpeedBoostEnabled = [[SpeedBoostEnabledElement stringValue] boolValue];
    }

}

/*************************************************************************** 
 Now the variables are populated from xml data we create an instance of
 TemplateData to pass back to whatever called this method.

 The initWithExampleInt:exampleBool:exampleString will need to be replaced
 with whatever method you have updaed in the TemplateData class.
 ***************************************************************************/

//NSLog(@"XML value read for exampleInt = %i", exampleInt);
//NSLog(@"XML value read for exampleBool = %i", exampleBool);
//NSLog(@"XML value read for exampleString = %@", exampleString);

GlobalSettings *Data = [[GlobalSettings alloc] initWithcurrency:currency
                                                  BankerBossDefeated:BankerBossDefeated
                                               BabyBossDefeated:BabyBossDefeated     DuckBossDefeated:DuckBossDefeated BaseBallBossDefeated:BaseBallBossDefeated     NewtonBossDefeated:NewtonBossDefeated
                                                  CatchExtender:CatchExtender
                                                     SpeedBoost:SpeedBoost     CatchExtenderEnabled:CatchExtenderEnabled
                                                     SpeedBoostEnabled:SpeedBoostEnabled];

[doc release];
[xmlData release];
return Data;
[Data release];
}

+ (void)saveData:(GlobalSettings *)saveData {


/*************************************************************************** 
 This method writes data to the xml based on a TemplateData instance
 You will have to be very aware of the intended xml contents and structure
 as you will be wiping and re-writing the whole xml file.

 We write an xml by creating elements and adding 'children' to them.

 You'll need to write a line for each element to build the hierarchy // <-- MODIFY CODE ACCORDINGLY
 ***************************************************************************/

GDataXMLElement *GlobalSettingsElement = [GDataXMLNode elementWithName:@"GlobalSettings"];

GDataXMLElement *currencyElement = [GDataXMLNode elementWithName:@"currency" 
                                                       stringValue:[[NSNumber numberWithInt:saveData.currency] stringValue]];

GDataXMLElement *BankerBossDefeatedElement = [GDataXMLNode elementWithName:@"BankerBossDefeated"   
                                                        stringValue:[[NSNumber numberWithBool:saveData.BankerBossDefeated] stringValue]];

GDataXMLElement *BabyBossDefeatedElement = [GDataXMLNode elementWithName:@"BabyBossDefeated"   
                                                               stringValue:[[NSNumber numberWithBool:saveData.BabyBossDefeated] stringValue]];

GDataXMLElement *DuckBossDefeatedElement = [GDataXMLNode elementWithName:@"DuckBossDefeated"   
                                                               stringValue:[[NSNumber numberWithBool:saveData.DuckBossDefeated] stringValue]];

GDataXMLElement *BaseBallBossDefeatedElement = [GDataXMLNode elementWithName:@"BaseBallBossDefeated"   
                                                               stringValue:[[NSNumber numberWithBool:saveData.BaseBallBossDefeated] stringValue]];

GDataXMLElement *NewtonBossDefeatedElement = [GDataXMLNode elementWithName:@"NewtonBossDefeated"   
                                                               stringValue:[[NSNumber numberWithBool:saveData.NewtonBossDefeated] stringValue]];
GDataXMLElement *CatchExtenderElement = [GDataXMLNode elementWithName:@"CatchExtender"
                                                               stringValue:[[NSNumber numberWithBool:saveData.CatchExtender] stringValue]];
GDataXMLElement *SpeedBoostElement = [GDataXMLNode elementWithName:@"SpeedBoost"
                                                               stringValue:[[NSNumber numberWithBool:saveData.SpeedBoost] stringValue]];
GDataXMLElement *CatchExtenderEnabledElement = [GDataXMLNode elementWithName:@"CatchExtenderEnabled"
                                                          stringValue:[[NSNumber numberWithBool:saveData.CatchExtender] stringValue]];
GDataXMLElement *SpeedBoostEnabledElement = [GDataXMLNode elementWithName:@"SpeedBoostEnabled"
                                                       stringValue:[[NSNumber numberWithBool:saveData.SpeedBoost] stringValue]];


// Using the elements just created, set up the hierarchy
[GlobalSettingsElement addChild:currencyElement];
[GlobalSettingsElement addChild:BankerBossDefeatedElement];
[GlobalSettingsElement addChild:BabyBossDefeatedElement];
[GlobalSettingsElement addChild:DuckBossDefeatedElement];
[GlobalSettingsElement addChild:BaseBallBossDefeatedElement];
[GlobalSettingsElement addChild:NewtonBossDefeatedElement];
[GlobalSettingsElement addChild:CatchExtenderElement];
[GlobalSettingsElement addChild:SpeedBoostElement];
[GlobalSettingsElement addChild:CatchExtenderEnabledElement];
[GlobalSettingsElement addChild:SpeedBoostEnabledElement];

GDataXMLDocument *document = [[[GDataXMLDocument alloc] 
                               initWithRootElement:GlobalSettingsElement] autorelease];

NSData *xmlData = document.XMLData;

NSString *filePath = [self dataFilePath:TRUE];
NSLog(@"Saving data to %@...", filePath);
[xmlData writeToFile:filePath atomically:YES];
}

@end

编辑:实际问题从这里开始:

在我的菜单类中,当 CatchExtender 和 SpeedBoost 启用时,我有两个开关(它们是在游戏商店中购买的)。在这些开关中,我想根据开关设置 SpeedBoostEnabled 和 CatchExtenderEnabled。

这些是开关:

在我的初始化中:

if (GlobalSettings.CatchExtender == TRUE) {
        if(GlobalSettings.SpeedBoost == TRUE){
            catchSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(220, 400, 10, 10)];
            catchSwitch.center = CGPointMake(240, 450);

            CCLabelTTF *catchLabel = [CCLabelTTF labelWithString:@"Catch Extender" fontName:@"Chalkduster" fontSize:15];
            catchLabel.color = ccWHITE;
            catchLabel.position = CGPointMake(240, 60);
            [self addChild: catchLabel];
        }else{
            catchSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(160, 400, 10, 10)];
            catchSwitch.center = CGPointMake(160, 450);
            CCLabelTTF *catchLabel = [CCLabelTTF labelWithString:@"Catch Extender" fontName:@"Chalkduster" fontSize:15];
            catchLabel.color = ccWHITE;
            catchLabel.position = CGPointMake(160, 60);
            [self addChild: catchLabel];
        }

        catchSwitch.on = NO;  //set to be OFF at start
        catchSwitch.tag = 1;  // this is not necessary - only to find later
        [catchSwitch addTarget:self action:@selector(catchAction:) forControlEvents:UIControlEventValueChanged];
        [[[CCDirector sharedDirector] openGLView] addSubview:catchSwitch];


    }

    if (GlobalSettings.SpeedBoost == TRUE) {
        if(GlobalSettings.CatchExtender == TRUE){
            speedSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(100, 400, 10, 10)];
            speedSwitch.center = CGPointMake(80, 450);
            CCLabelTTF *speedLabel = [CCLabelTTF labelWithString:@"Speed Enhancer" fontName:@"Chalkduster" fontSize:15];
            speedLabel.color = ccWHITE;
            speedLabel.position = CGPointMake(80, 60);
            [self addChild: speedLabel];
        }else{
            speedSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(160, 400, 10, 10)];
            speedSwitch.center = CGPointMake(160, 450);
        }

        speedSwitch.on = NO;  //set to be OFF at start
        speedSwitch.tag = 1;  // this is not necessary - only to find later
        [speedSwitch addTarget:self action:@selector(speedAction:) forControlEvents:UIControlEventValueChanged];
        [[[CCDirector sharedDirector] openGLView] addSubview:speedSwitch];
    }

在行动中:

- (void)catchAction:(id)sender
{
// Your logic when the switch it used
// NSLog(@"switchAction: value = %d", [sender isOn]);
if ([sender isOn]) {
    GlobalSettings *GlobalSettings = [SettingsParser loadData];
    GlobalSettings.CatchExtenderEnabled = TRUE;

    UIAlertView* dialog = [[UIAlertView alloc] init];
    [dialog setDelegate:self];
    [dialog setTitle:@"ON"];
    [dialog setMessage:@"Catch Extender is on"];
    [dialog addButtonWithTitle:@"Sweet!"];
    [dialog show];
    [dialog release];
    [SettingsParser saveData:GlobalSettings];

}else{
    GlobalSettings *GlobalSettings = [SettingsParser loadData];
    GlobalSettings.CatchExtenderEnabled = FALSE;
    UIAlertView* dialog = [[UIAlertView alloc] init];
    [dialog setDelegate:self];
    [dialog setTitle:@"OFF"];
    [dialog setMessage:@"Catch Extender is off"];
    [dialog addButtonWithTitle:@"Thanks"];
    [dialog show];
    [dialog release];
    [SettingsParser saveData:GlobalSettings];
}
}

- (void)speedAction:(id)sender
{
// Your logic when the switch it used
// NSLog(@"switchAction: value = %d", [sender isOn]);
if ([sender isOn]) {
    GlobalSettings *GlobalSettings = [SettingsParser loadData];
    GlobalSettings.SpeedBoostEnabled = TRUE;

    UIAlertView* dialog = [[UIAlertView alloc] init];
    [dialog setDelegate:self];
    [dialog setTitle:@"ON"];
    [dialog setMessage:@"Speed Enhancer is on"];
    [dialog addButtonWithTitle:@"Sweet!"];
    [dialog show];
    [dialog release];
    [SettingsParser saveData:GlobalSettings];

}else{
    GlobalSettings *GlobalSettings = [SettingsParser loadData];
    GlobalSettings.SpeedBoostEnabled = FALSE;
    UIAlertView* dialog = [[UIAlertView alloc] init];
    [dialog setDelegate:self];
    [dialog setTitle:@"OFF"];
    [dialog setMessage:@"Speed Enhancer is off"];
    [dialog addButtonWithTitle:@"Thanks"];
    [dialog show];
    [dialog release];
    [SettingsParser saveData:GlobalSettings];
    }
}

在保存游戏关卡数据的类中,我通常使用一个简单的 if 语句检查这些布尔值。但它似乎不起作用,设置似乎没有保存,因为在日志中,XML 文件中的值似乎没有改变..

再次对长篇文章感到抱歉,但这个问题有点困扰我。

4

1 回答 1

2

我以前从未使用过 Cocos2D,但这看起来就像您NSUserDefaults在典型的 iOS 应用程序中使用的一样,如下所示:[[NSUserDefaults standardUserDefaults] setBool:YES ForKey:@"Key"];

于 2012-11-15T01:37:14.487 回答