【问题标题】:Add script inheriting from scriptableobject to game object将继承自 scriptableobject 的脚本添加到游戏对象
【发布时间】:2018-05-15 09:36:38
【问题描述】:

我有一个名为 Weapon.cs 的脚本,它是一个可编写脚本的对象。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Weapon : ScriptableObject {

protected Camera _mainCamera;
protected Transform _weaponTransform;
protected int _damage;
protected int _fireRatePerSecond;
protected bool _isAutomaticWeapon;

protected void FireWeapon()
{
    //if the weapon is automatic
    if (_isAutomaticWeapon)
    {
        ShootRapidFireOnMouseHold();
    }
    //if the weapon is semi automatic
    else
    {
        ShootSingleBulletOnMouseClick();
    }
}

protected void MoveWeaponWithCamera(Transform weaponTransform)
{
    _weaponTransform.rotation = _mainCamera.transform.rotation; //temporary way of making sure the gun moves with the camera
}

protected void ShootSingleBulletOnMouseClick()
{
    if (Input.GetKeyDown(KeyCode.Mouse0)) //if left mouse button is clicked
    {
        CastRay();
    }
}

protected void ShootRapidFireOnMouseHold()
{
    if (Input.GetKey(KeyCode.Mouse0)) //if left mouse button is held down
    {
        CastRay(); //rapid fire
        //PlayShootAnimation();
    }
}

protected void CastRay()
{
    RaycastHit hit;
    if (Physics.Raycast(_mainCamera.transform.position, _mainCamera.transform.forward, out hit, 100))
    {
        Debug.Log(hit.transform.name);
    }
}
//protected abstract void PlayShootAnimation();
}

我还有一个名为 MachineGun.cs 的脚本,它继承自 Weapon.cs,因此间接继承自可编写脚本的对象。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MachineGun : Weapon{

private GameObject _machineGunBarrel;

//private float _animationVelocity;

// Use this for initialization
void Start () {
    //initialize the basic properties of a weapon
    _damage = 7;
    _fireRatePerSecond = 10;
    _isAutomaticWeapon = true;

    _weaponTransform = GameObject.Find("Weapon_MachineGun").transform;
    _machineGunBarrel = GameObject.Find("machinegun_p1");

    _mainCamera = Camera.main;

}

// Update is called once per frame
void Update () {
    MoveWeaponWithCamera(_weaponTransform);
    FireWeapon();
}

//protected override void Shoot()
//{
//    RaycastHit hit;
//    if(Physics.Raycast(_mainCamera.transform.position, _mainCamera.transform.forward, out hit, 100))
//    {
//        Debug.Log(hit.transform.name);
//    }
//}

void PlayShootAnimation()
{
    _machineGunBarrel.transform.RotateAround(_machineGunBarrel.transform.up, _fireRatePerSecond * Time.deltaTime);
    PlayShootAnimation(); //play the shoot animation of the gun
}
}

目前这是不可能的,因为 MachineGun.cs 不再从 monobehaviour 继承。

我的场景中有一个武器游戏对象,所以这是我的问题: 如何将 MachineGun.cs 脚本作为组件添加到我的武器游戏对象中?或者既然这是不可能的,

我应该如何使用通用的 Weapon.cs 脚本构建一个武器系统,所有武器都可以从中继承基本功能和字段/变量?

编辑 1:在我的帖子中提供了代码并添加了“我为什么要这样做”。

提前致谢!

【问题讨论】:

  • 如果脚本不继承自Component(或MonoBehaviour),则无法将其添加为游戏对象的组件。 ScriptableObjects 是您项目中的资产(在大多数情况下保存数据)。然后,您可以在其他脚本中使用它们,这些脚本继承自 MonoBehaviour,附加到 GameObjects。
  • 我已经编辑了我的帖子以明确我的意图。
  • 我需要让Weapon 继承自ScriptableObject 吗?你不使用CreateAssetMenu 属性....所以我猜你没有在你的项目选项卡中创建一个真正的 ScriptableObject ? (除非您有相应的编辑器脚本来执行此操作)
  • 我认为这是从 ScriptableObject 获得与从公共抽象武器类中获得相同行为的好方法,并具有继承字段的额外好处..
  • 脚本附加到游戏对象后,会创建一个新实例,并且您在编辑器中(或在运行时通过脚本)提供的值不会影响其他实例(除非你使用static类变量)

标签: c# unity3d inheritance scripting


【解决方案1】:

ScriptableObjects 应该主要以面向数据的方式使用,它们非常方便且高效地完成任务。此外,困扰您的 MonoBehaviour 项目是一种非常糟糕(且广泛传播)的做法。

IMO,您应该有一个带有武器逻辑管理的 MonoBehaviour,并且您的 ScriptableObjects 应该是您的武器数据(通过加载它们来解释在你的武器 MonoBehaviour)中,这样你就有了 Minigun、Glock、Katana.. Scriptable objects,其中包含攻击速度、装填速度、充电器大小、武器型号等数据/textures,参考模型 hitbox,yadayadayada。 (您可能有一个通用的武器 MonoBehaviour,但派生出一把枪、一把刀等。用于非常具体的管理,但仍需要来自 ScriptableObjects 的数据)

简而言之,您的 MonoBehaviours 定义使用和交互,而您的 ScriptableObjects 定义特征

【讨论】:

  • 你能给一个代码示例吗?因为我不确定我是否完全理解你在说什么。所以我应该创建一个包含武器可能拥有的所有字段的 ScriptableObject,以及一个武器可能拥有的所有方法的 Weapon monobehaviour 脚本?
  • @Thrindil 我会尝试模拟一些东西,但我在搜索时偶然发现了这里,我目前正在工作,所以我可能没有机会很快发布。但如果这有帮助,ScriptableObjects 具有类似数据库的特性,它们将只包含可以使用或转换的信息。你可以在 MonoBehaviours 中完成所有这些,很多人都这样做,但因为你可以,并不意味着你应该这样做。对于一个非常简短的解释,想想一个 HP 战斗系统,你的当前/最大 hp 是你的脚本对象,而 Inflicting/TakingDamage 是你的单体行为。
  • @Thrindil 一个很好的例子(无代码)是虚拟纸牌游戏(例如:炉石传说/杀戮尖塔等。)您的可编写脚本的对象将包含以下卡片:名称、伤害、最大 Hp/电流Hp、描述和类型(可能还有一个 buff/debuff 字段或其他东西,但不管怎样)。由于我们的信息是通用的,我们不会创建 500 个几乎相同卡片的游戏对象,不,由于您的 SO 数据,我们有一个可以构建您的卡片的构建器,还会有一个通用的行为,基本上只是一个 @987654323 @ 这将激活卡片可以做的任何事情,不再需要。
  • @Thrindil 要了解我想说什么,我建议你看看Ability System lesson from UnityOverthrowing the MonoBehaviour tyranny in a glorious ScriptableObject revolution,没有什么是绝对的,有很多方法当然,我提出的大部分内容都是出于清晰、抽象和可维护性的原因。
  • 感谢您的澄清,即使您在工作。我将通读/观看您提供的文档,并接受您的正确答案,因为您非常乐于助人。
【解决方案2】:

ScriptableObject 说:

说明

如果你想创建不 需要附加到游戏对象上

因此,如果您想将此脚本附加到游戏对象,则不应将此脚本附加到游戏对象,或者从“MonoBehaviour”派生您的对象。

你为什么从ScriptableObject派生出来?

【讨论】:

  • 武器具有射击、移动、重装等行为,因此应将其定义为MonoBehaviour。您使用的任何武器的常见行为都应在 Weapon 类中定义。您还可以从此处比较 ScriptableObject 的使用:unity3d.com/learn/tutorials/modules/beginner/…。也许它会给你一个更好的想法来使用 ScriptableObject。
猜你喜欢
  • 2021-11-24
  • 2020-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多