1

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?

Chris Watts
  • 2,284
  • 4
  • 23
  • 28
  • what did you do, delete and re-ask the question? Not a great way to get answers – µBio Jul 21 '10 at 23:58
  • 1
    It's probably strange to have an object come along and modify an object from the outside (and arguably breaks several guidelines). Is there any reason you need to do this, as opposed to having the modification code internal to the object? – Noon Silk Jul 21 '10 at 23:58
  • @Lucas it was an accedent... =/ and I didnt get to read the answers that were posted so i tried to re ask it... sorry. Did you answer it before? would you mind reposting your answer? again sorry it was my mistake. @silky I was thinking if i had a way to modify the object from the outside it would make it easier to be able to change the object's properties on the fly like in an editor. – Chris Watts Jul 22 '10 at 00:03
  • @Chris: It's almost always better to build the modification process in. The reason is that you can write class-specific code inside the class, and you have access to the private functionality, etc. Consider changing to this approach, and I basically guarantee your life will be better and your code will be easier to follow :) – Noon Silk Jul 22 '10 at 00:07
  • I think it would be better have Entity have an Apply(IModifier modifier) method. entity.Apply(moveToNewPosition) looks more useful – Tion Jul 22 '10 at 00:09
  • @silky Well what if i had a colored ball and i wanted to change the color every 5 seconds and had a trigger that would fire every 5 seconds to change the color how would I gain access to that balls color attribute without having the code in the actual ball class. because i dont want to have every case in the ball class. – Chris Watts Jul 22 '10 at 00:11
  • @Tion can you give an example of how that would work? – Chris Watts Jul 22 '10 at 00:16
  • @Chris I'm no games programmer, so I probably can't comment. Naively, I would consider some sort of event-model to say 'ChangeState' and pass in the state to change (colour) and let the object handle it appropriately (it may not change, if it doesn't want to). – Noon Silk Jul 22 '10 at 00:19
  • @silky that is interesting i will look into that. – Chris Watts Jul 22 '10 at 00:22
  • I'm honestly not sure it's possible in C#. In a language like Objective-C, where you can send any message you want to any object you want, you can implement this sort of thing with impunity; if something doesn't support your message, it doesn't matter. In C#, either the modifier has to know about the entity, or vice versa. As my example below shows, you can't even have a base modifier class that doesn't know about the specific entity type you're trying to modify. I'll be very interested to see if this gets solved as generically as you're hoping for. – Matt Mills Jul 22 '10 at 00:42
  • I think someone answered it with a way to do it but i accidentally deleted the post... =/ – Chris Watts Jul 22 '10 at 00:45

3 Answers3

1

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
  • 1,470
  • 17
  • 27
0

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;
    }
}
Matt Mills
  • 8,692
  • 6
  • 40
  • 64
  • 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 Jul 22 '10 at 00:34
  • 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#. – Matt Mills Jul 22 '10 at 00:44
0

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.

Vasiliy Kulakov
  • 5,401
  • 1
  • 20
  • 15