将ScriptableObjects加载到单个预制件/多个预制件的最佳实践是什么? [英] What is the best practice to load ScriptableObjects to single prefab/multiple prefabs?

查看:267
本文介绍了将ScriptableObjects加载到单个预制件/多个预制件的最佳实践是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(ScriptableObject = SO)

(ScriptableObject = SO)

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

I've recently been trying to learn about ScriptableObjects and have set up a project in Unity where I simply want to shoot incoming enemies that spawn. I have set it up so I can create different enemies through the SO:s but noticed that I still need to create a prefab for every single enemy. Therefore after not much luck googling I wanted to ask if there is a way to load in specific SO:s for every enemy spawned?

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

Say I have a spawnmanager that is spawning different enemies depending on their % to spawn. Is it possible in run-time through scripts check the probability for which enemy to spawn and then load/find that specific data created through SO:s?

推荐答案

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

TLDR : use Monobehvaiour to implement an enemy. Use SO just to setup its data or to implement part of its logic. So it's better not to spawn one SO per enemy. You spawn enemy as prefab and in their prefab you may add one or more SO to achieve composition.

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

To understand this I can explain the history of the SO, so you can find all the usual implementations.

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

Initially SO was made to store (non mutable) data. They could work as TEMPLATES.

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

IE, you have one Weapon SO and you instantiate it one for each weapon. In this way you can just attach the weapon to an unit.

    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用于数据的一些不错的教程是: 使用可编写脚本的对象自定义UI

Some nice tutorials about SO used for data are these: Customising UI With Scriptable Objects

在第1阶段之后,有人指出 SO可能用于许多不同的事情. 如此众多的开发人员开始在SO内部添加逻辑.

After phase 1, someone noted that SO may be used for many different things. So many developers started adding logic inside the 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敌人,并且可以附加武器武器或武器剑.

Doing so you can decouple a great deal of logic from the monobehaviour and attach any logic on the SO itself. You won't have one monobehaviour enemy with 2 derived class enemyWithAxe and enemyWithSword. You will have one Monobehaviour enemy and you may attach weaponAxe or weaponSword.

本系列教程是了解此逻辑并将事件应用于AI的重要资料. 带有可脚本编写对象的可插入式AI

A great source to understand this logic and apply event to AI is this series of tutorials. Pluggable Ai With Scriptable Objects

最后,我们有了 Unite Austin 2017 .

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

This is more advanced that the other ideas, and requires to understand the Observer pattern and the C# event system, but it is a great way to use scriptable objects.

这可能被用作生成器.

    [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 are great to implement OOP pattern I'm still not sure what will be their future with the new ECS, but I hope there will be a place for them too.

结论

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

I'm a great fan of SO, but there are a few cases where you want to spawn one SO for enemy. And anyway SO shouldn't replace MonoBehaviours everywhere. I would use a MonoBehaviour to represent an enemy.

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

If you still need to have one SO for each monobehaviour you may create them with ScrictableObject.CreateInstance at awake, but in this case they won't be much different from a base serializable class.

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

Still you may implement SO to setup its data (such as health or weapon damage), to handle part of its logic (such as adding effect to each weapon), or to handle the event of the spawn mechanics. I strongly suggest to give a look at the links I shared here. Choose where to start based on your experience, Phase 1 videos are the easier while Phase 3 are the most advanced. (Anyway all of them are easy enough, only the last one requires to understand the event of c#)

这篇关于将ScriptableObjects加载到单个预制件/多个预制件的最佳实践是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆