質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

パラメータ

関数やプログラム実行時に与える設定値をパラメータと呼びます。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

8681閲覧

ゲーム開始時にScriptableObjectの初期化関数を実行する方法

segnana

総合スコア28

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

パラメータ

関数やプログラム実行時に与える設定値をパラメータと呼びます。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2020/07/12 06:15

こんにちは。Unity初心者です。タイトルの通りなのですが、ゲーム開始時にScriptableObjectの初期化関数を実行したいのですがどうすればよいでしょうか?

ScriptableObjectはパラメータを保存することができますが、たとえばですがキャラクターの攻撃力をHPの1/10にしたいなど、パラメータそのものではなくパラメータを決める規則があるとします。その場合ゲーム開始時にパラメータを計算し、そのあとずっと求まった値を使いまわしたいと思うのですが、どうすればよいでしょうか?

ScriptableObjectのAwake関数がありますが、調べてみるとどうやらゲーム開始時に実行されるわけではないようなのです。以下のようにAwake関数を書いても、攻撃力はHPの1/10にはなりませんし、コンソール出力もありません。

C#

1public class Data : ScriptableObject 2{ 3 public string name; 4 public int HP; 5 public int power; 6 7  public void Awake(){ 8 power = HP/10; 9 Debug.Log("awake"); 10 } 11} 

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IShix

2020/07/12 11:34

DataクラスはInspectorからアタッチする想定ですか?
segnana

2020/07/12 11:51

返信ありがとうございます。 そうです。[CreateAssetMenu(menuName = "Param/Data")]をスクリプトに書いて右クリック→Crate→Param→DataでAssetを生成し、それをGameObjectにアタッチしています。
guest

回答2

0

ベストアンサー

ScriptableObjectAwakeOnEnableMonoBehaviourAwakeOnEnableとでまったく異なるタイミングで走るのでまずその説明をさせてください。

MonoBehaviourとScriptableObject イベント関数の違い

ヒエラルキーに設置しているオブジェクト(MonoBehaviour)とアタッチしているScriptableObjectはゲーム(ランタイム)開始時に自動的に生成されると思ってください。

▼ MonoBehaviour
[Awake] ゲーム(ランタイム)中に生成された時1度だけ走る
[OnEnable] ゲーム(ランタイム)中に表示された時毎回走る(生成時やSetActive(true)した時)

▼ ScriptableObject
[Awake] 生成された時走る(クラスに[CreateAssetMenu]アトリビュートをアタッチし右クリック > Create > スクリプト名で生成する時や既に存在するScriptableObjectを複製した時スクリプトを修正した時)
[OnEnable] ゲーム(ランタイム)中初めて読み込まれた時に1度だけ走る

ScriptableObjectAwakeのみランタイムは関係ありません。
生成後Project上に残り続けるデータだからです。メソッド名が同じなので混乱しますね。違う名前にして欲しかったです。

###今回の用件に合いそうなのはScriptableObject.OnEnable()
Awake()OnEnable()に書き換えれば求める挙動になります。1つ訂正する点があるとすればpowerScriptableObjectに書き込まれてしまうので下記のようにすると良いです。

C#

1using System; 2using UnityEngine; 3 4// 右クリックでScriptableObjectを生成できるようにする 5[CreateAssetMenu(menuName = "ScriptableObject/Data")] 6public class Data : ScriptableObject 7{ 8 public string name; 9 public int HP; 10 11 // この変数は保存されないようにアトリビュートを追加 12 [NonSerialized] public int power; 13 14 public void OnEnable() 15 { 16 power = HP / 10; 17 Debug.Log("awake"); 18 } 19}

イベントの実行順

ヒエラルキーに設置したオブジェクト(MonoBehaviour)とアタッチしているScriptableObjectと想定すると下記の実行順となります。

  1. ScriptableObject.OnEnable()
  2. MonoBehaviour.Awake()
  3. MonoBehaviour.OnEnable()
  4. MonoBehaviour.Start()

今回詳しく解説した理由

今回のpowerは取得タイミングによって値が変わります。
OnEnableが走る前は0を返し、OnEnableが走った後は計算された値を返します。
こういうのをプログラム用語で「副作用がある」と言います。
今回の説明でOnEnablepowerに代入すれば常に計算された値を取得できる事が保証されているのが分かると思います。
特に今回のような戻り値のあるもので副作用がある場合、バグになりやすいので徹底的に問題無いか調査するのをおすすめします。

投稿2020/07/13 07:53

編集2020/07/13 13:35
IShix

総合スコア1724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ScriptableObjectのAwake関数がありますが、調べてみるとどうやらゲーム開始時に実行されるわけではないようなのです。以下のようにAwake関数を書いても、攻撃力はHPの1/10にはなりませんし、コンソール出力もありません。

ScriptableObject には Awake 関数というものはありません。質問のように Awake 関数を書いても、それはただ自分で勝手に宣言した Awake 関数であって、「そのスクリプトコンポーネントがアタッチされた GameObject がシーン上でインスタンス化する時に呼び出される」Awake 関数とはまったく関係ない、自分で勝手に作った単に同じ名前の関数であるだけです。

いつも使っている「勝手に呼び出されてくれる Awake 関数」は MonoBehaviour クラスのメンバ変数であり、MonoBehaviour クラスを継承した「GameObject にアタッチして実行するスクリプト コンポーネント」である場合のみ動作します。

質問へのコメントで「アタッチ」という言葉を使っていますが、それらは「アサイン」ですね。アタッチとは異なる操作です。

ScriptableObjectはパラメータを保存することができますが、たとえばですがキャラクターの攻撃力をHPの1/10にしたいなど、パラメータそのものではなくパラメータを決める規則があるとします。

その場合は、ScriptableObject のアセットからデータを読み込んで値を求めて、MonoBehaviour を継承したクラス内のメンバ変数に保存します。

以下の記事も読むとよいでしょう。ScriptableObject で作ったものは「コンポーネント」ではなく「アセット」です。アセットの設定値(プロパティ)をゲーム実行中にスクリプトから変更してそれをアセットに保存することはできない、というのは Unity 全体で共通のルールです。

  • [【Unity】ScriptableObjectってなんなん? って時に読む記事【解説】 -

セーブデータを記録するのには使えない](https://ekulabo.com/about-scriptable-object#outline__7)

投稿2020/07/12 12:53

bboydaisuke

総合スコア5270

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

bboydaisuke

2020/07/14 15:09 編集

間違いを書いてしまったので訂正します。 > ScriptableObject には Awake 関数というものはありません。... ScriptableObject.Awake はありました。呼ばれるタイミングは ScriptableObject を使って作ったアセットがシーンにロードされた時です。 ref. https://docs.unity3d.com/ScriptReference/ScriptableObject.Awake.html 次のようなコードを書いて soArray に3つの Data アセットをアサインした場合、それぞれの Data オブジェクトに対してオブジェクトがロードされるたびに1度ずつ ScriptableObject.Awake() が呼ばれます。 using UnityEngine; public class SO : MonoBehaviour { Data[] soArray; void Start() { foreach(var so in soArray) { Debug.Log(so.HP); Debug.Log(so.power); } } }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問