bodangly
bodangly

Reputation: 2624

How would I have properties of an object modified only by components of that object in C#?

So let's say I have an interface in my game, IItem. IItem represents an object with a render component, a weight, and an attached "process". The process may be attached by someone using some ability to affect the item. Maybe something like an "enchantment" in an RPG. Let's say I want that attached process to be able to modify the weight of the IItem. However, I only want a process which is a component of the IItem to be able to do so. Objects outside of the IItem need to be able to get the weight though.

Do I implement a Weight property, with just a getter in the interface? Then does the base class implement a "SetWeight" method, which is declared internal to the Item namespace? That still does not really guarantee that only a component owned by the particular IItem can affect it of course, but at least something in the Input namespace cannot directly change the weight of an item. In C I could do something similar to linked lists in the kernel which can get their container, this would give me a way to make sure the weight and the process had the same container object, however, I do not see an easy way to do this in C#. Furthermore, I think it kind of damages the component based design for a component to have to have a reference back to its parent.

This is a general problem I am running in to as I design my interfaces and classes.

Upvotes: 0

Views: 67

Answers (2)

Falgantil
Falgantil

Reputation: 1310

Have you considered using a Dictionary, instead of properties? Something like this:

// Item base class
public Dictionary<string, object> Attributes { get; private set; }

public List<Process> Enchantments { get; private set; }

public virtual T Get<T>(string identifier)
{
    var att = this.Attributes.FirstOrDefault(att => att.Key == identifier);
    if (att == null) throw new MissingAttributeExeption(identifier); // Or perhaps just return default(T)
    if ((att.Value is T) == false) throw new InvalidAttributeCastException(identifier, typeof(T));  

    var value = att.Value;
    foreach (var ench in this.Enchantments)
    {
        ench.Modify(identifier, ref value);
    }

    return value as T; // Maybe you need to cast value to Object, and then to T, I can't remember.
}

// Process class

public string ValueToModify { get; set }

public virtual void Modify(string identifier, ref object value)
{
    if (identifier != this.ValueToModify) return;

    // In an inherited class, for example a Weightless-Enchantment: Halfs all weight
    var castedVal = value as int
    value = castedVal / 2;
    // Now this one item weights 50% of normal weight, and the original value is still stored in Item's Attributes dictionary.
}

// Some random class

public void Update()
{
    var totalWeight = 0;
    foreach (var item in this.itemCollection)
    {
        int weight = item.Get<int>("Weight");
        totalWeight += weight;
    }
    Console.WriteLine("The player weights: {0}", totalWeight);
}

Obviously this means you can't really hardcode attributes, but... Do you ACTUALLY want to do this, in the long run? I mean once you start adding Intelligence, Agility, Strength, Stamina, Endurance, etc.

I know this doesn't solve your posed question, but I should think it's a pretty decent alternative.

Upvotes: 1

Giora Guttsait
Giora Guttsait

Reputation: 1300

Well, I think I get what you're talking about.

To ensure that your process, e.g. IEnchantment may take an IItem as a dependency(keep it as a member), and have IItem have Update/Set methods that take an IEnchantment, and then you can check that, for example:

public void Update(IEnchantment enchantment)
{
    if (enchantment.AttachedItem != this)
        throw new Exception("Cannot Update Item!");
    /*
     * Execute Updating Logics
     */
}

Here's one library I tried designing for my own games, maybe it can help you think about something. It's far from perfect, it's barely anything at all, but I hope it can help in any way.

Upvotes: 1

Related Questions