11.チュートリアル
1105.Effekseerの使用
このサンプルは
FullSample105というディレクトリに含まれます。
BaseCrossDx11VS2017.sln、BaseCrossDx11VS2019.slnというソリューションを開くと
Dx11版が起動します。
VS2017、VS2019はVisualStdioのバージョンです。
Effekseerについて
Effekseerはエフェクト作成のためのツールです。高機能なうえに軽いツールで、フリーで配布されているので、学習のためや、小規模なソフトハウスでも気軽に使うことができます。
BaseCross64でも
パーティクル描画という方法で
エフェクトの描画は可能ですが、細かな演出には向いていません。というのは、エフェクトの動的な部分を
計算で指定してあげなければいけないからです。
簡単なエフェクトや、連番アニメーションであればこれでもいいのですが、手の込んだエフェクトはやはりツールが必要です。そこで、
Effekseerで作成したデータを
BaseCross64で再生するサンプルを作成しました。それが
FullSample105です。
ライブラリの準備
Effekseer再生のためのライブラリは、
GitHub情報サイト
https://effekseer.github.io/jp/
からダウンロードできます。ここから
ダウンロードリンクをクリックし
Effekseer for Runtimeをダウンロードしてください。
ダウンロードするのは、zipファイルです。そのままではセキュリティによりビルドに含めるとエラーが出ますので、zipの状態で、右ボタンをクリックして、
プロパティで、セキュリティ警告を解除してください。
解凍しますと
Compiledというディレクトリが出てきます。この中の
includeおよび
libの内容を以下のように、
BaseCross64のLibsディレクトリ内にコピーしてください。
【includeファイル】
Compiled/include/Effekseer.h
Compiled/include/EffekseerRendererDX11.h
Compiled/include/EffekseerSoundXAudio2.h
を、BaseCross64の
Libs/include/Effekseer.h
Libs/include/EffekseerRendererDX11.h
Libs/include/EffekseerSoundXAudio2.h
としてコピー。
【libファイル(デバッグ用)】
Compiled/lib/VS2017WIN64/Debug/Effekseer.lib
Compiled/lib/VS2017WIN64/Debug/EffekseerRendererDX11.lib
Compiled/lib/VS2017WIN64/Debug/EffekseerSoundXAudio2.lib
を、BaseCross64の
Libs/lib/Dx11/Debug/Effekseer.lib
Libs/lib/Dx11/Debug/EffekseerRendererDX11.lib
Libs/lib/Dx11/Debug/EffekseerSoundXAudio2.lib
としてコピー。
【libファイル(リリース用)】
Compiled/lib/VS2017WIN64/Release/Effekseer.lib
Compiled/lib/VS2017WIN64/Release/EffekseerRendererDX11.lib
Compiled/lib/VS2017WIN64/Release/EffekseerSoundXAudio2.lib
を、BaseCross64の
Libs/lib/Dx11/Release/Effekseer.lib
Libs/lib/Dx11/Release/EffekseerRendererDX11.lib
Libs/lib/Dx11/Release/EffekseerSoundXAudio2.lib
としてコピー。
以上で準備は終わりです。もし、BaseCross64内に
Libs/lib/Dx11/などのディレクトリがない(存在しない)場合は、手作業で作成してもいいですが、ほかのサンプルを
デバッグモードとリリースモード両方でリビルドしてみてください。
DitectXTXのライブラリがビルドされたときにディレクトリも作成されます。
サンプルの起動
FullSample105の
BaseCrossDx11.slnというソリューションを開くと
Dx11版が起動します。
リビルドして実行するとプレイヤーだけが配置される画面が出てきます。
ここで
Aボタンを押すと、派手なエフェクトがでます。このエフェクトは
Effekseerのランタイムのダウンロードに含まれるテスト用のサンプルです。このようなエフェクトを
BaseCross64でも再生できるようになります。
以下がその画面です。
図1105a
制限事項
実は、このサンプルには
サウンドの情報も入ってます。エフェクト発射と同時に再生されるはずですが、
BaseCross64で使用する場合は
サウンド機能はこのサンプルでは使用できません。
理由は、
Effekseerは
X3DAudioという機能を使用してますが、これが入ってない環境もあるため、その場合、別にセットアップをする必要があります。できるだけ、
Windows10デフォルトで動作するようにしたいので、
Effekseerサウンド機能は実装してません。ただ、
EffekseerSoundXAudio2のインクルード及びlibファイルの設置はしていても問題はありません。
コード解説
Effekseerのランタイムは
BaseCross64のライブラリには含まれません。ですので、
ゲームコンテンツ側の実装となります。関係するのは
GameSourcesの中の
EfkInterface.h/cppです。これは、フルバージョンだけではなく、シンプルバージョンでもこの2つのファイルをプロジェクトに実装すれば
Effekseerのデータを再生できるようになります。
また、
Effekseerのランタイムの使用は、このサンプルのように
EfkInterface.h/cpp内のクラスを使う必要があるわけではありません。
Effekseerのランタイムは、非常に使いやすくインターフェイスが整っているので、べたに記述しても簡単に利用可能でしょう。
このファイルの中には
EfkEffectクラス、EfkPlayクラス、EfkInterfaceクラスの3つのクラスがあります。それぞれ役割があります。
EfkEffectクラス
このクラスは
エフェクトファイル(.efk拡張子)のオブジェクトを管理します。エフェクトを使う
GameObjectなどで実装します。
EfkPlayクラス
このクラスは
実際に再生中のオブジェクトを管理します。
EfkEffectランタイムでは
ハンドルという概念で各エフェクトがオブジェクト化されます。
EfkPlayクラスはこの
各ハンドルをカプセル化したものです。
EfkInterfaceクラス
このクラスは
Effekseerの
マネージャとレンダラーをカプセル化しています。
これらのクラスは
BaseCross64との相性が良いようにラッピングされたものですが、
Effekseerは生ポインタを使用していて、自分でオブジェクトの解放をしなければなりません。
スマートポインタを使うことで、これらの処理をクラス内に収めることができますのでこのような設計になってます。ですから、上記の3つのクラスを使用する分には、
メモリの解放は意識しなくても大丈夫です。
コードの記述
まず
Effekseerを使うゲームでは
EfkInterface.h/cppをプロジェクトに加え、
Project.hに以下を追加します。
#pragma once
#include "EfkInterface.h"
#include "ProjectShader.h"
#include "ProjectBehavior.h"
//以下略
このようにして、
GameStageクラスの宣言などに、以下のように記述します
class GameStage : public Stage {
//エフェクトのインターフェイス
shared_ptr<EfkInterface> m_EfkInterface;
//中略
public:
//中略
//初期化
virtual void OnCreate()override;
//エフェクトのインターフェイスの取得
shared_ptr<EfkInterface> GetEfkInterface() const {
return m_EfkInterface;
}
//更新
virtual void OnUpdate() override;
//描画
virtual void OnDraw() override;
};
このようにして
GameStage::OnCreate()に以下のように記述します
void GameStage::OnCreate() {
try {
//中略
//エフェクト作成
m_EfkInterface = ObjectFactory::Create<EfkInterface>();
//中略
//プレーヤーの作成
CreatePlayer();
}
catch (...) {
throw;
}
}
エフェクトは今回はプレイヤーで使うので、プレイヤーが構築される前に実装しておきます。
続いて
OnUpdate()とOnDraw()です。多重定義して実装します。
//更新
void GameStage::OnUpdate() {
m_EfkInterface->OnUpdate();
}
//描画
void GameStage::OnDraw() {
auto& camera = GetView()->GetTargetCamera();
m_EfkInterface->SetViewProj(camera->GetViewMatrix(), camera->GetProjMatrix());
m_EfkInterface->OnDraw();
}
続いて、プレイヤーです。以下はヘッダです。
class Player : public GameObject {
//エフェクト
shared_ptr<EfkEffect> m_EfkEffect;
//エフェクト実行オブジェクト
shared_ptr<EfkPlay> m_EfkPlay;
//中略
public:
//中略
};
以下は
Player::OnCreate()です。エフェクトファイルを読み込みます。
void Player::OnCreate() {
//中略
//エフェクトの初期化
wstring DataDir;
App::GetApp()->GetDataDirectory(DataDir);
wstring TestEffectStr = DataDir + L"Effects\\test.efk";
auto ShEfkInterface = GetTypeStage<GameStage>()->GetEfkInterface();
m_EfkEffect = ObjectFactory::Create<EfkEffect>(ShEfkInterface, TestEffectStr);
//中略
}
最後に、実際にエフェクトの発射です。Aボタンのハンドラである
Player::OnPushA()に記述します。
//Aボタンハンドラ
void Player::OnPushA() {
auto grav = GetComponent<Gravity>();
grav->StartJump(Vec3(0,4.0f,0));
auto Ptr = GetComponent<Transform>();
//エフェクトのプレイ
auto ShEfkInterface = GetTypeStage<GameStage>()->GetEfkInterface();
m_EfkPlay = ObjectFactory::Create<EfkPlay>(m_EfkEffect, Ptr->GetPosition());
}
このように、ボタンが押されるたびに
m_EfkPlayが上書きされるようになっています。
m_EfkPlayは
shared_ptrですので、上書きされるたびに、まえのshared_ptrのデストラクタが動きます。そのデストラクタでは、実行中のエフェクトを
ストップしてから破棄されるよう記述があるので、
ハンドルが中途半端に残ることはありません。
もし、複数の、同じエフェクトを同時に表示させる場合は
m_EfkPlayを1つではなく配列で管理します。そうすると
ハンドルの再利用ができるようになります。
。