将ScriptableObjects加载到单个预制件/多个预制件的最佳实践是什么?

时间:2019-05-09 08:05:24

标签: c# unity3d

(ScriptableObject = SO)

我最近一直在尝试学习ScriptableObjects,并在Unity中建立了一个项目,我只想拍摄产生的敌人。我已经设置好了,所以我可以通过SO:s来创建不同的敌人,但是注意到我仍然需要为每个敌人创建一个预制件。因此,在没有太多运气之后,我想问一下是否有一种方法可以为每个生成的敌人加载特定的SO:s?

说我有一个生成管理器,它根据要生成的%生成不同的敌人。是否可以在运行时通过脚本检查生成敌人的概率,然后加载/查找通过SO:s创建的特定数据?

1 个答案:

答案 0 :(得分:0)

TLDR:使用Monobehvaiour实施敌人。仅使用SO来设置其数据或实现其逻辑的一部分。因此最好不要为每个敌人生成一个SO。您将敌人生成为预制体,并且可以在其预制体中添加一种或多种SO以实现合成。

要了解这一点,我可以解释SO的历史,因此您可以找到所有常用的实现。

第1阶段-数据容器

最初使用SO来存储(不可更改的)数据。他们可以充当模板。

IE,您有一个Weapon SO,并且为每种武器实例化了一个。 这样,您可以将武器附加到一个单元上。

    public class Attacker : MonoBehaviour
    {
        public Weapon weapon;

        public void Attack(IDamageGetter target) => target.GetDamage(weapon.damage);
    }

    public interface IDamageGetter
    {
       void GetDamage(int Damage);
    }

    [CreateAssetMenu(menuName = "Base Weapon")]
    public class Weapon : ScriptableObject
    {
        public int damage = 5;
    }

关于SO用于数据的一些不错的教程是: Customising UI With Scriptable Objects

第2阶段-SO构成逻辑

在阶段1之后,someone noted可以将SO用于许多不同的事物。 如此众多的开发人员开始在SO内部添加逻辑。

    public class AttackerWithLogic : MonoBehaviour
    {
        public WeaponWithLogic weapon;

        public void Attack(IDamageGetter target) => weapon.Attack(target);
    }

    public abstract class WeaponWithLogic : ScriptableObject
    {
        public int damage = 5;

        public abstract void Attack(IDamageGetter target);
    }

这样做可以将大量逻辑与单行为分离开来,并将任何逻辑附加到SO本身。 您将不会有一个具有2个派生类的invalideWithAxe和敌人WithSword的单一行为敌人。 您将有一个Monobehaviour敌人,并且可以附加武器武器或武器剑。

本系列教程是了解此逻辑并将事件应用于AI的重要资料。 Pluggable Ai With Scriptable Objects

阶段3-反应性可编写脚本的对象

最后,我们有了使用Unite Austin 2017中所述的可脚本化对象的新方法。

这比其他想法更高级,并且需要了解Observer模式和C#事件系统,但这是使用可编写脚本的对象的好方法。

这可能被用作生成器。

    [CreateAssetMenu(menuName = "EnemySpawner")]
    public class EnemySpawner : ScriptableObject
    {
        public event Action<Enemy> OnSpawn;

        public Enemy enemyPrefab;

        public void SpawnEnemyWithSword()
        {
            var enemy = Instantiate(enemyPrefab);
            //..
            //code to setup sword 
            //..
            OnSpawn?.Invoke(enemy);
        }

        public void SpawnEnemyWithAxe()
        {
            //any other logic with the same event
        }
    }

SO很好地实现了OOP模式,我仍然不确定新ECS的未来是什么,但我希望他们也会有一个机会。

结论

我是SO的忠实拥护者,但在某些情况下,您希望为敌人生成一个SO。而且无论如何,不​​应该在任何地方取代MonoBehaviours。我会用MonoBehaviour来代表敌人。

如果每个单行为仍然需要一个SO,则可以在醒着时使用ScrictableObject.CreateInstance创建它们,但是在这种情况下,它们与可序列化的基类没有太大不同。

仍然可以实施SO来设置其数据(例如健康或武器损坏),处理其逻辑的一部分(例如为每种武器增加效果)或处理生成机制的事件。 我强烈建议您看一下我在此处共享的链接。根据您的经验选择从哪里开始,第1阶段的视频比较容易,而第3阶段的视频则最先进。 (无论如何,它们都很容易,只有最后一个需要理解c#的事件