knowledgeからインポート中

knowledgeはtomcatとかいう振られ気分でロックンロールなタフボーイが、指先一つでダウンする可能性があり、我が生涯に一変の悔い無しにはなりたくないため、こちらに無双転生しようとするが、一子相伝なのでどうなるかは、やってみないとサイバーブルーである。

チャプター作ってみる

チャプター作るとどうなるか確認用

チャプター作ってみる

初めての記事を書いてみるテスト

見出し

見出し1

見出し2

見出し3

見出し4

見出し5
見出し6

リスト

オーダードリスト

  1. ひとつひとよりちからもち
  2. 二つふるさと後にして
  3. はなのとうきょうでうでだめし
  4. みっつみらいのおおものだ
  5. 大ちゃんあっちょれ人気者
  6. てんてんてんかのいなか~ぺ

コード記述

using std::cout;
using std::cin;
using std::endl;
//2つの値を表示する関数
void printAB(double _a, double _b)
{
	cout << "(a, b) = (" << _a << ", " << _b << ")" << endl;
}
//2つの変数の値を入れ替える関数(交換できない(´;ω;`))
//changeAB(0.0, 128.7); _a <- 0.0 _b <- 128.7
void changeAB(double _a, double _b) //_a,_b 仮引数
{
	double tmp;
	tmp = _a; //tmpにaを保存 tmp:1.2 _a:1.2 _b:200.5
	_a = _b; //_aに_bを代入 tmp:1.2 _a:200.5 _b:200.5
	_b = tmp; //保存しておいた_aを_bに代入 tmp:1.2 _a:200.5 _b:1.2
	cout << "---ここは関数内です---" << endl;	
	printAB(_a, _b);
}//<-仮引数_a, _bの生存範囲

コード記述


using std::cout;
using std::cin;
using std::endl;
//2つの値を表示する関数
void printAB(double _a, double _b)
{
	cout << "(a, b) = (" << _a << ", " << _b << ")" << endl;
}
//2つの変数の値を入れ替える関数(交換できない(´;ω;`))
//changeAB(0.0, 128.7); _a <- 0.0 _b <- 128.7
void changeAB(double _a, double _b) //_a,_b 仮引数
{
	double tmp;
	tmp = _a; //tmpにaを保存 tmp:1.2  _a:1.2  _b:200.5
	_a = _b; //_aに_bを代入  tmp:1.2  _a:200.5  _b:200.5
	_b = tmp; //保存しておいた_aを_bに代入 tmp:1.2  _a:200.5  _b:1.2
	cout << "---ここは関数内です---" << endl;	
	printAB(_a, _b);
}//<-仮引数_a, _bの生存範囲

int main() {double A = 1.2;double B = 200.5;printAB(A, B); //交換前のA,Bを表示 A,B 実引数//printAB(1.2, 200.5); changeAB(A, B); //AとBを交換する関数printAB(A, B); //交換後のA,Bを表示std::swap(A, B);printAB(A, B); //交換後のA,Bを表示}

リンク Yz-learning

画像image-20240423084902635.pngimage-20240423084902635.png

image-20240423084945425.png 30%

画像サイズの変更(マークダウンからはできなさそう)

テーブル

Left alignRight alignCenter align
テスト1テスト2テスト3
123451234512345
abcdeabcdeabcde

[slide 5]

$$ math H(x)= \begin{cases} 1, \text{for $x 0$} \tag{1}\ 0, \text{for $x 0$} % \tag{2}をつけようとするとエラーが出る \end{cases} $$

$ A(x) = a_{0}+a_{1}x+a_{2}x^{2} $

新しいDx11base設計方針(今進んでいるところまで)



✅ 主要クラスの役割一覧

クラス名

役割

主な責務

他クラスとの関係

Dx11Base

DirectX初期化&基盤

デバイス・コンテキスト・スワップチェイン・バックバッファなどの管理

ビューポートやラスタライザ設定もここで一元化

全クラスが依存。最下層の基盤クラス

ShaderBucket

シェーダーの一括管理

.hlsl

を読み込んで、VS/PS/IL を生成・キャッシュ

キーでシェーダー切り替えを容易にする

ModelRenderer

Sprite

など描画系から利用される

Camera

カメラ情報の管理

ビュー行列・プロジェクション行列を提供

LookAtや移動処理も持つ

ModelRenderer

などが View/Proj を取得する

SimpleModel

モデルの純粋なデータ保持

頂点・インデックス・テクスチャ・サンプラ・名前など

必要なバッファを持ち描画準備済みの状態

ModelManager

から生成され、

ModelRenderer

に使われる

ModelManager

モデルの読み込み・キャッシュ

ファイルから

SimpleModel

を生成

ハンドル付きでモデルを管理・再利用

ModelRenderer

からハンドル経由で取得される

ModelRenderer

モデル描画の実行役

SimpleModel

+

Transform

情報を使って描画

内部で

Dx11Base

,

Camera

,

ShaderBucket

を使って描画する

SimpleModel

を渡されて描画処理を行う

Transform

(補助)

モデルの変換行列生成

SRTからWorld行列生成、法線変換行列も作成可

ModelRenderer

が使用


🎯 クラス関係図(概略)

┌────────────┐
│ Dx11Base   │ ← デバイスやレンダリングパイプラインの基盤
└────┬───────┘
     │
┌────▼───────┐          ┌──────────────┐
│ ShaderBucket│◄────────┤ ModelRenderer │
└────────────┘          └────┬─────────┘
                             │ uses
                       ┌─────▼────────┐
                       │ SimpleModel  │◄─────┐
                       └──────────────┘      │
                                             │
                          ┌────────────┐     │
                          │ ModelManager│────┘
                          └────────────┘

┌────────┐
│ Camera │ ← View/Proj取得用
└────────┘

🧠 役割分離の利点

設計

メリット

SimpleModel

に描画コードを持たせない

同じモデルを複数箇所で描画可能(インスタンス化)

ModelRenderer

に描画処理を集中

ステート設定、シェーダー設定、描画の変更が一元管理できる

ModelManager

に読み込みとキャッシュを集中

同じファイルを何度も読み込む無駄を防止

ShaderBucket

のキー管理

"Basic3D"

"Sprite"

"ShadowMap"

など切り替えが簡単

Dx11Base

に初期化・基盤処理を集中

DirectX設定の複雑さを隠蔽し、他クラスをシンプルに保てる


🔚 まとめ

このような分離設計は、
単体テストや差し替えがしやすく、
✅ **描画方式の拡張(PBR、影、インスタンス描画など)**にも柔軟に対応できます。

必要であれば、ModelRenderer::Draw()ModelManager::GetHandle() など、具象的なコード実装例も提供できます。


モデル関係責任分割

クラス

責任

SimpleModel

データ所有者

:頂点・インデックス・テクスチャ等のDirectXリソース保持。

※レンダリングコードは持たない

ModelRenderer

描画担当

SimpleModel

のデータを使って描画処理を実行。Transformやシェーダーとの連携もここで処理

ModelManager

管理担当

SimpleModel

をファイルからロードし、キャッシュとして保持。ハンドル管理なども行う


今迷っているところ


6月17日現在の様子

🎯 DirectX11 モデル描画エンジン:構造と設計レビュー

🎯 DirectX11 モデル描画エンジン クラス構成概要

┌────────────┐
│ Dx11Base   │ ← デバイスやレンダリングパイプラインの基盤
└────┬───────┘
     │
┌────▼───────┐          ┌──────────────┐
│ ShaderBucket│◄────────┤ ModelRenderer │
└────────────┘          └────┬─────────┘
                             │ uses
                       ┌─────▼────────┐
                       │ SimpleModel  │◄─────┐
                       └──────────────┘      │
                                             │
                          ┌────────────┐     │
                          │ ModelManager│────┘
                          └────────────┘

┌────────┐
│ Camera │ ← View/Proj取得用
└────────┘

✅ メリット

1. 役割分離された設計

2. マテリアル単位の柔軟な管理

3. シェーダーステート集中管理

4. リソース共有対応

5. アニメーション拡張の布石あり

class_diagram_structured.png


⚠️ デメリット・今後の課題

1. スキンアニメーション未対応

2. 階層構造の保持なし

3. インスタンシング未対応

4. 描画順制御がアプリ依存

5. グローバル依存の可能性


🔄 改善ロードマップ

ステージ改善内容

✅ 現在

非アニメモデル・マテリアル描画まで実装済み

🔜 次

Bone構造・スキンウェイト・アニメーションクリップ導入

🔜 拡張

GPUスキニング、Shaderの構造整理、AnimationClip管理クラスの追加

🔜 拡張

Zソート処理、半透明オブジェクトの描画順制御の導入

🔜 拡張

階層Transform・ノードアニメーションの導入、カメラアニメ対応




おま環とは

おま環」とは、ネットスラングで「お前の環境が原因」の略です。
主に以下のような状況で使われます:


🧩 意味

「他の人では再現しない問題が、特定のユーザーの環境だけで起きている」

ということを指す言葉です。


🧠 具体例

という具合です。
つまり「PC設定や環境(OS・フォント・IME・拡張機能など)の問題かもよ?」という含みを持っています。

メモ

🎮 前提条件(仕様)



🔍 判定に使うブロック範囲(図)

プレイヤーの足元 py として、
進行方向の dx, dz を使って座標 (px+dx, py, pz+dz) などを調べます。

上から見た進行方向(Z奥に進む場合)
     ↑ 進行方向
     z
     |
     |
[x][y+2][z+1] ← ジャンプ時の頭上クリアチェック
[x][y+1][z+1] ← 頭位置
[x][y  ][z+1] ← 足元 or 障害物

[x][y+1][z]   ← 現在地(頭)
[x][y  ][z]   ← 現在地(足)


✅ 判定ロジックまとめ(擬似コード)

bool CanMoveForward(int px, int py, int pz, int dx, int dz) {
    int tx = px + dx;
    int tz = pz + dz;

    // ケース①:目の前が空いていて、2ブロック分スペースがある
    if (isAir(tx, py, tz) && isAir(tx, py + 1, tz)) {
        return true; // そのまま前進
    }

    // ケース②:1段段差があるけど、ジャンプで登れる
    if (!isAir(tx, py, tz) && isAir(tx, py + 1, tz) && isAir(tx, py + 2, tz)) {
        return true; // ジャンプで前進可能
    }

    // その他:ぶつかる or 高すぎる
    return false;
}


🧱 判定図(側面図)

ケース①:そのまま進める

       空気
    [ ][y+1][ ]
    [ ][ y ][ ] ← 前方2ブロックが空なので通れる
    ↑↑↑
  頭 胴 足

ケース②:1段ジャンプ可能

    [ ][y+2][ ] ← 空気(ジャンプ後の頭)
    [x][y+1][ ] ← 空気(ジャンプ後の胴体)
    [x][ y ][ ] ← ブロック(ジャンプ対象)

ケース③:進めない(壁 or 高すぎ)

    [x][y+2][x]
    [x][y+1][x] ← どこかが詰まってるのでNG
    [x][ y ][x]


🛠 isAirとは?

bool isAir(int x, int y, int z) {
    return world[x][y][z] == BLOCK_AIR;
}


✅ メリット

🎮 状態のしくみ:プレイヤーの「行動モード」を理解しよう!


🎲 プレイヤーの3つの状態

  1. 歩いてる(=普通に移動)
  2. ジャンプ中(=1段上へピョン!)
  3. 落下中(=足元が空で落ちてる)

🔁 状態の流れ(図っぽく)

↑
      ジャンプ ←────────
        ↑               │
        │               │
   落下中に終点到達   落下する条件
        ↑               │
        │               ↓
[歩いてる] ──→ [落下中] ──→ [落下中継続]
        ↑                     │
        └──── ジャンプできる? ───┘

🧠 状態の切り替え条件(とってもやさしく!)


🚶‍♂️ 歩く状態(isWalking)

● いつこの状態になる?

● 何をする?


🦘 ジャンプ状態(isJumping)

● いつこの状態になる?

● 何をする?


🕳️ 落下状態(isFalling)

● いつこの状態になる?

● 何をする?


🧩 状態フラグで管理(プログラム上)

フラグ

true の意味

false の意味

isWalking

歩いてる最中

止まってる

isJumping

ジャンプ中

ジャンプしてない

isFalling

空中で落ちてる

地面に立ってる


🧪 状態チェックは毎フレーム行う!

ゲームの Update() 関数の中で、毎フレームこういうチェックをしてます:

if (!isFalling) {
    PlayerInput();    // 入力を見て
    PlayerMovement(); // 動かす
} else {
    PlayerFallDown(); // 落下処理
}

📝 イメージでまとめると…

状態

条件

行動

歩く

前が空いてる

スーッと1マス進む

ジャンプ

前にブロック、その上が空

ピョンと1段上に乗る

落下

足元が空(またはジャンプ後)

スーッと1段ずつ下がる


✅ ポイントまとめ


Windowsプログラミングの初めの一歩手前の穴

メッセージループとコールバックとWinProc

🎮 たとえるなら…

ゲームセンターの受付とスタッフの関係!


🌀「メッセージループ」は、ゲームセンターの受付のお兄さん


// ゲームセンター受付のお兄さん(これがメッセージループ)
while (お客さんが来たら) {
    お客さんの内容を読む(TranslateMessage)
    担当スタッフに渡す(DispatchMessage)
}

🧑‍🔧「WndProc(ウィンドウプロシージャ)」は、ゲーム機のスタッフ


// ゲーム機のスタッフ(WndProc)
switch (お客さんの用事) {
    case 「遊びたい」:
        → スタートボタン押す
    case 「壊れてる」:
        → 修理する
    case 「帰る」:
        → ゲーム終了
    default:
        → 本社(OS)に任せる
}

🔁 2人の連携で成り立ってる!

誰?

役割

メッセージループ(受付)

お客さん(イベント)を拾ってスタッフに渡す

WndProc(スタッフ)

イベントに合わせて処理する(絵を描く・音を出す・終了する)


🎨 具体例(「絵を描いて!」って言われたら?)

  1. Windows(OS)が「このウィンドウ、描き直してね!」って言う(WM_PAINTというイベントが届く)
  2. メッセージループがそれを受け取って、WndProcに渡す
  3. WndProcが「よし、描き直そう」と絵を描く処理をする

📌 まとめ

現象

例え

プログラム上では

イベントが届く

お客さんが来る

Windows がメッセージを出す

メッセージループ

受付のお兄さん

GetMessage → DispatchMessage

WndProc

スタッフ

イベントに応じた処理をする関数


つまり、「メッセージループ」が お知らせを渡す人
「WndProc」が 実際に処理をする人 です!



🧠 まず「コールバック」とは?

✅ 意味:

自分で作った関数だけど、あとで誰か(=OSやライブラリ)が呼んでくれる関数のことです。


🎮 たとえるなら…「イベント係に任せる自作の処理」

たとえば、学校でイベントをやるとして…

これが コールバック です。


🪟 WndProc とは何か?

✅ 意味:

WndProc は、**「ウィンドウに届いたメッセージをどう処理するかを書く関数」**です。

例えば、

などを処理する関数です。


💡 WndProcは「OSに登録するコールバック関数」

あなたは最初にこう書きます:


wc.lpfnWndProc = MyWindowProc;

これは、

「このウィンドウの処理は MyWindowProc() という関数を使ってね!

OSに登録してるということです。


📞 呼び出しの流れ(コールバックの仕組み)

  1. ユーザーが何か操作する(例:ウィンドウを閉じる)
  2. OSが「メッセージ」を作って、プログラムに送る
  3. プログラムの「メッセージループ」がそのメッセージを受け取る
  4. 登録された WndProc関数(コールバック) が呼ばれる!

🎨 たとえ話まとめ:先生と出席係

役割

たとえ

実際の名前

イベントが起きる

生徒が手をあげる

OSがメッセージを送る

受付が確認

出席係が生徒を見つける

メッセージループ

処理担当が動く

先生がその子に対応する

WndProc()

呼ばれる仕組み

担任を事前に登録しておいた

コールバック関数


✅ 結論まとめ(超ざっくり)

用語

やさしい意味

コールバック関数

OSに「この関数をあとで呼んでね」と渡しておく関数

WndProc

ウィンドウの出来事を処理するコールバック関数

lpfnWndProc

「WndProcはこれだよ」とOSに登録するための場所

呼び出し

イベントが起きたらOSが自動で呼んでくれる(=コールバック)

改良案

===== 🎯 Character 分割 実行順おすすめ(3コミットで見栄えが出る) =====

目標: 1ファイル1000行超の Character.cpp を段階的に分割し、責務を明確化。
Visual Studio プロジェクト(CMake 不使用)で、見た目を変えずにコードの「整理力」「設計力」をアピールできる構成にします。


🧩 Character(変更後)

Character::Draw() → CharacterModelBlink::Draw()
Character::Update() → CharacterVfx::Update()

📈 効果:視覚表現が明確に分離。300行以上軽量化。


🥈 コミット2:Shadow / Air / Forward 抽出

🧩 Character(変更後)

Update() → shadow.tick() → air.tick() → forward.tick()
Draw() → shadow.draw()

📈 効果:ランタイムの共通処理が整理され、Facade 化が進行。


🥉 コミット3:Movement / Rotate / Charge / Hit / Fence / Csv / Observer の順次抽出

🧩 Character(変更後)

Update() → movement.tick() → rotate.tick() → charge.tick() → hit.tick() → fence.tick()

📈 効果:Player / Enemy 側の共通処理が削ぎ落とされ、状態遷移と入力処理に集中できる。


📦 ファイル移行マップ(Visual Studio での構成)

.cpp を Visual Studio の「ソースファイル」フォルダに新規作成し、既存関数を下表のファイルに移動します。

移行元(Character.cpp内の関数)

移行先(新ファイル)

DrawCharacterModel

CharacterModelBlink.cpp / .h

DrawCharacterImGui

CharacterDebugPanel.cpp / .h

InitShadow / ShadowSet / ShadowDraw

CharacterShadow.cpp / .h

CharacterGravity / SetJump

CharacterAir.cpp / .h

RotateVecFront / FrontVectorConfirm

CharacterForward.cpp / .h

CharacterMove / CreateMoveVector / MoveConfirm / IsOutsideStage / 減速系関数群

CharacterMovement.cpp / .h

RotateDirectionVector / MoveRotateX / FastRotateX / RotateXStop

CharacterRotate.cpp / .h

Charging / ChargeRelease / ChargeReset / SetArrow / DrawArrow

CharacterCharge.cpp / .h

Reflect / KnockBack / InvincibilityTimeCalculation / etc.

CharacterHit.cpp / .h

GetWireNormal / FenceReflect / NotifyFenceHit

CharacterFence.cpp / .h

SetCSVStatus

CharacterCsvLoader.cpp / .h

AddObserver / RemoveObserver

CharacterObserver.cpp / .h

💾 補足


🧱 仕上げ(README / BookStack反映時)

🧩 Before / After の依存図

Before: Character.cpp(1000行超)
 ├─ 表示(VFX/点滅/影)
 ├─ 挙動(移動/回転/ジャンプ/チャージ)
 ├─ 当たり(被弾/ノックバック/柵反射)
 ├─ データ(CSV読み込み)
 └─ 管理(Observer/ImGui)

After: Character Facade + 8モジュール
 ├─ CharacterVfx
 ├─ CharacterModelBlink
 ├─ CharacterShadow
 ├─ CharacterAir
 ├─ CharacterMovement / Rotate / Charge
 ├─ CharacterHit / Fence
 ├─ CharacterCsvLoader
 └─ CharacterObserver

🗂️ 責務表

モジュール

主な役割

代表関数

CharacterVfx

VFX 発火・制御

SetHitEffect() 他

CharacterModelBlink

無敵中点滅描画

Draw()

CharacterShadow

影生成・描画

InitShadow(), ShadowDraw()

CharacterAir

重力・ジャンプ

CharacterGravity(), SetJump()

CharacterMovement

地上移動・減速処理

CharacterMove(), MoveConfirm()

CharacterRotate

回転ユーティリティ

RotateDirectionVector() 他

CharacterCharge

チャージ・矢印描画

Charging(), ChargeRelease()

CharacterHit

被弾・ノックバック

Reflect(), KnockBack()

CharacterFence

柵反射処理

GetWireNormal(), FenceReflect()

CharacterCsvLoader

パラメータ読込

SetCSVStatus()

CharacterObserver

監視者管理

AddObserver(), RemoveObserver()

🧱 動作不変性の説明

🤖 将来拡張例


💡 TIP:


仕上げ(READMEに載せると採点が伸びる)

📄 新規 .h / .cpp 最小テンプレート一式(Visual Studio 追加用)

そのまま貼り付けて新規ファイルとして保存できます。必要に応じて型名(Transform/Vec3 など)を既存プロジェクトのものに合わせてください。

例)保存先:Game/Actors/Character/ 配下


CharacterParams.h

#pragma once
// 既存の型に合わせて置換してください
struct Vec3 { float x{}, y{}, z{}; };

struct InitializeParam { /* TODO: 初期姿勢/速度など */ };
struct MoveParam       { float maxSpeed{6.0f}; float accel{40.0f}; float decel{50.0f}; };
struct RotateParam     { float yawSpeed{360.0f}; float pitchSpeed{0.0f}; };
struct JumpParam       { float power{8.5f}; float coyoteTime{0.08f}; float bufferTime{0.12f}; };
struct HitParam        { float iFrames{0.25f}; float knockback{6.0f}; };
struct FenceHitParam   { float reflectScale{1.0f}; float cooldown{0.15f}; };
struct ShadowParam     { float size{1.0f}; float offsetY{0.05f}; };

CharacterModelBlink.h

#pragma once
struct Transform; // 前方宣言(既存のTransform型に合わせてください)
class CharacterModelBlink {
public:
  void Draw(int modelHandle, const Transform& t) const; // 無敵点滅込みの描画
};

CharacterModelBlink.cpp

#include "CharacterModelBlink.h"
// #include 必要に応じて: マテリアル/タイマー/無敵状態参照 など

void CharacterModelBlink::Draw(int modelHandle, const Transform& t) const {
  // TODO: 旧 DrawCharacterModel() の中身を移設
  (void)modelHandle; (void)t;
}

CharacterVfx.h

#pragma once
class CharacterVfx {
public:
  void InitFromCsv(const char* path);
  void SetChargingEffect();
  void SetFullChargeEffect();
  void SetAttackLocusEffect();
  void SetHitEffect();
  void SetFenceHitEffect();
  void Tick(float dt);
};

CharacterVfx.cpp

#include "CharacterVfx.h"
void CharacterVfx::InitFromCsv(const char* ){}
void CharacterVfx::SetChargingEffect(){}
void CharacterVfx::SetFullChargeEffect(){}
void CharacterVfx::SetAttackLocusEffect(){}
void CharacterVfx::SetHitEffect(){}
void CharacterVfx::SetFenceHitEffect(){}
void CharacterVfx::Tick(float){ }

CharacterShadow.h

#pragma once
struct Transform;
class CharacterShadow {
public:
  void Init();
  void Tick(const Transform& t);
  void Draw() const;
};

CharacterShadow.cpp

#include "CharacterShadow.h"
void CharacterShadow::Init(){}
void CharacterShadow::Tick(const Transform&){ }
void CharacterShadow::Draw() const { }

CharacterAir.h

#pragma once
class CharacterAir {
public:
  void TickGravity(float dt);
  void RequestJump();
  bool IsJumpBuffered() const { return false; }
};

CharacterAir.cpp

#include "CharacterAir.h"
void CharacterAir::TickGravity(float){ }
void CharacterAir::RequestJump(){ }

CharacterForward.h

#pragma once
struct Vec3; struct Transform;
class CharacterForward {
public:
  void Tick(const Transform& t);
  const Vec3& Front() const { return front_; }
private:
  Vec3 front_{}; // 右手系/左手系は既存に合わせる
};

CharacterForward.cpp

#include "CharacterForward.h"
void CharacterForward::Tick(const Transform&){ /* TODO: 回転→前方更新 */ }

CharacterMovement.h

#pragma once
struct Vec3; struct Transform; struct MoveParam;
class CharacterMovement {
public:
  void Tick(float dt, const MoveParam& prm, Transform& t);
  void MoveConfirm(Transform& t);
  bool IsOutsideStage(const Transform& t) const; // 必要ならステージ参照を注入
  // 減速/加速系
  static void Deceleration(float& v, float amount, float dt);
  static void FrictionDeceleration(float& v, float amount, float dt);
  static void AccelerationStop(float& v, float threshold);
  static bool IsDashStop(float v, float threshold);
};

CharacterMovement.cpp

#include "CharacterMovement.h"
void CharacterMovement::Tick(float, const MoveParam&, Transform&){ }
void CharacterMovement::MoveConfirm(Transform&){ }
bool CharacterMovement::IsOutsideStage(const Transform&) const { return false; }
void CharacterMovement::Deceleration(float& v, float a, float dt){ v -= a*dt; }
void CharacterMovement::FrictionDeceleration(float& v, float a, float dt){ v -= a*dt; }
void CharacterMovement::AccelerationStop(float& v, float th){ if(fabsf(v)<th) v=0.0f; }
bool CharacterMovement::IsDashStop(float v, float th){ return fabsf(v)<=th; }

CharacterRotate.h

#pragma once
struct Transform; struct RotateParam;
class CharacterRotate {
public:
  void Tick(float dt, const RotateParam& prm, Transform& t);
  void RotateDirectionVector(Transform& t);
  void MoveRotateX(Transform& t);
  void MoveRotateXReverse(Transform& t);
  void FastRotateX(Transform& t);
  void FastRotateXReverse(Transform& t);
  void RotateXStop(Transform& t);
};

CharacterRotate.cpp

#include "CharacterRotate.h"
void CharacterRotate::Tick(float, const RotateParam&, Transform&){ }
void CharacterRotate::RotateDirectionVector(Transform&){ }
void CharacterRotate::MoveRotateX(Transform&){ }
void CharacterRotate::MoveRotateXReverse(Transform&){ }
void CharacterRotate::FastRotateX(Transform&){ }
void CharacterRotate::FastRotateXReverse(Transform&){ }
void CharacterRotate::RotateXStop(Transform&){ }

CharacterCharge.h

#pragma once
struct Transform;
class CharacterCharge {
public:
  void Charging(float dt);
  void ChargeRelease();
  void ChargeReset();
  void SetArrow();
  void DrawArrow(const Transform& t) const;
};

CharacterCharge.cpp

#include "CharacterCharge.h"
void CharacterCharge::Charging(float){ }
void CharacterCharge::ChargeRelease(){ }
void CharacterCharge::ChargeReset(){ }
void CharacterCharge::SetArrow(){ }
void CharacterCharge::DrawArrow(const Transform&) const { }

CharacterHit.h

#pragma once
struct Transform; struct HitParam;
class CharacterHit {
public:
  void Reflect(const Transform& hitNormal);
  void KnockBack(float power);
  bool IsKnockBackEnd() const { return true; }
  void KnockBackVelocityReset();
  void InvincibilityTimeCalculation(float dt, const HitParam& prm);
};

CharacterHit.cpp

#include "CharacterHit.h"
void CharacterHit::Reflect(const Transform&){ }
void CharacterHit::KnockBack(float){ }
void CharacterHit::KnockBackVelocityReset(){ }
void CharacterHit::InvincibilityTimeCalculation(float, const HitParam&){ }

CharacterFence.h

#pragma once
struct Transform; struct FenceHitParam;
class CharacterFence {
public:
  void GetWireNormal(/* args: 環境からの法線取得に必要な情報 */);
  void FenceReflect(const FenceHitParam& prm);
  void NotifyFenceHit();
};

CharacterFence.cpp

#include "CharacterFence.h"
void CharacterFence::GetWireNormal(){ }
void CharacterFence::FenceReflect(const FenceHitParam&){ }
void CharacterFence::NotifyFenceHit(){ }

CharacterCsvLoader.h

#pragma once
#include "CharacterParams.h"
class CharacterCsvLoader {
public:
  bool Load(const char* csvPath, InitializeParam& init, MoveParam& move,
            RotateParam& rot, JumpParam& jump, HitParam& hit,
            FenceHitParam& fence, ShadowParam& shadow);
};

CharacterCsvLoader.cpp

#include "CharacterCsvLoader.h"
bool CharacterCsvLoader::Load(const char*, InitializeParam&, MoveParam&, RotateParam&, JumpParam&, HitParam&, FenceHitParam&, ShadowParam&){
  // TODO: 旧 SetCSVStatus() を分解して移設
  return true;
}

CharacterObserver.h

#pragma once
#include <vector>
class ICharacterObserver { public: virtual ~ICharacterObserver() = default; /* OnHit/OnDie など */ };
class CharacterObserver {
public:
  void AddObserver(ICharacterObserver* o);
  void RemoveObserver(ICharacterObserver* o);
private:
  std::vector<ICharacterObserver*> obs_;
};

CharacterObserver.cpp

#include "CharacterObserver.h"
#include <algorithm>
void CharacterObserver::AddObserver(ICharacterObserver* o){ obs_.push_back(o); }
void CharacterObserver::RemoveObserver(ICharacterObserver* o){
  obs_.erase(std::remove(obs_.begin(), obs_.end(), o), obs_.end());
}

CharacterAssets.h

#pragma once
class CharacterAssets {
public:
  void Init();             // SE / モデル / マテリアルのロード
  int  ArrowModel() const { return arrowModel_; }
private:
  int arrowModel_ = -1;    // 例:DxLib/自作Engineのハンドル
};

CharacterAssets.cpp

#include "CharacterAssets.h"
void CharacterAssets::Init(){ /* TODO: 旧 InitArrow()/SEロード等を移設 */ }

必要なら 各クラス間の依存を注入する小さな Facade(Character 本体) の見本も追加できます。既存 Character.h/.cpp にメンバとしてこれらを持ち、Update/Draw で順に呼ぶだけの薄い制御層にしてください。


🧰 Facade 見本:Character 本体(依存注入・薄い制御層)

既存のエンジンフック(Init/Update/FixedUpdate/Render/OnCollision 等)を想定。
依存は コンストラクタ注入 or Setter 注入で受け取り、各モジュールへ渡します。

Character.h(Facade)

#pragma once
#include <memory>
#include <string>
#include "CharacterParams.h"
#include "CharacterModelBlink.h"
#include "CharacterVfx.h"
#include "CharacterShadow.h"
#include "CharacterAir.h"
#include "CharacterForward.h"
#include "CharacterMovement.h"
#include "CharacterRotate.h"
#include "CharacterCharge.h"
#include "CharacterHit.h"
#include "CharacterFence.h"
#include "CharacterCsvLoader.h"
#include "CharacterObserver.h"

// ---- Engine 側(前方宣言にして依存を最小化) ----
struct Transform;            // 既存の Transform 型
class IPhysics;              // レイ/衝突問合せ(エンジン提供)
class IStageQuery;           // 地形/柵/足場の問合せ
class IAudio;                // SE 再生命令
class ITime;                 // deltaTime 提供(必要なら)

class Character /* : public GameObject 等 */ {
public:
  struct Deps { IPhysics* physics{}; IStageQuery* stage{}; IAudio* audio{}; ITime* time{}; };

  explicit Character(const Deps& deps);
  ~Character();

  // --- ライフサイクル(エンジンのフックから呼ばれる想定) ---
  bool Init(const char* csvPath);              // パラメータ読み込み + アセット初期化
  void Update();                               // 1フレーム更新(順序制御のみ)
  void FixedUpdate(float fixedDt);             // 物理刻みが分かれている場合に使用
  void Render() const;                         // 影 + モデル点滅描画など

  // --- 衝突・イベント ---
  void OnCollision(/* Engine の接触情報を薄く受ける */);
  void OnFenceHit();
  void OnTakeDamage(int dmg);                  // 被弾イベント入口

  // --- 状態アクセス(UI 等から参照) ---
  const Transform& GetTransform() const { return *transform_; }
  int HP() const { return hp_; }

  // --- Optional: Setter 注入(コンストラクタ後に差し替えたい依存がある場合) ---
  void SetDeps(const Deps& d) { deps_ = d; }

private:
  // ---- 依存/データ ----
  Deps deps_{};
  Transform* transform_{};      // 位置/回転/スケール:エンジン所有を生ポインタで参照(または保持)

  InitializeParam init_{}; MoveParam move_{}; RotateParam rot_{}; JumpParam jump_{};
  HitParam hitp_{}; FenceHitParam fencep_{}; ShadowParam shadowp_{};
  int hp_{100};

  // ---- モジュール(Composition) ----
  CharacterModelBlink blink_;
  CharacterVfx        vfx_;
  CharacterShadow     shadow_;
  CharacterAir        air_;
  CharacterForward    forward_;
  CharacterMovement   movement_;
  CharacterRotate     rotate_;
  CharacterCharge     charge_;
  CharacterHit        hit_;
  CharacterFence      fence_;
  CharacterCsvLoader  csv_;
  CharacterObserver   observer_;

  // ---- 内部ユーティリティ ----
  void TickRuntime_();
  void DrawModel_() const;
};

Character.cpp(Facade)

#include "Character.h"
// 最小限の Engine ヘッダのみを include(Physics/Stage/Audio/Time/Transform 等)

Character::Character(const Deps& deps) : deps_(deps) {}
Character::~Character() = default;

bool Character::Init(const char* csvPath) {
  // 1) CSV/データローディング
  if (!csv_.Load(csvPath, init_, move_, rot_, jump_, hitp_, fencep_, shadowp_)) {
    return false;
  }

  // 2) Transform はエンジンから取得(生成/アタッチ方法は既存に合わせる)
  // transform_ = Engine::CreateTransform(init_.pos, init_.rot, ...);

  // 3) アセット/VFX/影などの初期化
  shadow_.Init();
  vfx_.InitFromCsv(csvPath); // 必要に応じて別CSV
  // Audio 初期化が必要なら deps_.audio を使う

  return true;
}

void Character::Update() {
  // 依存の取得(必要なら):float dt = deps_.time ? deps_.time->Delta() : 1.0f/60.0f;
  TickRuntime_();
}

void Character::FixedUpdate(float fixedDt) {
  // 物理刻みが別のときに Movement/Hit などの一部をここで進める設計も可
  (void)fixedDt;
}

void Character::Render() const {
  // 影→モデル点滅描画の順
  if (transform_) {
    shadow_.Draw();
    DrawModel_();
  }
}

void Character::OnCollision() {
  // エンジンの接触情報から法線・相手属性などを得て、Hit/Fence へ振り分け
  // 例:fence_.FenceReflect(fencep_);  hit_.InvincibilityTimeCalculation(dt, hitp_);
}

void Character::OnFenceHit() {
  fence_.FenceReflect(fencep_);
  vfx_.SetFenceHitEffect();
}

void Character::OnTakeDamage(int dmg) {
  (void)dmg; // 必要なら HP 減算・ノックバック決定
  hit_.KnockBack(hitp_.knockback);
  vfx_.SetHitEffect();
}

void Character::TickRuntime_() {
  // ※ 呼び順は従来どおりに維持(動作不変性の鍵)
  // shadow → air → forward → movement → rotate → charge → hit → fence → vfx
  if (!transform_) return;

  // 例: air_ は重力/ジャンプの内部タイマを進行
  air_.TickGravity(/*dt*/ 0.016f);

  forward_.Tick(*transform_);
  movement_.Tick(/*dt*/ 0.016f, move_, *transform_);
  rotate_.Tick(/*dt*/ 0.016f, rot_, *transform_);
  charge_.Charging(/*dt*/ 0.016f);
  hit_.InvincibilityTimeCalculation(/*dt*/ 0.016f, hitp_);
  vfx_.Tick(/*dt*/ 0.016f);

  // 影の位置更新:必要なら Transform を渡す
  shadow_.Tick(*transform_);
}

void Character::DrawModel_() const {
  // モデルハンドルなどは Engine/Assets 管理の取得方式に合わせる
  const int modelHandle = /* Engine::GetModelHandle(...) */ 0;
  blink_.Draw(modelHandle, *transform_);
}

使い方(例)

Character::Deps deps{ physicsSys, stageQuery, audioSys, timeSys };
Character player(deps);
player.Init("Data/Character.csv");
// game loop:
player.Update();
player.Render();

ポイント


あたおかSPI

1. “物流・流通経路図”というものの性質

SPI(適性検査)の非言語分野で出る “物流(物の流れと比率)” の図は、典型的にはこういう構造です:

こういう図は、「フローチャート」や「流れ図 (flow diagram)」「流通チャネル図」「矢印付きの有向ネットワーク図」などの親戚にあたる手法です。
数学的にはグラフ(頂点 + 辺)で表現できますが、図の主眼は 比率と流量の算定を視覚的に補助するための記号的な補助図法 で、グラフ理論そのもの(最短経路、巡回、連結性、次数などを主対象とする理論)とは目的も手法も異なります。

この種の図はおそらく教育・試験・参考書の便宜上、編集者・著者が工夫して使い始めたものと考えられ、特定の学者や発明者がいる、という情報は公開には残っていないようです。


2. 類似する図示法・理論的背景

以下の図示法・理論が、SPI の物流図と近縁性を持つ可能性があります:

種類

説明

関連性 / 差異

信号流 (Signal-flow graph)

主に制御工学・システム理論で、変数間の線形関係を矢印付きのグラフで表す手法。Mason の “signal-flow graph” が有名。

ウィキペディア

流れ(信号・量)を伝播させる表現という意味で近いが、SPI の物流図は比率を定める算式中心で、システムの動的性は含まれない点で目的が異なる。

流量ネットワーク / フローグラフ (flow network graphs)

ネットワークフロー理論(最大流、最小カットなど)で使われる。容量付きの有向辺を使って、ある源から別のシンクへ流れる最大流量を考える。

構造的には類似するが、SPI 図は「比率」>「容量最大化」といった最適化主題ではない。

有向グラフ (directed graphs)

頂点と向き付き辺を持つグラフ。一般グラフ理論の基本構造。

コーネル大学コンピュータサイエンス学部+1

SPI 図は有向グラフの一種と見なせる。ただし通常のグラフ理論では重み、最短路、探索アルゴリズム等を扱うが、SPI 図は “比率を合成して最終流量を求める” という線形代数的処理が主。

フローチャート / 流れ図 (flowchart, flow diagram)

手順や工程・物の流れを可視化する図。業務プロセス、物流プロセス、化学プロセスなどで広く使われる。

SPI 図はこれを借用した “分岐・合流” 図を比率付きで表したものとみなせる。

有向重み付きネットワーク (weighted directed network)

辺に重み(この場合比率)を持ち、有向性を持つネットワーク。グラフ理論・ネットワーク科学で広く扱われる

構造的にはこれと一致するが、SPI の使用場面(試験問題)として簡略化されたもの。


3. 「誰が考えた」の問いに対する考察


もしよければ、私が日本の受験・入試数学/就活適性検査分野で使われているこの種の図の初出例を探してみましょうか?それで “発展の系譜” を推定できるかもしれません。やりましょうか?

あなた:

このように、一般の学問の領域から外れた図を、あたかもデファクトスタンダードであるかのように使うことの危険性はないのでしょうか?

ChatGPT:

とても重要な視点です。
結論からいえば――危険性はあります。しかも二重の意味で。


1. 学問的危険性:論理体系の断絶

SPI の「流通経路図」のような図は、
あくまで“解法を早く視覚化するための便宜的記号”にすぎません。
しかしそれが体系的な理論(例えばネットワークフロー理論や確率過程)と無関係なまま独立して定着してしまうと、次のような問題が起こります。

問題

説明

概念の混乱

「比率を掛ける」と「流量を保存する」など、数学的には異なる操作が同じ線や矢印で表され、論理的整合性が曖昧になる。

誤学習の固定化

「こういう図を書けば正解になる」という作業手順が目的化し、背後の数量関係(保存則、分配則、条件付き確率など)への理解が育たない。

他分野への転用不能

同じ“流れ”でも、経済学・情報学・物理学では定義や制約条件が違うため、SPI式の図はそのまま応用できない。

つまり――論理的支柱を持たない「見た目の定番」は、体系的理解の発芽を阻む温床になります。


2. 教育的危険性:思考の形式化・再現性の欠如

教育的にも、「図を見ればなんとなく分かる」ことは短期的な便益を生みますが、
それが共通言語としての再現性を欠くと、長期的には以下のような歪みが生じます。

このような「属人的な図解のデファクト化」は、
学問的基盤の劣化教育のローカル化を招きやすいです。


3. なぜ定着したのか(社会的側面)

SPIや就職適性試験の世界では、

教育現場や出版社側から見れば、それは“合理化”ですが、
理論側から見れば“体系の断裂”です。


4. 対応策:どう扱うべきか

  1. 「実用記号」として限定的に教える
     →「この図は便利な“計算補助ツール”であり、理論的厳密性は保証しない」と明示する。
  2. 理論的対応物を紹介する
     → 例:「この図は、数学的には“フローネットワーク”に対応している」と補足。
  3. 記号体系を統一・定義する
     → 教材内で“矢印=比率を掛ける”“ノード=流量の保存点”などと明文化。
  4. 学問的翻訳を促す訓練
     → “この図を線形方程式系で表せ”など、理論側に戻す練習を行う。

🔍まとめ

一般の学問の領域から外れた図を、デファクトのように使うことは、
理解の効率を上げる短期的利点と、
理論的基盤を損なう長期的リスクの両方を伴います。

便利な道具であることを否定する必要はありませんが、
**“これは数学ではなく表記上の便法だ”**という一線を明示し、
学問体系との橋渡しを行うことが、教育者・編集者側の責任と言えるでしょう。

たとえ話にしてみたよ

むかしむかし——。

世界の根底には、グラフ理論という神の法則がありました。
神は頂点と辺を創り、すべての流れを数理的に支配しました。
流れは保存され、道は有向に、重みには意味がありました。
それは完全な秩序であり、どの頂点も無駄なく因果で結ばれていました。

やがてその世界に、人間が生まれました。
人間は神の創った法則を見上げながら、
「なんて複雑なんだ、これでは試験で時間が足りない」と嘆きました。

そこで人間は、自分たちの理解のために
“模造の世界”——すなわち SPIの流通図——を描きました。
そこでは流れは単純な比率で示され、
矢印はただの「かけ算の道具」として並べられました。
保存も、最短経路も、次数も存在しない。
けれど、彼らにとっては便利で分かりやすい小さな宇宙でした。


⚡神の視点:理の外に生まれた模造物

神はその様子を天上から見下ろして言いました。

「彼らは私の世界を模倣しているが、因果を削り、法則を抜いた。
だが、それでも“流れ”を感じ取ろうとしている……。
ならば、それもまた人間らしい創造だ。」

神は怒りませんでした。
ただ、こうも言いました。

「だが忘れるな。
模造はあくまで模造。
そこには“整合性”という魂が宿らぬ。
理を離れた図は、やがて矛盾を孕み、
それを真理と信じた者を惑わせるであろう。」


🧠人間の視点:祈りとしての図

人間たちは、その言葉を聞いてもなお図を描き続けました。
なぜなら、その図は彼らの理解の祈りの形だったからです。

本物の理(グラフ理論)は、神の目には明快でも、
人間の頭には遠すぎた。
だから彼らは「便利さ」という祭壇を築き、
「計算のしやすさ」という小さな灯火を灯しました。

そして言いました。

「この図は真理そのものではない。
だが、真理に向かう階段のひとつだ。」


🌌結び:神と人の協奏

こうして世界は二層になりました。
上層には、神の完璧な秩序=グラフ理論の世界。
下層には、人間の不完全な模造=SPIの図。

神は完全さを尊び、
人は不完全さの中で学ぶ。

そしてときどき、ある者は気づくのです。

「この“SPIの矢印”も、実は神の世界の影ではないか?」

そのとき初めて、
模造の図は祈りを超えて、真理への入口になるのです。

ゲーム音楽とMIDI

✅ MIDIが昔ゲームで使われていた背景


❌ MIDIが最近のゲームであまり使われなくなった理由

以下が主な理由です:

  1. 録音されたオーディオ(PCM/ストリーミング音声)の品質・容量コストが下がった
    → 昔は「演奏データ+音源」で済ましたが、今は「録音された音楽トラック(オーケストラ/ライブ演奏)+高ビットレート音声データ」が技術的に可能/安価になったため、MIDI方式の “シンセ演奏っぽさ” が相対的に見劣りするようになっています。
    → 実際「CD-ROM時代になり、MIDIの利点(低データ量)が薄れた」という議論があります。 vogons.org+1
  2. 音源の再生環境にばらつきがある/制御が難しい
    → MIDIの場合「どの楽器音源/どの音色セット(サウンドバンク)」を使うかで音質・演奏感が大きく変わります。ゲーム機・PC・サウンドカードごとに異なる音源が使われていると、ユーザー体験が揃いません。
    → 最近はゲーム開発者側が「何を再生しても同じ音で出る」ことを重視するため、録音された音をそのまま流す方式が好まれています。
  3. 制作ワークフロー/サウンドデザインの変化
    → ゲーム音楽・サウンドデザインは「DAW(Digital Audio Workstation)で録音/ミックス/マスタリング」→「ゲームに組み込む」という流れが強くなっています。MIDI形式だけで終わらせるには限界が出てきています。
    → また、音楽が映画・ドラマクラスのクオリティを求められるようになったことも影響しています。
  4. プラットフォーム・音声再生技術の進化
    → ハードウェア/ソフトウェアともに「ストリーミング音声」「マルチチャンネル(5.1ch/7.1ch/立体音響)」「高サンプリングレート」「圧縮音声」などが使えるようになってきたため、MIDIのみでは対応しづらい部分があります。
    → 例えば、環境音・ボイス・音楽が一体化して動的に切り替わるようなゲームでは、単純なMIDIではなく「音声トラック+リアルタイム音響処理」のほうが運用が楽になります。

🧐 例外・補足


じゃぁ、MIDIはどんな風に減っていった?

📌 例1:PCゲームでのMIDIの利用と減少


📌 例2:家庭用ゲーム機/コンソールでの状況


📌 例3:具体的な転換点・傾向

ゲームそのもので見てみよう

🎮 タイトル例:MIDIから録音音源への移行事例

【1】Final Fantasy VII(PS1/1997)







【2】Unreal(PC/1998)







📊 移行の潮流まとめ

時期

主流フォーマット

備考

~1990年代中期

MIDI/FM音源/サンプラー再生

容量制約重視。リアルタイム演奏方式。

1990年代後半

モジュール音楽(tracker)

PCMサンプルと演奏データの併用。

2000年代以降

録音済み音声(WAV/MP3/OGG)

ストレージ容量拡大によりストリーミング方式が主流に。


💬 補足

MIDIの「演奏データ+音源依存」の仕組みは、容量削減という面では優秀でしたが、再生環境ごとに音が変わる問題がありました。
ハード性能が上がり録音音源をそのまま扱えるようになったことで、開発者が意図した音を確実に再生できる録音方式(PCM/圧縮音声)が標準となっていきました。


ゲーム別と年代で見たまとめ

🎼 ゲーム音楽フォーマットの変遷(1990〜2000年代)

年代

主なハード/時代区分

主な使用フォーマット

主なタイトル例

録音音源への移行状況

1990〜1993

SFC/メガドライブ/PC-98

FM音源・PCM少量・MIDI相当データ

『ファイナルファンタジーIV』(1991)、『ソニック・ザ・ヘッジホッグ』(1991)

🎵

MIDI的演奏データが中心

。音はチップ音源によるリアルタイム合成。

1994〜1996

PS1登場前夜、PCのサウンドカード普及期

MIDI/モジュール(MOD)音楽

『DOOM』(1993, PC)、『Quake』(1996)

🧩 MIDIまたはTracker形式が主流。音源依存あり。

1997〜1999

PS1/N64/初代PC 3D世代

MIDI+サンプル音源(ADPCM)

→ 一部

録音音源併用

『Final Fantasy VII』(1997)、『ゼルダの伝説 時のオカリナ』(1998)、『Unreal』(1998)

⚙️

MIDI+PCMハイブリッド期

。容量節約目的で演奏データ多用。

1999〜2002

PS2/Dreamcast/初代Xbox/Windows XP世代

WAV/MP3/ADPCM録音音声が主流に

『Final Fantasy VIII』(1999)、『Halo: Combat Evolved』(2001)、『Devil May Cry』(2001)

完全録音音源時代の幕開け

。スタジオ録音・生演奏が一般化。

2003〜2006

PS2後期/Xbox360黎明期

ストリーミング音声(WAV/OGG/MP3)

『Halo 2』(2004)、『FFX-2』(2003)、『メタルギアソリッド3』(2004)

🎧

MIDIは事実上消滅

。ゲーム音楽=録音トラックが標準化。

2007〜2010

Xbox360/PS3/Wii

マルチチャンネル音声(5.1ch/7.1ch)・圧縮音声

『Skyrim』(2011前後)、『FFXIII』(2009)

🎬 映画並みのオーケストラ録音。サラウンドミックス時代へ。

2011〜2015

スマホ黎明期/Unity普及

AAC/MP3/OGG

(圧縮音声)

『パズドラ』(2012)、『モンスト』(2013)

📱 モバイルでは軽量圧縮音声を採用。MIDI再生は非対応。

2016〜現在

PS4〜PS5/Switch/PC

高音質WAV/FLAC/リアルタイムミキシング

『ゼルダの伝説 ブレス オブ ザ ワイルド』(2017)、『FFVII Remake』(2020)

🌍

完全に録音音声ベース

。MIDIは内部制御用途に限定。


🎧 総括:MIDIが消えたタイミング

要素

消滅/移行時期

コメント

ゲーム内BGMをMIDIで直接再生

2000年前後にほぼ消滅

PS2/Xbox初期世代では録音音声が標準化。

シーケンス(演奏データ)形式(MOD/XMなど)

2002〜2005年頃まで生き残り

一部インディーや携帯機で継続(GBA等)。

MIDIを内部的制御データとして使用

今も一部で継続

リズムゲームや音ゲーの「譜面」制御として利用。

録音音声(PCM/MP3/OGG)

2000年以降は完全主流

以後すべてのAAAタイトルで録音音源使用。


💬 解説

現代のBGMとゲーム制作:ミドルウェアの台頭

🎮 ゲームサウンドミドルウェアとは?

サウンドミドルウェアとは、ゲーム内で音楽や効果音、環境音などを効率よく管理・再生・制御するための中間層ソフトウェアです。
かつては開発者が直接プログラムで音声API(DirectSoundやOpenALなど)を操作していましたが、音量調整や3D定位、ループ制御などを個別に実装するのは非常に手間がかかりました。

ミドルウェアは、これらの処理をGUIベースで視覚的に設定できるようにし、
さらにBGMのブレンド(Adaptive Music)や環境音のリアルタイムミキシングイベントドリブンなサウンド再生を実現します。

代表的なミドルウェアには、CRIWARE(ADX2), FMOD, Wwise があり、いずれもUnityやUnreal Engineなどの主要ゲームエンジンに統合されています。


🎧 2000年代以降の録音方式とミドルウェアの関係

時期

主な音声フォーマット

特徴

採用ミドルウェア/エンジン

解説

2000〜2005

WAV(PCM)

非圧縮・高音質・容量大

独自実装(DirectSound, XAudio)

PS2/Xbox時代は「録音音源+DirectX API」直呼び。容量との戦い。

2005〜2010

MP3/OGG(圧縮音声)

高圧縮・音質維持・CPU負荷低

FMOD

CRI Middleware (ADX)

ストリーミング再生が一般化。音楽・SE・ボイスを同時再生可能に。

2010〜2015

OGG/AAC/WAV(ミックス)

スマホ普及期。メモリ効率と音質のバランス重視

CRIWARE ADX2

FMOD Studio

Wwise

サウンドイベント制御・3D定位・リアルタイムミキシングが可能に。

2016〜現在

FLAC/WAV/HCA/OPUS

ハイレゾ音源・低遅延・可逆圧縮

CRIWARE

Wwise

Unreal/Unity内蔵Audio

シネマティック音響、環境音ミキシング、RTPC制御などが標準化。


🧩 主なサウンドミドルウェア解説

🎛️ ① CRIWARE(ADX2 / HCA)


🎚️ ② FMOD(Firelight Technologies, オーストラリア)


🎚️ ③ Wwise(Audiokinetic, カナダ)


🔊 補足:フォーマット別の特徴まとめ

形式

種別

主な用途

長所

短所

WAV

PCM

高音質・SE・BGM素材

可逆・低遅延

容量大

MP3

圧縮(非可逆)

一般BGM

容量小

ループ処理しづらい

OGG Vorbis

圧縮(非可逆)

BGM/SE

高音質・ライセンス無料

デコード負荷やや高

HCA(CRIWARE)

独自圧縮

コンソール・スマホ全般

高圧縮率+ループ対応

専用ミドルウェア必須

FLAC

可逆圧縮

ハイレゾBGM・ムービー

高音質・保存用

容量大、再生負荷高


🧠 まとめ:ミドルウェアがもたらした変化

時代

サウンド開発の主眼

代表技術

〜1990年代

データ容量節約

MIDI・ADPCM・FM音源

2000年代

高音質録音再生

PCM/MP3/OGG

2010年代

動的サウンド制御

FMOD/ADX2/Wwise

2020年代〜

AI/物理連動サウンド

RTPC/DSP/Spatial Audio(3D立体音響)


📘 教育応用のヒント:



🎮 ゲーム制作計画書(エンジニア志望向け)評価項目 詳細説明

説明

(1) コンセプトの明確さ


(2) ゲームシステム構成


(3) 技術構成・アーキテクチャ


(4) 図表・資料構成力


(5) 技術的挑戦度・創意工夫


(6) スケジュールと実行計画


(7) 技術検証・プロトタイピング計画


(8) 面白そう?(魅力設計・体験価値)

ゲーム会社に応募した時何見られるんだ?

1. 動画構成(見せ方)の評価

採用側は動画全編を丁寧には見ません。
多くは以下の流れになります:

  1. 最初の10秒で「面白そうか / センスあるか」を判定
  2. 1分程度で「技術力があるか」を判断
  3. 最後まで視聴するのは高評価時のみ

評価されやすい構成:

マイナス評価:


2. 技術アピール度の評価

ゲーム会社が知りたいポイントは

高評価される書き方例:

・ゲームエンジン:自作(DX11ベース)
・スキニング:CPU / GPU対応
・モデル読み込み:ufbx利用
・地形:自前生成(法線計算あり)
・影:丸影を独立クラスで実装 ← 重要

3. クリエイティブ・デザイン評価

採用側は以下を見ることが多い:


4. 就活動画として強いか・弱いか

ゲーム業界向けの評価観点:

観点

求められるもの

備考

作品完成度

バグ少・動作安定

企業は安定動作を見る

技術力

内部構造の理解

黙っていても伝わる情報量

美術的センス

視覚的訴求力

画面に気持ちよさがある

UI/UX

遊びやすさ

プレイヤー視点

ゲームデザイン

面白くできる人か

ただ動くだけはNG

プレゼン能力

説明の明瞭さ

チーム内で会話できるか


1. プログラマー応募として強いアピール点になる要素

A. 自作フレームワーク+DxLib

企業の評価:

この時点で、多くの応募学生との差別化になります。


2. アピールしたい項目に対する、企業側の評価視点

A. カメラワーク

企業が見たいのは:

さらに評価される書き方例:

・TPSカメラにおいて、RPG-7カメラ問題を回避するため  
 RayCastで視界遮断判定を行い、距離自動補正を実装  
・ターゲット注視時はlook-at制御による滑らかな補間

B. 敵の移動アルゴリズム

採用側の評価ポイント:

高評価される言い方:

・敵AIは状態遷移(FSM)で管理  
 例:巡回 → 索敵 → 追跡 → 攻撃 → 回避  
・プレイヤーが視界圏内に入るとRayCastで視線判定  
・目標位置は逐次補間し、振動や細かい震えを抑制

C. RayCastでの武器軌道

企業はこう見る:

高評価される説明文:

・近接武器はフレームごとに位置をサンプリングし  
 RayCastで連続的な衝突判定を実施  
 高速振り動作時の「すり抜け」を防止

3. あなたがすべき「動画中の具体的説明方法」

字幕例(動画内テロップ)

【Camera System】
・障害物判定による自動距離補正
・ターゲット注視モードへの滑らかな遷移

【Enemy AI】
・視界内検知(RayCast認識)
・位置予測による経路決定
・状態遷移による行動管理(FSMベース)

【Weapon Collision】
・RayCastによるフレーム間連続判定
・速度に依存したヒット補正

採用担当者は コードを見ません
→動画テロップで理解できる必要があります。


4. 実際の採用担当者の目線(リアル)

30秒〜1分で判断します。

判断ポイント:

逆にマイナス評価:


5. 高評価を狙う具体的対策

動画の最初10秒に必ず入れるべき

Programming Portfolio
自作フレームワーク + DxLib
─ アルゴリズム重視 ─

そして次にいきなり
AIの動きを見せる!

説明は後!


6. さらに強いアピール方法

動画最後に技術要素一覧:

▼技術要素
・自作エンジン構造
・ゲームループ
・時間差分処理 deltaTime
・カメラ制御(視界補正)
・敵AI(FSM)
・RayCast衝突
・行列変換
・3Dベクトル処理

面接官の心の動き:

「この人、数学できるな」
「基礎理解あるな」
「伸びる人材だな」


7. あなたへの最終アドバイス

あなたの動画は
プログラマーの強みを映像で伝える必要がある

つまり:

そして最終的に評価されるのは:

・リアルタイム処理の理解
・ゲーム数学の応用
・最適化への感覚
・堅実なプログラム設計