c# - 将 ScriptableObjects 加载到单个预制件/多个预制件的最佳实践是什么?
问题描述
(ScriptableObject = SO)
我最近一直在尝试了解 ScriptableObjects,并在 Unity 中建立了一个项目,我只是想射击生成的传入敌人。我已经设置好了,所以我可以通过 SO:s 创建不同的敌人,但注意到我仍然需要为每个敌人创建一个预制件。因此,在没有太多运气谷歌搜索之后,我想问是否有办法为每个生成的敌人加载特定的 SO:s?
假设我有一个 spawnmanager,它根据生成的百分比来生成不同的敌人。是否可以在运行时通过脚本检查生成哪个敌人的概率,然后加载/查找通过 SO:s 创建的特定数据?
解决方案
TLDR : 使用 Monobehvaiour 来实现敌人。使用 SO 只是为了设置其数据或实现其部分逻辑。所以最好不要为每个敌人生成一个 SO。您将敌人生成为预制件,在他们的预制件中您可以添加一个或多个 SO 以实现组合。
为了理解这一点,我可以解释 SO 的历史,这样你就可以找到所有常用的实现。
阶段 1 - 数据容器
最初 SO 用于存储(非可变)数据。他们可以作为模板工作。
IE,你有一个武器 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 用于数据的不错的教程: Customizing UI With Scriptable Objects
第 2 阶段 - 组合的 SO 逻辑
在第一阶段之后,有人指出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 个派生类enemyWithAxe 和enemyWithSword。您将有一个 Monobehaviour 敌人,您可以附加武器斧或武器剑。
了解此逻辑并将事件应用于 AI 的一个重要来源是本系列教程。 具有可编写脚本对象的可插拔 Ai
第 3 阶段 - 反应式可编写脚本的对象
最后,我们有了这种使用Unite Austin 2017中描述的 Scriptable 对象的新方法。
这比其他想法更高级,并且需要了解观察者模式和 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
}
}
实现 OOP 模式非常棒我仍然不确定新 ECS 的未来会怎样,但我希望他们也能有一席之地。
综上所述
我是 SO 的忠实粉丝,但在某些情况下,您想为敌人生成一个 SO。无论如何,SO不应该在任何地方取代MonoBehaviours。我会使用 MonoBehaviour 来代表敌人。
如果您仍然需要为每个单一行为创建一个 SO,您可以在清醒时使用 ScrictableObject.CreateInstance 创建它们,但在这种情况下,它们与基本可序列化类没有太大区别。
您仍然可以实现 SO 来设置其数据(例如生命值或武器伤害),处理其部分逻辑(例如为每个武器添加效果),或处理生成机制的事件。我强烈建议看看我在这里分享的链接。根据您的经验选择从哪里开始,第 1 阶段的视频更容易,而第 3 阶段的视频最先进。(反正都很简单,只有最后一个需要了解c#的事件)
推荐阅读
- python - 根据最后 4 个字符从两个列表中返回匹配字符串
- ruby - Bundler 找不到 gem "globalize" 的兼容版本:
- redirect - 同站点内容安全策略
- python - 如果它们相似,如何通过元素而不是索引在熊猫系列中进行切片
- firebase - FLUTTER 个人资料图片在用户离开页面时消失
- authentication - 使用一个用户数据库对 2 个不同的基于云 (aws/gcp) 中的用户进行身份验证,并且只验证一次
- aws-cdk - 如何通过 AWS CDK 使用“域名”引用 ACM 证书
- javascript - 在类型脚本/角火中三个点是什么意思
- python - PySpark - 为 24 小时窗口提取列的最大值,然后删除重复项
- javascript - addEventListener 中 this 的值