【DXライブラリ】Effekseer「エフェクシア」の使い方

# はじめに

記事作成者は専門学校にてDXライブラリを使用しゲームを制作した者です。

誤った情報もあるかもしれませんので、この記事のみを鵜呑みにするのは勘弁してください。

**今回は3Dエフェクトのみ解説します。**
2Dエフェクトはエフェクシア公式様のサンプルをご確認ください。

DXライブラリの初期設定は行っているものとします。

# 実装イメージ
:::note info
こんな爆発エフェクトを実装していきます↓
:::
![スクリーンショット 2024-11-20 152258.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/98f4d573-56b6-bf1a-e3a9-6a75258d2d04.png)


# 環境
- OS: Windows11
- 開発環境: Visual Studio 2022

# Effekseer(エフェクシアについて)
DXライブラリ、Unity等で使用できるエフェクトツールです。
→　https://effekseer.github.io/jp/

DXライブラリでエフェクトを追加するなら一番簡単で効果的な方法かと思います。

今回はこちらを利用してDXライブラリでエフェクトを実装します。

# お品書き
1. Effekseerダウンロード
2. VisualStudioにて追加のインクルードディレクトリを指定
3. コード実装
4. ピックアップ解説
5. まとめ
6. 参考サイト

# 1. Effekseerダウンロード
:::note info
リンク→https://effekseer.github.io/jp/index.html
公式サイトからDXライブラリに対応したエフェクシアのライブラリをダウンロードしていきます。↓
:::
![スクリーンショット 2024-11-13 162030.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/269a0c79-b90d-dc47-5b3d-c1a3f9a7a20d.png)

---

:::note info
Effeksser For DXライブラリをダウンロード↓
:::
![スクリーンショット 2024-11-13 162030 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/dc001b54-afc8-21f0-6c87-69548d5c396b.png)

---

:::note info
ファイルを解凍します。↓解凍後
:::
![スクリーンショット 2024-11-13 162407.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/36a62681-90c5-66d7-54ce-1717e5f78c93.png)

---

:::note info
分かりやすいようファイル名を「EffekseerForDXLib」に変更しておきます↓
:::
![スクリーンショット 2024-11-17 141356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/f869ee9e-2b98-162a-259e-9f58797c26ef.png)



# 2. VisualStudioにて追加のインクルードディレクトリを指定

現在のプロジェクトにエフェクシアのファイル内の内容を使用できるようにする作業です。

:::note info
ダウンロードしたファイルをプロジェクトファイルと同様の階層に置きます
(これは自分の好きな場所でも大丈夫です)↓
:::
![スクリーンショット 2024-11-17 141608.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/0ab350f3-1087-38fc-7d2c-654a8eb77dae.png)

---

:::note info
プロジェクトファイルを開き、プロジェクト名の部分で右クリックします↓
:::
![新規プロジェクト (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/21aa5c7a-a092-08b1-e5be-81a5ea785382.png)

---

:::note info
プロパティを選択↓
:::
![新規プロジェクト (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/40491ce9-edee-a748-ba8d-cf9c8bb2f7bc.png)

---

:::note info
プロパティ上部分の構成(C):を「すべての構成」、プラットフォーム(P):を「すべてのプラットフォーム」に設定されていることを確認↓
:::
![新規プロジェクト (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/84b8a9a9-89b4-93e2-7bad-d4a639fd551a.png)

---

:::note info
構成プロパティ > C/C++ > 全般 > 追加のインクルードディレクトリ　の右側のマークをクリック↓
:::
![新規プロジェクト (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/8a0db9ec-6587-1581-5f82-7752b46b4fdd.png)

---

:::note info
編集をクリック↓
:::
![新規プロジェクト (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/ee76c461-a88b-256f-d644-b2446b472c21.png)

---

:::note info
右上のファイルマークをクリック↓
:::
![スクリーンショット 2024-11-17 132929.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/21b6c231-c5f4-9055-82b6-5f8e022a63fc.png)

---

:::note info
ファイルパスを入力できるようになるので、「`../EffekseerForDXLib`」と入力↓
:::
![スクリーンショット 2024-11-17 141954.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/0757ebd7-7bd9-7063-30ef-b8a44b16ab32.png)

---

:::note info
同様の手順で　構成プロパティ > リンカー > 全般 > 追加のライブラリディレクトリを指定↓
C/C++の時と同様に「`../EffekseerForDXLib`」
:::
(右のマークを押さずに、直入力でもできます。)

![スクリーンショット 2024-11-17 142147.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/32cbc006-8e61-73c5-3585-e492ca369605.png)

---

:::note info
「適用」をクリック後、「OK」をクリック↓
:::
![スクリーンショット 2024-11-17 142430.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/f2b69be0-db85-b14c-6423-1c269c06dbe6.png)

---

:::note info
### これでエフェクシア導入は完了しました。
:::
`EffekseerForDXLibファイル`内にDXライブラリ使用で必要なファイルもすでに入っているので
この作業で指定するファイルは`EffekseerForDXLib`のみで大丈夫です。

エラーや不明点があるときは「絶対参照、相対参照ファイルパス」
などで検索して解決するとよいと思います。


# 3. コード実装
## 注意事項
- 今回は簡略されたクラスで実装します
- ３Dエフェクトを再生する際は**カメラが実装されていなければなりません**

:::note warn
実用的な実装にする際はエフェクト利用を行うクラスにクラス分けしたり、
すべてのエフェクトをまとめて管理するシングルトンクラスなどにすると良いかもしれません
:::

## 実装するクラス
- `EffectManager`: エフェクトを管理するクラスです
- `Camera`: カメラを管理するクラスです
- `TestObject`: 動かせるプレイヤー、ステージを管理するクラスです

それでは実装コードです。

```c++:EffectManager.h
#pragma once
#include <EffekseerForDXLib.h> // 先ほど指定したエフェクシアファイルをインクルード

// エフェクト管理クラス
class EffectManager
{
public:
	EffectManager();					// コンストラクタ
	~EffectManager();					// デストラクタ
	void Initialize();					// 初期化
	void Load();						// 読み込み
	void Update(VECTOR playPosition);	// 更新
	void Draw();						// 描画
private:
	// 定数
	const int	EffectParticleLimit	= 20000;				// 画面に表示できる最大パーティクル数
	const char* EffectFilePath		= "Data/Flame.efk";		// エフェクトのファイルパ
	const float EffectSize			= 1.0f;					// エフェクトのサイズ
	const int	EffectPlayInterval	= 300;					// エフェクトを再生する周期
	const float	EffectMoveSpeed		= 0.2f;					// エフェクトが移動する速度

	// 変数
	int effectResourceHandle;	// エフェクトのリソース用
	int playingEffectHandle;	// 再生中のエフェクトハンドル
	
	// 今回の動作でにみ必要な変数
	int		playCount;			// 周期敵に再生するためのカウント
};


```

```c++:EffectManager.cpp
#include "DxLib.h"
#include "EffectManager.h"

// コンストラクタ
EffectManager::EffectManager()
    : effectResourceHandle  (-1)
    , playingEffectHandle   (-1)
    , playCount             (0)
{
    // 初期化
    Initialize();

    // 読み込み
    Load();
}

// デストラクタ
EffectManager::~EffectManager()
{
    // エフェクトリソースの開放
    // (Effekseer終了時に破棄されるので削除しなくてもいい)
    DeleteEffekseerEffect(effectResourceHandle);
}

// 初期化
void EffectManager::Initialize()
{
    // DirectX11を使用するようにする。(DirectX9も可、一部機能不可)
    // Effekseerを使用するには必ず設定する。
    SetUseDirect3DVersion(DX_DIRECT3D_11);

    // 引数には画面に表示する最大パーティクル数を設定する。
    if (Effkseer_Init(EffectParticleLimit) == -1) { DxLib_End(); }

    // フルスクリーンウインドウの切り替えでリソースが消えるのを防ぐ。
    // Effekseerを使用する場合は必ず設定する。
    SetChangeScreenModeGraphicsSystemResetFlag(FALSE);

    // DXライブラリのデバイスロストした時のコールバックを設定する。
    // ウインドウとフルスクリーンの切り替えが発生する場合は必ず実行する。
    Effekseer_SetGraphicsDeviceLostCallbackFunctions();

    // Zバッファを有効にする。
    // Effekseerを使用する場合、2DゲームでもZバッファを使用する。
    SetUseZBuffer3D(TRUE);

    // Zバッファへの書き込みを有効にする。
    // Effekseerを使用する場合、2DゲームでもZバッファを使用する。
    SetWriteZBuffer3D(TRUE);
}

// 読み込み
void EffectManager::Load()
{
    // エフェクトのリソースを読み込む
    effectResourceHandle = LoadEffekseerEffect(EffectFilePath, EffectSize);
}

/// <summary>
/// 更新
/// </summary>
/// <param name="playPosition">再生座標</param>
void EffectManager::Update(VECTOR playPosition)
{
    // 定期的にエフェクトを再生する
    if (!(playCount % EffectPlayInterval))
    {
        // エフェクトを再生する。
        playingEffectHandle = PlayEffekseer3DEffect(effectResourceHandle);
    }

    // 再生カウントを進める
    playCount++;

    // 再生中のエフェクトを移動する。
    SetPosPlayingEffekseer3DEffect(playingEffectHandle, playPosition.x, playPosition.y, playPosition.z);

    // Effekseerにより再生中のエフェクトを更新する。
    UpdateEffekseer3D();
}

// 描画
void EffectManager::Draw()
{
    // Effekseerにより再生中のエフェクトを描画する。
    DrawEffekseer3D();
}

```

```c++:Camera.h
#pragma once
#include <EffekseerForDXLib.h>
class Camera
{
public:
	Camera();			// コンストラクタ
	~Camera();			// デストラクタ
	void Initialize();	// 初期化
	void Update();		// 更新
private:
	// 定数
	const float	 CameraNearClip				= 0.1f;			// カメラから見て最も近い描画距離の設定
	const float	 CameraFarClip				= 600.0f;		// カメラから見て最も遠い描画距離の設定
	const VECTOR InitializePosition			= { 0,10,-50 };	// 初期化時の座標
	const VECTOR InitializeTargetPosition	= { 0,0,0 };	// 初期化時の視点座標
	const float  FovDegrees = 60.0f * DX_PI_F / 180.0f;		// カメラの視野角(度数)
	// 変数
	VECTOR	position;			// 座標(どこから見るのか)
	VECTOR	targetPosition;		// 視点座標(自分が見ている位置)
};
```

```c++:Camera.cpp
#include "Camera.h"
// コンストラクタ
Camera::Camera()
    : position          (InitializePosition)
    , targetPosition    (InitializeTargetPosition)
{
    // 初期化
    Initialize();
}

// デストラクタ
Camera::~Camera()
{
    // 処理なし
}

// 初期化
void Camera::Initialize()
{
    // 描画範囲の設定
    SetCameraNearFar(CameraNearClip, CameraFarClip);

    // カメラを設定
    SetCameraPositionAndTarget_UpVecY(position, targetPosition);

    // 視野角設定
    SetupCamera_Perspective(FovDegrees);
}

// 更新
void Camera::Update()
{
    // DXライブラリのカメラとEffekseerのカメラを同期する。
    Effekseer_Sync3DSetting();

    // カメラの更新
    SetCameraPositionAndTarget_UpVecY(position, targetPosition);
}
```

```c++:TestObject.h
#pragma once
#include <EffekseerForDXLib.h>

// とりあえずオブジェクト実装
// テスト用オブジェクト
class TestObject
{
public:
	TestObject();
	~TestObject();
	void Update();
	void Draw();
	VECTOR GetPlayerPosition() { return playerPosition; }
private:
	VECTOR playerPosition;	// プレイヤー座標
	VECTOR stagePosition;	// ステージ座標
	int playerModelHandle;	// プレイヤーモデルハンドル
	int stageModelHandle;	// ステージモデルハンドル
};
```

```c++:TestObject.cpp
#include "TestObject.h"

TestObject::TestObject()
    : playerPosition    (VGet(0,0,0))
    , stagePosition     (VGet(0,-10,0))
{
    // モデル読み込み
    playerModelHandle = MV1LoadModel("Data/PlayerModel.mv1");
    stageModelHandle = MV1LoadModel("Data/StageModel.mv1");

    // スケール調整
    MV1SetScale(playerModelHandle, VGet(0.01f, 0.01f, 0.01f));
    MV1SetScale(stageModelHandle, VGet(0.1f,0.1f, 0.1f));
}

TestObject::~TestObject()
{
    // モデル削除
    MV1DeleteModel(playerModelHandle);
    MV1DeleteModel(stageModelHandle);
}

void TestObject::Update()
{
    // プレイヤーの移動
    if (CheckHitKey(KEY_INPUT_LEFT)) { playerPosition.x -= 0.25f; }
    else if (CheckHitKey(KEY_INPUT_RIGHT)) { playerPosition.x += 0.25f; }
    if (CheckHitKey(KEY_INPUT_UP)){ playerPosition.z += 0.25f; }
    else if (CheckHitKey(KEY_INPUT_DOWN)){ playerPosition.z -= 0.25f; }

    // 座標更新
    MV1SetPosition(playerModelHandle, playerPosition);
    MV1SetPosition(stageModelHandle, stagePosition);
}

void TestObject::Draw()
{
    // モデル描画
    MV1DrawModel(playerModelHandle);
    MV1DrawModel(stageModelHandle);
}
```


```c++:Main.cpp
#include <EffekseerForDXLib.h>
#include "EffectManager.h"
#include "Camera.h"
#include "TestObject.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	ChangeWindowMode(true);
	SetDrawScreen(DX_SCREEN_BACK);
	if (DxLib_Init() == -1) { return -1; }

	// インスタンス化
	EffectManager	effectManager;	// エフェクト管理クラス
	Camera			camera;			// カメラ
	TestObject		testObject;		// テストオブジェクト

	// ゲームループ
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && !CheckHitKey(KEY_INPUT_ESCAPE))
	{
		// 更新
		testObject.Update();
		camera.Update();
		effectManager.Update(testObject.GetPlayerPosition());

		// 描画
		testObject.Draw();
		effectManager.Draw();
	}

	// Effekseerを終了する。
	Effkseer_End();

	// DXライブラリの後始末
	DxLib_End();

	return 0;				// ソフトの終了
}
```

## 必要ファイル
:::note info
このプロジェクト内に必要なエフェクトデータをダウンロードしてください↓
:::
https://drive.google.com/drive/folders/1N-9ghJAjzOyvxBmHdanXuzpnwLNPJsDa?usp=sharing

---

:::note warn
このようなファイル構成位置にしてください↓
:::
![スクリーンショット 2024-11-20 141108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3847430/de9af76a-44f4-7049-3dea-582fed453c7c.png)

:::note alert
※必ず`Dataフォルダ`を`プロジェクトファイル`と同じファイル階層においてください。
:::

:::note info
この実装で起動確認してます。
:::

# 4. ピックアップ解説

:::note alert
## `この部分は脳死で実装しないと動作しません。↓`
:::
```c++:EffectManager.cpp
// 初期化
void EffectManager::Initialize()
{
    SetUseDirect3DVersion(DX_DIRECT3D_11);
    if (Effkseer_Init(EffectParticleLimit) == -1) { DxLib_End(); }    
    SetChangeScreenModeGraphicsSystemResetFlag(FALSE);
    Effekseer_SetGraphicsDeviceLostCallbackFunctions();
    SetUseZBuffer3D(TRUE);
    SetWriteZBuffer3D(TRUE);
}
```

---

:::note info
## `この流れで実装したら基本いけると思います↓`

1. 読み込み　　　　　　　　`LoadEffekseerEffect`
2. 再生　　　　　　　　　　`PlayEffekseer3DEffect`
3. 再生座標設定　　　　　　`SetPosPlayingEffekseer3DEffect`
4. すべての再生座標更新　　`UpdateEffekseer3D`
5. すべてのエフェクト描画　`DrawEffekseer3D`
:::

---

## `LoadEffekseerEffect`で読み込むファイルについて

:::note alert
読み込むファイルは必ず`.efk`ファイルでないとエラーが発生します。
:::
    リソースハンドル = LoadEffekseerEffect("Data/Flame.efk"); // としてください

`.efkproj`ファイルがありますが、これはエフェクシアのツール上で使用するファイルです。
`efkefc`ファイルは`efk`ファイル同様に使用できるようです。

1. `.efkproj` をエフェクシアツールで開く
2. ゲームエンジンで使用可能な形にエクスポート
3. `.efk`　が出力される

エフェクシアは本来エフェクトを制作、編集するツールですのでそちらを利用して自分が使用したいエフェクトを作成する形になります。
(自分は公式サイト様からすでに作成されているエフェクトを利用させていただきました。)

:::note info
分からなかったら.efkファイルだけ使いましょう。
:::

# 5. まとめ
簡単にDXライブラリでエフェクシアを実装する方法についてまとめてみました。
実用的なものには程遠いですが、参考になれば幸いです。

最後に作成したプロジェクトファイルのリンクを置いておきます。↓
https://drive.google.com/drive/folders/1UwZ8tpZxEFtKaHM8cp2TO02twBLF3nSl?usp=sharing


# 6. 参考サイト
EffekseerのDXライブラリで使用可能なすべての関数↓
https://github.com/effekseer/EffekseerForDXLib/blob/master/Dev/EffekseerForDXLib/EffekseerForDXLib.h