views:

84

answers:

3
+1  Q: 

Modifier System C#

I am trying to figure out a system that can easily modify objects on the fly.

here is an example, Lets say I have an Entity2D that inherits from Entity. Entity2D has a Position property.

Now I have a class called ModifyPosition that inherits from Modifier.

Here is some code

public class Entity
{
/// <summary>
/// Applies the modifier to this entity.
/// </summary>
/// <param name="modifier">The modifier to apply.</param>
public void ApplyModifier(Modifier modifier)
{
    modifier.Apply(this);
}
}

/// <summary>
/// Modifies an entities position
/// </summary>
public class ModifyPosition : Modifier
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ChangePosition"/> class.
    /// </summary>
    /// <param name="position">The position.</param>
    public ChangePosition(Vector2 position)
    {
        this.Position = position;
        this.IsModifyingChildren = false;
    }

    /// <summary>
    /// Gets the position.
    /// </summary>
    /// <value>The position.</value>
    public Vector2 Position { get; private set; }

    /// <summary>
    /// Applies this change to the specified entity.
    /// </summary>
    /// <param name="entity">The entity.</param>
    internal override void Apply(Entity entity)
    {
        ((Entity2D)entity).X += this.Position.X;
        ((Entity2D)entity).Y += this.Position.Y;
    }
}

But if you are calling this multiple times per second I would think that the casting would slow it down.

Is there another way to go about this without having to cast?

+1  A: 

if you use an interface IEntity

interface IEntity
{
 double X{get;}
 double Y{get;}
}

have Entity implement that interface

public class Entity: IEntity
{
...
}

and use that as the parameter type for Apply

internal override void Apply(IEntity entity)
    {
        entity.X += this.Position.X;
        entity.Y += this.Position.Y;
    }

then you don't have to cast

Tion
A: 

With C# you have to ensure that the type you're modifying supports your modification (not true with some languages). So your modifiers will have to know explicitly which types they're modifying. (Alternately your entities could know about the modifiers, but it seems more reasonable to give the modifiers the knowledge.)

I don't actually have an answer for you at this point; this is my attempt, but I get a compiler error in the ModifyPosition.Apply declaration stating that you cannot specify type constraints on an overridden method implementation.

public interface IPositionableEntity
{
    Vector2 Position { get; set; }
}

public class Entity
{
    public void ApplyModifier<T>(T modifier) where T : Modifier 
    {
        modifier.Apply(this);
    }
}

public class Entity2D : Entity, IPositionableEntity
{
    public Vector2 Position { get; set; }
}

public class Vector2
{
    public double X { get; set; }
    public double Y { get; set; }
}

public abstract class Modifier
{
    public abstract void Apply<T>(T entity);
}

public class ModifyPosition : Modifier
{
    public ModifyPosition(Vector2 position)
    {
        Position = position;
    }

    public Vector2 Position { get; private set; }

    //Compiler error here:
    //Constraints for explicit interface implementation method are inherited
    //from the base method, so they cannot be specified directly
    public override void Apply<T>(T entity) where T : IPositionableEntity
    {
        entity.Position.X += Position.X;
        entity.Position.Y += Position.Y;
    }
}

EDIT - Here's one that at least compiles. The only change is to ModifyPosition.

public class ModifyPosition : Modifier
{
    public ModifyPosition(Vector2 position)
    {
        Position = position;
    }

    public Vector2 Position { get; private set; }

    public override void Apply(object entity)
    {
        if (!(entity is IPositionableEntity))
        {
            return; //throw, whatever
        }

        var positionableEntity = (IPositionableEntity) entity;
        positionableEntity.Position.X += Position.X;
        positionableEntity.Position.Y += Position.Y;
    }
}
arootbeer
Interesting, this might work but it might get anoying to have a lot of interfaces attached to a class when it starts to have a lot of properties that you want to change.
Chris Watts
See my comment on your question - I don't think it's going to be possible to solve this problem as generically as you want to in C#.
arootbeer
Your edit wouldn't help you are casting again.
Chris Watts
A: 

Hi,

Try something like this:

class CatEntity : Entity, IModifiablePosition
{
  // Interface method
  public void ModifyPosition(Vector2 blah) { ... }
...
}


class RobotEntity : Entity, IModifiableShader, IModifiablePosition
{
// Interface method
public void PushShader(RobotEffect bleh) { ... }
public void ModifyPosition(Matrix blah) { ... }
...
}

class ShaderModifier : IModifier
{
  public override void Apply(IModifiableShader obj)
  {
    obj.PushShader(m_furryEffect);
  }
}

class PositionModifier : IModifier
{
  public override void Apply(IModifiablePosition obj)
  {
    obj.ModifyPosition(m_mxTranslation);
  }
}

This seems easily readable and safe -- hope it works for ya.

vdeych