虛幻引擎:4.22
VS:2017
XML文件的讀取,對於應用開發,項目配置很是方便。
此帖將XML文件讀取集成爲UE4的插件,然後寫了一個簡單的工程,解釋了實際項目開發中的使用。
XML文件讀取插件,利用了Tinyxml來讀取xml文件,給出他的官網地址:http://www.grinninglizard.com/tinyxml/
直接附上XML文件讀取插件的Github地址:https://github.com/zhangmei126/XML
接下來講一下XML文件讀取的工程,開發框架:
1、先創建一個空工程命名爲XMLTest
2、然後創建繼承自GameInstance的類,命名爲XMLTestGameInstance
- 目的:當項目設置了自定義的XMLTestGameInstance類,在XMLTestGameInstance初始化的時候,加載項目所有的系統配置(比如分辨率,語言設置,HTTP初始化,OSS服務器初始化,第三方庫等等)。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "XMLTestGameInstance.generated.h"
/**
*
*/
UCLASS()
class XMLTEST_API UXMLTestGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
virtual void Init() override;
virtual void Shutdown() override;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestGameInstance.h"
#include "XMLTestPrototypeManager.h"
void UXMLTestGameInstance::Init()
{
Super::Init();
//加載系統所有配置.
XMLTestPrototypeManager::GetInstance()->LoadAllSystemPrototype();
}
void UXMLTestGameInstance::Shutdown()
{
}
3、創建管理XML配置文件的Manager類,命名爲XMLTestPrototypeManager
- 目的:項目中會有很多XML配置,Manager類就很關鍵,它是個全局訪問的單利,提供統一的接口,查找到對應的XML表。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include <map>
#include "XMLTestBasePrototype.h"
//通過pid直接獲取Prototype對象.
typedef std::map<int32, XMLTestBasePrototype*> XMLTestPrototypeMap;
/**
*
*/
class XMLTEST_API XMLTestPrototypeManager
{
public:
XMLTestPrototypeManager();
virtual ~XMLTestPrototypeManager();
//單利
static XMLTestPrototypeManager * GetInstance();
void LoadAllSystemPrototype();
bool LoadPrototype(const FString & _XmlPath);
XMLTestBasePrototype* GetPrototypeByPID(int32 _Pid);
template<typename T>
T* GetPrototypeByPID(int32 _Pid)
{
std::map<int32, XMLTestBasePrototype*>::iterator it = m_PrototypeMap.find(_Pid);
if (it != m_PrototypeMap.end())
{
XMLTestBasePrototype* mPrototype = it->second;
return (T*)mPrototype;
}
return nullptr;
}
public:
static XMLTestPrototypeManager* m_XMLTestPrototypeManager;
//PrototypeMap字典.
XMLTestPrototypeMap m_PrototypeMap;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestPrototypeManager.h"
#include <string>
#include "XMLTestBasePrototype.h"
#include "XMLTestLanguagePrototype.h"
#include "Runtime/Core/Public/Misc/Paths.h"
#include "Runtime/Core/Public/Misc/FileHelper.h"
//初始化在主線程前.
XMLTestPrototypeManager* XMLTestPrototypeManager::m_XMLTestPrototypeManager = nullptr;
XMLTestPrototypeManager::XMLTestPrototypeManager()
{
}
XMLTestPrototypeManager::~XMLTestPrototypeManager()
{
}
XMLTestPrototypeManager * XMLTestPrototypeManager::GetInstance()
{
//判斷是否第一次調用.
if (m_XMLTestPrototypeManager == nullptr)
{
m_XMLTestPrototypeManager = new XMLTestPrototypeManager();
}
return m_XMLTestPrototypeManager;
}
void XMLTestPrototypeManager::LoadAllSystemPrototype()
{
FString mConfigDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectConfigDir());
FString mXmlConfigDir = FString::Printf(TEXT("%s%s"), *mConfigDir, TEXT("XML/"));
LoadPrototype(FString::Printf(TEXT("%s%s"), *mXmlConfigDir, TEXT("ChinesePrototype.xml")));
}
bool XMLTestPrototypeManager::LoadPrototype(const FString & _XmlPath)
{
TiXmlDocument mXmlDocument;
FString mStrContent;
if (!FFileHelper::LoadFileToString(mStrContent, *_XmlPath))
{
return false;
}
FString mContent = mStrContent;
std::string mStdContent = TCHAR_TO_UTF8(*mContent);
const char * mXmlContent = mStdContent.c_str();
mXmlDocument.Parse(mXmlContent);
TiXmlElement* mXmlRoot = mXmlDocument.FirstChildElement();
if (mXmlRoot == NULL)
{
mXmlDocument.Clear();
return false;
}
const char * mXmlNodeType = mXmlRoot->Attribute("type");
for (TiXmlElement* mElem = mXmlRoot->FirstChildElement(); mElem != NULL; mElem = mElem->NextSiblingElement())
{
XMLTestBasePrototype * mPrototype;
const char * mPid = mElem->Attribute("pid");
//根據Pid查找Prototype.
std::map<int32, XMLTestBasePrototype*>::iterator it = m_PrototypeMap.find(atoi(mPid));
if (it != m_PrototypeMap.end())
{
mPrototype = it->second;
mPrototype->LoadXMLData(mElem);
}
else
{
mPrototype = (XMLTestBasePrototype *)(new XMLTestLanguagePrototype());
mPrototype->LoadXMLData(mElem);
m_PrototypeMap.insert(std::make_pair(atoi(mPid), mPrototype));
}
}
mXmlDocument.Clear();
return true;
}
XMLTestBasePrototype* XMLTestPrototypeManager::GetPrototypeByPID(int32 _Pid)
{
std::map<int32, XMLTestBasePrototype*>::iterator it = m_PrototypeMap.find(_Pid);
if (it != m_PrototypeMap.end())
{
XMLTestBasePrototype* mPrototype = it->second;
return mPrototype;
}
return nullptr;
}
4、創建XML配置文件的一個基類,命名爲XMLTestBasePrototype
- 目的:各個XML配置文件其實都有相同之處,創建一個基類是很有必要的。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "tinyxml.h"
#include "tinystr.h"
/**
*
*/
class XMLTEST_API XMLTestBasePrototype
{
public:
XMLTestBasePrototype();
virtual ~XMLTestBasePrototype();
virtual void LoadXMLData(TiXmlElement * _XmlElement) final;
protected:
virtual void OnLoadXMLData(TiXmlElement * _XmlElement);
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestBasePrototype.h"
XMLTestBasePrototype::XMLTestBasePrototype()
{
}
XMLTestBasePrototype::~XMLTestBasePrototype()
{
}
void XMLTestBasePrototype::LoadXMLData(TiXmlElement * _XmlElement)
{
OnLoadXMLData(_XmlElement);
}
void XMLTestBasePrototype::OnLoadXMLData(TiXmlElement * _XmlElement)
{
}
4、創建繼承自XMLTestBasePrototype的類,命名爲XMLTestLanguagePrototype
- 目的:在這個測試XML文件讀取的項目中,舉了一個例子測試讀取語言配置的XML文件,所以創建對應的派生。然後具體的實現將會存儲語言配置XML文件中,key和value的對應值,方便接下來的查找。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "XMLTestBasePrototype.h"
/**
*
*/
class XMLTEST_API XMLTestLanguagePrototype : public XMLTestBasePrototype
{
public:
XMLTestLanguagePrototype();
virtual ~XMLTestLanguagePrototype();
protected:
virtual void OnLoadXMLData(TiXmlElement* _XmlElement) override;
public:
FString GetLanguage(const FString& _Key);
FString GetLanguageTexture2D(const FString& _Key);
private:
//文字對應的Key Value;
TMap<FString, FString> m_Values;
//圖片對應的Key Value;
TMap<FString, FString> m_AssetValues;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestLanguagePrototype.h"
XMLTestLanguagePrototype::XMLTestLanguagePrototype()
{
}
XMLTestLanguagePrototype::~XMLTestLanguagePrototype()
{
}
void XMLTestLanguagePrototype::OnLoadXMLData(TiXmlElement* _XmlElement)
{
for (TiXmlElement* mXmlElement = _XmlElement->FirstChildElement(); mXmlElement != NULL; mXmlElement = mXmlElement->NextSiblingElement())
{
const char* mKey = mXmlElement->Attribute("key");
const char* mValue = mXmlElement->Attribute("value");
const char* mAssetUrl = mXmlElement->Attribute("asset");
m_Values.Add(UTF8_TO_TCHAR(mKey), UTF8_TO_TCHAR(mValue));
m_AssetValues.Add(UTF8_TO_TCHAR(mKey), UTF8_TO_TCHAR(mAssetUrl));
}
}
FString XMLTestLanguagePrototype::GetLanguage(const FString& _Key)
{
if (m_Values.Contains(_Key))
{
return m_Values[_Key];
}
return TEXT("");
}
FString XMLTestLanguagePrototype::GetLanguageTexture2D(const FString& _Key)
{
if (m_AssetValues.Contains(_Key))
{
return m_AssetValues[_Key];
}
return TEXT("");
}
5、創建讀取語言配置XML文件的工具類,命名爲XMLTestLanguageTool
- 目的:項目中直接調用XMLTestLanguageTool單利對應的獲取語言的方法,而不用管上面其他類的實現。因爲上面的類的功能都是在XMLTestGameInstance加載的時候就已經實現了。項目中直接調用的話,就使用一個XMLTestLanguageTool中的單利直接調用,方便而且封裝性好。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class XMLTEST_API XMLTestLanguageTool
{
public:
XMLTestLanguageTool();
virtual ~XMLTestLanguageTool();
static XMLTestLanguageTool * GetInstance();
FString GetLanguage(const FString & _key);
FString GetLanguageTexture2D(const FString & _key);
private:
// 單利.
static XMLTestLanguageTool * m_LanguageInstance;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestLanguageTool.h"
#include "XMLTestPrototypeManager.h"
#include "XMLTestLanguagePrototype.h"
//初始化在主線程之前.
XMLTestLanguageTool* XMLTestLanguageTool::m_LanguageInstance = nullptr;
XMLTestLanguageTool::XMLTestLanguageTool()
{
}
XMLTestLanguageTool::~XMLTestLanguageTool()
{
}
XMLTestLanguageTool * XMLTestLanguageTool::GetInstance()
{
//判斷是否第一次調用.
if (m_LanguageInstance == nullptr)
{
m_LanguageInstance = new XMLTestLanguageTool();
}
return m_LanguageInstance;
}
FString XMLTestLanguageTool::GetLanguage(const FString & _Key)
{
return XMLTestPrototypeManager::GetInstance()->GetPrototypeByPID<XMLTestLanguagePrototype>(100)->GetLanguage(_Key);
}
FString XMLTestLanguageTool::GetLanguageTexture2D(const FString & _Key)
{
return XMLTestPrototypeManager::GetInstance()->GetPrototypeByPID<XMLTestLanguagePrototype>(100)->GetLanguage(_Key);
}
6、創建一個測試Actor類,命名爲XMLTestActor
- 直接調用XMLTestLanguageTool類這個單利中的方法,傳入XML文件中語言配置對應的key,獲取對應的中文配置。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "XMLTestActor.generated.h"
UCLASS()
class XMLTEST_API AXMLTestActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AXMLTestActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestActor.h"
#include "XMLTest.h"
#include "XMLTestLanguageTool.h"
// Sets default values
AXMLTestActor::AXMLTestActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AXMLTestActor::BeginPlay()
{
Super::BeginPlay();
FString mValue = XMLTestLanguageTool::GetInstance()->GetLanguage(TEXT("key100"));
UE_LOG(XMLTestLog, Log, TEXT("%s"), *mValue);
}
// Called every frame
void AXMLTestActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
7、創建一個XML文件,命名爲ChinesePrototype.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
中文語言設置!!!
-->
<root type="LanguagePrototype">
<Platform pid="100" name="">
<language key="key100" value="扳機鍵" asset=""/>
<language key="key101" value="滑動鍵" asset=""/>
<language key="key102" value="槍頭鍵" asset=""/>
<language key="key103" value="撥動鍵" asset=""/>
<language key="key104" value="撥動鍵" asset=""/>
</root>
8、將第7步的XML文件,放到項目Config/XML文件夾下
- 當加載XMLTestGameInstance的時候,會找到項目工程Config/XML目錄下的xml文件,讀取裏面的中文配置
- 源碼測試工程同上面的插件地址:https://github.com/zhangmei126/XML