植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/8UFMs
UserData.h
在头文件中定义了枚举类型openUserDataReturnType,用于表示打开用户数据文件的返回状态。FileExistError表示文件存在但是打开错误,FileExistCorrect表示文件在且正确,FileNotExist表示文件不存在。
enum class openUserDataReturnType
{
FileExistError = 1,
FileExistCorrect,
FileNotExist
};
UserData
是一个单例类,通过getInstance()
方法获取其唯一的实例。
class UserData :public Director
{
public:
static UserData* getInstance();
void flushUserData();
void flushLevelData();
void flushSurvivalData();
void caveUserData(char* key, double value);
void caveUserData(char* key, bool value);
void caveUserData(char* key, char* value);
void caveUserData(char* key, int value);
void caveLevelData(char* key);
void openLevelData(char* key);
bool isHaveLevelData(char* key);
void caveSurvivalData(char* key);
void openSurvivalData(char* key);
bool isHaveSurvivalData(char* key);
void openLevelPlantsData(char* key);
void openLevelZombiesData(char* key);
void openLevelSelectCardData(char* key);
void openLevelSunData(char* key);
void openLevelCoinData(char* key);
void openLevelCarData(char* key);
void openLevelBulletData(char* key);
void openLevelOtherData(char* key);
void openSurvivalOtherData(char* key);
void removeLevelData(char* key);
int openIntUserData(char* key);
double openDoubleUserData(char* key);
bool openBoolUserData(char* key);
const char* openStringUserData(char* key);
void createNewUserDataDocument();
void createNewLevelDataDocument();
void setAnewReadData(const bool newRead);
private:
UserData();
~UserData();
string getUserDataFileName();
string getLevelDataFileName();
string getSurvivalDataFileName();
openUserDataReturnType openUserData();
openUserDataReturnType openLevelData();
openUserDataReturnType openSurvivalData();
bool isHaveMember(char* key);
bool readLevelData();
void caveLevelPlantsData(char* key);
void caveLevelZombiesData(char* key);
void caveLevelSelectPlantsData(char* key);
void caveLevelSunData(char* key);
void caveLevelCoinData(char* key);
void caveLevelCarData(char* key);
void caveLevelBulletData(char* key);
void caveLevelOtherData(char* key);
void caveSurvivalOtherData(char* key);
void replaceScene();
#ifndef DLLTEST
string encryption(string& str);
string decryption(string& str);
#endif // !DLLTEST
private:
Document* _userDataDocument;
Document* _levelDataDocument;
FileUtils* _fileUtils;
Global* _global;
string _userData;
string _levelData;
bool _isAnewReadData;
vector<GSScene*>_gsScene;
static UserData* _instance;
};
- 公有函数:
- flushUserData()、flushLevelData()和flushSurvivalData():用于将用户数据、关卡数据和生存模式数据刷新到文件中。
- caveUserData():用于向用户数据中存储不同类型的值,如double、bool、char和int。
- caveLevelData():根据键值key保存关卡数据。
- openLevelData():打开关卡数据中指定键的值。
- isHaveLevelData():检查关卡数据中是否存在指定键的值。
- caveSurvivalData():根据键值key保存生存模式数据。
- openSurvivalData():打开生存模式数据中指定键的值。
- isHaveSurvivalData():检查生存模式数据中是否存在指定键的值。
- openLevelPlantsData()、openLevelZombiesData()等:打开关卡数据中不同类型的值,如植物数据、僵尸数据、选择卡片数据等。
- removeLevelData():从关卡数据中移除指定键的值。
- openIntUserData()、openDoubleUserData()、openBoolUserData()和openStringUserData():打开用户数据中不同类型的值。
- createNewUserDataDocument()、createNewLevelDataDocument():创建新的用户数据和关卡数据文档
- setAnewReadData():设置是否重新读取数据的标志。
- 私有函数:
- string getUserDataFileName():返回用户数据文件的名称。该函数会返回一个字符串,指定用于存储用户数据的文件名。
- string getLevelDataFileName():返回关卡数据文件的名称。该函数会返回一个字符串,指定用于存储关卡数据的文件名。
- string getSurvivalDataFileName():返回生存模式数据文件的名称。该函数会返回一个字符串,指定用于存储生存模式数据的文件名。
- openUserDataReturnType openUserData():打开用户数据。该函数会返回枚举值,用于指示用户数据的打开状态或结果。
- openUserDataReturnType openLevelData():打开关卡数据。类似于openUserData(),该函数会返回一个枚举值,用于指示关卡数据的打开状态或结果。
- openUserDataReturnType openSurvivalData():打开生存模式数据。类似于openUserData(),该函数会返回一个枚举值值,用于指示生存模式数据的打开状态或结果。
- bool isHaveMember(char* key):检查指定键是否存在于数据中。该函数接受一个char*类型的键作为参数,并返回一个布尔值,指示该键是否存在于数据中。
- bool readLevelData():读取关卡数据。该函数可能会返回一个布尔值。
- void caveLevelPlantsData(char* key):向关卡数据中存储植物数据。该函数接受一个char*类型的键作为参数,并将植物数据存储在关卡数据中。
- void caveLevelZombiesData(char* key):向关卡数据中存储僵尸数据。类似于caveLevelPlantsData(char* key),该函数将僵尸数据存储在关卡数据中。
- void caveLevelSelectPlantsData(char* key):向关卡数据中存储选择的植物数据。类似于前面的函数,该函数将选择的植物数据存储在关卡数据中。
- void caveLevelSunData(char* key):向关卡数据中存储阳光数据。类似于前面的函数,该函数将阳光数据存储在关卡数据中。
- void caveLevelCoinData(char* key):向关卡数据中存储金币数据。类似于前面的函数,该函数将金币数据存储在关卡数据中。
- void caveLevelCarData(char* key):向关卡数据中存储车辆数据。类似于前面的函数,该函数将车辆数据存储在关卡数据中。
- void caveLevelBulletData(char* key):向关卡数据中存储子弹数据。类似于前面的函数,该函数将子弹数据存储在关卡数据中。
- void caveLevelOtherData(char* key):向关卡数据中存储其他类型的数据。类似于前面的函数,该函数将其他类型的数据存储在关卡数据中。
- void caveSurvivalOtherData(char* key):向生存模式数据中存储其他类型的数据。类似于前面的函数,该函数将其他类型的数据存储在生存模式数据中。
- void replaceScene():替换场景。
- 私有变量:
_userDataDocument
、_levelDataDocument
:指向用户数据和关卡数据的Document
对象。_fileUtils
:指向FileUtils
对象,用于文件操作。_global
:指向Global
对象。_userData
、_levelData
:存储用户数据和关卡数据的字符串。_isAnewReadData
:是否重新读取数据的标志。_gsScene
:存储GSScene
对象的向量。
UserData.cpp
构造函数
UserData::UserData() :
_global(Global::getInstance())
, _fileUtils(FileUtils::getInstance())
, _userDataDocument(nullptr)
, _levelDataDocument(nullptr)
, _isAnewReadData(false)
{
}
构造函数
UserData::UserData()
初始化了UserData
类的成员变量。具体来说:
_global(Global::getInstance())
:将Global
类的唯一实例赋值给_global
成员变量。Global
类可能是游戏中的全局管理类,通过调用getInstance()
方法获取其唯一实例。
_fileUtils(FileUtils::getInstance())
:将FileUtils
类的唯一实例赋值给_fileUtils
成员变量。FileUtils
类可能是用于文件操作的工具类,通过调用getInstance()
方法获取其唯一实例。
_userDataDocument(nullptr)
和_levelDataDocument(nullptr)
:将用户数据和关卡数据的文档指针初始化为nullptr
,表示当前没有打开的数据文档。
_isAnewReadData(false)
:将重新读取数据的标志初始化为false
,表示默认情况下不重新读取数据。
析构函数
UserData::~UserData()
{
if (_userDataDocument) delete _userDataDocument, _userDataDocument = nullptr;
if (_levelDataDocument) delete _levelDataDocument, _levelDataDocument = nullptr;
_isAnewReadData = false;
}
析构函数
UserData::~UserData()
用于清理UserData
类的资源。具体来说:
if (_userDataDocument) delete _userDataDocument, _userDataDocument = nullptr;
:如果_userDataDocument
不为nullptr
,则删除它指向的对象,并将其设置为nullptr
,以释放用户数据文档的内存资源。
if (_levelDataDocument) delete _levelDataDocument, _levelDataDocument = nullptr;
:如果_levelDataDocument
不为nullptr
,则删除它指向的对象,并将其设置为nullptr
,以释放关卡数据文档的内存资源。
_isAnewReadData = false;
:将重新读取数据的标志设置为false。
getInstance()函数
UserData* UserData::getInstance()
{
if (_instance == nullptr)
{
_instance = new (std::nothrow)UserData;
}
return _instance;
}
该函数实现了单例模式,用于获取
UserData
类的唯一实例。具体来说:
if (_instance == nullptr)
:检查静态成员变量_instance
是否为nullptr
,即是否已经创建了实例。
_instance = new (std::nothrow) UserData;
:如果_instance
为nullptr
,则创建一个新的UserData
对象,并将其赋值给_instance
。这里使用了std::nothrow
,表示在内存分配失败时不会抛出异常,而是返回nullptr
。
return _instance;
:返回_instance
,即UserData
类的唯一实例。通过调用
UserData::getInstance()
,可以获取到UserData
类的单例实例,确保在整个程序中只有一个UserData
对象存在。
flushUserData()函数
void UserData::flushUserData()
{
StringBuffer buffer;
rapidjson::Writer<StringBuffer> Writer(buffer);
_userDataDocument->Accept(Writer);
string str = string(buffer.GetString());
#ifdef DEBUG
_fileUtils->writeStringToFile(str, getUserDataFileName());
#else
# ifndef DLLTEST
_fileUtils->writeStringToFile(encryption(str), getUserDataFileName());
# else
char* buf = new char[str.length() * 3];
encryption(str.c_str(), buf);
_fileUtils->writeStringToFile(buf, getUserDataFileName());
CC_SAFE_DELETE(buf);
# endif
#endif
_isAnewReadData = false; // if flush must anew read data
}
该函数用于将用户数据刷新到文件中。具体来说:
将
_userDataDocument
中的数据序列化为字符串形式,并保存在str
中。根据编译选项进行不同的处理:
#ifdef DEBUG
:如果定义了DEBUG
宏,则直接将字符串数据写入文件,不进行加密处理。#ifndef DLLTEST
:如果未定义DLLTEST
宏,则使用加密函数encryption()
对字符串进行加密,并将加密后的数据写入文件。#else
:如果定义了DLLTEST
宏,则先将字符串转换为char*
类型的缓冲区buf
,然后使用加密函数encryption()
对数据进行加密,最后将加密后的数据写入文件。注意,在写入文件后,需要使用CC_SAFE_DELETE
删除缓冲区的内存。
_isAnewReadData = false;
:将重新读取数据的标志设置为false
,表示在刷新数据后不需要重新读取数据。该函数的作用是将
_userDataDocument
中的数据保存到文件中,根据编译选项和宏定义进行不同的处理(如加密),以满足特定的需求和安全性要求。
flushLevelData()函数
void UserData::flushLevelData()
{
StringBuffer buffer;
rapidjson::Writer<StringBuffer> Writer(buffer);
_levelDataDocument->Accept(Writer);
string str = string(buffer.GetString());
#ifdef DEBUG
_fileUtils->writeStringToFile(str, getLevelDataFileName());
#else
# ifndef DLLTEST
_fileUtils->writeStringToFile(encryption(str), getLevelDataFileName());
# else
char* buf = new char[str.length() * 3];
encryption(str.c_str(), buf);
_fileUtils->writeStringToFile(buf, getLevelDataFileName());
CC_SAFE_DELETE(buf);
# endif
#endif
}
该函数用于将关卡数据刷新到文件中。具体来说:
将
_levelDataDocument
中的数据序列化为字符串形式,并保存在str
中。根据编译选项进行不同的处理:
#ifdef DEBUG
:如果定义了DEBUG
宏,则直接将字符串数据写入文件,不进行加密处理。#ifndef DLLTEST
:如果未定义DLLTEST
宏,则使用加密函数encryption()
对字符串进行加密,并将加密后的数据写入文件。#else
:如果定义了DLLTEST
宏,则先将字符串转换为char*
类型的缓冲区buf
,然后使用加密函数encryption()
对数据进行加密,最后将加密后的数据写入文件。注意,在写入文件后,需要使用CC_SAFE_DELETE
删除缓冲区的内存。该函数的作用是将
_levelDataDocument
中的数据保存到文件中,根据编译选项和宏定义进行不同的处理(如加密),以满足特定的需求和安全性要求。
openUserData()函数
openUserDataReturnType UserData::openUserData()
{
// 如果有这个存档
if (_fileUtils->isFileExist(getUserDataFileName()))
{
if (_userData.empty()|| !_isAnewReadData)
{
_isAnewReadData = true;
#ifdef DEBUG
_userData = _fileUtils->getStringFromFile(getUserDataFileName());
_userDataDocument->Parse<rapidjson::kParseDefaultFlags>(_userData.c_str());
#else
# ifndef DLLTEST
_userData = _fileUtils->getStringFromFile(getUserDataFileName());
_userDataDocument->Parse<rapidjson::kParseDefaultFlags>(decryption(_userData).c_str());
# else
_userData = _fileUtils->getStringFromFile(getUserDataFileName());
char* buf = new char[_userData.length()];
if (decryption(_userData.c_str(), buf)) {
_userDataDocument->Parse<rapidjson::kParseDefaultFlags>(buf);
}
else {
CC_SAFE_DELETE(buf);
return openUserDataReturnType::FileExistError;
}
CC_SAFE_DELETE(buf);
# endif
#endif
if (_userDataDocument->HasParseError()) {
return openUserDataReturnType::FileExistError;
}
}
return openUserDataReturnType::FileExistCorrect;
}
else
{
if (!_userDataDocument->IsObject())
{
_userDataDocument->SetObject();
rapidjson::Value _object(rapidjson::kObjectType);
_userDataDocument->AddMember("UserData", _object, _userDataDocument->GetAllocator());
}
return openUserDataReturnType::FileNotExist;
}
}
该函数用于打开用户数据文件并读取数据。具体来说:
首先判断用户数据文件是否存在,通过调用
_fileUtils->isFileExist(getUserDataFileName())
来检查。如果文件存在,执行以下操作:
- 检查
_userData
是否为空或_isAnewReadData
是否为false
。- 如果满足条件,进行数据的读取和解析:
#ifdef DEBUG
:如果定义了DEBUG
宏,则直接从文件中读取字符串数据到_userData
,然后使用_userDataDocument
对象进行解析。#ifndef DLLTEST
:如果未定义DLLTEST
宏,则先从文件中读取经过加密的字符串数据到_userData
,然后使用解密函数decryption()
对数据进行解密,并使用_userDataDocument
对象进行解析。#else
:如果定义了DLLTEST
宏,则先从文件中读取字符串数据到_userData
,然后创建一个缓冲区buf
,调用解密函数decryption()
对数据进行解密,将解密后的数据通过_userDataDocument
进行解析。如果解密失败,则释放缓冲区内存,返回openUserDataReturnType::FileExistError
。- 检查解析过程中是否出错,通过调用
_userDataDocument->HasParseError()
来判断。如果出错,返回openUserDataReturnType::FileExistError
。如果文件不存在,执行以下操作:
- 检查
_userDataDocument
是否为对象类型,如果不是,则将其设置为对象类型,并添加一个名为 "UserData" 的成员对象。- 返回
openUserDataReturnType::FileNotExist
。该函数的作用是打开用户数据文件,根据文件的存在与否执行相应的读取和解析操作,并返回相应的状态枚举值,用于判断操作是否成功以及文件的存在状态。
openLevelData()函数
openUserDataReturnType UserData::openLevelData()
{
// 如果有这个存档
if (_fileUtils->isFileExist(getLevelDataFileName()))
{
#ifdef DEBUG
_levelData = _fileUtils->getStringFromFile(getLevelDataFileName());
_levelDataDocument->Parse<rapidjson::kParseDefaultFlags>(_levelData.c_str());
#else
# ifndef DLLTEST
_levelData = _fileUtils->getStringFromFile(getLevelDataFileName());
_levelDataDocument->Parse<rapidjson::kParseDefaultFlags>(decryption(_levelData).c_str());
# else
_levelData = _fileUtils->getStringFromFile(getLevelDataFileName());
char* buf = new char[_levelData.length()];
if (decryption(_levelData.c_str(), buf)) {
_levelDataDocument->Parse<rapidjson::kParseDefaultFlags>(buf);
}
else {
CC_SAFE_DELETE(buf);
return openUserDataReturnType::FileExistError;
}
CC_SAFE_DELETE(buf);
# endif
#endif
if (_levelDataDocument->HasParseError()) {
return openUserDataReturnType::FileExistError;
}
return openUserDataReturnType::FileExistCorrect;
}
else{
return openUserDataReturnType::FileNotExist;
}
}
解释同理,见openUserData()函数。
caveUserData()函数
void UserData::caveUserData(char* key, double value)
{
switch (openUserData())
{
case openUserDataReturnType::FileExistCorrect:
if (isHaveMember(key))
(*_userDataDocument)["UserData"][key].SetDouble(value);
else
(*_userDataDocument)["UserData"].AddMember(rapidjson::StringRef(key), value, _userDataDocument->GetAllocator());
break;
case openUserDataReturnType::FileNotExist:
(*_userDataDocument)["UserData"].AddMember(rapidjson::StringRef(key), value, _userDataDocument->GetAllocator());
break;
case openUserDataReturnType::FileExistError:
remove(getUserDataFileName().c_str());
break;
}
flushUserData();
}
该函数用于在用户数据中添加或更新指定键(
key
)对应的双精度浮点数值(value
)。具体来说:
调用
openUserData()
函数打开用户数据文件,并根据返回的状态进行不同的操作。使用
switch
语句根据不同的返回状态进行处理:
openUserDataReturnType::FileExistCorrect
:如果文件存在且打开成功,执行以下操作:
- 调用
isHaveMember(key)
函数检查指定键是否存在于用户数据中。- 如果键存在,使用
SetDouble()
函数更新对应的双精度浮点数值。- 如果键不存在,使用
AddMember()
函数将指定键和值添加到用户数据中。openUserDataReturnType::FileNotExist
:如果文件不存在,执行以下操作:
- 使用
AddMember()
函数将指定键和值添加到用户数据中。openUserDataReturnType::FileExistError
:如果文件存在但打开出错,执行以下操作:
- 调用
remove(getUserDataFileName().c_str())
函数删除用户数据文件。调用
flushUserData()
函数将更新后的用户数据刷新到文件中。该函数的作用是在用户数据中添加或更新指定键对应的双精度浮点数值,并将更新后的用户数据保存到文件中。
openIntUserData()函数
int UserData::openIntUserData(char* key)
{
switch (openUserData())
{
case openUserDataReturnType::FileExistCorrect:
if (isHaveMember(key))
return (*_userDataDocument)["UserData"][key].GetInt();
break;
case openUserDataReturnType::FileExistError:
remove(getUserDataFileName().c_str());
break;
default: break;
}
return 0;
}
该函数用于从用户数据中获取指定键(
key
)对应的整数值,并返回该整数值。具体来说:
调用
openUserData()
函数打开用户数据文件,并根据返回的状态进行不同的操作。使用
switch
语句根据不同的返回状态进行处理:
openUserDataReturnType::FileExistCorrect
:如果文件存在且打开成功,执行以下操作:
- 调用
isHaveMember(key)
函数检查指定键是否存在于用户数据中。- 如果键存在,使用
GetInt()
函数获取对应的整数值,并返回该值。openUserDataReturnType::FileExistError
:如果文件存在但打开出错,执行以下操作:
- 调用
remove(getUserDataFileName().c_str())
函数删除用户数据文件。如果未满足上述条件,则返回默认值 0。
该函数的作用是从用户数据中获取指定键对应的整数值,并返回该值。如果用户数据文件存在且打开成功,并且指定键存在于用户数据中,则返回对应的整数值;否则返回默认值 0。如果文件存在但打开出错,则删除用户数据文件。
createNewUserDataDocument()函数
void UserData::createNewUserDataDocument()
{
if (_userDataDocument)
{
delete _userDataDocument;
_userDataDocument = nullptr;
}
_userDataDocument = new Document();
_userData.clear();
_isAnewReadData = false;
}
该函数用于创建一个新的用户数据文档对象。具体来说:
首先检查
_userDataDocument
是否已存在,如果存在,则执行以下操作:
- 使用
delete
关键字释放_userDataDocument
的内存。- 将
_userDataDocument
指针设置为nullptr
,以确保不再指向已释放的内存。创建一个新的
Document
对象,并将其赋值给_userDataDocument
。清空
_userData
字符串。将
_isAnewReadData
设置为false
,表示没有重新读取数据。该函数的作用是创建一个新的用户数据文档对象,并进行必要的清理和重置操作,以便重新使用和处理用户数据。
caveLevelData()函数
void UserData::caveLevelData(char* key)
{
switch (openLevelData())
{
case openUserDataReturnType::FileExistCorrect:
if ((*_levelDataDocument).HasMember(key))
(*_levelDataDocument).RemoveMember(key);
break;
case openUserDataReturnType::FileExistError:
remove(getLevelDataFileName().c_str());
return;
break;
}
if (!_levelDataDocument->IsObject())_levelDataDocument->SetObject();
rapidjson::Value object(rapidjson::kObjectType);
_levelDataDocument->AddMember(rapidjson::StringRef(key), object, _levelDataDocument->GetAllocator());
caveLevelPlantsData(key);
caveLevelZombiesData(key);
caveLevelSelectPlantsData(key);
caveLevelOtherData(key);
caveLevelSunData(key);
caveLevelCoinData(key);
caveLevelCarData(key);
caveLevelBulletData(key);
flushLevelData();
}
该函数用于在关卡数据中创建一个新的键(
key
)。具体来说:
调用
openLevelData()
函数打开关卡数据文件,并根据返回的状态进行不同的操作。使用
switch
语句根据不同的返回状态进行处理:
openUserDataReturnType::FileExistCorrect
:如果文件存在且打开成功,执行以下操作:
- 检查关卡数据文档中是否存在指定键(
key
)。- 如果存在,使用
RemoveMember()
函数从关卡数据中移除该键。openUserDataReturnType::FileExistError
:如果文件存在但打开出错,执行以下操作:
- 调用
remove(getLevelDataFileName().c_str())
函数删除关卡数据文件。- 返回函数,即终止函数的执行。
检查
_levelDataDocument
是否为对象类型,如果不是,则使用SetObject()
函数将其设置为对象类型。创建一个新的
Value
对象,并将其添加到关卡数据文档中,键为指定键(key
),值为空对象。调用其他函数(如
caveLevelPlantsData()
、caveLevelZombiesData()
等)来处理关卡数据的其他方面。调用
flushLevelData()
函数将更新后的关卡数据保存到文件中。该函数的作用是在关卡数据中创建一个新的键,并进行相关的数据处理和保存操作。
caveLevelPlantsData()函数
void UserData::caveLevelPlantsData(char* key)
{
unsigned int plantsNumber = 0;
rapidjson::Value _object(rapidjson::kObjectType);
rapidjson::Document::AllocatorType& allocator = _levelDataDocument->GetAllocator();
(*_levelDataDocument)[key].AddMember("Plants", _object, allocator);
for (auto plant : PlantsGroup)
{
rapidjson::Value object(rapidjson::kObjectType);
auto visible = plant.second->getPlantAnimation()->isVisible();
if (visible)
{
object.AddMember("PlantsTag", plant.second->getPlantTag(), allocator);
object.AddMember("PlantsHealthPoint", plant.second->getPlantHealthPoint(), allocator);
object.AddMember("PlantsPositionX", plant.second->getPlantAnimation()->getPositionX(), allocator);
object.AddMember("PlantsPositionY", plant.second->getPlantAnimation()->getPositionY(), allocator);
object.AddMember("PlantsRow", plant.second->getPlantRow(), allocator);
object.AddMember("PlantsColumn", plant.second->getPlantColumn(), allocator);
object.AddMember("PlantsLocalZOrder", plant.second->getPlantAnimation()->getLocalZOrder(), allocator);
object.AddMember("PlantsType", static_cast<int>(plant.second->getPlantType()), allocator);
object.AddMember("PlantVisible", visible, allocator);
switch (plant.second->getPlantType())
{
case PlantsType::SunFlower:
object.AddMember("SunShowTime.X", dynamic_cast<SunFlower*>(plant.second)->getSunShowTime().x, allocator);
object.AddMember("SunShowTime.Y", dynamic_cast<SunFlower*>(plant.second)->getSunShowTime().y, allocator);
break;
case PlantsType::PotatoMine:
object.AddMember("BreakGround", dynamic_cast<PotatoMine*>(plant.second)->getBreakGround(), allocator);
break;
default:
break;
}
auto number = to_string(++plantsNumber);
char* str = new char[number.size() + 1];
strcpy(str, number.c_str());
str[number.size()] = '\0';
(*_levelDataDocument)[key]["Plants"].AddMember(rapidjson::StringRef(str), object, _levelDataDocument->GetAllocator());
}
}
(*_levelDataDocument)[key]["Plants"].AddMember("PlantsNumber", plantsNumber, allocator);
}
该函数用于处理关卡数据中的植物数据。具体来说:
创建一个无类型的
_object
对象,用于作为关卡数据文档中 "Plants" 键的值。获取
_levelDataDocument
的分配器(allocator)。将
_object
添加到关卡数据文档中的指定键(key
)下的 "Plants" 键。遍历
PlantsGroup
,这是一个存储植物对象的容器。对于每个植物对象(
plant
)进行以下操作:
- 检查植物动画是否可见,如果可见则继续处理。
- 创建一个无类型的
object
对象,用于存储植物的数据。- 将植物的各种属性(如标签、生命值、位置、行列、层级、类型等)添加到
object
中。- 根据植物类型的不同,添加特定类型的属性到
object
中。- 生成一个表示植物数量的字符串,将其转换为字符数组,并将其作为键添加到关卡数据文档中的 "Plants" 键下,并将
object
作为值。最后,将 "PlantsNumber" 键和植物数量值添加到关卡数据文档中的 "Plants" 键下。
该函数的作用是处理关卡数据中的植物相关信息,包括植物的位置、属性和数量,并将其保存到关卡数据文档中。
openLevelPlantsData()函数
void UserData::openLevelPlantsData(char* key)
{
auto plantsNumbers = (*_levelDataDocument)[key]["Plants"]["PlantsNumber"].GetInt();
for (int i = 1; i <= plantsNumbers; ++i)
{
auto type = static_cast<PlantsType>((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsType"].GetInt());
auto plants = animationLayerInformation->createDifferentPlants(type);
plants->setPlantPosition(Vec2(
(*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsPositionX"].GetFloat(),
(*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsPositionY"].GetFloat()));
plants->setPlantLocalZOrder((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsLocalZOrder"].GetInt());
plants->setPlantRowAndColumn(Vec2(
(*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsRow"].GetInt(),
(*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsColumn"].GetInt()));
plants->setPlantTag((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsTag"].GetInt());
switch (type)
{
case PlantsType::SunFlower:
dynamic_cast<SunFlower*>(plants)->setSunShowTime(
Vec2((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["SunShowTime.X"].GetFloat(),
(*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["SunShowTime.Y"].GetFloat()));
break;
case PlantsType::PotatoMine:
dynamic_cast<PotatoMine*>(plants)->setBreakGround((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["BreakGround"].GetFloat());
break;
default:
break;
}
plants->createPlantAnimation();
plants->setPlantHealthPoint((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsHealthPoint"].GetFloat());
plants->getPlantAnimation()->setVisible((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantVisible"].GetBool());
plants->getPlantAnimation()->getChildByName("SplashOfSoil")->setOpacity(0);
PlantsGroup.insert(pair<int, Plants*>((*_levelDataDocument)[key]["Plants"][to_string(i).c_str()]["PlantsTag"].GetInt(), plants));
controlLayerInformation->_gameMapInformation->plantsMap[plants->getPlantColumn()][plants->getPlantRow()] = static_cast<unsigned int>(type);/* 地图记录种植的植物 */
}
}
该函数用于读取关卡数据中的植物信息,并根据这些信息创建和设置植物对象。具体来说:
获取存储在关卡数据文档中的 "PlantsNumber" 键的整数值,表示植物的数量。
使用循环遍历每个植物的索引,从 1 到植物数量。
根据索引,获取植物的类型,并将其转换为
PlantsType
枚举类型。使用
animationLayerInformation
对象的createDifferentPlants()
方法创建具有指定类型的植物对象,并将其存储在plants
变量中。从关卡数据文档中获取植物的位置、层级、行列、标签等属性,并将这些属性设置到植物对象中。
根据植物类型的不同,进一步处理特定类型的属性,如太阳花的太阳出现时间或土豆雷的破土状态。
创建植物的动画,并设置植物的生命值、可见性以及相关动画的属性。
将植物对象添加到
PlantsGroup
容器中,使用植物标签作为键。在
controlLayerInformation->_gameMapInformation->plantsMap
中记录植物的位置这段代码看起来是一个游戏开发中的函数,用于读取关卡中的植物数据,并创建相应的植物对象。创建植物的动画,并设置植物的生命值、可见性以及相关动画的属性。
将植物对象添加到
PlantsGroup
容器中,使用植物标签作为键。在地图数据中记录植物的位置。
这段代码的目的是根据关卡数据创建植物对象,并将其放置在游戏场景中的适当位置上。具体的实现细节可能根据上下文和代码的其他部分有所变化。
removeLevelData()函数
void UserData::removeLevelData(char* key)
{
switch (openLevelData())
{
case openUserDataReturnType::FileExistCorrect:
if ((*_levelDataDocument).HasMember(key))
(*_levelDataDocument).RemoveMember(key);
break;
default:
return;
break;
}
flushLevelData();
}
该函数用于从关卡数据中移除指定键值的数据。具体来说:
调用
openLevelData()
函数,根据返回值判断关卡数据文件是否存在并正确打开。使用
switch
语句根据openLevelData()
的返回值执行不同的操作。如果返回值是
openUserDataReturnType::FileExistCorrect
,表示关卡数据文件存在且正确打开。检查关卡数据文档是否包含指定的键
key
,如果存在则执行下一步操作。使用
RemoveMember(key)
函数从关卡数据文档中移除指定的键值对。如果
openLevelData()
的返回值不是openUserDataReturnType::FileExistCorrect
,或者关卡数据文档不包含指定的键,则函数直接返回。在移除键值对后,调用
flushLevelData()
函数来刷新关卡数据,将更改写入到磁盘。该函数的作用是删除关卡数据中特定键值的条目,并将更改保存到磁盘。请注意,函数中使用的
openLevelData()
和flushLevelData()
函数的实现没有给出,因此具体的逻辑和实现细节可能在这些函数中。
encryption函数
string UserData::encryption(string& str)
{
char* encryptString, * encryptString1;
base64Encode((unsigned char*)str.c_str(), (unsigned int)str.length(), &encryptString);
string sss(encryptString);
reverse(sss.begin(), sss.end());
for (auto& s : sss)
{
if (s >= 'a' && s <= 'z')s = ((s - 'a') + 2) % 26 + 'a';
if (s >= 'A' && s <= 'Z')s = ((s - 'A') + 5) % 26 + 'A';
if (s >= '0' && s <= '9')s = ((s - '0') + 7) % 10 + '0';
if (s == '=')s = '+';
}
base64Encode((unsigned char*)sss.c_str(), (unsigned int)sss.length(), &encryptString1);
string s(encryptString1);
CC_SAFE_FREE(encryptString);
CC_SAFE_FREE(encryptString1);
return s;
}
该函数用于对字符串进行加密处理。具体来说:
使用
base64Encode()
函数将字符串str
进行Base64编码,并将结果存储在encryptString
中。创建一个
string
类型的变量sss
,并将encryptString
赋值给它。使用
reverse()
函数将sss
字符串进行反转。遍历
sss
字符串中的每个字符,根据字符的范围进行不同的加密操作:
- 如果字符在小写字母
a
和z
之间,将字符进行循环右移2位。- 如果字符在大写字母
A
和Z
之间,将字符进行循环右移5位。- 如果字符在数字
0
和9
之间,将字符进行循环右移7位。- 如果字符是等号
=
,将其替换为加号+
。使用
base64Encode()
函数将经过加密处理后的sss
字符串进行Base64编码,并将结果存储在encryptString1
中。创建一个
string
类型的变量s
,并将encryptString1
赋值给它。使用
CC_SAFE_FREE()
函数释放encryptString
和encryptString1
的内存。返回加密后的字符串
s
。该函数的作用是对输入的字符串进行加密处理,首先使用Base64编码,然后进行字符位置的循环右移和字符替换操作。
decryption()函数
string UserData::decryption(string& str)
{
unsigned char* decryptString = nullptr, * decryptString1 = nullptr;
auto ret = base64Decode((unsigned char*)str.c_str(), (unsigned int)str.length(), &decryptString);
if (ret > 0) decryptString[ret] = '\0';
else return "";
string sss(reinterpret_cast<char*>(decryptString));
for (auto& s : sss)
{
if (s >= 'a' && s <= 'z')s = ((s - 'a') + 24) % 26 + 'a';
if (s >= 'A' && s <= 'Z')s = ((s - 'A') + 21) % 26 + 'A';
if (s >= '0' && s <= '9')s = ((s - '0') + 3) % 10 + '0';
if (s == '+')s = '=';
}
reverse(sss.begin(), sss.end());
ret = base64Decode((unsigned char*)sss.c_str(), (unsigned int)sss.length(), &decryptString1);
if (ret > 0) decryptString1[ret] = '\0';
else { CC_SAFE_FREE(decryptString); return ""; }
string s(reinterpret_cast<char*>(decryptString1));
CC_SAFE_FREE(decryptString);
CC_SAFE_FREE(decryptString1);
return s;
}
该函数用于对加密过的字符串进行解密处理。具体来说:
创建两个指针
decryptString
和decryptString1
,并初始化为nullptr
。使用
base64Decode()
函数将字符串str
进行Base64解码,并将结果存储在decryptString
中。保存解码后的字节数到ret
中。如果解码成功,将
decryptString
最后一个字节设置为\0
,表示字符串的结束。否则,返回空字符串。使用
reinterpret_cast
将decryptString
转换为string
类型,并赋值给sss
。遍历
sss
字符串中的每个字符,根据字符的范围进行不同的解密操作:
- 如果字符在小写字母
a
和z
之间,将字符进行循环左移2位。- 如果字符在大写字母
A
和Z
之间,将字符进行循环左移5位。- 如果字符在数字
0
和9
之间,将字符进行循环左移3位。- 如果字符是加号
+
,将其替换为等号=
。使用
reverse()
函数将sss
字符串进行反转。使用
base64Decode()
函数将经过解密处理后的sss
字符串进行Base64解码,并将结果存储在decryptString1
中。保存解码后的字节数到ret
中。如果解码成功,将
decryptString1
最后一个字节设置为\0
,表示字符串的结束。否则,释放decryptString
的内存,并返回空字符串。使用
reinterpret_cast
将decryptString1
转换为string
类型,并赋值给s
。使用
CC_SAFE_FREE()
函数释放decryptString
和decryptString1
的内存。返回解密后的字符串
s
。该函数的作用是对输入的加密字符串进行解密处理,包括Base64解码、字符位置的循环左移和字符替换操作。
其他函数
函数众多,列举了部分重要函数,其他函数看自行查看。