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

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

ただいまの
回答率

88.93%

Prefabがデバッグ実行時に更新されてしまう

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,428

eckolo

score 27

前提

アクション系のゲームを作成しています。
Unityはほぼ初心者です。

下記のようなクラス構成において、ClassAをアタッチしたPrefabをあるゲームオブジェクトに記憶させています。

public class ClassA : MonoBehaviour
{
    public ClassC instanceC0 = new ClassC();

    public class ClassB
    {
        public string name = "";
        public ClassC instanceC1 = new ClassC();
    }
    public ClassB instanceB
    {
        get
        {
            return new ClassB
            {
                name = gameObject.name,
                instanceC1 = instanceC0,
            };
        }
        set
        {
            value = value ?? new ClassB();
            instanceC0 = value.instanceC1;
        }
    }
}
public class ClassC : MonoBehaviour
{
    //中略
}

発生している問題

デバッグ実行中にClassAのアタッチされたオブジェクト(Object0)のinstanceBをClassAのアタッチされた別のオブジェクト(Object1)のinstanceBへ代入します。
ここでObject1のinstanceC0を更新すると、Prefabとして保存されているObject0のメンバinstanceC0まで更新されてしまいます。

ClassA instanceA0;
ClassA instanceA1;
//中略
instanceA0.instanceB = instanceA1.instanceB;
instanceA0.instanceC = new ClassC();


上記のコードの場合は、最終行実行時にPrefabにアタッチされたinstanceA1のメンバーinstanceC0が更新されます。
さらに一度デバッグ実行を終了しても更新されたデータはそのままです。
Prefabはゲーム中の動作に影響されずデータを保持するという認識でしたが、勝手に更新されてしまうと厄介なことになります。

試したこと

ある程度調べましたが、そもそもデバッグ実行中にPrefabへ影響を与えるためには特殊な操作が必要という情報しか探せませんでした。
現状は初期値を固定とすることで応急処置していますが最終的には別の方策が必要となります。

何かしら初歩的な思い違いのような気もしますが、自身での対応が限界近くなったためこちらで相談とさせていただきました。
よろしくお願いします。

補足情報(言語/FW/ツール等のバージョンなど)

Unityのバージョンは5.4.1f1Personalです。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • sakura_hana

    2016/11/04 14:08

    1.「instanceC」という変数は存在しないようですが、「instanceC0」の間違いでしょうか。 2.念の為Object0とObject1をInstantiateしているコードも提示頂けますでしょうか。 3.「Prefabとして保存されているObject0のメンバinstanceC0まで更新されてしまいます。」とは、具体的にどういう状態でしょうか。(何をもって更新されていると判断したのでしょうか)

    キャンセル

回答 1

checkベストアンサー

0

質問投稿後に何となく分かったような分からないような気がしたので、一応回答投稿しておきます。

■大前提
=で代入したり、setを通してもクラスは全て「参照渡し」になります。

1.最初(インスタンス化された時)
public ClassB instanceB のgetによって、
instanceA0.instanceB.instanceC1 は instanceA0.instanceC0 と同じもの。
instanceA1.instanceB.instanceC1 は instanceA1.instanceC0 と同じもの。
これを(1)とします。

2.instanceA0.instanceB = instanceA1.instanceB; した時
public ClassB instanceB のsetによって、
instanceA0.instanceC0 は instanceA1.instanceB.instanceC1 と同じもの。これを(2)とします。
(1)と(2)から、
instanceA0.instanceC0 は instanceA1.instanceC0 となります。これを(3)とします。

3.instanceA0.instanceC0 = new ClassC(); した時(「instanceC」は「instanceC0」だと仮定)
(3)から、
instanceA1.instanceC0 = new ClassC(); としているのと同義になります。

よって『「instanceA1のメンバーinstanceC0が更新されます。 」とは「instanceA1のメンバーinstanceC0が初期値に戻ります。(new ClassC()された状態になります)」 という意味である』ならば、それは正常な動作です。


■Prefabが更新されている?
仰る通り、『インスタンス化される前の』Prefab(に付いたスクリプト)は通常のスクリプトから変更されません(EditorScriptを書く必要があります)。
逆に言うと、『インスタンス化された後の』Prefab(=Prefabを元にインスタンス化しただけの普通のオブジェクト)は自由に編集可能です。

この辺りの確認をしたく、「何をもって更新されていると判断したのでしょうか」と質問させて頂きました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/04 23:51

    ご回答ありがとうございます。
    instanceA0.instanceC0 = new ClassC();で上書きされる現象については理解が追いつきました。下記の件と混同して混乱していたようです。

    Prefabに関してですが、インスペクタから確認しています。Projectウィンドウ中のPrefabを選択した状態でInspectorウィンドウの値が更新され、デバック実行終了後もそのままであることを確認しています。
    なんとなく今回質問に挙げた以外の部分のコードが影響していそうな気がするのですが、箇所の見当がつきません。こちらの要因となりそうな記述の仕方など心当たりあればご教授願えませんでしょうか。

    キャンセル

  • 2016/11/05 14:41

    Prefabの編集をするコードは「PrefabUtility」です。
    https://docs.unity3d.com/ja/current/ScriptReference/PrefabUtility.html

    挙動を見るに「PrefabUtility.ReplacePrefab」されていそうですね。
    一般的な使い方の例は以下となります。
    https://forum.unity3d.com/threads/apply-prefab-script.140705/

    キャンセル

  • 2016/11/05 18:54

    あやふやな疑問点に丁寧なご回答ありがとうございます。
    PrefabUtilityを直接記述した覚えはありませんが、こちらを軸にもう一度調べ直してみようと思います。

    キャンセル

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

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る