前言:
手游項目《天天打蚊子》終於上線,特地寫幾篇技術分享文章,分享一下其中使用到的技術,其中使用cocos2d-x引擎,首選平台iOS,也請有iPhone或者iPad的朋友幫忙下載好評。十分感謝。
目前完美支持iPhone4、iPhone 4S、iPhone 5、iPad所有版本,iOS 5以上開始支持。
目前開發團隊3個人,本人客戶端+服務端,另有1名客戶端,1名美術,目前創業剛剛起步,請各位好友支持!
《天天打蚊子》下載地址:https://itunes.apple.com/cn/app/id681203794
一、Cocos2d-x中的數據存儲。
1、CCUserDefault數據存儲
CCUserDefault頭文件:

1 class CC_DLL CCUserDefault 2 { 3 public: 4 ~CCUserDefault(); 5 6 // get value methods 7 8 /** 9 @brief Get bool value by key, if the key doesn't exist, a default value will return. 10 You can set the default value, or it is false. 11 */ 12 bool getBoolForKey(const char* pKey); 13 bool getBoolForKey(const char* pKey, bool defaultValue); 14 /** 15 @brief Get integer value by key, if the key doesn't exist, a default value will return. 16 You can set the default value, or it is 0. 17 */ 18 int getIntegerForKey(const char* pKey); 19 int getIntegerForKey(const char* pKey, int defaultValue); 20 /** 21 @brief Get float value by key, if the key doesn't exist, a default value will return. 22 You can set the default value, or it is 0.0f. 23 */ 24 float getFloatForKey(const char* pKey); 25 float getFloatForKey(const char* pKey, float defaultValue); 26 /** 27 @brief Get double value by key, if the key doesn't exist, a default value will return. 28 You can set the default value, or it is 0.0. 29 */ 30 double getDoubleForKey(const char* pKey); 31 double getDoubleForKey(const char* pKey, double defaultValue); 32 /** 33 @brief Get string value by key, if the key doesn't exist, a default value will return. 34 You can set the default value, or it is "". 35 */ 36 std::string getStringForKey(const char* pKey); 37 std::string getStringForKey(const char* pKey, const std::string & defaultValue); 38 39 // set value methods 40 41 /** 42 @brief Set bool value by key. 43 */ 44 void setBoolForKey(const char* pKey, bool value); 45 /** 46 @brief Set integer value by key. 47 */ 48 void setIntegerForKey(const char* pKey, int value); 49 /** 50 @brief Set float value by key. 51 */ 52 void setFloatForKey(const char* pKey, float value); 53 /** 54 @brief Set double value by key. 55 */ 56 void setDoubleForKey(const char* pKey, double value); 57 /** 58 @brief Set string value by key. 59 */ 60 void setStringForKey(const char* pKey, const std::string & value); 61 /** 62 @brief Save content to xml file 63 */ 64 void flush(); 65 66 static CCUserDefault* sharedUserDefault(); 67 static void purgeSharedUserDefault(); 68 const static std::string& getXMLFilePath(); 69 static bool isXMLFileExist(); 70 71 private: 72 CCUserDefault(); 73 static bool createXMLFile(); 74 static void initXMLFilePath(); 75 76 static CCUserDefault* m_spUserDefault; 77 static std::string m_sFilePath; 78 static bool m_sbIsFilePathInitialized; 79 };
其中包括多種方法(getBoolForKey,getFloatForKey,getIntegerForKey等等),可根據具體需要存儲的數據類型進行選擇。
具體實現:
比如在游戲開發過程中,要實現本地存儲新手引導中的某一步是否已經訪問過,我可以這樣:
1 bool DataHelper::getIsVisit(EnumNewUserGuid type) 2 { 3 const char * key = CCString::createWithFormat("NewUserGuid_%d",type)->getCString(); 4 return CCUserDefault::sharedUserDefault()->getBoolForKey(key, false); 5 } 6 7 void DataHelper::setVisit(EnumNewUserGuid type) 8 { 9 const char * key = CCString::createWithFormat("NewUserGuid_%d",type)->getCString(); 10 CCUserDefault::sharedUserDefault()->setBoolForKey(key, true); 11 }
其中,EnumNewUserGuid為新手引導的步驟的枚舉。
下面將使用CCUserDefault實現音效管理。
2、iOS keychain數據存儲
上篇文章講到iOS keychain的數據存儲方法,本文加上為C++的接口。keychain.h keychain.m文件再貼一次。

1 #import <Foundation/Foundation.h> 2 3 @interface Keychain : NSObject 4 //keychain 5 + (NSMutableDictionary *)getKeychainQuery:(NSString *)service; 6 + (void)saveData:(NSString *)service data:(id)data; 7 + (id)loadData:(NSString *)service; 8 + (void)deleteData:(NSString *)service; 9 @end

1 #import "Keychain.h" 2 3 @implementation Keychain 4 5 //keychain 6 + (NSMutableDictionary *)getKeychainQuery:(NSString *)service 7 { 8 NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: 9 (id)kSecClassGenericPassword,(id)kSecClass, 10 service, (id)kSecAttrService, 11 service, (id)kSecAttrAccount, 12 (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible, 13 nil]; 14 return dict; 15 } 16 17 + (void)saveData:(NSString *)service data:(id)data 18 { 19 //Get search dictionary 20 NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 21 //Delete old item before add new item 22 SecItemDelete((CFDictionaryRef)keychainQuery); 23 //Add new object to search dictionary(Attention:the data format) 24 [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData]; 25 //Add item to keychain with the search dictionary 26 SecItemAdd((CFDictionaryRef)keychainQuery, NULL); 27 } 28 29 + (id)loadData:(NSString *)service 30 { 31 id ret = nil; 32 NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 33 //Configure the search setting 34 //Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue 35 [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; 36 [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; 37 CFDataRef keyData = NULL; 38 if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { 39 @try { 40 ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData]; 41 } @catch (NSException *e) { 42 CLog(@"Unarchive of %@ failed: %@", service, e); 43 } @finally { 44 } 45 } 46 if (keyData) 47 CFRelease(keyData); 48 return ret; 49 } 50 51 + (void)deleteData:(NSString *)service 52 { 53 NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 54 SecItemDelete((CFDictionaryRef)keychainQuery); 55 } 56 57 @end
下面用keychain記錄本地賬號:
DBInfoAccount.h
1 #include "cocos2d.h" 2 3 using namespace cocos2d; 4 5 class DBInfoAccount { 6 7 public: 8 9 int m_iUserID; 10 CCString * m_pAccountID; 11 CCString * m_pPassword; 12 13 DBInfoAccount(); 14 static DBInfoAccount * getInstance(); 15 bool isHasAccount(); 16 17 //數據存取 18 void loadData(); 19 static void saveData(); 20 static void reset(); 21 };
DBInfoAccount.mm
1 #import "Keychain.h" 2 #include "DBInfoAccount.h" 3 4 5 6 //#define kAccount @"Account" 7 #define kAccountAccountID @"Account_Account_ID" 8 #define kAccountUserID @"Account_UserID" 9 #define kAccountPassword @"Account_Pwd" 10 11 12 13 static DBInfoAccount * s_pDBInfoAccount = NULL; 14 15 DBInfoAccount::DBInfoAccount(): 16 m_iUserID(0) 17 { 18 m_pAccountID = new CCString(""); 19 m_pPassword = new CCString(""); 20 } 21 22 DBInfoAccount * DBInfoAccount::getInstance() 23 { 24 if (s_pDBInfoAccount == NULL) { 25 s_pDBInfoAccount -> loadData(); 26 if (s_pDBInfoAccount == NULL) { 27 s_pDBInfoAccount = new DBInfoAccount; 28 } 29 } 30 31 return s_pDBInfoAccount; 32 } 33 34 bool DBInfoAccount::isHasAccount() 35 { 36 return m_pAccountID!= NULL && m_pAccountID -> length()>0; 37 } 38 39 void DBInfoAccount::loadData() 40 { 41 if (s_pDBInfoAccount == NULL) { 42 NSString * accountID = [Keychain loadData: kAccountAccountID]; 43 NSString * userID = [Keychain loadData: kAccountUserID]; 44 NSString * password = [Keychain loadData: kAccountPassword]; 45 s_pDBInfoAccount = new DBInfoAccount; 46 const char * c_accountID = [accountID cStringUsingEncoding:NSUTF8StringEncoding]; 47 DWORD c_userID = [userID intValue]; 48 const char * c_password = [password cStringUsingEncoding:NSUTF8StringEncoding]; 49 50 if (c_accountID != NULL && c_password != NULL) { 51 s_pDBInfoAccount -> m_pAccountID -> m_sString = c_accountID; 52 s_pDBInfoAccount -> m_iUserID = c_userID; 53 s_pDBInfoAccount -> m_pPassword -> m_sString = c_password; 54 } 55 } 56 } 57 58 void DBInfoAccount::saveData() 59 { 60 NSString * accountID = [NSString stringWithCString:s_pDBInfoAccount->m_pAccountID->getCString() encoding:NSUTF8StringEncoding]; 61 NSString * userID = [NSString stringWithFormat:@"%d",s_pDBInfoAccount->m_iUserID]; 62 NSString * password = [NSString stringWithCString:s_pDBInfoAccount->m_pPassword->getCString() encoding:NSUTF8StringEncoding]; 63 [Keychain saveData:kAccountAccountID data: accountID]; 64 [Keychain saveData:kAccountUserID data: userID]; 65 [Keychain saveData:kAccountPassword data: password]; 66 } 67 68 void DBInfoAccount::reset() 69 { 70 [Keychain deleteData:kAccountAccountID]; 71 [Keychain deleteData:kAccountUserID]; 72 [Keychain deleteData:kAccountPassword]; 73 }
具體用法一目了然,不再贅述。
二、音效管理。
廢話不說,直接上代碼:
1 void DataHelper::initMusicAndEffect() 2 { 3 bool isEffectEnabel = DataHelper::getEffectEnable(); 4 CocosDenshion::SimpleAudioEngine::sharedEngine()->setEffectsVolume(isEffectEnabel); 5 6 bool isMusicEnable = DataHelper::getMusicEnable(); 7 CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(isMusicEnable); 8 } 9 bool DataHelper::getEffectEnable() 10 { 11 return CCUserDefault::sharedUserDefault()->getBoolForKey("Effect_Enable", true); 12 } 13 bool DataHelper::getMusicEnable() 14 { 15 return CCUserDefault::sharedUserDefault()->getBoolForKey("Music_Enable", true); 16 } 17 void DataHelper::setEffectEnable(bool isEnable) 18 { 19 CCUserDefault::sharedUserDefault()->setBoolForKey("Effect_Enable", isEnable); 20 CocosDenshion::SimpleAudioEngine::sharedEngine()->setEffectsVolume(isEnable); 21 } 22 void DataHelper::setMusicEnable(bool isEnable) 23 { 24 CCUserDefault::sharedUserDefault()->setBoolForKey("Music_Enable", isEnable); 25 CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(isEnable); 26 }
其中,CocosDenshion::SimpleAudioEngine::sharedEngine()->setEffectsVolume(isEffectEnabel),setEffectsVolume為設置的音效大小(0~1)的方法,這里使用false(0)和true(1)直接設置,實現是否設置為靜音。
至於播放背景音樂和音效,最好使用mp3格式的,iOS和安卓同時支持。
具體:
1 CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("bg.mp3", true);//播放背景音樂,第二個參數為是否循環播放 2 3 CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("anjian.mp3");//播放音效,比如按鍵聲
《天天打蚊子》下載地址:https://itunes.apple.com/cn/app/id681203794
請各位多多支持,給個好評呀!謝謝!或者掃描二維碼下載:
游戲視頻:
后續cocos2d-x技術文章陸續放出,敬請關注!!