Darkbound
Darkbound

Reputation: 3444

C# Make properties visible if a condition is satisfied

I finally went on and started studying OOP principles and I am currently making a simple game. Here is the situation: I have one abstract class called Items that holds all the possible attributes of an item as properties and the quality of the item as an enumeration:

public enum ItemQuality
{
    Common,
    Uncommon,
    Rare,
    Epic,
    Legendary
}

public abstract class Items
{
    public ItemQuality ItemQuality { get; set; }
    public int Stamina { get; set; }
    public int Strength { get; set; }
    public int Agility { get; set; }
    public int Intelligence { get; set; }
    public int Damage { get; set; }
    public int Block { get; set; }
    public int Armor { get; set; }
}

I have two more classes called Weapon and Armor (they inherit the Items class) and they hold the WeaponType and ArmorType respectively, both of which are also enumerations.

Consider the following scenario: I make a new Weapon of type Sword, I am able to give it a value for Blocking, but it's a weapon it can't block. I want to make different properties visible depending on the Weapon/Armor type.

Weapon weapon = new Weapon();
weapon.WeaponType = WeaponType.Sword;
weapon.Block = 5;

In this case I shouldn't be able to see the Block property.

To go even further I don't want to have to instantiate Weapons and Armors separately from the Character (I also have a Character class).

My end goal is to do something like this:

Character character = new Character();
character.WeaponType = WeaponType.Sword;
character.WeaponType.Damage = 10;

Or something like this, I am not even sure if my structure is correct so I am open to suggestions! Thanks!

Upvotes: 0

Views: 797

Answers (3)

David Arno
David Arno

Reputation: 43264

Forget inheritance here and use composition. For example, start with the basics:

public enum ItemQuality { Common, Uncommon, Rare, Epic, Legendary }

public class Item
{
    public ItemQuality ItemQuality { get; set; }

    // other things common to all items here

    public List<IFeature> features { get; set; }
}

So what is IFeature. Well to start with, it's an empty interface:

public interface IFeature { }

But let's now start adding weapons:

public interface IAttackWeapon : IFeature
{
    int Damage { get; set; }
}

public interface IDefenceWeapon : IFeature
{
    int Block { get; set; }
}

We can then start defining some classes:

public class Weapon : IAttackWeapon
{
    public Damage { get; set }
}

public class Shield : IDefenceWeapon
{
    public int Block { get; set; }
}

So then, I might define some weapons:

public static readonly Item ShortSword = new Item
{
    ItemQuality = ItemQuality.Common,
    Cost = 5,
    Features = new List<IFeature>
    {
        new Weapon { Damage = 4 }
    }
}

By taking this composition approach, if we say want a magic sword at a later date, we do not need to create lots more classes, lots more properties to hide etc. Nor do we run into problems of "should my magic sword inherit from weapon or magic item?". Instead, we'd add a new feature, eg:

public static readonly Item MagicSword = new Item
{
    ItemQuality = ItemQuality.Rare,
    Cost = 5000,
    Features = new List<IFeature>
    {
        new Weapon { Damage = 10 },
        new MagicItem { Spell = Spells.TurnToFrog }
    }
}

Upvotes: 1

Marc Wittmann
Marc Wittmann

Reputation: 2671

I would not choose that way especially if you want to maintain good OOP.

Why won`t you use interfaces for example one IAttackable and IBlockable. A shield would implement the IBlockable interface only, a sword IAttackable and IBlockable and a Gun only IAttackable

You would be abe to ask if the weapon object is blockable

   if (currentWeapon is IBlockable)
   {
        var blockWeapon = currentWeapon as IBlockable;
        blockWeapon.blockHorizontal();
        blockWeapon.blockVertical();
   }

Upvotes: 1

Dmytro Bogatov
Dmytro Bogatov

Reputation: 796

According to OOP principles, it is a bad design to define object type as an enumerator. Good OOP would make use of inheritance and possibly polymorphism. Like that:

public abstract class Weapon {
    public int cost {get; set;}
}
public class Sword : Weapon {
    public int damage {get; set;}
}
public class Shield : Weapon {
    public int defense {get; set;}
}

Now you can say:

Sword blade = new Sword();
blade.cost = 5;
blade.damage = 6;

Shield myShield = new Shield();
myShield.cost = 4;
myShield.defense = 7;

If you need a new type of a weapon you may subclass Weapon class like we did with Sword and Shield (let's say, you want Bow). If you need another attacking weapon like knife, you may subclass Sword, for example.

public class Knife {
    public int length {get; set;}
}

Upvotes: 0

Related Questions