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 };
CCUserDefault.h

  其中包括多种方法(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
keychain.h
 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.m

  下面用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技术文章陆续放出,敬请关注!!

原文地址:https://www.cnblogs.com/chenshengtai/p/tiantiandawenzi.html