【问题标题】:how to clone several game objects in a way that clone properties of one can be adjusted to match all others in scene view如何以一种可以调整克隆属性以匹配场景视图中的所有其他对象的方式克隆多个游戏对象
【发布时间】:2018-06-28 18:11:02
【问题描述】:

我问过How can I adjust shape/dimensions of one clone to affect all other clones in the scene view,得到的答案是正确的。它只能克隆一个游戏对象。我尝试进行一些调整,但我想出的唯一解决方案是为其他对象添加重复的方法。这在处理要克隆的多个游戏对象时效果不佳。

如何克隆多个独特的游戏对象,以便调整一个克隆的组件/属性会影响场景视图中该对象的所有其他克隆?

请注意,我不想在运行时实现这一点,也不想使用预制件。我正在使用它来帮助创建复杂的关卡,因此正在调整的克隆的实时更新非常重要。

此外,我还需要一种方法来关闭每个克隆上重复的属性/组件复制,最好使用按钮。

【问题讨论】:

  • 您介意发布您已经提出的代码吗?
  • 您应该看看新的预制系统(在 Unity 2018.3.x 中)。看起来实际上预制件是您的解决方案,因为您不需要在运行时应用更改。否则,您应该创建某种管理器,其中所有创建的对象都可以注册自己,这样您就可以从一个地方处理更改......或者在所有对象上使用静态事件并将它们全部订阅这些事件,但这两个选项更多地用于运行时。

标签: unity3d unity-editor


【解决方案1】:

我不想使用预制件

Unity 中的新预制系统正是您所需要的。它符合您的所有要求:

  • Clone several unique game objects

    预制系统用于克隆独特的游戏对象。它甚至支持预制嵌套。

  • I don't want to achieve this at runtime

    太好了,只有在您单击编辑器中的覆盖按钮时,预制件才会全局更新。

  • I need a way to turn off the this repeated property/component replication on each clone

    这相当于解包对象(断开连接)。

如果您有充分的理由避免使用预制件,您始终可以编写一个自定义脚本来跟踪您要共享的属性的变化,并立即更新所有其他对象。您可以通过将[ExecuteInEditMode] 属性添加到它所在的类来使该脚本在编辑模式下运行,只是不要忘记在运行项目时禁用它。同样,我强烈建议使用预制件。

【讨论】:

    【解决方案2】:

    您应该使用 ScriptableObject 作为数据容器并将其附加到游戏对象,所有克隆都将使用相同的同步 ScriptableObject。

    【讨论】:

      【解决方案3】:

      你应该使用事件。 Unity3d教程有一个很好的,简单的解释:https://unity3d.com/learn/tutorials/topics/scripting/events

      【讨论】:

      • 这个答案会更好,如果它提供了关于如何应用事件来解决这个问题的具体描述。
      【解决方案4】:

      这仅用于在编辑器中编辑对象吗?如果是这样,那么听起来预制件是要走的路;您可以直接编辑预制件,它在场景中的所有“克隆”都将进行所有更改,包括所有单体行为、变换以及未复制到预制件的内容。

      如果您需要它在运行时工作,那么您可能需要一些代码来为您执行此操作。您还没有完全说明您到底想要做什么,因此对于下面的示例,我假设您有一个带有网格或精灵组件的游戏对象,并希望它的大小/比例与它的所有“一起修改”克隆”;

      using UnityEngine;
      using System.Collections.Generic;
      
      public class ShapeClone : MonoBehaviour
      {
          //This will hold references to the other "clone" gameobjects.
          public List<GameObject> otherClones = new List<GameObject>();
      
          //All the "clones" in the list otherClones will have their scale matched to this gameobject's scale
          public bool leader;
      
      
          private void Update()
          {
              if (leader) //Only change other clones' scales if marked as leader, to avoid every single clone
                          //overriding each other's scale every single frame, which could be rather chaotic
              {
                  for (int i = 0; i < otherClones.Count; i++)
                  {
                      //setting each of the other clones' scale to that of this object.
                      otherClones[i].transform.localScale = this.transform.localScale;
                  }
              }
          }
      }
      

      上面是一个简短的例子,可以给你一个想法,绝不是广泛的,但你应该能够将它应用到你正在尝试做的事情中;例如,如果您想在游戏对象之间复制精灵的颜色,则可以将otherClones 修改为Sprite 引用的列表,而不是在更新中设置比例,您可以设置每个对象的颜色该对象的 Sprite 组件。

      如果您只需要在编辑器中而不是在运行时需要此功能 - 我强烈建议您使用预制件的第一个选项,因为它会以一小部分成本和性能为您提供更多功能。

      【讨论】:

      • 这仅用于在编辑器中编辑对象。确实,问题中没有出现许多细节。这是因为链接的问题 (stackoverflow.com/questions/50167887/…) 密切相关,有很多我认为不值得重复的信息。链接的问题回答了如何在编辑器模式下调整一个对象的克隆,我想将该方法用于具有克隆的多个对象。请检查问题和接受的答案以获得更好的想法。
      【解决方案5】:

      听起来你有一个有多个克隆的对象。您想更改其中任何对象的形状或尺寸以影响其他对象吗?

      为此,每个对象都需要了解其他对象。您可以做到这一点去中心化(每个对象包含对彼此的引用)或集中式(一个对象管理其余对象)。

      集中式方法更简单,所以我将举一个简单的例子。

      public class Shape
      {
          public int length;
      }
      
      public class ShapeCentral
      {
          public List<Shape> shapes = new List<Shape>();
      
          public void CloneShape()
          {
              //instantiate new shape
              shapes.Add(new Shape());
          }
      
          public void SetCloneLength(int l)
          {
              shapes.ForEach(x => x.length = l);
          }
      }
      

      如您所见,一个对象可以同时控制所有克隆。诀窍是不要使用其他方法创建克隆,否则您会遇到麻烦。

      如果您想加强您的变量访问(我建议,这是一个很好的练习),您可以使用发布者/订阅者模式。在这种情况下,当实例化一个新克隆时,它会订阅 SetCloneLength 方法。当您想更改长度时,中心类会发布该消息并将其发送给所有订阅者。

      这里的区别在于,在我的示例中,中心类需要跟踪所有克隆,在发布者/订阅者中,您不需要。

      【讨论】:

      • 问题中确实没有出现许多细节。这是因为链接的问题 (stackoverflow.com/questions/50167887/…) 密切相关,有很多我认为不值得重复的信息。链接的问题回答了如何在编辑器模式下调整一个对象的克隆,我想将该方法用于具有克隆的多个对象。请检查问题和接受的答案以获得更好的想法。
      【解决方案6】:

      创建脚本 CopycatManager 将持有一个领导者,然后使用专用的设置器来复制具有相同类型的其他对象属性。如果属性是默认属性,则可能需要在脚本中设置此类属性的代理或使用触发器。我会推荐代理。像这样:

      class CopycatManager {
      
          public GameObject leader;
      
          SomeAttributeType attributeToCopyFromLeader {get; private set}
      
          void Start () {
              // The first CopycatManager to start is the leader
              List<CopycatManager> allCMs = parent.GetComponentsInChildren();
              CopycatManager foundLeader = allCMs.Find(o => o.leader == o);
              if (foundLeader == null) {
                  // There's no leader yet, set yourself a leader
                  leader = this;
              } else {
                  // Found a leader, accept
                  leader = foundLeader;
              }
          }
      
          public void SetAttribute (SomeAttributeType newVal) {
              // If we're setting the attribute of the leader - we should set this attribute for all children
              if (leader == gameObject) {
                  // Find all copycat manager scripts attached to children of current parent
                  // Meaning siblings
                  // WARNING: It will include children of siblings and the leader itself
                  // WARNING: It will not include parents of the Copycat Manager type, add if required
                  List<CopycatManager> allCMs = parent.GetComponentsInChildren();
                  foreach (CopycatManager manager in allCMs) {
                      SetAttributeFromLeader (newVal);
                  }
              } else {
                  // Non-leader is attempting to change attribute - call leader
                  leader.SetAttribute(newVal);
              }
          }
      
          // Called by leader to each child
          public void SetAttributeFromLeader (SomeAttributeType newVal) {
              attributeToCopyFromLeader = newVal;
          }
      }
      

      如果旧的领导者被摧毁,请确保分配一个新的领导者。只能通过专用函数使用 CopycatManager 销毁对象。

      【讨论】:

        【解决方案7】:

        制作所有需要缩放名为WorldObjects 的空子对象的项目,然后缩放世界对象,它将相应地缩放其所有子对象。然后,您可以手动或通过脚本删除父对象以使对象独立。没有预制件的最佳方式...

        【讨论】:

          【解决方案8】:

          使用单例类。将该脚本添加到所有对象,然后您可以调用其中一个,它将调整所有对象。

          您也可以使用静态类来执行此操作,但单例方法更简洁,并为您提供更多选择。

          public class MySingleton
          {
          
              private static MySingleton fetch; // keep the static reference private
          
              public bool myBool = false;
          
              // and expose static members through properties
              // this way, you have a lot more control over what is actually being sent out.
              public static bool MyBool { get { return fetch ? fetch.myBool : false; } }
          
              void Awake()
              {
                  fetch = this;
              }
          }
          

          阅读here 了解有关这两个选项的一些重要信息!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-08-05
            • 2021-11-13
            • 2015-02-08
            • 2012-05-06
            • 1970-01-01
            • 2021-11-23
            相关资源
            最近更新 更多