Getter to return default Value

Hello,

I’m sorry that the Heading is not that exact to describe the problem, but I cant change it anymore. My problem is, that I have an abstract class and implemented it with different subclasses. But when it is instantiated all fields are going to be doubled in the object as you can see on the gyazo upload at the end of the post.
I created an abstract class

public abstract class Weapon : ScriptableObject
{
    public string weaponName;

    public WeaponType type;

    public int price;

    public int magazineSize;

    public int damage;

    private int currentBulletsInMagazine;
    public int CurrentBulletsInMagazine{ get => currentBulletsInMagazine; }
}

I try to have inherited Classes that just returns fixed values and that the currentBulletsLeft are set to the value of MagazineSize at start:

public class WeaponUspS : Weapon
{
    public new string weaponName { get => "USP-S"; }
    public new WeaponType type { get => WeaponType.PISTOL; }
    public new int price { get => 200; }
    public new int magazineSize { get => 12; }
    public new int damage { get => 40; }
    public new int CurrentBulletsInMagazine { get => currentBulletsInMagazine; }

    void Start()
    {
        this.currentBulletsInMagazine = MagazineSize;
    }
}

I initialized a new WeaponUspS on a Weapon object with:

Weapon secondWeapon = gameObject.AddComponent<WeaponUspS>();

But when I for example want to access the damage property, I just get no values. e.g.: damage==0 instead of damage==40, etc.
Aswell as the currentBulletsInMagazine just wont be set.

Could somebody tell me how I could create a class, where I can add inherited classes with constant values that will be used when I want to access the

secondWeapon.damage == 40;


shows that the fileds are doubled:

You can achieve this by having abstract properties in the base class.

public abstract class Weapon : ScriptableObject
{
    public abstract string WeaponName { get; }
    public abstract WeaponType Type { get; }
    public abstract int Price { get; }
    public abstract int MagazineSize { get; }
    public abstract int Damage { get; }
 
    public int CurrentBulletsInMagazine { get; private set; }

    void Start()
    {
        CurrentBulletsInMagazine = MagazineSize;
    }
}

Then you can actually override the members from the base class, instead of merely hiding them.

public sealed class WeaponUspS : Weapon
{
    public override string WeaponName { get => "USP-S"; }
    public override WeaponType Type { get => WeaponType.PISTOL; }
    public override int Price { get => 200; }
    public override int MagazineSize { get => 12; }
    public override int Damage { get => 40; }
}
1 Like

oh wow, so its that easy, okay thank you!

1 Like

Also note that another option entirely would be to use serialized fields, and then create an asset for each weapon type and define the values using the Inspector. It could even be that you wouldn’t need to define unique classes for all weapon types with this approach.

If the serialized fields are made private and only accessible by other classes through read-only properties, then they would be constant values in practice at runtime.

[CreateAssetMenu]
public class Weapon : ScriptableObject
{
    [SerializeField] private string weaponName;
    [SerializeField] private WeaponType type;
    [SerializeField] private int price;
    [SerializeField] private int magazineSize;
    [SerializeField] private int damage;
 
    public WeaponType Type => type;
    public int Price => price;
    public int MagazineSize => magazineSize;
    public int Damage => damage;
    public int CurrentBulletsInMagazine { get; private set; }

    void Start()
    {
        CurrentBulletsInMagazine = magazineSize;
    }
}
1 Like

To follow up on what Sisus wrote, this is a completely pointless use of inheritance and subclasses. It’s not even a good example to learn how they work. It’s also a very, very easy problem to solve with a normal Weapon class. Suppose you have 6 types of weapons. Make an array of weapons (your weapon class, or the one Sisus redid) and give it size 6 in the Inspector. For the first one enter your first set of stats: USP-S,Pistol,200,12,40. Enter the next set of stats for the second weapon, and so on.

2 Likes

Yeah it’s true that, in its current form at least, it looks like there may not be any good reason for Weapon to derive from ScriptableObject at all.

If it didn’t have any state that changes at runtime (CurrentBulletsInMagazine), then it could be used to reduce memory usage and loading times in cases where multiple objects use the same weapons (the flyweight pattern).

One potential benefit of using a ScriptableObject would be the ability to more easily create a bunch of different weapons as ScriptableObject assets, and then easily swap them out to try out different loadouts.

Also if the weapons can be swapped dynamically at runtime, like for example through collecting them from drop points in levels, or purchasing them from stores, it could also make sense to use ScriptableObjects, to make it possible for multiple prefabs and objects in different scenes (player, drop point, store) easily reference the same Weapon.

Well, maybe. But my point was there’s no reason to do what the OP wanted to do, which is making a subclass of each weapon. Instead of making a USP-S subclass that returns those values, just make another instance of Weapon with those values typed in.

One way or another, 6 weapon types means 6 instances of Weapon. The easiest way is putting public Weapon[ ] in the player’s code. A harder way (that might be better later on) is making one ScriptableObject with that same array. Another might be having Weapon also be a ScriptableObject. Then you just make 6 Weapon assets (and have someone else have a public Weapon[ ] to remember them). But in every way, if you want a Bazooka, it’s easier to just make one more Weapon instance with bazooka values entered (and not a Bazooka subclass).

Yeah, I agree fully. It can make sense if for example a virtual/abstract Shoot method is added to the Weapon class which some derived classes override. But based on just the code that was posted, it’s unnecessary.