Support System

開発支援・ユーティリティ構造

FlFileWatcher – ファイル監視と資産同期

FlFileWatcher は、エディタ環境におけるファイル変化の検出・自動更新・同期の中核です。 std::filesystemstd::thread を活用し、非同期にディレクトリ全体を監視します。 更新が検出されると、即座にコールバックを通じて関連システム (例:メタファイル更新・アセット再ロード) へ反映します。


// --- 抜粋: FlFileWatcher::Start ---
void FlFileWatcher::Start(Callback callback)
{
    m_running = true;
    m_thread = std::thread([this, callback]() {
        while (m_running) {
            std::this_thread::sleep_for(m_interval);

            // ファイル更新・新規作成検出
            for (auto& file : std::filesystem::recursive_directory_iterator(m_pathToWatch)) {
                const auto pathStr = file.path().string();
                const auto lastWriteTime = std::filesystem::last_write_time(file);

                if (!Contains(pathStr)) {
                    m_paths[pathStr] = lastWriteTime;
                    callback(file.path(), FileStatus::Created);
                }
                else if (m_paths[pathStr] != lastWriteTime) {
                    m_paths[pathStr] = lastWriteTime;
                    callback(file.path(), FileStatus::Modified);
                }
            }

            // 削除検出
            for (auto it = m_paths.begin(); it != m_paths.end();) {
                if (!std::filesystem::exists(it->first)) {
                    callback(it->first, FileStatus::Erased);
                    it = m_paths.erase(it);
                } else ++it;
            }
        }
    });
}
  

主な特徴

FlVisualStudioManager – Visual Studioのプロジェクト自動生成・追加

FlVisualStudioManager は、FlScriptModuleEditorで入力された名前でプロジェクトとフィルタと必要最低限のコードファイルを テンプレートコードから作成、またはそのプロジェクトの削除を行います。 .slnにプロジェクトを追加し、プリコンパイルヘッダなどの設定を済ませます。


// --- 抜粋: FlVisualStudioProjectManager::CreateNewProject ---
auto projDir = targetDir / projectName;

// ---------------------------------------------------
// (1) ディレクトリ作成
// ---------------------------------------------------
try {
    std::filesystem::create_directories(projDir);
}
catch (...) {
    FlEditorAdministrator::Instance().GetLogger()->AddErrorLog("Failed to create directory: %s", projDir.string().c_str());
    return false;
}

// ---------------------------------------------------
// (2) 初期コードファイル生成
// ---------------------------------------------------
if (!CreateSourceFiles(projDir, projectName)) {
    return false;
}

// ---------------------------------------------------
// (3) .vcxproj と .filters を生成
// ---------------------------------------------------
if (!CreateVcxproj(projDir, projectName)) return false;
if (!CreateFilters(projDir, projectName)) return false;

// ---------------------------------------------------
// (4) .sln に Project を追加
// ---------------------------------------------------
auto projFile = projDir / (projectName + ".vcxproj");
if (!AddProjectToSolution(m_solutionPath, projFile, projectName)) {
    return false;
}

FlEditorAdministrator::Instance().GetLogger()->AddLog("Project '%s' created & added to solution.", projectName.c_str());
return true;
  

主な特徴

FlAutomaticFileAddSystem – 自動コード生成とXMLパーサ連携

FlAutomaticFileAddSystem は、 新しいコードファイルを、.vcxproj および .filters に即時登録するためのシステムです。 内部的には tinyxml2 によるXMLパーサを利用してVisual Studioのプロジェクト構成を解析・更新します。


// --- 抜粋: FlAutomaticFileAddSystem::AddFiles ---
if (files.empty()) return true;

auto normalizedFilterPath{ std::filesystem::path(filterPath).lexically_normal().string()};

// 出力先ディレクトリの作成
auto outputDir{ m_projectDir / normalizedFilterPath };
if (!std::filesystem::exists(outputDir))
{
    try {
        std::filesystem::create_directories(outputDir);
    }
    catch (...) {
        return false;
    }
}

// 1. 実ファイルの書き込み
for (const auto& file : files) 
{
    auto fullPath = outputDir / file.fileName;
    if (!WriteFileToDisk(fullPath, file.content)) return false;
}

// 2. vcxprojの更新 (一度だけLoad/Save)
{
    tinyxml2::XMLDocument doc;
    if (doc.LoadFile(m_vcxprojPath.string().c_str()) != XML_SUCCESS) return false;

    for (const auto& file : files)
    {
        auto fullPath = outputDir / file.fileName;
        if (file.itemType == Def::EmptyStr) AddToVcxproj(doc, fullPath, DetectItemType(file.fileName));
        else AddToVcxproj(doc, fullPath, file.itemType);
    }

    if (doc.SaveFile(m_vcxprojPath.string().c_str()) != XML_SUCCESS) return false;
}

// 3. filtersの更新 (一度だけLoad/Save)
{
    tinyxml2::XMLDocument doc;
    if (doc.LoadFile(m_filtersPath.string().c_str()) != XML_SUCCESS) return false;

    // 指定されたフィルタ階層が存在しない場合は作成
    EnsureFilterPathExists(doc, normalizedFilterPath);

    for (const auto& file : files)
    {
        auto fullPath = outputDir / file.fileName;
        if (file.itemType == Def::EmptyStr) AddToFilters(doc, fullPath, DetectItemType(file.fileName), normalizedFilterPath);
        else AddToFilters(doc, fullPath, file.itemType, normalizedFilterPath);
    }

    if (doc.SaveFile(m_filtersPath.string().c_str()) != XML_SUCCESS) return false;
}

return true;
  

上記の関数は、指定したフィルタに複数のコードファイルを プロジェクトファイルへXML要素を追加します。 フィルタ階層の作成や一意識別子の付与も自動化されており、 Visual Studio上でのソース構成を即座に反映します。

XML操作の一例


// --- 抜粋: FlAutomaticFileAddSystem::AddToFilters ---
XMLElement* root = doc.RootElement();
if (!root) return false;

// ItemTypeに対応するItemGroupを探す
XMLElement* itemGroup = nullptr;
for (XMLElement* ig = root->FirstChildElement("ItemGroup"); ig; ig = ig->NextSiblingElement("ItemGroup"))
{
    if (ig->FirstChildElement(itemType.c_str()))
    {
        itemGroup = ig;
        break;
    }
}

if (!itemGroup)
{
    itemGroup = doc.NewElement("ItemGroup");
    root->InsertEndChild(itemGroup);
}

auto relPath = std::filesystem::relative(filePath, m_projectDir).generic_string();
std::string filterPathWin = filterPathStr;
std::replace(filterPathWin.begin(), filterPathWin.end(), '/', '\\');

// 重複チェック
for (XMLElement* e = itemGroup->FirstChildElement(itemType.c_str()); e; e = e->NextSiblingElement(itemType.c_str()))
{
    const char* inc = e->Attribute("Include");
    if (inc && relPath == inc) return true;
}

XMLElement* elem = doc.NewElement(itemType.c_str());
elem->SetAttribute("Include", relPath.c_str());

XMLElement* filterElem = doc.NewElement("Filter");
filterElem->SetText(filterPathWin.c_str());
elem->InsertEndChild(filterElem);

itemGroup->InsertEndChild(elem);
return true;
  

主な特徴

FlSolutionParser – Visual Studioソリューション構造解析

FlSolutionParser は、Visual Studio の .sln ファイルを解析し、 含まれる .vcxproj プロジェクトの構造情報を抽出するためのユーティリティです。 Editor内部では、プロジェクトのBuildに活用されています。


// --- 抜粋: FlSolutionParser::Load ---
bool FlSolutionParser::Load(const std::filesystem::path& slnPath)
{
    m_projects.clear();
    m_solutionPath = slnPath;

    std::ifstream file(slnPath);
    if (!file.is_open()) return false;

    std::string line;
    while (std::getline(file, line)) {
        if (line.rfind("Project(", 0) == 0)) {
            // ダブルクォート位置を取得
            std::vector<size_t> quotes;
            for (size_t pos = 0; pos < line.size(); ++pos)
                if (line[pos] == '"') quotes.push_back(pos);

            if (quotes.size() >= 6) {
                // プロジェクト名・パス抽出
                std::string name    = line.substr(quotes[2] + 1, quotes[3] - quotes[2] - 1);
                std::string relPath = line.substr(quotes[4] + 1, quotes[5] - quotes[4] - 1);
                std::replace(relPath.begin(), relPath.end(), '\\', '/');

                std::filesystem::path projectPath = m_solutionPath.parent_path() / relPath;
                std::string ext = projectPath.extension().string();
                std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

                if (ext == ".vcxproj") {
                    FlProjectInfo info;
                    info.name         = name;
                    info.relativePath = relPath;
                    info.fullPath     = std::filesystem::absolute(projectPath).lexically_normal();
                    m_projects.push_back(info);
                }
            }
        }
    }
    return !m_projects.empty();
}
  

主な特徴

利用例


FlSolutionParser parser;
if (parser.Load("FalconEngine.sln")) {
    const auto* project = parser.FindProjectByName("FlComponentSystem");
    if (project)
        std::cout << "Found project: " << project->name 
                  << " at " << project->fullPath << std::endl;
}
  

このクラスは、MSBuildコマンドでBuildもしくはCleanを行うために、ソリューションに含まれるプロジェクトの名前とパスを検出します。

FlChronus – 時間制御と計測ユーティリティ

FlChronus は、時間管理・計測・制御の基盤を担うユーティリティクラスです。 ストップウォッチ、ラップタイマー、ティッカー、FPS計測、スコープ計測など、 開発・計測・最適化のあらゆる場面で活用できる高精度ツール群を内包しています。


// --- 抜粋: FlChronus 基本構造 ---
class FlChronus 
{
public:
    using Steady = std::chrono::steady_clock;   // 経過時間用 (単調時計)
    using System = std::chrono::system_clock;   // 現実時間用 (壁時計)

    FlChronus(bool startNow = true) { if (startNow) start(); }

    void start() noexcept { if (!_running) { _running = true; _t0 = Steady::now(); } }
    void stop() noexcept  { if (_running) { _acc += Steady::now() - _t0; _running = false; } }
    void reset() noexcept { _acc = Dur::zero(); _running = false; _t0 = Steady::now(); }

    template
    D elapsed() const noexcept {
        Dur d{ _acc };
        if (_running) d += (Steady::now() - _t0);
        return std::chrono::duration_cast(d);
    }
};
  

主な構成機能

便利ユースケース例


// --- 例1: FPSの計測 ---
FlChronus::FpsAverager fpsAvg;
auto [current, average] = fpsAvg.on_frame();
std::cout << "FPS: " << current << " (" << average << " avg)\n";

// --- 例2: スコープ計測 ---
{
    FlChronus::Scoped measure([](auto dur){
        std::cout << "処理時間: " << FlChronus::to_seconds(dur) << "秒\n";
    });
    RunHeavyProcess(); // 処理時間を自動計測
}
  

特徴

FlEasing – アニメーション補間関数ライブラリ

FlEasing は、アニメーションやトランジション効果に滑らかな動きを付与するための イージング関数群をまとめたユーティリティクラスです。 物理的な動きや自然な加速・減速をシンプルに表現でき、 UIエフェクト・ゲーム演出・補間計算など幅広く利用できます。


// --- 抜粋: FlEasing 基本構造 ---
class FlEasing 
{
public:
    static double Linear(double t) noexcept { return t; }

    // 二次曲線 (Quad)
    static double EaseInQuad(double t) noexcept { return t * t; }
    static double EaseOutQuad(double t) noexcept { return t * (2 - t); }

    // 三次曲線 (Cubic)
    static double EaseInCubic(double t) noexcept { return t * t * t; }
    static double EaseOutCubic(double t) noexcept { return 1 + (--t) * t * t; }

    // 正弦補間 (Sine)
    static double EaseInSine(double t) noexcept {
        return 1 - std::cos((t * M_PI) / 2.0);
    }
};
  

主な特徴

使用例


// --- 例: 時間t[0,1]に応じて値を補間 ---
double t = 0.5;
double value = FlEasing::EaseInOutCubic(t);
pos.x = Math::Lerp(start.x, end.x, value);
pos.y = Math::Lerp(start.y, end.y, value);
  

このように、FlEasing はゲーム・UIエフェクト・スライダー挙動など あらゆる「時間変化」に直感的な表現力を与えます。 FlChronus と組み合わせることで、 時間制御と補間を高精度かつ簡潔に扱うことができます。

FlAnimator – 時間制御 × 補間の統合クラス

FlAnimator は、FlChronusFlEasing を統合した 「時間ベース補間クラス」です。
アニメーションの経過時間を自動的に管理し、イージング関数を適用した進行度を算出します。 ゲーム内UI・トランジション・フェードなど、あらゆる時間変化処理を簡潔に実装できます。


// --- 抜粋: FlAnimator ---
class FlAnimator
{
public:
    using EaseFunc = std::function<double(double)>;

    FlAnimator(double durationSec, EaseFunc ease = FlEasing::Linear)
        : m_duration(durationSec), m_ease(ease) {}

    void start()  { m_timer.start();  m_running = true; }
    void reset()  { m_timer.reset();  m_running = false; }

    bool isRunning() const { return m_running && progress() < 1.0; }

    // イージング適用済みの進行度 (0.0〜1.0)
    double value() const { return m_ease(progress()); }

    // 生の進行度(イージング未適用)
    double progress() const {
        if (!m_running) return 0.0;
        double t = std::chrono::duration_cast<std::chrono::duration<double>>(
            m_timer.elapsed()).count() / m_duration;
        return std::clamp(t, 0.0, 1.0);
    }

private:
    FlChronus m_timer;
    double m_duration;
    EaseFunc m_ease;
    bool m_running = false;
};
  

主な特徴

使用例


// --- UIフェードアニメーション例 ---
FlAnimator fade(2.0, FlEasing::EaseInOutQuad);
fade.start();

while (fade.isRunning()) {
    double alpha = fade.value(); // 0.0〜1.0 の補間値
    DrawUI(alpha);
}
  

FlAnimator により、時間計測と補間を一体化した柔軟なアニメーション管理が可能です。 コード上での時間制御が明快になり、UI/演出処理を「データ駆動的」に記述できます。

FlMetaFileManager – アセットメタ情報自動生成・追従システム

FlMetaFileManager は、ゲームエンジン内で使用される全アセット(モデル・テクスチャ・サウンドなど)に対して、 一意の GUID と管理情報を付与するメタファイル (.flmeta) を自動生成・更新・追従するクラスです。 Unity の .meta 管理に類似しており、ファイルのリネーム・移動・削除にも自動対応します。


// --- 抜粋: FlMetaFileManager.h ---
class FlMetaFileManager
{
public:
    void StartMonitoring(const std::string& rootPath, int intervalSeconds = 1);
    void StopMonitoring();

    void CreateMetaFileIfNotExist(const std::string& assetPath);
    void OnAssetRenamedOrMoved(const std::filesystem::path& oldPath, const std::filesystem::path& newPath);
    void IncrementLoadFlag(const std::string& assetPath);

    const std::optional<std::string> FindAssetByGuid(const std::string& guid) const;
    const std::optional<std::string> FindGuidByAsset(const std::filesystem::path& path) const;

private:
    void CreateOrUpdateFlMetaFile(const std::filesystem::path& assetPath);
    bool IsInsideFlMeta(const std::filesystem::path& path) const;
    void OnFileEvent(const std::filesystem::path& path, FlFileWatcher::FileStatus status);

    FlFileWatcher m_fileWatcher;
    std::unordered_map<std::string, std::string> m_guidMap;
};
  

主な特徴

動作概要


void FlMetaFileManager::StartMonitoring(const std::string& rootPath, int intervalSeconds)
{
    m_rootPath = rootPath;
    std::filesystem::create_directories(m_rootPath);

    // 初回スキャンで既存アセットにメタ付与
    for (const auto& entry : std::filesystem::recursive_directory_iterator(m_rootPath))
        if (!IsInsideFlMeta(entry.path()))
            CreateOrUpdateFlMetaFile(entry.path());

    // ファイル監視開始
    m_fileWatcher.SetPathAndInterval(rootPath, std::chrono::seconds(intervalSeconds));
    m_fileWatcher.Start([this](const auto& path, auto status) {
        OnFileEvent(path, status);
    });
}
  

内部処理

メタファイル例


{
  "Guid": "B8345E9A-9A6E-42A3-A7E9-41F3AD9FEC15",
  "assetPath": "Assets/Textures/skybox.png",
  "isDirectory": false,
  "lastModified": "2025-10-06T08:13:12Z",
  "loadFlag": false
}
  

利用例


FlMetaFileManager meta;
meta.StartMonitoring("Assets");

// メタファイル自動生成・追従開始
if (auto guid = meta.FindGuidByAsset("Assets/Textures/skybox.png"))
    std::cout << "GUID: " << *guid << std::endl;

// 移動時の追従処理
meta.OnAssetRenamedOrMoved("Assets/Textures/skybox.png", "Assets/Environment/skybox.png");
  

技術的ポイント

このクラスは、アセットの永続的な一意識別を保証し、 再インポートやエディタ再起動時にも GUID が保持されるよう設計されています。 ファイル管理の自動化基盤として FlFileEditor と密接に連携します。

FlResourceAdministrator – アセット統合管理システム

FlResourceAdministrator は、ゲーム内で使用するすべてのアセットを一元的に管理する中核クラスです。 ShaderTextureModelAudioBinary といった各種ローダーを統合し、 GUIDベースでキャッシュされたリソースを即座に取得できるよう設計されています。

各アセットローダーは Flyweight パターン によって設計されており、 同一リソースの多重ロードを防ぎ、効率的なメモリ利用を実現します。


// --- 抜粋: FlResourceAdministrator.h ---
class FlResourceAdministrator
{
public:
    void Load(const std::initializer_list<std::string>& assetsPaths) noexcept;

    template<typename T>
    const std::shared_ptr<T>& Get(const std::string& path);

    template<typename T>
    const std::shared_ptr<T>& GetByGuid(const std::string& guid);

    void AllAssetsCacheClear() noexcept;

    const auto& GetMetaFileManager() const noexcept { return m_meta; }

    static auto& Instance() noexcept
    {
        static auto instance{ FlResourceAdministrator{} };
        return instance;
    }

private:
    FlResourceAdministrator();
    ~FlResourceAdministrator();

    std::unique_ptr<ShaderManager>    m_shader;
    std::unique_ptr<FlTextureManager> m_texture;
    std::unique_ptr<ModelManager>     m_model;
    std::unique_ptr<FlAudioManager>   m_audio;
    std::unique_ptr<FlBinaryManager>  m_binary;
    std::unique_ptr<FlMetaFileManager> m_meta;
};
  

主な特徴

動作概要


// --- Shader 取得例 ---
auto shader = FlResourceAdministrator::Instance().Get<ComPtr<ID3DBlob>>("Shaders/StandardVS.hlsl");

// --- Texture 取得例 ---
auto texture = FlResourceAdministrator::Instance().Get<Texture>("Textures/UI/button.png");

// --- GUID から直接取得 ---
auto model = FlResourceAdministrator::Instance().GetByGuid<ModelData>("A1B2C3D4-5678-9012-3456-ABCDEF123456");
  

Flyweight パターンの構造

各ローダーは共通の基底クラス BaseBasicResourceManager<T> を継承しており、 アセットのロード済みキャッシュを共有します。これにより、同一アセットを複数オブジェクトで参照しても メモリ上には一つだけのインスタンスが存在します。


// --- 抜粋: BaseBasicResourceManager.h ---
template<typename T>
class BaseBasicResourceManager
{
public:
    virtual ~BaseBasicResourceManager() = default;
    virtual const bool Load(const std::string& path) = 0;

    const std::shared_ptr<T>& Get(const std::string& path, const std::string& guid) noexcept
    {
        // 既にロード済みなら再利用
        if (auto it = m_resources.find(guid); it != m_resources.end())
            return it->second;

        // 未ロードならロード処理を実行
        if (!Load(path)) return nullptr;
        return m_resources[guid];
    }

    void Clear() { m_resources.clear(); }

protected:
    std::unordered_map<std::string, std::shared_ptr<T>> m_resources;
};
  

技術的ポイント


FlResourceAdministrator は、アセットパイプラインの中心的な役割を担います。 ファイル監視・キャッシュ・識別を自動化し、 各アセットマネージャーとの連携によって “一度ロードしたものをどこでも即座に再利用” できる環境を構築しています。

FlAssetProtector – アセット暗号化システム

FlAssetProtector は、ゲーム開発中および配布時の アセットの二次配布防止データ秘匿化 を目的とした 軽量暗号化システムです。 スタティックライブラリとしてビルドされ、ゲーム本体とは独立して動作するため、 不正な復号・解析を難しくします。


// --- 抜粋: FlCrypter.h ---
namespace FlAssetProtector
{
    class CryptoManager
    {
    public:
        static bool EncryptXOR(const std::vector<uint8_t>& plaintext,
                               std::vector<uint8_t>& ciphertext);

        static bool DecryptXOR(const std::vector<uint8_t>& ciphertext,
                               std::vector<uint8_t>& plaintext);

        static std::string EncryptFilename(const std::string& original);
        static std::string DecryptFilename(const std::string& encryptedName);
    };

    bool EncryptAssetFile(const std::filesystem::path& inputPath,
                          const std::filesystem::path& outputDir);

    bool DecryptAssetFile(const std::filesystem::path& encryptedPath,
                          std::vector<uint8_t>& outData);

    bool EncryptAllInDirectory(const std::filesystem::path& inputDir,
                               const std::filesystem::path& outputDir);

    bool DecryptAllToOriginal(const std::filesystem::path& encryptedDir,
                              const std::filesystem::path& outputDir);
}
  

主な特徴

暗号処理の仕組み

XOR演算による単純な暗号化を採用し、バイナリ全体とファイル名の両方を保護します。 XOR_KEY を使用して全バイトを排他的論理和し、元データを難読化します。


// --- XORによる暗号・復号処理 ---
for (size_t i = 0; i < plaintext.size(); ++i)
{
    ciphertext[i] = plaintext[i] ^ XOR_KEY;
}
  

ファイル名も同様に1文字ずつXOR変換され、16進数表現へエンコードされます。 このため、アセットパス構造をそのまま読み取ることができません。

ディレクトリ単位の暗号化処理


// --- Assetsフォルダ全体を暗号化 ---
FlAssetProtector::EncryptAllInDirectory(
    "Assets/",
    "ProtectedAssets/"
);

// --- 復号化 ---
FlAssetProtector::DecryptAllToOriginal(
    "ProtectedAssets/",
    "DecryptedAssets/"
);
  

ファイル名暗号化の流れ

    OriginalName : "texture_diffuse.png"
               ▼ XOR + HEX
    EncryptedName : "A1B2C3D4E5F6..."
               ▼ 復号時
    DecryptedName : "texture_diffuse.png"
    

ストリーム経由での復号読み込み

暗号化されたファイルは、DecryptedInputStream を介して直接読み取ることも可能です。 内部で復号を行い、通常の std::istream として扱えます。


// --- 例: 復号ストリームの使用 ---
FlAssetProtector::DecryptedInputStream stream("ProtectedAssets/logo.enc");
if (stream.IsValid())
{
    std::string contents((std::istreambuf_iterator<char>(stream)),
                          std::istreambuf_iterator<char>());
}
  

技術的ポイント

FlAssetProtector は、 開発資産の セキュリティレイヤー を担うモジュールです。 アセットの無断流用やリバースエンジニアリングに対し、 軽量ながら確実な防御策を提供します。

DebugLogger – 外部ログ出力クラス

DebugLogger は、実行中のエンジンやエディタの状態を 外部ファイルへ出力するための デバッグログ管理クラス です。 各種エラー、アサート、または開発時の挙動確認を目的として設計されています。

概要

このクラスは指定したファイルに対してテキスト出力を行い、 ファイル名・行番号・メッセージを含む詳細なデバッグ情報を記録します。 デフォルト出力先は Assets/Data/Log/DebugLog.log です。

コード抜粋


// ログ出力用クラス
class DebugLogger
{
public:
    explicit DebugLogger(const std::string_view& filename = 
        "Assets/Data/Log/DebugLog.log")
    {
        m_logFile.open(filename, std::ios::out | std::ios::app);
        m_upFPM = std::make_unique<FlFilePathManager>();
        if (!m_logFile) _ASSERT_EXPR(false, L"ログファイルがありません");
    }

    void LogDebug(const std::string& message, const char* file, int line)
    {
        if (m_logFile.is_open())
        {
            auto refl = m_upFPM->GetRelative(file).generic_string();
            m_logFile << GetCurrentDateTime() << std::endl
                      << "[File: " << refl << "] "
                      << "[Line: " << line << "] "
                      << message << std::endl;
        }
    }
};

// 呼び出しマクロ
#define DEBUG_LOG(logger, message) logger->LogDebug(message, __FILE__, __LINE__)
    

利用例


auto logger = std::make_shared<DebugLogger>();

// ファイル書き込みログ
DEBUG_LOG(logger, "Initialize Renderer Success");

// 出力内容例:
// 2025-10-06 17:05:12.123456789
// [File: Source/Graphics/Renderer.cpp] [Line: 85] Initialize Renderer Success
    

特徴

Formula – 便利関数群

Formula 名前空間は、ゲームロジックやシミュレーションで頻出する 数学的・確率的処理を簡潔に記述するためのユーティリティ集です。 乱数生成、確率抽選、三角関数カーブ、距離計算などを統一的に提供します。

主な機能

コード抜粋


namespace Formula
{
    // ===== 基本乱数 =====
    template<typename T>
    decltype(auto) Rand(const T min, const T max) noexcept
    {
        std::random_device rd;
        std::mt19937 mt{ rd() };

        if constexpr (std::is_integral_v<T>)
            return std::uniform_int_distribution<T>{ min, max }(mt);
        else
            return std::uniform_real_distribution<T>{ min, max }(mt);
    }

    // ===== 重み付き抽選 =====
    const std::string Lottery(const std::unordered_map<std::string, double>& items) noexcept
    {
        std::vector<std::pair<std::string, double>> cdf;
        double cumulative = 0.0;
        for (auto& item : items)
        {
            cumulative += item.second;
            cdf.emplace_back(item.first, cumulative);
        }
        auto r = Rand(0.0, cumulative);
        auto it = std::lower_bound(cdf.begin(), cdf.end(), r,
            [](const auto& e, double val){ return e.second < val; });
        return it->first;
    }

    // ===== 三角カーブ =====
    inline auto SinCurve(float deg, double amp = 1.0, double freq = 1.0, double phase = 0.0) noexcept
    {
        const auto rad = DirectX::XMConvertToRadians(deg);
        return amp * std::sin(freq * rad + phase);
    }

    // ===== 距離計算 =====
    inline auto GetDistance(const Math::Vector3& a, const Math::Vector3& b) noexcept
    {
        return std::sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
    }
}
    

利用例


// 整数乱数
int n = Formula::Rand(0, 10);

// 浮動小数点乱数
float t = Formula::Rand(0.0f, 1.0f);

// 抽選(レアドロップ判定など)
std::unordered_map<std::string, double> table = {
  { "Common", 70.0 },
  { "Rare",   25.0 },
  { "Epic",    5.0 }
};
auto result = Formula::Lottery(table);

// サイン波によるゆらぎ
float offset = Formula::SinCurve(time * 60.0f, 5.0, 1.0);

// 座標間の距離
float dist = Formula::GetDistance(playerPos, targetPos);
    

特徴