Cocos2d-x手游技术分享(1)-【天天打蚊子】数据存储与音效篇
前言:
手游项目《天天打蚊子》终于上线,特地写几篇技术分享文章,分享一下其中使用到的技术,其中使用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技术文章陆续放出,敬请关注!!