1

I have a script called Weapon.cs, which is a scriptable object.

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();
}

I have a second script called MachineGun.cs, which inherits from Weapon.cs, and thus indirectly from scriptable object.

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
}
}

It's currently impossible, since MachineGun.cs doesn't inherit from monobehaviour anymore.

I have a weapon gameobject in my scene, and so here's my question: How do I go about adding the MachineGun.cs script as a component to my weapon gameobject? Or since this is impossible,

How should I build a weapon system with a general Weapon.cs script from which all weapons can inherit basic functions and fields/variables?

EDIT 1: provided code to my post and added the "why I wanna do this".

Thanks in advance!

8
  • If a script does not inherit from Component (or MonoBehaviour), there is no way to add it as a component of a GameObject. ScriptableObjects are meant to be assets in your project (holding data in most of the cases). Then, you can use them in other scripts inheriting from MonoBehaviour, attached to GameObjects. Commented May 15, 2018 at 9:49
  • I've edited my post to make my intentions clear. Commented May 15, 2018 at 10:26
  • I do you need to make Weapon inherit from ScriptableObject? You don't use the CreateAssetMenu attribute.... So I guess you don't create a real ScriptableObject in your project tab? (unless you have the appropriate Editor script to do so) Commented May 15, 2018 at 10:34
  • I thought it was a good way to get the same behaviour from a ScriptableObject as from a public abstract Weapon class, with the added benefit of inherited fields.. Commented May 15, 2018 at 11:32
  • 1
    Once the script is attached to a GameObject, a new instance is created, and the values you provide in the editor (or by script, at runtime), won't affect the other instances (except if you use static class variables) Commented May 15, 2018 at 12:34

2 Answers 2

2

ScriptableObjects should mainly be used in a data oriented way, they are very convenient and quite efficient for the task. Also, plaguing your project of MonoBehaviour is a very bad (and wide-spread) practice.

IMO, you should have a MonoBehaviour with weapon logic management and your ScriptableObjects should be your weapon data (which is interpreted by loading them up in your Weapon MonoBehaviour), such that you have Minigun, Glock, Katana.. Scriptable objects which have data like, attack speed, reload speed, charger size, weapon model/textures, reference to model hitbox, yadayadayada. (You might have a generic Weapon MonoBehaviour, but derive a Gun one, a Blade etc.. for very specific management, but which will still need data from ScriptableObjects)

In short your MonoBehaviours define usage and interaction, while your ScriptableObjects define characteristics

Sign up to request clarification or add additional context in comments.

9 Comments

Could you give a code sample of this? Since I'm not sure I completely understand what you're saying. So I should create a ScriptableObject which contains all the fields a weapon could have, and also a Weapon monobehaviour script with all methods a weapon could have?
@Thrindil I'll try and mock something up, but I stumbled here while searching, I'm currently at work so, I might not have the opportunity to post any time soon. But if this could help, ScriptableObjects have database-like characteristics, they will only contain information which can be used or transformed. You could do all this inside MonoBehaviours, a lot of people do it, but because you can, doesn't mean that you should. For a very brief explanation, think of a HP combat system, your current/max hp is your scriptableObject and Inflicting/TakingDamage is your monobehaviour.
@Thrindil A very good exemple (without code) is Virtual Card Games (ex: Hearthstone/Slay the spire etc..) Your scriptable object will have the cards : Name, Damage, max Hp/current Hp, Description and Type (and possibly a buff/debuff field or something, but what ever). Since our information is generic, we arent going to create 500 gameobjects of almost identical cards, no, we have a builder which can construct your card thanks to your SO data, there will also be a behaviour which is generic, basically just a Use() which will activate whatever the card can do, no more needed.
@Thrindil For a sense of what I'm trying to say, i'd advise you to look at the Ability System lesson from Unity as well as Overthrowing the MonoBehaviour tyranny in a glorious ScriptableObject revolution, Nothing is really absolute and there are many ways of doing of course, most of what i've put forward are for reasons of clarity, abstraction and maintainability.
Thanks for your clarification even though you're at work. I'll read through/watch your provided documentation, and accept your answer as the right one since you've been very helpful.
|
1

ScriptableObject says:

Description

A class you can derive from if you want to create objects that don't need to be attached to game objects.

So either you should not attach this script to game object or derive your object from "MonoBehaviour" if you want to attach it to game object.

Why did you derive it from ScriptableObject ?

1 Comment

Weapon has behaviour like shoot, move, reload etc so it should be defined as MonoBehaviour. Common behaviour of any weapon you are using should be defined in Weapon class. You can also compare the use of ScriptableObject from here: unity3d.com/learn/tutorials/modules/beginner/…. Perhaps it will give you a better idea for the use of ScriptableObject.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.