• ゲーム
  • Industry
  • リソース
  • コミュニティ
  • 学習
  • サポート
開発
Unityエンジン
任意のプラットフォーム向けに2Dおよび3Dゲームを構築
ダウンロードプランと価格
収益化
アプリ内課金(IAP)
ストア全体でIAPを発見し、管理する
Mediation
収益を最大化し、マネタイズを最適化する
Ad Quality
アプリのユーザーエクスペリエンスを保護する
Tapjoy
長期的なユーザーの忠誠心を構築する
すべてのマネタイズ製品
詳しく見る
詳しく見る
発見され、モバイルユーザーを獲得する
UnityベクターAI
プレイヤーを適切なゲームに接続する
Auraのオンデバイス広告
ピークエンゲージメント時にデバイス上のユーザーにリーチする
すべての成長製品
活用事例
3Dコラボレーション
リアルタイムで3Dプロジェクトを構築およびレビューする
没入型トレーニング
没入型環境でのトレーニング
顧客体験
インタラクティブな3D体験を作成する
すべての業界ソリューション
業界
製造業
運用の卓越性を達成する
小売
店内体験をオンライン体験に変換する
自動車
革新と車内体験を高める
全業界
技術ライブラリ
ドキュメント
公式ユーザーマニュアルとAPIリファレンス
開発者ツール
リリースバージョンと問題追跡
ロードマップ
今後の機能をレビューする
用語集
技術用語のライブラリ
インサイト
ケーススタディ
実際の成功事例
ベストプラクティスガイド
専門家のヒントとコツ
すべてのリソース
新機能
ブログ
更新情報、情報、技術的ヒント
お知らせ
ニュース、ストーリー、プレスセンター
コミュニティハブ
ディスカッション
議論、問題解決、つながる
イベント
グローバルおよびローカルイベント
コミュニティストーリー
Made with Unity
Unityクリエイターの紹介
ライブストリーム
開発者、クリエイター、インサイダーに参加する
Unity Awards
世界中のUnityクリエイターを祝う
すべてのレベルに対応
Unity Learn
無料でUnityスキルをマスターする
プロフェッショナルトレーニング
Unityトレーナーでチームをレベルアップ
Unity初心者向け
スタートガイド
学習を開始しましょう
Unityエッセンシャルパスウェイ
Unity は初めてですか?旅を始めましょう
ハウツーガイド
実用的なヒントとベストプラクティス
教育
学生向け
キャリアをスタートさせる
教育者向け
教育を大幅に強化
教育機関向けライセンス
Unityの力をあなたの機関に持ち込む
認定教材
Unityのマスタリーを証明する
サポートオプション
ヘルプを得る
Unityで成功するためのサポート
Success Plan
専門的なサポートで目標を早く達成する
FAQ
よくある質問への回答
お問い合わせ
私たちのチームに連絡する
プランと価格
言語設定
  • English
  • Deutsch
  • 日本語
  • Français
  • Português
  • 中文
  • Español
  • Русский
  • 한국어
ソーシャル
通貨
購入
  • プロダクト
  • Unity Ads
  • サブスクリプション
  • Unity Asset Store
  • リセラー
教育
  • 学生
  • 教育関係者
  • 教育機関
  • 認定資格試験
  • 学ぶ
  • スキル開発プログラム
ダウンロード
  • Unity Hub
  • ダウンロードアーカイブ
  • ベータプログラム
Unity Labs
  • ラボ
  • 研究論文
リソース
  • Learn プラットフォーム
  • コミュニティ
  • ドキュメント
  • Unity QA
  • FAQ
  • サービスのステータス
  • ケーススタディ
  • Made with Unity
Unity
  • 当社について
  • ニュースレター
  • ブログ
  • イベント
  • キャリア
  • ヘルプ
  • プレス
  • パートナー
  • 投資家
  • アフィリエイト
  • セキュリティ
  • ソーシャルインパクト
  • インクルージョンとダイバーシティ
  • お問い合わせ
Copyright © 2025 Unity Technologies
  • 法規事項
  • プライバシーポリシー
  • クッキーについて
  • 私の個人情報を販売または共有しないでください

「Unity」の名称、Unity のロゴ、およびその他の Unity の商標は、米国およびその他の国における Unity Technologies またはその関係会社の商標または登録商標です(詳しくはこちら)。その他の名称またはブランドは該当する所有者の商標です。

Hero background image
Last updated January 2020, 10 min. read

ScriptableObject を使用してゲームを構築する 3 つの方法

このウェブページは、お客様の便宜のために機械翻訳されたものです。翻訳されたコンテンツの正確性や信頼性は保証いたしかねます。翻訳されたコンテンツの正確性について疑問をお持ちの場合は、ウェブページの公式な英語版をご覧ください。
ここをクリックしてください。

このページから得られるもの:ゲームコードを簡単に変更し、デバッグできるように、スクリプタブルオブジェクトを使って設計するためのヒント。

これらのヒントは、ライアン・ヒップル、シェル・ゲームズの主任エンジニアからのもので、スクリプタブルオブジェクトを使用してゲームを設計する上級者向けの経験があります。ライアンのスクリプタブルオブジェクトに関するユナイトトークはこちらで視聴できます。また、スクリプタブルオブジェクトの素晴らしい入門セッションを見ていただくことをお勧めします。

  • ScriptableObject とは?
  • ゲームエンジニアリングの 3 つの柱
  • 変数の設計
  • 例:プレイヤーのヒットポイント
  • イベントの設計
  • コード例:GameEvent ScriptableObject
  • コード例:GameEventListener
  • プレイヤーの死を処理するイベントシステム
  • その他システムの設計

ScriptableObject とは?

スクリプタブルオブジェクトは、スクリプトインスタンスとは独立して、大量の共有データを保存できるシリアライズ可能なUnityクラスです。ScriptableObject を使用すると、変更やデバッグの管理が容易になります。ゲーム内の異なるシステム間で柔軟なコミュニケーションを構築できるため、制作中にそれらを変更・適応しやすく、コンポーネントを再利用することができます。

ゲームエンジニアリングの 3 つの柱

モジュール設計を使用する:

  • 互いに直接依存するシステムを作成しないようにしましょう。例えば、インベントリシステムはゲーム内の他のシステムと通信できる必要がありますが、ハードリファレンスを作成したくないため、異なる構成や関係にシステムを再構成するのが難しくなります。
  • シーンをクリーンスレートとして作成します: シーン間に一時的なデータが存在しないようにします。シーンを切り替えるたびに、まったく新しくロードが実行されるようにしてください。これにより、他のシーンには存在しないユニークな動作を持つシーンを作成でき、ハックを行う必要がなくなります。
  • プレハブを独立して機能するように設定します。できる限りシーン内にドラッグする各プレハブには、ひとつひとつ、その内部に機能を持たせるようにします。こうすることで、シーンがプレハブのリストとなり、プレハブに個々の機能が含まれるようになるため、大規模なチームでソース管理を行いやすくなります。その結果、ほとんどのチェックインがプレハブレベルで行われ、シーン内の競合が少なくなります。
  • 各コンポーネントを単一の問題を解決することに集中させます。これにより、複数のコンポーネントを組み合わせて新しいものを構築しやすくなります。

パーツを簡単に変更・編集できるようにする:

  • ゲームの可能な限り多くをデータ駆動型にします。ゲームシステムをデータを指示として処理する機械のように設計すると、実行中でも効率的にゲームを変更できます。
  • システムができるだけモジュール式でコンポーネントベースになるように設定されていると、アーティストやデザイナーにとっても編集が容易になります。デザイナーが明示的な機能を求めることなくゲーム内で物事を組み合わせることができる場合(それぞれが一つのことだけを行う小さなコンポーネントを実装するおかげで)、彼らは新しいゲームプレイやメカニクスを見つけるために異なる方法でそのようなコンポーネントを組み合わせることができます。ライアンは、彼のチームがゲームで取り組んできた最もクールな機能のいくつかはこのプロセスから生まれたものであり、彼が「エマージェントデザイン」と呼ぶものです。
  • チームがランタイムでゲームを変更できることが重要です。ランタイムでゲームを変更できるほど、バランスや値を見つけることができ、もしランタイム状態をScriptable Objectsのように保存できるなら、素晴らしい状況にいます。

デバッグを簡単にする:

これは最初の二つのサブピラーです。ゲームをモジュール化するほど、ひとつひとつのモジュールを検証しやすくなります。ゲームがより編集しやすければ(つまり、独自のインスペクタービューを備えている機能が多ければ)、デバッグが楽になります。Inspectorでデバッグ状態を表示できることを確認し、デバッグ方法の計画がない限り、機能が完了したと考えないでください。

変数の設計

ScriptableObjectsを使って構築できる最もシンプルなものの一つは、自己完結型のアセットベースの変数です。以下はFloatVariableの例ですが、これは他のシリアライズ可能な型にも拡張されます。

チームの誰もが、どれだけ技術的であっても、新しいFloatVariableアセットを作成することで新しいゲーム変数を定義できます。任意のMonoBehaviourまたはScriptableObjectは、この新しい共有値を参照するためにpublic floatの代わりにpublic FloatVariableを使用できます。

さらに良いことに、あるMonoBehaviourがFloatVariableの値を変更すると、他のMonoBehaviourもその変更を見ることができます。これにより、互いに参照を必要としないシステム間のメッセージングレイヤーが作成されます。

例:プレイヤーのヒットポイント

例:プレイヤーのヒットポイント

これの使用例は、プレイヤーのヒットポイント(HP)です。ローカルプレイヤーが 1 人のゲームで、PlayerHP という名前の FloatVariable をプレイヤーの HP として設定できます。プレイヤーがダメージを受けるとPlayerHPから減算され、プレイヤーが回復するとPlayerHPに加算されます。

シーン内に健康バーのPrefabを想像してみてください。HP バーは PlayerHP 変数を監視し、その表示を更新します。コードを変えることなく、簡単に別の変数(PlayerMP 変数など)を監視するよう設定することも可能です。健康バーはシーン内のプレイヤーについて何も知りません。ただ、プレイヤーが書き込むのと同じ変数から読み取るだけです。

このように設定されると、PlayerHPを監視するためにさらに多くのものを追加するのが簡単です。音楽システムは、PlayerHPが低下すると変化し、敵はプレイヤーが弱いと知ると攻撃パターンを変えることができ、画面空間効果は次の攻撃の危険性を強調することができます。ここで鍵となるのは、Player スクリプトはこれらのシステムにはメッセージを送信していないということで、言うなればこれらのシステムはプレイヤーゲームオブジェクトを認識している必要がない、ということになります。ゲームが実行中のときにInspectorに入ってPlayerHPの値を変更してテストすることもできます。

FloatVariableの値を編集する際には、ScriptableObjectに保存されている値を変更しないために、データをランタイム値にコピーするのが良いアイデアかもしれません。これを行うと、MonoBehaviourはディスクに保存されているInitialValueを編集しないようにRuntimeValueにアクセスする必要があります。

イベントの設計

Ryanのお気に入りの機能の1つは、ScriptableObjectの上に構築するイベントシステムです。イベントアーキテクチャを使うと、互いを直接認識しないシステム間でメッセージを送信させることで、コードをモジュール化しやすくなります。これにより、更新ループで常に監視することなく、状態の変化に応じて反応することができます。

以下のコード例は、GameEvent ScriptableObjectとGameEventListener MonoBehaviourの2つの部分からなるイベントシステムに由来しています。デザイナーは、重要な送信可能メッセージを表す GameEvent をプロジェクト内にいくつでも作成できます。GameEventListenerは特定のGameEventが発生するのを待ち、UnityEventを呼び出すことで応答します(これは真のイベントではなく、シリアライズされた関数呼び出しのようなものです)。

コード例:GameEvent ScriptableObject

GameEvent ScriptableObject:

コード例:GameEventListener

GameEventListener:

プレイヤーの死を処理するイベントシステム

プレイヤーの死を処理するイベントシステム

これの例は、ゲームにおけるプレイヤーの死亡を処理することです。この部分には実行内容の大幅な変更が伴う可能性がありますが、すべてのロジックをコーディングする場所を決めるのが難しい場合があります。Player スクリプトでゲームオーバーの UI をトリガーして音楽を変更すべき?プレイヤーがまだ生きているかどうかを敵に毎フレームチェックさせたほうが良いか?イベントシステムは、このような問題のある依存関係を回避することを可能にします。

プレイヤーが死亡すると、PlayerスクリプトはOnPlayerDiedイベントでRaiseを呼び出します。Player スクリプトは単純なブロードキャストであるため、どのシステムが Player スクリプトを待ち受けているかは認識しません。Game Over UI は OnPlayerDied イベントをリッスンし、アニメーション化を開始します。カメラスクリプトは OnPlayerDied をリッスンして黒へのフェードを開始し、音楽システムは音楽変更のレスポンスを返します。各敵もOnPlayerDiedをリスニングし、挑発アニメーションをトリガーしたり、アイドル動作に戻るための状態変更を行うことができます。

このパターンにより、プレイヤーの死亡に対する新しい反応を追加するのが非常に簡単になります。さらに、InspectorのボタンやテストコードからイベントでRaiseを呼び出すことで、プレイヤーの死亡に対する反応をテストするのが簡単です。

Schell Gamesで構築されたイベントシステムは、はるかに複雑なものに成長し、データを渡したり、自動生成された型を許可する機能を持っています。この例は、彼らが今日使用しているものの出発点でした。

その他システムの設計

Scriptable Objectsは単なるデータである必要はありません。MonoBehaviour に実装しているシステムを例にとり、その実装を ScriptableObject に移すことができるか検討してみてください。DontDestroyOnLoad MonoBehaviourにInventoryManagerを持つ代わりに、ScriptableObjectに置いてみてください。

シーンに結びついていないため、Transformはなく、Update関数も取得しませんが、特別な初期化なしでシーンの読み込み間で状態を維持します。インベントリシステムのオブジェクトへのアクセスにスクリプトが必要な場合は、シングルトンの代わりに、public な参照を使用してください。これにより、シングルトンを使用している場合よりも、テストインベントリやチュートリアルインベントリを簡単にスワップできます。

ここでは、プレイヤースクリプトがインベントリシステムへの参照を取得することを想像できます。プレイヤーがスポーンされるタイミングで、Player スクリプトで所有しているすべてのオブジェクトを Inventory に要求し、装備をスポーンできます。装備UIもインベントリを参照し、アイテムをループして描画するものを決定できます。