HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMajor

Mini RPG equipment code

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
rpgcodeequipmentmini

Problem

what do you think about this code? It's upgraded version of:
Classes representing items in an RPG game

```
using System;
using System.Collections.Generic;

public class Item
{
public string Name { get; protected set; }
public int Cost { get; protected set; }

public override string ToString()
{
return "Name: " + Name + "\nCost: " + Cost;
}

public Item(string name, int cost)
{
Name = name;
Cost = cost;
}
}

public abstract class SpecialItem : Item
{
public virtual int GetSpecialProperty { get; }
public override string ToString() { return base.ToString() + "\nDamages/ArmorPts/HungryRestorePts: " + GetSpecialProperty; }
public SpecialItem(string name, int cost) : base(name, cost) { }
}

public abstract class ElementalsItem : SpecialItem
{
public int Fire { get; protected set; }
public int Water { get; protected set; }
public int Earth { get; protected set; }
public int Wind { get; protected set; }
public override string ToString()
{
return base.ToString()
+ "\nFire Damages/Resistance: " + Fire
+ "\nWater Damages/Resistance: " + Water
+ "\nEarth Damages/Resistance: " + Earth
+ "\nWind Damages/Resistance: " + Wind;
}
protected ElementalsItem(string name,
int cost,
int fire,
int water,
int earth,
int wind)
: base(name, cost)
{
Fire = fire;
Water = water;
Earth = earth;
Wind = wind;
}
}

public class Weapon : ElementalsItem
{
public int Damages { get; private set; }
public override int GetSpecialProperty { get { return Damages; }}
public override string ToString() { return base.ToString(); }

public Weapon(string name,
int cost,
int damages,

Solution

Edge cases are where such class hierarchies often fall short.

  • An offhand short sword that adds to defense?



  • A shield that does damage when you bash with it?



  • A magic potion that not only makes you less hungry but also adds


armor when you drink it?

How will those fit into your current hierarchy? One way to avoid those problems is to use aggregation instead of inheritance and treat each game object as a collection of arbitrary properties, that can be added to object or removed from it. You might want to look at how, for example, things are done in Unity, to get a better understanding of how things are actually designed in modern engines.

To be clear, there is nothing wrong with having game object hierarchies in small projects. It is the easiest approach and sometimes it is enough, especially if all you want is to write some code. I just wanted to give you some perspective.

EDIT
Since this question is getting a lot of attention I though I might as well update my answer with a simplified example.

First, you have to create some "components". For the sake of this example, you can think of components as properties that define the item and make it different and special. What is a fire sword? It is an item that:

  • people in the village call "Lightbringer"



  • requires some "sword" skill to use



  • looks like a big burning knife



  • can do slicing damage to things



  • but does fire damage too



  • it weights 8 kg



  • it costs 1000g and can be bought or sold



  • etc...



Those are the aspects of a fire sword that make it what it is. And every one of those aspects can be defined as separate component.

abstract class ItemComponent
{
    //What goes into base class entirely depends 
    //on how your game engine is implemented.
    //I left it out because it is irrelevant 
    //in context of this example
}

class Valuable : ItemComponent
{
    public int Cost { get; set; }

    public override string ToString()
    {
        return "It is a valuable item, that can be bought for " + Cost + "g.";
    }
}

class PhysicalDamage : ItemComponent
{
    public int Slashing { get; set; }
    public int Bashing { get; set; }
    public int Piercing { get; set; }

    public override string ToString()
    {
        return String.Format("It does {0}/{1}/{2} physical damage.", Slashing, Bashing, Piercing);
    }
}

class ElementalDamage : ItemComponent
{
    public int Fire { get; set; }
    public int Water { get; set; }
    public int Earth { get; set; }
    public int Wind { get; set; }

    public override string ToString()
    {
        return String.Format("It does {0}/{1}/{2}/{3} elemental damage.", Fire, Water, Earth, Wind);
    }
}

//etc...


And this is a typical game object that theoretically can represent anything from a stone on the ground to a bullet. It's just a collection of arbitrary components.

class Item
{
    public Item(string name)
    {
        Name = name;
    }
    //Name can be a component too! 
    public string Name { get; private set; }

    public Item AddComponent(ItemComponent component)
    {
        _components.Add(component);
        return this;
    }

    public T GetComponent()
    {
        return (T)_components.OfType().FristOrDefault();
    }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(Name);
        _components.ForEach(c => sb.AppendLine(c.ToString()));
        return sb.ToString();
    }

    private List _components = new List();
}


Then to create a fire sword all you need to do is create an item with all the necessary aspects:

var fireSword = new Item("Lightbringer")
                   .AddComponent(new Valuable { Cost = 1000 })
                   .AddComponent(new PhysicalDamage { Slashing = 10 })
                   .AddComponent(new ElementalDamage { Fire = 10 })
//Maybe it also makes you weak to water attacks? 
//No problem, just define and add new component
                   .AddComponent(new ElementalResistance { Water = -10 };
Console.WriteLine(fireSword.ToString())


This allows you to do all sorts of neat stuff later on. For example, to calculate total resistances of a player, you can call GetComponent() for every equipped item and sum the result.

Code Snippets

abstract class ItemComponent
{
    //What goes into base class entirely depends 
    //on how your game engine is implemented.
    //I left it out because it is irrelevant 
    //in context of this example
}

class Valuable : ItemComponent
{
    public int Cost { get; set; }

    public override string ToString()
    {
        return "It is a valuable item, that can be bought for " + Cost + "g.";
    }
}

class PhysicalDamage : ItemComponent
{
    public int Slashing { get; set; }
    public int Bashing { get; set; }
    public int Piercing { get; set; }

    public override string ToString()
    {
        return String.Format("It does {0}/{1}/{2} physical damage.", Slashing, Bashing, Piercing);
    }
}

class ElementalDamage : ItemComponent
{
    public int Fire { get; set; }
    public int Water { get; set; }
    public int Earth { get; set; }
    public int Wind { get; set; }

    public override string ToString()
    {
        return String.Format("It does {0}/{1}/{2}/{3} elemental damage.", Fire, Water, Earth, Wind);
    }
}

//etc...
class Item
{
    public Item(string name)
    {
        Name = name;
    }
    //Name can be a component too! 
    public string Name { get; private set; }

    public Item AddComponent(ItemComponent component)
    {
        _components.Add(component);
        return this;
    }

    public T GetComponent<T>()
    {
        return (T)_components.OfType<T>().FristOrDefault();
    }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(Name);
        _components.ForEach(c => sb.AppendLine(c.ToString()));
        return sb.ToString();
    }

    private List<ItemComponent> _components = new List<ItemComponent>();
}
var fireSword = new Item("Lightbringer")
                   .AddComponent(new Valuable { Cost = 1000 })
                   .AddComponent(new PhysicalDamage { Slashing = 10 })
                   .AddComponent(new ElementalDamage { Fire = 10 })
//Maybe it also makes you weak to water attacks? 
//No problem, just define and add new component
                   .AddComponent(new ElementalResistance { Water = -10 };
Console.WriteLine(fireSword.ToString())

Context

StackExchange Code Review Q#150855, answer score: 23

Revisions (0)

No revisions yet.