一日分の備忘録

ゲーム制作におけるいろいろな実装の備忘録。基本的にはゲームエンジン中心。その中でもUE4がメイン。プログラマーなのでプログラム的な記事が多くなるかも

自作アセットインポートの備忘録。

音ゲー作りたいけどcsvで管理するといろいろ面倒だったのがきっかけで作ってみた。


独自アセットクラスの実装
今回は.txtファイルを読み込みたいのでFString1つだけで良さそう。独自の形式を作りたいときはそれ用に色々変数を作ると良いと思います。
以下のコードを書いた。

.cpp

#include "UTextObject.h"
UTextObject::UTextObject(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{

}

.h

#pragma once
#include "UTextObject.generated.h"

UCLASS()
class UTextObject : public UObject
{
	GENERATED_UCLASS_BODY()

private:

public:
	UPROPERTY(EditAnywhere)
	FString textData;
};

この時問題になったのが、generated.hがなくてインクルードで怒られるところ。
実際何で解決したのか正確にはわかっていない。
詳しくはまだわかってないので調べてます。
知っている方がいたらtwitterでこっそり教えてください。

GenerateVisualStudioFileをしたら良いっぽい?

次にFactoryクラスを実装。コレはアセットを作成できるようにしたり、インポートしたりをできるようにする感じで作ります。

.cpp

#include "UTextObjectFactory.h"
#include "UTextObject.h"

UTextObjectFactory::UTextObjectFactory(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{

	SupportedClass = UTextObject::StaticClass();
	bCreateNew = false;
	bEditorImport = true;
	bText = true;
	Formats.Add(TEXT("txt;TextFile"));

}

bool UTextObjectFactory::DoesSupportClass(UClass* Class)
{

	return (Class == UTextObject::StaticClass());

}

UClass* UTextObjectFactory::ResolveSupportedClass()
{

	return UTextObject::StaticClass();

}

UObject* UTextObjectFactory::FactoryCreateNew(
	UClass* InClass,
	UObject* InParent,
	FName InName,
	EObjectFlags Flags,
	UObject* Context,
	FFeedbackContext* Warn)
{
	UTextObject* NewMyAsset =
		CastChecked<UTextObject>(StaticConstructObject_Internal(InClass, InParent, InName, Flags));

	return NewMyAsset;
}

.h

#pragma once
#include "Factories/Factory.h"
#include "UTextObjectFactory.generated.h"

UCLASS()
class UTextObjectFactory : public UFactory
{
	GENERATED_UCLASS_BODY()

	virtual bool DoesSupportClass(UClass* Class) override;
	virtual UClass* ResolveSupportedClass() override;
	virtual UObject* FactoryCreateNew(
		UClass* _Class,
		UObject* _Parent,
		FName _Name,
		EObjectFlags _Flag,
		UObject* _Context,
		FFeedbackContext* _Warn) override;

};

ここまでできたら一旦ビルドして確認。新規作成>その他からTextObjectが作れるようになっているはず。
もしコレをインポートのみにしたい場合はbCreatenewをfalseにすると良い。
Formatsはファイル拡張子;説明と言った感じ。

bText = trueはテキストファイルからのインポートを指定している。コレをtrueにしていない場合は
以下でFactoryCreateText()を実装しているが、そのかわりにFactoryCreateBinary()を実装する必要がある。

Factoryクラスに以下を追加

UObject* UTextObjectFactory::FactoryCreateText(
	UClass* _Class,
	UObject* _Parent,
	FName _Name,
	EObjectFlags Flags,
	UObject* Context,
	const TCHAR* Type,
	const TCHAR*& Buffer,
	const TCHAR* BuferEnd,
	FFeedbackContext* Warn)
{

	FString Values;
	Values = FString(Buffer);

	UTextObject* NewMyAsset =
		CastChecked<UTextObject>(StaticConstructObject_Internal(_Class, _Parent, _Name, Flags));
	
	
	NewMyAsset->textData = Values;

	return NewMyAsset;
}

ここまで作ると、ひとまずtxtファイルがインポートできるはず。

次回はReimportについて書こうかな。

第3回UE4勉強会in大阪

参加してきました。というよりも、現在勤めている会社が主催でした。

今回はたいらも勉強会で「UE4でVR入門」という内容でしゃべらせてもらいました。

いかがそのスライドになります(なんかyoutube対応したら挿入される場所がいろいろおかしいくなってしまった)

 
togetterにもまとめられています↓

togetter.com

たいらの講演は、というよりも全講演なかなかいい感じの反応をもらえており、とても安心しました。

今回で弊社から登壇者が出たということで、今後もこの勉強会を開く意義?というものを感じられますね!(棒)

 

またツイートの方で、スライド中に出てくる参考資料などのurlを公開していますので、こちらにもはっつけておきます。

 

実は今日から東京出張に来ているので、今年の更新はもしかするとこれで最後になるかもしれません。あとVR触れない。つらい。

Twitterの方はたぶん2~3日おきくらいに更新すると思います。もしかするともう少し頻度は高いかもしれません。

ということで、簡単にですが第3回UE4勉強会in大阪の報告でした。

第4回は1月予定です。次回話すかどうかといわれるとおそらく平良は話しませんが、話すネタはいろいろ考えておきたいなぁと思います。

UE4で指定フォルダからファイルの読み込み(CSV編)

作っちゃったし備忘録書く必要あるかなとも思ったがとりあえず書いとく。CSV編としているが他のファイル形式を読み込んだものを書くかと言われると多分書かない。

.h

public:	

	UFUNCTION(BlueprintCallable, Category = "CSVReader")
	void LoadCSVData(FString Filename);
	UFUNCTION(BlueprintCallable, Category = "CSVReader")
	TArray<FString> GetRowDataByKey(FString Key);
	UFUNCTION(BlueprintCallable, Category = "CSVReader")
	TArray<FString> GetKey();

public:
	//変数
	TMap<FString, TArray<FString>> RowData;
	TArray<FString> KeyList;

.cpp

void ACSVReader::LoadCSVData(FString Filename)
{
	//CurrentDirectory取得
	FString dir = FPaths::GameDir();
	//ファイル名
	FString filename = dir + Filename + ".csv";
	//ファイル取得
	FString csvFullData;
	FFileHelper::LoadFileToString(csvFullData, *filename);
	//列で分解
	TArray<FString> row;
	csvFullData.ParseIntoArray(row, TEXT("\n"), true);
	//キーを登録
	row[0].ParseIntoArray(KeyList, TEXT(","), true);
	for(int i = 0 ; i != KeyList.Num() ; i++)
	{
		RowData.Add(KeyList[i]);
	}

	//キー以外の各要素をRowDataにキーと関連付けて登録
	TArray<FString> element;
	for (int i = 1; i != row.Num(); i++)
	{
		row[i].ParseIntoArray(element, TEXT(","), true);
		for (int j = 0; j != element.Num(); j++)
		{
			RowData[KeyList[j]].Add(element[j]);
		}
	}
}
TArray<FString> ACSVReader::GetRowDataByKey(FString Key)
{
	return RowData[Key];
}
TArray<FString> ACSVReader::GetKey()
{
	return KeyList;
}

どうやらFPaths::GameDir();でCurrentDirectoryが取得できるらしい。(ここだけ伝えたかった)
パッケージ化前は[各種ドライブ://~~~/MyProject/]
パッケージ化後は[各種ドライブ://~~~/exeファイルのある階層/MyProject/]
を取得する。
ちなみにブログ用に若干プログラムコードはサボってるので実装するときは各自ちゃんと作ってください。
使いみちあるかと言われると微妙になさそう。ユーザーに配布したゲームでCSV作ったらステージ自分で作れます!的な感じにしたらもしかするともしかするかもしれない。

UnityのProjectでDLLを使う備忘録

VisualStudio2015を開く
VisualC++ -> Win32コンソールアプリケーションを作成
Win32アプリケーションウィザードが開いたら次へ
アプリケーションの種類:DLL
追加のオプション:空のプロジェクトをonにして完了
.cppと.hを作る。

source.h

#pragma once

#define CPULUSSOURCE_API __declspec(dllimport) 

extern "C"//Unityで使うため
{
	CPULUSSOURCE_API float DllMultiPly(float a, float b, int loopNum = 100000000);
}

source.cpp

#include "CPlusSource.h"

float DllMultiPly(float a, float b, int loopNum)
{
	for (int i = 0; i < loopNum; i++)
	{
		float p = a * b;
	}
	return a * b;
}

ものすごい重い計算処理(仮)
ビルド前にソリューションプラットフォームをx64に変更。
ビルドしたらプロジェクトフォルダ内のx64内にDLLができている。
できたDLLをUnityProject/Assets/Plugins内に入れてUnity起動。
Scriptを作成しこんな感じで書く

script.cs

public class DllTestScript : MonoBehaviour {


    [DllImport("DLLTest", EntryPoint = "DllMultiply")]//今回作ったdll
    public static extern float CPlusOnlyDllMultiplyt( float a, float b, int loopNum = 100000000);
    void Start () {
        float tempFloatData = 0;

        //C++
        ProcessLoadTimeStart();

        tempFloatData = CPlusOnlyDllMultiplyt(8, 8);

        ProcessLoadTimeEnd();
        Debug.Log(tempFloatData);


        //C#
        ProcessLoadTimeStart();

        tempFloatData = TestCSharpLibrary.TestCSharpLibrary.SharpMultiply(100000000, 3, 5);//別で用意していたC#dllを使用
	//for(int i = 0 ; i < 100000000 ; i++)
	//{
	//	float p = 3 * 5;
	//}
	//ない場合はこれを関数化して使用

        ProcessLoadTimeEnd();
        Debug.Log(tempFloatData);

    }


    private float CheckTimer = 0;
    void ProcessLoadTimeStart()
    {
        // 現在の経過時間を取得
        CheckTimer = Time.realtimeSinceStartup;
    }

    void ProcessLoadTimeEnd()
    {
        // 処理完了後の経過時間から、保存していた経過時間を引く=処理時間
        CheckTimer = Time.realtimeSinceStartup - CheckTimer;

        Debug.Log("ProcessLoadTime : " + CheckTimer.ToString("0.00000"));
    }
    // Update is called once per frame
    void Update () 
    {
	
    }
}

Emptyを作ってScriptをアタッチして実行。
割りと苦戦したが1回できてしまえば後はあっさりできた。

プロパティ指定子の備忘録

プロパティ指定子使いそうなものについてまとめ

UPROPERTY()で設定できるもののこと


AdvancedDisplay
Detalis(詳細)パネルの拡張ドロップダウンリストに表示される。

AssetRegistrySearchable
メンバー変数として格納するアセットクラスインスタンスからこのプロパティと値が自動でアセットレジストリに追加される。
構造体やパラメータの使用は厳禁
難しく言ってるけど要するに検索できるようにする。

BlueprintAssignable
マルチキャストデリゲートのみ使用可能。ブループリントへ割り当てるためにプロパティを公開する。

BlueprintCallable
マルチキャストデリゲートのみ使用可能。ブループリントのグラフでの呼び出しのために公開するプロパティです。

BlueprintReadOnly
プループリントでの読み取りのみ可能。

BlueprintReadWrite
ブループリントでの読み書き可能

Category
プロパティのカテゴリを指定をする。"|"を使ってネスト(入れ子)設定もできる。

UPROPERTY(Category="CategoryName|SubCategoryName")
Type VariableName;

Config
iniファイルで値を保存することができ、作成時にロードされる。編集はできない。

EditAnywhere
プロパティエディタに公開されて編集可能になる。
前記事参照oneday-memorandum.hateblo.jp


EditDefaultsOnly
プロパティウィンドウでのみ編集可能。Visible* とは互換性がない。

EditFixedSize
配列の長さの変更を制限する。

EditInline
アンリアルエディタのプロパティインスペクタ内で編集できるようになる。

EditInstanceOnly
詳細タブのみ編集可能になる。

NoClear
オブジェクト参照がNoneにならないようにする。

VisibleAnywhere
エディターでプロパティで表示する。編集は不可。

VisibleInstanceOnly
詳細タブでプロパティで表示する。編集は不可。

多分こんなもん