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のライブラリがビルドされたときにディレクトリも作成されます。

サンプルの起動

 FullSample105BaseCrossDx11.slnというソリューションを開くとDx11版が起動します。
 リビルドして実行するとプレイヤーだけが配置される画面が出てきます。
 ここでAボタンを押すと、派手なエフェクトがでます。このエフェクトはEffekseerのランタイムのダウンロードに含まれるテスト用のサンプルです。このようなエフェクトをBaseCross64でも再生できるようになります。
 以下がその画面です。

 

図1105a

 


制限事項

 実は、このサンプルにはサウンドの情報も入ってます。エフェクト発射と同時に再生されるはずですが、BaseCross64で使用する場合はサウンド機能はこのサンプルでは使用できません。
 理由は、EffekseerX3DAudioという機能を使用してますが、これが入ってない環境もあるため、その場合、別にセットアップをする必要があります。できるだけ、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_EfkPlayshared_ptrですので、上書きされるたびに、まえのshared_ptrのデストラクタが動きます。そのデストラクタでは、実行中のエフェクトをストップしてから破棄されるよう記述があるので、ハンドルが中途半端に残ることはありません。
 もし、複数の、同じエフェクトを同時に表示させる場合はm_EfkPlayを1つではなく配列で管理します。そうするとハンドルの再利用ができるようになります。