- Macで開発しているが、最終的にWindows 11でも動かす必要がある
- 「開発中はMacで、最後にWindows対応すればいい」と考えていたが、それで本当に大丈夫か不安
- Codex/Claudeなどのコーディングエージェントと一緒に開発している
こういう人向けに、「作業時間の9割はMacで開発してよいが、設計だけは最初からWindowsを意識しておく」という考え方と、その具体的なやり方を解説します。

1. なぜ「作業配分」と「設計思想」を分けて考えるのか
クロスプラットフォーム開発でよくある誤解は、「Windows対応は最後にまとめてやればいい」という考え方です。これは半分正しく、半分危険です。
- 作業量としては Macで動作確認しながら開発を進めるのが効率的(正しい)
- 設計としては 「後からWindows対応すればいい」という前提でコードを書くと、Core(中核ロジック)の中にMac前提の処理が染み込んでしまう(危険)
一度Core全体にMac前提のロジックが染み込むと、後からの分離は「全部やり直し」に近い作業量になります。これを避けるために、作業配分は90:10でもよいが、設計上は常に50:50を意識する、という二段構えのルールが有効です。
2. 常設ルールとして最初に決めておくこと
プロジェクトの最初に、次のようなルールをドキュメント(README、CONTRIBUTING、あるいはAIエージェントへのシステムプロンプト)に明記しておきます。
開発・通常検証はmacOSで継続する。ただしWindows 11 x64対応を常に維持し、OS依存実装をCoreへ入れない。Windows固有部分はApp/Rendering層へ隔離する。
このルールには2つの要素があります。
ルールA:CoreにはOS依存コードを入れない
Core(ゲームロジック、データ処理、ビジネスルールなど、アプリの「頭脳」部分)は、macOSでもWindowsでも同じコードがそのまま動くように書きます。ファイルパスの扱い、フォントレンダリング、GPU API呼び出しなど、OSごとに異なる処理はCoreに置きません。
ルールB:OS固有処理はApp/Rendering層に隔離する
画面描画(Metal/DirectX/Vulkanなど)、ファイルダイアログ、ウィンドウ管理といったOS依存の処理は、Coreとは別の層(App層・Rendering層)にまとめます。Coreはこれらの層に対して「描いてほしい内容」や「保存してほしいデータ」を渡すだけで、実際にOSのAPIを呼ぶのはApp/Rendering層の役割です。
この構造は「ポート&アダプター(Ports and Adapters)」や「依存性逆転の原則」と呼ばれる、ソフトウェア設計の定石です。図で表すとこうなります。
┌─────────────────────────────┐
│ Core │ ← OS依存ゼロ。Mac/Windows共通コード
│ (ゲームロジック等) │
└──────────┬──────────────────┘
│ インターフェース越しにやり取り
┌──────────┴──────────────────┐
│ App / Rendering層 │ ← ここにOS依存コードを集約
│ macOS実装 │ Windows実装 │
└──────────────────────────────┘
3. なぜ「設計だけ」50:50が必要なのか
「作業は90:10でいいのに、なぜ設計は50:50で考えるのか」という疑問が出ると思います。理由は、Coreの設計ミスは後から発見しづらく、修正コストが跳ね上がるからです。
具体的に、Coreに入り込みやすい「隠れたOS依存」の例を挙げます。
| 落とし穴 | Macでの挙動 | Windowsでの挙動 |
|---|---|---|
| パス区切り文字 | / | \(/も一部使えるが混在は事故の元) |
| パスの長さ制限 | ほぼ気にしなくていい | 既定で260文字の制限(対策が必要な場合あり) |
| ファイル名の大小文字 | 区別しない場合が多い | 区別しない場合が多いが挙動が微妙に違う |
| 改行コード | LF | CRLFが混在しやすい |
| 文字コードの既定値 | UTF-8前提が多い | Shift-JIS前提のツールが残っている場合あり |
| タイマー精度・スレッド挙動 | 微妙に異なる | 微妙に異なる |
| 日本語入力(IME) | macOS方式 | Windows方式で挙動が異なる |
これらは「明示的にOSのAPIを呼んでいる」わけではないので、レビューで見落とされがちです。だからこそ、Coreを書く瞬間から「これはWindowsでも同じ結果になるか?」と自問する習慣が必要になります。これが「設計は50:50」という意味です。作業時間の配分ではなく、思考の配分の話です。
4. Windows確認のタイミング設計
「最後にまとめて確認する」のではなく、リスクが低いうちに小さく確認するのがコツです。目安として次の3段階がちょうどいいバランスです。
ステップ1:主要マイルストーン通過後に「ビルド確認」
例えば「M7フェーズ終了後」など、大きな機能がひとまとまり終わったタイミングで、一度Windows版をビルドして起動するかどうかだけ確認します。ここではゲームプレイ全体を検証する必要はありません。「コンパイルが通る」「アプリが立ち上がる」の2点が確認できれば十分です。
ステップ2:Rendering層の実装直後に軽く確認
Rendering層(画面描画部分)は、Mac/Windowsの差が最も濃縮される場所です。この部分の実装が一区切りついたら、時間軸のマイルストーンを待たずに一度確認しておくと安全です。
ステップ3:Ver.1完成時に本格検証
全機能が揃った段階で、実際のプレイフローを通した本格的なWindows検証を行います。ここまでに小さな確認を挟んでいれば、この段階で見つかる問題は「細かい調整」程度に収まりやすくなります。
開発開始 ──────────────► M7終了 ──────────► Rendering実装後 ──────────► Ver.1完成
(Mac中心) [起動確認] [軽い動作確認] [本格検証]
5. ルールを「文章」だけでなく「仕組み」で守る
人間が気をつける、AIエージェントに指示する、だけでは長期的にルールが守られなくなることがあります。特に開発が進み、機能が増えてくるとレビューの目も粗くなります。そこで、次の2つの仕組みを併用すると安心です。
CIで継続的にWindowsビルドをチェックする
手動でのWindows起動確認は上記の3段階でよいですが、「コンパイルが通るか」だけは毎回のコミット/プルリクエストで自動チェックしておきます。GitHub Actionsなどで、画面表示なしの状態(ヘッドレスビルド)だけ確認するのは低コストで実現できます。これにより「気づいたら半年前からWindowsビルドが壊れていた」という事故を防げます。
アーキテクチャレベルでの強制(Lint / 静的チェック)
「Coreディレクトリの中でOS固有のAPIやライブラリをimportしたらエラーにする」という仕組みを、Lintや簡単なスクリプトで用意しておくと、ルールが文章だけで終わらずに機械的に守られます。例えば「Core/配下のファイルからWindows.hやMetal関連のimportがあれば警告する」といったチェックです。
6. まとめ:初心者が押さえておくべき3点
- 作業配分と設計思想は別物。開発の9割をMacで行うのは合理的だが、Coreを書く時点では常に「Windowsでも同じ結果になるか」を考える。
- 層を分ける。OS依存コードはApp/Rendering層に隔離し、Coreはプラットフォーム共通のロジックだけを持つ。
- 確認は小さく・早く・複数回。「最後にまとめて」ではなく、「M7終了後の起動確認」「Rendering層実装後の軽い確認」「Ver.1完成時の本格検証」と段階的に行うことで、大きな手戻りを防ぐ。
この3点を最初に決めておくことで、Mac中心の開発スピードを落とさずに、Windows対応で「全部やり直し」になるリスクを大きく減らすことができます。



