Call constructor of derived class from base class -> or how to do a proper Bestiary

106 views Asked by At

what I have is:

namespace Heroes.Classes
{
class Enemy
{
    private int HP;
    private int Attack;
    private int Defense;

    public string Name;

    Dice dice = new Dice();

    public enum Bestiary
    {
        Beasts,
        Undeads
    }

    public enum Beast
    {
        Wolf,
        Bear,
        Boar
    }

    public enum Undead
    {
        Skeleton,
        Ghost,
        Ghoul
    }

    public Enemy()
    {
    // here I want to call random CLASS which is derived from this 
    // base class -> that means I want here to create object 
    // Beasts() if Beasts is selected from enum Bestiary
    }

    public void EnemySwitch(Bestiary bestiary)
    {

        switch (bestiary)
        {
            case Bestiary.Beasts:
                // here I want to call constructor without any parameter -> which means a call random Beast/Method from class Beasts
                break;
            case Bestiary.Undeads:
                // here I want to call constructor without any parameter -> which means a call random Undead/Method from class Undeads
                break;
        }
    }


    public static T RandomEnumValue<T>()
    {
        var v = Enum.GetValues(typeof(T));
        return (T)v.GetValue(new Random().Next(v.Length));
    }

    public class Beasts : Enemy
    {
        public Beasts()
        {
            Beast choice = RandomEnumValue<Beast>();
            EnemySwitch(choice);
        }

        public Beasts(Beast beast)
        {
            EnemySwitch(beast);
        }

        private void EnemySwitch(Beast beast)
        {

            switch (beast)
            {
                case Beast.Bear:
                    Bear();
                    break;
                case Beast.Wolf:
                    Wolf();
                    break;
                case Beast.Boar:
                    Boar();
                    break;
            }
        }

        public void Bear()
        {
            HP = 120;
            Attack = 20;
            Defense = 15;
            Name = "Bear";
        }

        public void Boar()
        {
            HP = 100;
            Attack = 30;
            Defense = 10;
            Name = "Boar";
        }

        public void Wolf()
        {
            HP = 50;
            Attack = 35;
            Defense = 5;
            Name = "Wolf";
        }
    }

    public class Undeads : Enemy
    {
        public Undeads()
        {
            Undead choice = RandomEnumValue<Undead>();
            EnemySwitch(choice);
        }

        public Undeads(Undead undead)
        {
            EnemySwitch(undead);
        }

        private void EnemySwitch(Undead undead)
        {
            switch (undead)
            {
                case Undead.Skeleton:
                    Skeleton();
                    break;
                case Undead.Ghost:
                    Ghost();
                    break;
                case Undead.Ghoul:
                    Ghoul();
                    break;
            }
        }

        private void Ghoul()
        {
            HP = 100;
            Attack = 30;
            Defense = 20;
            Name = "Ghoul";
        }

        private void Ghost()
        {
            HP = 100;
            Attack = 30;
            Defense = 20;
            Name = "Ghost";
        }

        private void Skeleton()
        {
            HP = 100;
            Attack = 30;
            Defense = 20;
            Name = "Skeleton";
        }
    }

Is there any way how to make it working that way? Or do I need to use any other solution? I am new in OOP and it seems to me like a perfect way to use Bestiary exactly the way I am trying to use it. To derive specific groups and create methods for specific creatures, right? The best would be probably some SQL database, but for the beginning and understanding OOP I want to go this way.

Thank you in advance for any help! Merry Christmas!

2

There are 2 answers

0
Ľuboš Pilka On

As far as I know calling constructor of derived class through base class is not possible. Although you can call base constructor on derived class via base keyword. e.g.

public class Beasts
{
    public Beasts(int a) { }
}

public class Enemy : Beasts
{
    public Enemy() : base(5) { }
}
1
Joshua Howard On

In a language agnostic view of OOP here is what I think you should do:

  1. break out all individual enemies into their own class, i.e. Bear, Boar, and Wolf should be individual classes and the same goes for all undead.

    public class Beast : Enemy    
    {
        public Beast(HP, Attack, Defense, Name) {
            this.HP = HP;
            this.Attack = Attack;
            this.Defense = Defense;
            this.Name = Name;
        }
    }
    
    public class Bear : Beast
    {
        public Bear() {
            Beast(120, 20, 15, "Bear");
        }
    }
    
  2. All classes should be contained in their own file (usually).

  3. Rather than calling a random class derived from enemy in the constructor, you want to use the Factory Pattern (https://en.wikipedia.org/wiki/Factory_method_pattern) as another seperate class. e.g.

    public class EnemyFactory
    {
        public static Enemy getEnemy() {
            // Logic previously in Enemy() constructor
            return enemy;
        }
    }
    

(I don't know C# so the code might be off)