3

I am trying to develop my understanding of OOP so I created a console adventure game. I have a battle class which basically has 3 methods:

public static void StartFight(Dragon dragonWarrior, Goblin goblinEnemy)
public static string YouAttack(Dragon dragonWarrior, Goblin goblinEnemy)
public static string EnemyAttack(Goblin goblinEnemy, Dragon dragonWarrior)

The first calls the other 2 until someone dies. YouAttack and EnemyAttack include messages like:

Console.WriteLine("{0} the dragon attacks {1} and has dealt {2} damage",
                  dragonWarrior.Name, goblinEnemy.Name, damageDone);

In all, lets says that my 3 methods collectively takes 90 lines of code.

My problem is this. Lets say, I have an orc. I can easily copy and paste the methods and overload them like this:

public static void StartFight(Orc orcWarrior, Goblin goblinEnemy)

But that's going to generate a lot of bloat. Especially as the number of object Warriors increase (Centaur, Demon, Dwarf etc etc)

So is there a way of passing an object and the compiler figuring out what object has been passed? If there is, does anyone know of a good tutorial? Is there another solution that I can research??

I am aware that this might be a rubbish question but I am entirely self taught. I don't have any friends or tutors that code so every problem can be a struggle. Thank you in advance

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Beginner
  • 129
  • 10
  • Look into abstract classes or better yet - interfaces. They help exactly with what you asked – Tadija Bagarić Nov 04 '17 at 18:56
  • the search terms you will need to make yourself familiar with the required concepts are "interface", "inheritance", "polymorphism" and maybe "generics". – Cee McSharpface Nov 04 '17 at 18:56
  • Also read about inheritance and virtual methods. – Shoter Nov 04 '17 at 18:57
  • The common way to handle this would be to either have a super class like "Fighter" that the different units classes inherit from. You declare your method with "Fighter" and then you can pass in any sub class of Fighter. You'll need to implement the methods/properties "used" in the superclass, but you can override them in the subclasses. You can achieve the same using interfaces. – Rory Nov 04 '17 at 18:58
  • Thank you for all the posiitive commencts. I have a monster class from which Orc, Goblin and Dragon derive, so I think I might have missed a trick using inheritance. Interfaces sound promising so i will try to locate some resources on that. – Beginner Nov 04 '17 at 19:08

3 Answers3

1

What you are looking for is called Inheritance (link) and Polymorphism (link) - both are one of the 3 major pillars of OOP (with third one being Encapsulation (link))

They allow you to use objects of which you do not know the exact class, but for which you can still describe the API or methods.

Some example use can be found here: What is the real significance(use) of polymorphism

In your example, lets say Dragon and Orc extend the Warrior class, and lets say that Goblin and Gnome extend the Enemy class. Then your methods would look like this:

public static void StartFight(Warror warrior, Enemy enemy)
public static string YouAttack(Warror warrior, Enemy enemy)
public static string EnemyAttack(Enemy enemy, Warror warrior)

And you could pass any object that extends the Enemy or Warrior class.

This inheritance tree is only an example, as others have mentioned, you can (and should) design it to your needs, more or less abstract that is.

Tadija Bagarić
  • 2,495
  • 2
  • 31
  • 48
  • What is the third "pillar of OOP"? – Uwe Keim Nov 04 '17 at 19:15
  • 1
    @UweKeim Encapsulation – Tadija Bagarić Nov 04 '17 at 19:16
  • I see. Doing this stuff since 1994, I've never heard of this [pillar concept](http://cs.smu.ca/~porter/csc/common_341_342/notes/oop_3pillars.html). – Uwe Keim Nov 04 '17 at 19:17
  • 1
    What did the kids call it back in the day? :D – Tadija Bagarić Nov 04 '17 at 19:18
  • 1
    @TadijaBagarić Thats very helpful. Thank you. – Beginner Nov 04 '17 at 19:22
  • @TadijaBagarić Thanks for this. I went back to the drawing board and though more carefully about inheritance and plymorphism and managed to solve the problem – Beginner Nov 04 '17 at 20:17
  • 1
    Note that C# doesn't support multiple (class) inheritance, so in most cases [interfaces](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface) are the way to go. Think of "is-a" vs. "has-a" when determining inheritance. If the ability to fight can be put in a separate interface, then you don't need both Dragons and Orcs to inherit the same base class (which may not be the correct base, since presumably Dragons are from reptile species and Orcs are mammals, they may have different base classes but still implement the `IAttackable` or `IFighter` interface). – Rufus L Nov 05 '17 at 18:31
1

To make good abstraction, I think you need to go through many tutorials... But you can start from something simple:

public interface IUnit
{
    string Name   { get; }
    int    HP     { get; set; }
    int    Armor  { get; }
    int    Damage { get; }
}

public class Goblin : IUnit
{
    public string Name { get; } = "Goblin";

    public int HP { get; set; } = 80;

    public int Armor  => 3;
    public int Damage => 8;
}

public class Knight : IUnit
{
    public string Name { get; } = "Knight";

    public int HP { get; set; } = 120;

    public int Armor  => 5;
    public int Damage => 12;
}

public class BattleSystem
{
    public void ProcessAttack (IUnit attacker, IUnit target)
    {
        Console.WriteLine (attacker.Name + " is attacking " + target.Name);

        int damage = Math.Max (0, attacker.Damage - target.Armor);

        target.HP -= damage;

        if (target.HP <= 0)
        {
            Console.WriteLine ("Enemy unit died...");
        }
    }
}

Try to avoid using concrete types like Goblin, Warrior etc. If one unit have second special weapon, you need to implement abstraction that will allow any unit to have second weapon (but most of them will use only one weapon of course).

Game programming patterns

apocalypse
  • 5,764
  • 9
  • 47
  • 95
1

You might consider a completely different approach:

Define a struct or class to hold the stats and skill levels of a creature: creature_name, strength, agility, sword_skill, archery_skill, fireball_skill, ...

Define a a single Attack() function, possibly calling sub-functions like BowAttack(skill_level, distance, arrow_type, ...) or Fireball(skill_level, distance, ...)

orc = new Creature("Orc A", 11, 0, 5, 1, 0, 0, 0, 0, ... ):
player = new Creature("Hero Bob", 20, 10, 11, 11, 1, 1, 1, 0, ... );

Fight( Creature& player, Creature& enemy)
while (player.health > 0 && enemy.health > 0)
{
player.Attack( enemy );
enemy.Attack( player );
}

This could be made more fancy by passing in arrays for both sides, and having a "round" or turn where the order of attack for each creature is chosen by their Reflex or Initiative skill.

Dave S
  • 1,427
  • 1
  • 16
  • 18