knowledgeからインポート中
knowledgeはtomcatとかいう振られ気分でロックンロールなタフボーイが、指先一つでダウンする可能性があり、我が生涯に一変の悔い無しにはなりたくないため、こちらに無双転生しようとするが、一子相伝なのでどうなるかは、やってみないとサイバーブルーである。
- チャプター作ってみる
- 新しいDx11base設計方針(今進んでいるところまで)
- おま環とは
- メモ
- Windowsプログラミングの初めの一歩手前の穴
- 改良案
- あたおかSPI
- ゲーム音楽とMIDI
- 🎮 ゲーム制作計画書(エンジニア志望向け)評価項目 詳細説明
- ゲーム会社に応募した時何見られるんだ?
チャプター作ってみる
チャプター作るとどうなるか確認用
初めての記事を書いてみるテスト
見出し
見出し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

画像サイズの変更(マークダウンからはできなさそう)
テーブル
| Left align | Right align | Center align |
|---|---|---|
| テスト1 | テスト2 | テスト3 |
| 12345 | 12345 | 12345 |
| abcde | abcde | abcde |
[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設計方針(今進んでいるところまで)
✅ 主要クラスの役割一覧
クラス名 | 役割 | 主な責務 | 他クラスとの関係 |
|---|---|---|---|
| DirectX初期化&基盤 | デバイス・コンテキスト・スワップチェイン・バックバッファなどの管理 ビューポートやラスタライザ設定もここで一元化 | 全クラスが依存。最下層の基盤クラス |
| シェーダーの一括管理 |
を読み込んで、VS/PS/IL を生成・キャッシュ キーでシェーダー切り替えを容易にする |
や
など描画系から利用される |
| カメラ情報の管理 | ビュー行列・プロジェクション行列を提供 LookAtや移動処理も持つ |
などが View/Proj を取得する |
| モデルの純粋なデータ保持 | 頂点・インデックス・テクスチャ・サンプラ・名前など 必要なバッファを持ち描画準備済みの状態 |
から生成され、
に使われる |
| モデルの読み込み・キャッシュ | ファイルから
を生成 ハンドル付きでモデルを管理・再利用 |
からハンドル経由で取得される |
| モデル描画の実行役 |
+
情報を使って描画 内部で
,
,
を使って描画する |
を渡されて描画処理を行う |
(補助) | モデルの変換行列生成 | SRTからWorld行列生成、法線変換行列も作成可 |
が使用 |
🎯 クラス関係図(概略)
┌────────────┐
│ Dx11Base │ ← デバイスやレンダリングパイプラインの基盤
└────┬───────┘
│
┌────▼───────┐ ┌──────────────┐
│ ShaderBucket│◄────────┤ ModelRenderer │
└────────────┘ └────┬─────────┘
│ uses
┌─────▼────────┐
│ SimpleModel │◄─────┐
└──────────────┘ │
│
┌────────────┐ │
│ ModelManager│────┘
└────────────┘
┌────────┐
│ Camera │ ← View/Proj取得用
└────────┘🧠 役割分離の利点
設計 | メリット |
|---|---|
に描画コードを持たせない | 同じモデルを複数箇所で描画可能(インスタンス化) |
に描画処理を集中 | ステート設定、シェーダー設定、描画の変更が一元管理できる |
に読み込みとキャッシュを集中 | 同じファイルを何度も読み込む無駄を防止 |
のキー管理 |
、
、
など切り替えが簡単 |
に初期化・基盤処理を集中 | DirectX設定の複雑さを隠蔽し、他クラスをシンプルに保てる |
🔚 まとめ
このような分離設計は、
✅ 単体テストや差し替えがしやすく、
✅ **描画方式の拡張(PBR、影、インスタンス描画など)**にも柔軟に対応できます。
必要であれば、ModelRenderer::Draw() や ModelManager::GetHandle() など、具象的なコード実装例も提供できます。
モデル関係責任分割
クラス | 責任 |
|---|---|
| データ所有者 :頂点・インデックス・テクスチャ等のDirectXリソース保持。 ※レンダリングコードは持たない |
| 描画担当 :
のデータを使って描画処理を実行。Transformやシェーダーとの連携もここで処理 |
| 管理担当 :
をファイルからロードし、キャッシュとして保持。ハンドル管理なども行う |
今迷っているところ
- modelにvertexbuffer、indexbuffer、textureを直接もたせるのは良いか悪いかよくわからない
- (現在のエンジンはFBX=モデル=全部入り)
- これだと、インスタンスごとにレンダリングを切り替えたりとかが色々やりづらいとおもう
- modelManagerにレンダリングリソースとして情報をもたせる方法を考えている
- ChatGPTによるとアニメーションとか拡張しようとするとめんどくさくなりそうな予感がする
- とりあえず、modelとFBXは完全に切り分けることにする(他のモデル形式とかも考えることもあるかもだから)
- model、manager、rendererによって責任を分割したけど、誰が何を持つかも分割されて困った
6月17日現在の様子
🎯 DirectX11 モデル描画エンジン:構造と設計レビュー
🎯 DirectX11 モデル描画エンジン クラス構成概要
┌────────────┐
│ Dx11Base │ ← デバイスやレンダリングパイプラインの基盤
└────┬───────┘
│
┌────▼───────┐ ┌──────────────┐
│ ShaderBucket│◄────────┤ ModelRenderer │
└────────────┘ └────┬─────────┘
│ uses
┌─────▼────────┐
│ SimpleModel │◄─────┐
└──────────────┘ │
│
┌────────────┐ │
│ ModelManager│────┘
└────────────┘
┌────────┐
│ Camera │ ← View/Proj取得用
└────────┘✅ メリット
1. 役割分離された設計
ModelManager,ModelRenderer,FBXLoaderが明確に責務を分担- モデルデータと描画用GPUリソースを分離しており拡張が容易
2. マテリアル単位の柔軟な管理
SimpleModel->MaterialMeshの構造によりマルチマテリアル対応が容易- マテリアルごとにテクスチャ、ポリゴンの分割が可能
3. シェーダーステート集中管理
ShaderBucketによりブレンド/Zステート管理を一元化- アルファブレンドやZWrite切替も柔軟に対応
4. リソース共有対応
- モデルパスごとに
ModelHandleを発行、リソースの使いまわしが可能 - 将来的に
MaterialPool,TextureManagerにも応用可能
5. アニメーション拡張の布石あり
VertexにcontrolPointIndexを保持済みで、スキンメッシュ対応の余地あり
⚠️ デメリット・今後の課題
1. スキンアニメーション未対応
- Bone構造、SkinWeight、Clip、Poseデータ未実装
VertexにboneWeight/boneIndex配列が未導入
2. 階層構造の保持なし
- FBXのノード親子構造がSimpleModel内に保持されていない
- 階層的なTransform更新や描画順の制御が難しい
3. インスタンシング未対応
- 同一モデルの多重描画でリソース効率化ができていない
4. 描画順制御がアプリ依存
- Zソートや描画カテゴリ分離が
ModelRenderer側に組み込まれていない
5. グローバル依存の可能性
ShaderBucket,Dx11Baseなどがグローバルに依存しやすく、テスト性が低下する懸念
🔄 改善ロードマップ
| ステージ | 改善内容 |
|---|---|
✅ 現在 | 非アニメモデル・マテリアル描画まで実装済み |
🔜 次 | Bone構造・スキンウェイト・アニメーションクリップ導入 |
🔜 拡張 | GPUスキニング、Shaderの構造整理、AnimationClip管理クラスの追加 |
🔜 拡張 | Zソート処理、半透明オブジェクトの描画順制御の導入 |
🔜 拡張 | 階層Transform・ノードアニメーションの導入、カメラアニメ対応 |
おま環とは
「おま環」とは、ネットスラングで「お前の環境が原因」の略です。
主に以下のような状況で使われます:
🧩 意味
「他の人では再現しない問題が、特定のユーザーの環境だけで起きている」
ということを指す言葉です。
🧠 具体例
- Aさん:「Visual Studioのツールチップが文字化けするんだけど」
- Bさん:「再現しないな、それおま環じゃ?」
という具合です。
つまり「PC設定や環境(OS・フォント・IME・拡張機能など)の問題かもよ?」という含みを持っています。
メモ
🎮 前提条件(仕様)
- プレイヤーは高さ 2ブロック分の大きさ(頭+胴体)
- ジャンプは1ブロック分のみ可能
- ブロック世界は
world[x][y][z]のようなグリッドで表現 - 「今立っている場所」と「前進方向」にあるブロックを調べて移動可能性を判定
🔍 判定に使うブロック範囲(図)
プレイヤーの足元 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;
}✅ メリット
- 複雑な物理処理なしで、ブロック単位で「進める or ジャンプできる」を判定できる
- 敵AIやパスファインディングでも使いやすい
- 斜面や複雑地形にも柔軟に対応可能
🎮 状態のしくみ:プレイヤーの「行動モード」を理解しよう!
🎲 プレイヤーの3つの状態
- 歩いてる(=普通に移動)
- ジャンプ中(=1段上へピョン!)
- 落下中(=足元が空で落ちてる)
🔁 状態の流れ(図っぽく)
↑
ジャンプ ←────────
↑ │
│ │
落下中に終点到達 落下する条件
↑ │
│ ↓
[歩いてる] ──→ [落下中] ──→ [落下中継続]
↑ │
└──── ジャンプできる? ───┘🧠 状態の切り替え条件(とってもやさしく!)
🚶♂️ 歩く状態(isWalking)
● いつこの状態になる?
- キーボードで前に進むキーを押したとき
- 進みたい先が 空いてる(ブロックがない)
● 何をする?
- 少しずつ前に動く
- 動き終わったら止まる(また入力待ち)
🦘 ジャンプ状態(isJumping)
● いつこの状態になる?
- 前にブロックがあるけど、
- その上に空間がある(=乗れる)
● 何をする?
- 放物線のアニメで、ピョンと1段上に乗る
- 着地したら「歩く状態」に戻る
🕳️ 落下状態(isFalling)
● いつこの状態になる?
- 足元に ブロックがない(空中に浮いてる)
● 何をする?
- 少しずつ下に落ちる
- 下にブロックがあるところで止まる
🧩 状態フラグで管理(プログラム上)
フラグ | true の意味 | false の意味 |
|---|---|---|
| 歩いてる最中 | 止まってる |
| ジャンプ中 | ジャンプしてない |
| 空中で落ちてる | 地面に立ってる |
🧪 状態チェックは毎フレーム行う!
ゲームの Update() 関数の中で、毎フレームこういうチェックをしてます:
if (!isFalling) {
PlayerInput(); // 入力を見て
PlayerMovement(); // 動かす
} else {
PlayerFallDown(); // 落下処理
}📝 イメージでまとめると…
状態 | 条件 | 行動 |
|---|---|---|
歩く | 前が空いてる | スーッと1マス進む |
ジャンプ | 前にブロック、その上が空 | ピョンと1段上に乗る |
落下 | 足元が空(またはジャンプ後) | スーッと1段ずつ下がる |
✅ ポイントまとめ
- 状態は3つだけ:「歩く」「ジャンプ」「落下」
- 条件に応じて状態を切り替えてるだけだから、考え方はシンプル!
- 実際の動きは
moveRatioを使って「ぬるっと動かしてる」
Windowsプログラミングの初めの一歩手前の穴
メッセージループとコールバックとWinProc
🎮 たとえるなら…
ゲームセンターの受付とスタッフの関係!
🌀「メッセージループ」は、ゲームセンターの受付のお兄さん
- 毎日ずっと、お客さん(メッセージ)が来るのを待ってる。
- お客さんが来たら、「どのゲームに用事があるのかな?」と考えて、そのゲームの担当スタッフに「お客さん来たよ!」と伝える。
// ゲームセンター受付のお兄さん(これがメッセージループ)
while (お客さんが来たら) {
お客さんの内容を読む(TranslateMessage)
担当スタッフに渡す(DispatchMessage)
}🧑🔧「WndProc(ウィンドウプロシージャ)」は、ゲーム機のスタッフ
- 受付から「○○の用事の人が来たよ」と聞いたら、
- 「遊びたいのかな?」
- 「壊れたのかな?」
- 「帰りたいのかな?」
…を判断して、それに応じた行動をする。
// ゲーム機のスタッフ(WndProc)
switch (お客さんの用事) {
case 「遊びたい」:
→ スタートボタン押す
case 「壊れてる」:
→ 修理する
case 「帰る」:
→ ゲーム終了
default:
→ 本社(OS)に任せる
}🔁 2人の連携で成り立ってる!
誰? | 役割 |
|---|---|
メッセージループ(受付) | お客さん(イベント)を拾ってスタッフに渡す |
WndProc(スタッフ) | イベントに合わせて処理する(絵を描く・音を出す・終了する) |
🎨 具体例(「絵を描いて!」って言われたら?)
- Windows(OS)が「このウィンドウ、描き直してね!」って言う(WM_PAINTというイベントが届く)
- メッセージループがそれを受け取って、WndProcに渡す
- WndProcが「よし、描き直そう」と絵を描く処理をする
📌 まとめ
現象 | 例え | プログラム上では |
|---|---|---|
イベントが届く | お客さんが来る | Windows がメッセージを出す |
メッセージループ | 受付のお兄さん | GetMessage → DispatchMessage |
WndProc | スタッフ | イベントに応じた処理をする関数 |
つまり、「メッセージループ」が お知らせを渡す人、
「WndProc」が 実際に処理をする人 です!
🧠 まず「コールバック」とは?
✅ 意味:
自分で作った関数だけど、あとで誰か(=OSやライブラリ)が呼んでくれる関数のことです。
🎮 たとえるなら…「イベント係に任せる自作の処理」
たとえば、学校でイベントをやるとして…
- 「ボタンを押されたときにこの処理をしてね」
→ と先生(OS)にお願いしておく - 実際にボタンが押されたら、先生があなたの関数を呼んでくれる
これが コールバック です。
🪟 WndProc とは何か?
✅ 意味:
WndProc は、**「ウィンドウに届いたメッセージをどう処理するかを書く関数」**です。
例えば、
- ウィンドウが閉じられた → 終了させる
- 再描画してほしい → 画面を描き直す
- キーが押された → 入力処理する
などを処理する関数です。
💡 WndProcは「OSに登録するコールバック関数」
あなたは最初にこう書きます:
wc.lpfnWndProc = MyWindowProc;これは、
「このウィンドウの処理は MyWindowProc() という関数を使ってね!」
とOSに登録してるということです。
📞 呼び出しの流れ(コールバックの仕組み)
- ユーザーが何か操作する(例:ウィンドウを閉じる)
- OSが「メッセージ」を作って、プログラムに送る
- プログラムの「メッセージループ」がそのメッセージを受け取る
- 登録された WndProc関数(コールバック) が呼ばれる!
🎨 たとえ話まとめ:先生と出席係
役割 | たとえ | 実際の名前 |
|---|---|---|
イベントが起きる | 生徒が手をあげる | OSがメッセージを送る |
受付が確認 | 出席係が生徒を見つける | メッセージループ |
処理担当が動く | 先生がその子に対応する |
|
呼ばれる仕組み | 担任を事前に登録しておいた | コールバック関数 |
✅ 結論まとめ(超ざっくり)
用語 | やさしい意味 |
|---|---|
コールバック関数 | OSに「この関数をあとで呼んでね」と渡しておく関数 |
WndProc | ウィンドウの出来事を処理するコールバック関数 |
lpfnWndProc | 「WndProcはこれだよ」とOSに登録するための場所 |
呼び出し | イベントが起きたらOSが自動で呼んでくれる(=コールバック) |
改良案
===== 🎯 Character 分割 実行順おすすめ(3コミットで見栄えが出る) =====
目標: 1ファイル1000行超の Character.cpp を段階的に分割し、責務を明確化。
Visual Studio プロジェクト(CMake 不使用)で、見た目を変えずにコードの「整理力」「設計力」をアピールできる構成にします。
🥇 コミット1:VFX / Blink 抽出
- 🎨 CharacterVfx に VFX 関数群を移設。
- InitCSVEffect / SetChargingEffect / SetFullChargeEffect / SetAttackLocusEffect / SetHitEffect / SetFenceHitEffect
- 💡 CharacterModelBlink に DrawCharacterModel を移設。
- 無敵中の点滅描画などの「表現」責務をまとめる。
- ✨ まずビジュアル責務を独立させることで、レビュー映え&最初のインパクトが大きい!
🧩 Character(変更後)
Character::Draw() → CharacterModelBlink::Draw()
Character::Update() → CharacterVfx::Update()📈 効果:視覚表現が明確に分離。300行以上軽量化。
🥈 コミット2:Shadow / Air / Forward 抽出
- 🌑 CharacterShadow に InitShadow / ShadowSet / ShadowDraw を移設。
- 🪶 CharacterAir に CharacterGravity / SetJump を移設。
- 🧭 CharacterForward に RotateVecFront / FrontVectorConfirm を移設。
- 🔁 Character::Update / Draw は新モジュール呼び出しのみの薄い制御層へ。
🧩 Character(変更後)
Update() → shadow.tick() → air.tick() → forward.tick()
Draw() → shadow.draw()📈 効果:ランタイムの共通処理が整理され、Facade 化が進行。
🥉 コミット3:Movement / Rotate / Charge / Hit / Fence / Csv / Observer の順次抽出
- 🏃 CharacterMovement / Rotate / Charge
- 移動・回転・チャージ処理を担当。
- 💥 CharacterHit / Fence
- 被弾/ノックバック/柵反射をまとめる。
- 📄 CharacterCsvLoader
- CSV パラメータ読み込みを専用化。
- 👁️ CharacterObserver
- Add / RemoveObserver など監視者管理を独立。
🧩 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 |
💾 補足:
CharacterParams.hを作成し、MoveParam / JumpParam / ShadowParam などの構造体を移動。Character.hでは各モジュールを前方宣言して include を最小化。- Visual Studio の「ソリューションエクスプローラ」で
Characterフォルダを右クリック → 「追加」→「新しい項目」で上記を順次作成。
🧱 仕上げ(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() |
🧱 動作不変性の説明
- Update の呼び順を保持(
shadow → air → forward → movement → ...) - API 仕様を変更せず、Player / Enemy 側の呼び元はそのまま利用可能。
- 表現系(VFX / SE)は Assets / Vfx 経由に統一。
🤖 将来拡張例
- Enemy も CharacterMovement / Hit / Fence を共通化 → AI 部分だけ差分に。
- Player 側の OnCollision → CollisionCharacter → Reflect は CharacterHit に委譲し、入力とステート遷移だけに集中可能。
💡 TIP:
- まず「VFX/Blink → Shadow/Air/Forward」から着手するのが最も安全。
見た目を変えずに 300〜400行削減、レビューにも強い第一歩!
仕上げ(READMEに載せると採点が伸びる)
- Before/After の依存図(
Character1000行 → Facade + 8モジュール) - 責務表(1行ずつ「点滅描画=Blink」「重力/ジャンプ=Air」…)
- 動作不変性の説明(
Updateの呼び順を保持。VFX/SE は Assets/Vfx 経由に) - 将来拡張例:
EnemyもCharacterMovement/Hit/Fenceを共有 → AI 部分だけの差分で成立。
※ Player 側のOnCollision → CollisionCharacter → ReflectはCharacterHitの窓口に寄せ、Player 独自は入力とステート遷移だけに整理可能。
Player
📄 新規 .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();ポイント
- **依存注入(Deps)**で Engine 側と疎結合化。単体テスト時にはモックを注入可能。
- Update の呼び順を固定して動作不変性を担保。差分は各モジュール内で閉じる。
- Facade は“薄い制御のみ”。ロジックや I/O をここに戻さない(肥大化の再発防止)。
あたおかSPI
1. “物流・流通経路図”というものの性質
SPI(適性検査)の非言語分野で出る “物流(物の流れと比率)” の図は、典型的にはこういう構造です:
- 複数のノード(地点、業者など)
- ノード間を矢印でつなぎ、それぞれに「比率 a,b,ca, b, ca,b,c」を表す
- ノードを通過したり、合流したりする流量を式で表す
- 最終地点で “全体のうち何割がここへ来るか” を求める
こういう図は、「フローチャート」や「流れ図 (flow diagram)」「流通チャネル図」「矢印付きの有向ネットワーク図」などの親戚にあたる手法です。
数学的にはグラフ(頂点 + 辺)で表現できますが、図の主眼は 比率と流量の算定を視覚的に補助するための記号的な補助図法 で、グラフ理論そのもの(最短経路、巡回、連結性、次数などを主対象とする理論)とは目的も手法も異なります。
この種の図はおそらく教育・試験・参考書の便宜上、編集者・著者が工夫して使い始めたものと考えられ、特定の学者や発明者がいる、という情報は公開には残っていないようです。
2. 類似する図示法・理論的背景
以下の図示法・理論が、SPI の物流図と近縁性を持つ可能性があります:
種類 | 説明 | 関連性 / 差異 |
|---|---|---|
信号流 (Signal-flow graph) | 主に制御工学・システム理論で、変数間の線形関係を矢印付きのグラフで表す手法。Mason の “signal-flow graph” が有名。 | 流れ(信号・量)を伝播させる表現という意味で近いが、SPI の物流図は比率を定める算式中心で、システムの動的性は含まれない点で目的が異なる。 |
流量ネットワーク / フローグラフ (flow network graphs) | ネットワークフロー理論(最大流、最小カットなど)で使われる。容量付きの有向辺を使って、ある源から別のシンクへ流れる最大流量を考える。 | 構造的には類似するが、SPI 図は「比率」>「容量最大化」といった最適化主題ではない。 |
有向グラフ (directed graphs) | 頂点と向き付き辺を持つグラフ。一般グラフ理論の基本構造。 | SPI 図は有向グラフの一種と見なせる。ただし通常のグラフ理論では重み、最短路、探索アルゴリズム等を扱うが、SPI 図は “比率を合成して最終流量を求める” という線形代数的処理が主。 |
フローチャート / 流れ図 (flowchart, flow diagram) | 手順や工程・物の流れを可視化する図。業務プロセス、物流プロセス、化学プロセスなどで広く使われる。 | SPI 図はこれを借用した “分岐・合流” 図を比率付きで表したものとみなせる。 |
有向重み付きネットワーク (weighted directed network) | 辺に重み(この場合比率)を持ち、有向性を持つネットワーク。グラフ理論・ネットワーク科学で広く扱われる | 構造的にはこれと一致するが、SPI の使用場面(試験問題)として簡略化されたもの。 |
3. 「誰が考えた」の問いに対する考察
- 教材・試験の世界では、こういう「経路と比率を可視化する矢印付き図」は、個々の著者や出版社が編集上の工夫として使いつづけ、広く流通するようになったスタイル、という可能性が最も高いと思われます。
- したがって、「数学者 X が発明した正式名称の図」みたいには公的記録が残っていないことが多いです。
- もしこの形式の図がいつごろから教育/試験分野で使われ始めたかを調べるなら、昭和~平成初期の数学解法参考書・受験用問題集を比較して、どの時点でこの形式が普及したかを探す歴史研究が必要になるでしょう。
もしよければ、私が日本の受験・入試数学/就活適性検査分野で使われているこの種の図の初出例を探してみましょうか?それで “発展の系譜” を推定できるかもしれません。やりましょうか?
あなた:
このように、一般の学問の領域から外れた図を、あたかもデファクトスタンダードであるかのように使うことの危険性はないのでしょうか?
ChatGPT:
とても重要な視点です。
結論からいえば――危険性はあります。しかも二重の意味で。
1. 学問的危険性:論理体系の断絶
SPI の「流通経路図」のような図は、
あくまで“解法を早く視覚化するための便宜的記号”にすぎません。
しかしそれが体系的な理論(例えばネットワークフロー理論や確率過程)と無関係なまま独立して定着してしまうと、次のような問題が起こります。
問題 | 説明 |
|---|---|
概念の混乱 | 「比率を掛ける」と「流量を保存する」など、数学的には異なる操作が同じ線や矢印で表され、論理的整合性が曖昧になる。 |
誤学習の固定化 | 「こういう図を書けば正解になる」という作業手順が目的化し、背後の数量関係(保存則、分配則、条件付き確率など)への理解が育たない。 |
他分野への転用不能 | 同じ“流れ”でも、経済学・情報学・物理学では定義や制約条件が違うため、SPI式の図はそのまま応用できない。 |
つまり――論理的支柱を持たない「見た目の定番」は、体系的理解の発芽を阻む温床になります。
2. 教育的危険性:思考の形式化・再現性の欠如
教育的にも、「図を見ればなんとなく分かる」ことは短期的な便益を生みますが、
それが共通言語としての再現性を欠くと、長期的には以下のような歪みが生じます。
- 問題集AとBで記号や矢印の意味が異なる
- 教師や著者ごとに**「自分流」表現**が混在
- 学習者が本来の数量モデル(保存則・確率分布)にたどり着けない
このような「属人的な図解のデファクト化」は、
学問的基盤の劣化と教育のローカル化を招きやすいです。
3. なぜ定着したのか(社会的側面)
SPIや就職適性試験の世界では、
- 問題の標準化
- 短時間での判断力測定
が目的であり、理論の厳密さよりも「実務的な分かりやすさ」が優先されます。
このため、**“理論を捨ててでも直感的に描ける図”**が選ばれたとも言えます。
教育現場や出版社側から見れば、それは“合理化”ですが、
理論側から見れば“体系の断裂”です。
4. 対応策:どう扱うべきか
- 「実用記号」として限定的に教える
→「この図は便利な“計算補助ツール”であり、理論的厳密性は保証しない」と明示する。 - 理論的対応物を紹介する
→ 例:「この図は、数学的には“フローネットワーク”に対応している」と補足。 - 記号体系を統一・定義する
→ 教材内で“矢印=比率を掛ける”“ノード=流量の保存点”などと明文化。 - 学問的翻訳を促す訓練
→ “この図を線形方程式系で表せ”など、理論側に戻す練習を行う。
🔍まとめ
一般の学問の領域から外れた図を、デファクトのように使うことは、
理解の効率を上げる短期的利点と、
理論的基盤を損なう長期的リスクの両方を伴います。
便利な道具であることを否定する必要はありませんが、
**“これは数学ではなく表記上の便法だ”**という一線を明示し、
学問体系との橋渡しを行うことが、教育者・編集者側の責任と言えるでしょう。
たとえ話にしてみたよ
むかしむかし——。
世界の根底には、グラフ理論という神の法則がありました。
神は頂点と辺を創り、すべての流れを数理的に支配しました。
流れは保存され、道は有向に、重みには意味がありました。
それは完全な秩序であり、どの頂点も無駄なく因果で結ばれていました。
やがてその世界に、人間が生まれました。
人間は神の創った法則を見上げながら、
「なんて複雑なんだ、これでは試験で時間が足りない」と嘆きました。
そこで人間は、自分たちの理解のために
“模造の世界”——すなわち SPIの流通図——を描きました。
そこでは流れは単純な比率で示され、
矢印はただの「かけ算の道具」として並べられました。
保存も、最短経路も、次数も存在しない。
けれど、彼らにとっては便利で分かりやすい小さな宇宙でした。
⚡神の視点:理の外に生まれた模造物
神はその様子を天上から見下ろして言いました。
「彼らは私の世界を模倣しているが、因果を削り、法則を抜いた。
だが、それでも“流れ”を感じ取ろうとしている……。
ならば、それもまた人間らしい創造だ。」
神は怒りませんでした。
ただ、こうも言いました。
「だが忘れるな。
模造はあくまで模造。
そこには“整合性”という魂が宿らぬ。
理を離れた図は、やがて矛盾を孕み、
それを真理と信じた者を惑わせるであろう。」
🧠人間の視点:祈りとしての図
人間たちは、その言葉を聞いてもなお図を描き続けました。
なぜなら、その図は彼らの理解の祈りの形だったからです。
本物の理(グラフ理論)は、神の目には明快でも、
人間の頭には遠すぎた。
だから彼らは「便利さ」という祭壇を築き、
「計算のしやすさ」という小さな灯火を灯しました。
そして言いました。
「この図は真理そのものではない。
だが、真理に向かう階段のひとつだ。」
🌌結び:神と人の協奏
こうして世界は二層になりました。
上層には、神の完璧な秩序=グラフ理論の世界。
下層には、人間の不完全な模造=SPIの図。
神は完全さを尊び、
人は不完全さの中で学ぶ。
そしてときどき、ある者は気づくのです。
「この“SPIの矢印”も、実は神の世界の影ではないか?」
そのとき初めて、
模造の図は祈りを超えて、真理への入口になるのです。
ゲーム音楽とMIDI
✅ MIDIが昔ゲームで使われていた背景
- MIDIは「音そのもの(波形)」ではなく、「演奏(どの音をいつ出すか・どの楽器で演奏するか)」を記録するフォーマットです。 ウィキペディア+2doomworld.com+2
- より具体的には、ゲームのBGMや効果音が比較的軽量に済むよう、「MIDI+音源(シンセサイザー/サウンドモジュール)」という構成が使われてきました。
- 特にPCゲームやDOS時代、CD-ROMが主流になる以前は、ストレージ・メモリ/音声再生能力の制限があったため、MIDIは軽量な音楽方式としてメリットがありました。 vogons.org+1
❌ MIDIが最近のゲームであまり使われなくなった理由
以下が主な理由です:
- 録音されたオーディオ(PCM/ストリーミング音声)の品質・容量コストが下がった
→ 昔は「演奏データ+音源」で済ましたが、今は「録音された音楽トラック(オーケストラ/ライブ演奏)+高ビットレート音声データ」が技術的に可能/安価になったため、MIDI方式の “シンセ演奏っぽさ” が相対的に見劣りするようになっています。
→ 実際「CD-ROM時代になり、MIDIの利点(低データ量)が薄れた」という議論があります。 vogons.org+1 - 音源の再生環境にばらつきがある/制御が難しい
→ MIDIの場合「どの楽器音源/どの音色セット(サウンドバンク)」を使うかで音質・演奏感が大きく変わります。ゲーム機・PC・サウンドカードごとに異なる音源が使われていると、ユーザー体験が揃いません。
→ 最近はゲーム開発者側が「何を再生しても同じ音で出る」ことを重視するため、録音された音をそのまま流す方式が好まれています。 - 制作ワークフロー/サウンドデザインの変化
→ ゲーム音楽・サウンドデザインは「DAW(Digital Audio Workstation)で録音/ミックス/マスタリング」→「ゲームに組み込む」という流れが強くなっています。MIDI形式だけで終わらせるには限界が出てきています。
→ また、音楽が映画・ドラマクラスのクオリティを求められるようになったことも影響しています。 - プラットフォーム・音声再生技術の進化
→ ハードウェア/ソフトウェアともに「ストリーミング音声」「マルチチャンネル(5.1ch/7.1ch/立体音響)」「高サンプリングレート」「圧縮音声」などが使えるようになってきたため、MIDIのみでは対応しづらい部分があります。
→ 例えば、環境音・ボイス・音楽が一体化して動的に切り替わるようなゲームでは、単純なMIDIではなく「音声トラック+リアルタイム音響処理」のほうが運用が楽になります。
🧐 例外・補足
- ただし、MIDIが完全に無くなったわけではありません。例えばリズムゲームや音楽ゲームの内部データフォーマットとして「演奏データ(MIDI相当)」を使い、そこに録音音源を組み合わせるというケースもあります。 Sonic Bloom
- また、MIDIが「音楽データそのもの」ではなく「演奏コントロールデータ」として有用な場面も残っています。
- さらに、規模の小さいインディーゲームやレトロ風のゲームでは、あえてMIDIやモジュール音源(昔のスタイル)を使うことで「雰囲気」を出す選択もあります。
じゃぁ、MIDIはどんな風に減っていった?
📌 例1:PCゲームでのMIDIの利用と減少
- PC用ゲームでは、1980~90年代にサウンドカード(例:Roland MT-32/SC-55等)と組み合わせて、MIDI演奏+音源という方式が普通でした。 The MIDI Music Adventure Show!+1
- たとえば、1990年代後半~2000年代初頭になると、ハードディスク容量や音声再生能力が向上し、録音されたPCM音源(WAV/MP3)をそのまま使う方式が普及し始めます。 スウィートウォーター+1
- そのため「MIDI形式で作曲・演奏・再生」していたゲーム音楽が、徐々に「録音されたトラックをストリーミング再生」する形に移行しました。
📌 例2:家庭用ゲーム機/コンソールでの状況
- コンソールゲーム(例:プレステ/Xbox世代)では、開発者が「再生される音が必ず同じように聞こえる」ことを重要視するようになりました。
- そのため、MIDI+ユーザー音源依存という方式ではなく、定められたサウンドバンク/録音済み素材を使う方式にシフトしました。
- さらに、オーケストラ録音やライブ演奏を音トラック化して使うケース(例えば ゼルダの伝説 スカイウォードソード のサウンドトラックでオーケストラ録音を取り入れた話)も出てきています。 WIRED
📌 例3:具体的な転換点・傾向
- 開発・制作側が「本物の楽器を録音」できる資源(予算・技術)が整ってきた 2000年代中盤〜後半 が、MIDI利用から録音トラックへの移行の大きな分岐点と見なせます。
- たとえば記事に「1986年頃から、作曲者はMIDIプログラミングに頼らず、リアルタイムで演奏・録音できるようになった」と書かれています。 スウィートウォーター
ゲームそのもので見てみよう
🎮 タイトル例:MIDIから録音音源への移行事例
【1】Final Fantasy VII(PS1/1997)






- 開発:Square (現スクウェア・エニックス)
- 音楽:植松伸夫
- 音楽フォーマットの特徴:
この作品ではリアル録音音源ではなく、**サンプリング音源+演奏データ(MIDI的/シークエンス的)**を使用していました。“The media capabilities of the console allowed for pre-recorded Linear PCM … but it was decided to generate the music in real time on the console instead, using samples and note data.”
— Wikipedia: Music of Final Fantasy VII - 解説:音楽ファイル(WAV/MP3)を直接流すストリーミング方式ではなく、演奏情報で音源をリアルタイム再生する方式。容量節約とハードの制約に対応した代表例。
【2】Unreal(PC/1998)






- 開発:Epic Games / Digital Extremes
- 音楽フォーマットの特徴:
「モジュール音楽(tracker形式)+PCMサンプルの組み合わせ」で構成。MIDIではないが、演奏データ+音源サンプルという仕組みは近い。“Module music … used stored PCM sound samples of musical instruments sequenced together to produce music.”
— Wikipedia: Unreal (1998 video game) - 解説:MIDIと同様にディスク容量を抑えつつ音楽を生成する方式。録音済み音声ではない「中間世代」のフォーマットであり、ストリーミング音源時代への橋渡しとなった。
📊 移行の潮流まとめ
- 1990年代前半〜中期:MIDI/演奏データ+音源(サンプリング)方式が主流。 Gearspace+1
- 1999〜2002年あたり:録音音源(スタジオ録音/オーケストラ/チャントなど)をゲーム音楽に本格導入した作品が増加。
- 2000年代中盤以降:ほぼすべてのAAAゲームが録音音声ベースを採用、「MIDI形式」はインディー/レトロ風など特殊用途に限定されるようになりました。
時期 | 主流フォーマット | 備考 |
|---|---|---|
~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タイトルで録音音源使用。 |
💬 解説
- 技術的背景:CD-ROM→DVD→Blu-rayとメディア容量が爆発的に増えたことで、もはや「軽量なMIDIデータ」で節約する必要がなくなりました。
- 制作ワークフロー:DAW(Cubase, Logic, ProToolsなど)で録音→ミックス→マスタリング→ゲーム実装、という映画音楽と同様の流れに統一。
- 残存用途:MIDIは“音楽”ではなく“演奏制御(リズム・同期・譜面)”としてのみ利用。例:シアトリズムFF、音ゲー系アプリ。
現代の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)
- 開発元:CRI・ミドルウェア(日本)
- 代表作:『モンスターハンターシリーズ』『ペルソナ5』『FFXV(日本版音声)』など
- 特徴:
- 独自コーデック HCA/HCA-MX による高圧縮・高音質(MP3より低負荷)
- サウンドキューシステム(キューシート単位で管理)
- ゲーム機・スマホ・アーケードすべて対応
- 教育的ポイント:
- “ADX2 Authoring Tool”でイベントドリブンなサウンド設計(ループ、クロスフェード、SE管理)をGUIで行える。
- Unity/Unreal統合が容易。国産タイトルに最も多い。
🎚️ ② FMOD(Firelight Technologies, オーストラリア)
- 代表作:『Resident Evil 4 Remake』『Celeste』『Forza Horizon』など
- 特徴:
- リアルタイムミキシング/DSP(Digital Signal Processing) 機能が強力。
- Adaptive Music(動的BGM) の実装が簡単。プレイヤーの状況で音楽をブレンド可能。
- OGG/WAV/MP3対応、低レイテンシ。
- 教育的ポイント:
- 無料版(非商用)でUnity・Unrealに統合可能。
- “イベント駆動型オーディオ”の教材として最適。
- 音量/フィルタ/ピッチをリアルタイム制御でき、AIや物理と連動可能。
🎚️ ③ Wwise(Audiokinetic, カナダ)
- 代表作:『God of War』『Assassin’s Creed』『Fortnite』『Genshin Impact』
- 特徴:
- RTPC(Real-Time Parameter Control) による物理連動サウンド。
- BGMや環境音をシーン条件に応じて動的ミキシング。
- HDRオーディオ(音量レンジ自動調整)など最新機能搭載。
- 教育的ポイント:
- プロ向けAAA標準。
- ゲーム開発科・サウンドコースでの「インタラクティブサウンド演習」に最適。
- Unity/Unreal連携が標準化しており、ボリューム・ピッチ・フィルタをコードレス制御可能。
🔊 補足:フォーマット別の特徴まとめ
形式 | 種別 | 主な用途 | 長所 | 短所 |
|---|---|---|---|---|
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立体音響) |
📘 教育応用のヒント:
- 授業での演習テーマ例:「FMODでプレイヤー距離に応じてBGMフェードを制御」「ADX2でループBGMとSEをキューで管理」
- Moodle課題テーマ:「CRIWARE・FMOD・Wwiseの比較レポート(機能・ライセンス・使用例)」
- 発展課題:「3Dサウンド空間をFMODまたはWwiseで設計する」
🎮 ゲーム制作計画書(エンジニア志望向け)評価項目 詳細説明
説明
(1) コンセプトの明確さ
- ゲームの目的やテーマが、一文で明確に伝わるか。
- 「なぜこのゲームを作るのか」が論理的に説明されているか。
- 他の作品との差別化や、独自の視点・体験が感じられるか。
- 技術的にどんな体験を支えるつもりなのかが読み取れるか。
(2) ゲームシステム構成
- ルール、操作、勝敗条件などが整理され、誰が読んでも理解できる構成か。
- 図やフローチャートなどで、プレイの流れが視覚的に説明されているか。
- プレイヤーの行動と結果のつながり(入力→反応→報酬)が明確か。
- 実装担当者やデザイナーにも共有しやすい構成になっているか。
(3) 技術構成・アーキテクチャ
- 使用エンジン・自作システム・ライブラリの関係性が整理されているか。
- ゲームを構成するクラスやモジュールの役割分担が理解できるか。
- 「どの部分を自作したのか」「どこを工夫したのか」が明示されているか。
- 開発者としての設計力やコード構成の理解を示しているか。
(4) 図表・資料構成力
- スライドや図のレイアウトが整っており、視覚的に読みやすいか。
- 各スライドの情報量が適切で、説明順序に一貫性があるか。
- 図やスクリーンショットが、技術や仕様の説明と一致しているか。
- 教師・審査者・仲間が見ても「分かりやすい」と感じる完成度か。
(5) 技術的挑戦度・創意工夫
- 既存の教材や一般的な機能を超えて、新しい技術に挑戦しているか。
- 実装面での工夫(最適化、エフェクト、物理、AIなど)が見られるか。
- 「これまでできなかったことを実現したい」という姿勢があるか。
- 学んだ知識を応用して、自分なりの解決策を提案しているか。
(6) スケジュールと実行計画
- 開発スケジュールが現実的か(期間・人員・機能バランス)。
- α版・β版などフェーズごとの目標が具体的に設定されているか。
- 技術課題に対して段階的な対処計画が組まれているか。
- チームの場合、役割と進行管理が明確に分担されているか。
(7) 技術検証・プロトタイピング計画
- 開発前に「どの技術を試すべきか」を具体的に挙げているか。
- 検証項目(描画、物理、AI、ネットワークなど)が整理されているか。
- 試作→評価→改善の流れを意識しているか。
- 開発のリスクを早期に発見・軽減する意識があるか。
(8) 面白そう?(魅力設計・体験価値)
- プレイヤーが「遊んでみたい」と感じるワクワク感があるか。
- 見た目・演出・操作感・世界観の一貫性が感じられるか。
- 技術面と体験面の両方から魅力を作れているか。
- コンセプトとゲーム体験が一致しているか。
ゲーム会社に応募した時何見られるんだ?
1. 動画構成(見せ方)の評価
採用側は動画全編を丁寧には見ません。
多くは以下の流れになります:
- 最初の10秒で「面白そうか / センスあるか」を判定
- 1分程度で「技術力があるか」を判断
- 最後まで視聴するのは高評価時のみ
評価されやすい構成:
- 最初にタイトル・コンセプト明示
- 実際のプレイ動画がメイン
- テキスト字幕で開発内容を補足
- 動作が見やすいカメラ / UI
マイナス評価:
- 作品の説明が長く、映像が出ない
- 文字が小さい・速すぎる
- 見せたいポイントが不明瞭
2. 技術アピール度の評価
ゲーム会社が知りたいポイントは
- どこまで自作?
- ライブラリは?
- エンジンは?
- アートは自作?
- チーム制作か個人?
- 実装難易度は?
- ゲームとして成立しているか?
高評価される書き方例:
・ゲームエンジン:自作(DX11ベース)
・スキニング:CPU / GPU対応
・モデル読み込み:ufbx利用
・地形:自前生成(法線計算あり)
・影:丸影を独立クラスで実装 ← 重要3. クリエイティブ・デザイン評価
採用側は以下を見ることが多い:
- 絵作りのセンス
- UIのバランス
- 色と配置
- キャラの魅力・世界観
- 画面レイアウト
- 可読性
- フォーカスポイント
- ゲームとしての面白さの匂い
4. 就活動画として強いか・弱いか
ゲーム業界向けの評価観点:
観点 | 求められるもの | 備考 |
|---|---|---|
作品完成度 | バグ少・動作安定 | 企業は安定動作を見る |
技術力 | 内部構造の理解 | 黙っていても伝わる情報量 |
美術的センス | 視覚的訴求力 | 画面に気持ちよさがある |
UI/UX | 遊びやすさ | プレイヤー視点 |
ゲームデザイン | 面白くできる人か | ただ動くだけはNG |
プレゼン能力 | 説明の明瞭さ | チーム内で会話できるか |
1. プログラマー応募として強いアピール点になる要素
A. 自作フレームワーク+DxLib
企業の評価:
- Unityではなく低レベル環境で作れる = 基礎能力が高い
- メモリ管理やパフォーマンス感覚がある
- ゲームループや描画制御を正しく理解している
- ライブラリの内部処理に意識が届いている
この時点で、多くの応募学生との差別化になります。
2. アピールしたい項目に対する、企業側の評価視点
A. カメラワーク
企業が見たいのは:
- カメラがキャラを追尾するだけか?
- 画面の見やすさ、プレイしやすさに貢献しているか?
- 視界確保が適切か?
- 曲線的な補間(Lerp/Slerp)があるか?
- 障害物による視界遮断対策があるか?(RayCast補正)
- カメラ揺れ・演出制御があるか?
- プレイヤーの入力に応じた最適画角変更があるか?
さらに評価される書き方例:
・TPSカメラにおいて、RPG-7カメラ問題を回避するため
RayCastで視界遮断判定を行い、距離自動補正を実装
・ターゲット注視時はlook-at制御による滑らかな補間B. 敵の移動アルゴリズム
採用側の評価ポイント:
- 単純な追尾か?
- プレイヤー位置予測をしているか?
- A* や Dijkstra を使っているか?
- 回避行動 / 包囲行動はあるか?
- 目的関数で行動選択しているか?
- ステートマシン?
- 振る舞い木(ビヘイビアツリー)?
高評価される言い方:
・敵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. あなたへの最終アドバイス
あなたの動画は
プログラマーの強みを映像で伝える必要がある
つまり:
- 見た目の派手さ → 重要ではない
- 機能の量 → 厳密にはあまり重要ではない
- 内部の理解 → とても重要
- 説明能力 → 極めて重要
そして最終的に評価されるのは:
・リアルタイム処理の理解
・ゲーム数学の応用
・最適化への感覚
・堅実なプログラム設計