UE4+XML文件讀取

虛幻引擎: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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章