2
\$\begingroup\$

I am trying to create a system that can easily modify objects on the fly. For example, lets say I have an Entity2D that inherits from Entity. Entity2D has a Position property. I also have a class called ModifyPosition that inherits from Modifier.

Here is the 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;
    }
}

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?

\$\endgroup\$
17
  • \$\begingroup\$ This "architecture" is pretty horrible, just by the way. The only place I could see this making sense is an editor where you undo and redo commands (modifiers). Which you won't be doing "on the fly" or "multiple times per second". Is there another way to do this? Yes - just modify the values directly! In game development you should never get more fancy than you need to. \$\endgroup\$ Jul 23, 2010 at 6:59
  • \$\begingroup\$ I have seen multiple particle engines use this type of method for modifying particles at runtime. How would you suggest I change values directly, lets say if there was an event that happened, like a ball hit the wall, and i wanted to change the color of that ball. How would I gain access to that property dynamicly lets say i want to set that up in the editor. \$\endgroup\$ Jul 23, 2010 at 17:03
  • \$\begingroup\$ @Andrew: In principle, I can think of a few cases where this sort of architecture would be useful. Think about strategy games: some object/entity properties might be modified by external factors (i.e. structures providing bonuses to various units). In such cases, you may not want to modify the effective value directly: instead, you would want want to recompute the effective value any time the base value changes or a modifier is added, removed, or invalidated. However, you would want the modifier to accept the base value and current effective value, and return the modified effective value. \$\endgroup\$ Aug 9, 2010 at 22:38
  • \$\begingroup\$ @Mike: In that case you'd still be better off making each bonus-giving object hold a delegate that defines the bonus behaviour. Rather than having an "additive bonus class" and a "multiplicative bonus class" and an "exponential bonus class" and so on. \$\endgroup\$ Aug 10, 2010 at 1:45
  • \$\begingroup\$ @Andrew: Well, one may want some additional metadata exposed, as well as an 'Invalidated' event to signal that a modifier's effect has changed and the affected property should be reevaluated. Therefore, it could be appropriate to have a Modifier class. However, instead of writing several different implementation classes, the Modifier class could simply accept a value modifier delegate (like what you described) and invoke as required. That's essentially what I have done in the past. \$\endgroup\$ Aug 10, 2010 at 4:57

4 Answers 4

6
\$\begingroup\$

To expand on my comment from earlier and give you a full answer:

A good way to modify values on the fly is to modify them directly using C#

It sounds like what you're trying to implement is something like Klik & Play or Unreal Kismet (and to a lesser extent the level-entity-triggering system from Unreal and some other engines).

What you need to keep in mind is that these systems make sense for companies like Epic because they (and their licensees) are creating enormous volumes of content - and it's cheaper to enable a non-programmer to make it dynamic, than it is to require a programmer to do it. (With volumes like Epic's - even a entry-level programmer working in a managed language like C# or UnrealScript is expensive enough to justify such a system.)

For the rest of us who are not making AAA middleware - making a system like that is just cargo-cult engineering. (And if you are making that kind of middleware, this is not how I'd approach it anyway.)

Basically you're adding a layer of indirection to your programming. Every time you want some new functionality you're going to have to program it anyway. Except you'll also have to wrap it in a new Modifier class (including, presumably: serialization, editable properties, considerations of re-usability, etc), and then add it to your level and link it up. And you lose the magic of version control, refactoring support, debugging, etc. And heaven help you if you want to modify a Modifier - have fun checking all your levels still work!

(By the way: I learned all this the hard way - which is why I'm being so opinionated about it.)

So that's my little rant about your architecture out of the way. What should you do?

Well you already have a fantastic editor: it's called Visual C#. In a very basic sense you should just give each level in your game a class/.cs file - and dynamically instance that class when the level starts (or whatever makes sense for your game).

And all the time you save not making your Modifer system, you could spend adding nice features like on-the-fly recompilation. (By the way: if you're concerned about end-user modding - remember that Visual C# Express is free, and the C# compiler comes with the .NET runtime.)

As to particle systems, which you mentioned in your comment: Are you nuts? Where did you see that? Particle systems need fast throughput - and I don't see that happening with a virtual function call and a cast, and using reference types for each particle!

In the ideal CPU performance case, a particle system should have a tight loop that moves through an array of structs containing a position and a velocity vector. Actually - better yet: a single draw call that gets the GPU to handle it all in a vertex shader.


Just to give you an idea of what I'm talking about, here's what your ball example might look like:

public void LevelStart()
{
    this.Walls["magicWall"].OnTouch += (touchedBy) =>
    {
        Ball ball = touchedBy as Ball;
        if(ball != null)
            ball.Color = Color.Blue;
    };
}
\$\endgroup\$
4
  • \$\begingroup\$ About the particle system, I didnt mean to say it was just like I had explained before. It used structs in a pretty tight loop but in that it would also pass those structs through a modifier class which would make the particles do things like change color or position or w/e Other than that I do think you have a good point about the AAA game titles, im still not sure if thats the way i want to go about it though \$\endgroup\$ Jul 24, 2010 at 17:36
  • \$\begingroup\$ @Chris: Rather than making a messy system with "modifiers", just code each "modifier" directly as a C# function and pass them to your particle system as delegates. This gives you a nice lightweight architecture and surprisingly good performance. (Of course you should do the benchmark if it matters, like this gent has done: gamedev.net/community/forums/topic.asp?topic_id=494239) \$\endgroup\$ Jul 25, 2010 at 0:36
  • \$\begingroup\$ thanks for the example, Im not that familiar with lambda expressions in C#. Could you explain a little more? \$\endgroup\$ Aug 10, 2010 at 18:24
  • \$\begingroup\$ @Chris: Do you understand delegates? It's just a shorter syntax (when used in this way). (touchedBy) => is the same as delegate(GameObject touchedBy). For the lambda the compiler will infer the type GameObject (or whatever) from what OnTouch is expecting. \$\endgroup\$ Aug 11, 2010 at 2:08
8
\$\begingroup\$

You really shouldn't need to worry about this unless you are doing this millions and millions of times per frame. This graph shows some empirical data about the speed of casting:

Casting Speeds
Source: "Type casting impact over execution performance in C#" by Emilio Guijarro, 2004

Keep in mind that there are about 17 milliseconds per frame at 60 frames per second, and about 33 milliseconds at 30 frames per second.

\$\endgroup\$
2
  • 5
    \$\begingroup\$ This answer makes a key point: Without data, arguing about performance is entirely useless. So if you think something is too slow, measure it. \$\endgroup\$ Jul 22, 2010 at 1:45
  • \$\begingroup\$ This is very good news i will keep this in mind from now on =) \$\endgroup\$ Aug 10, 2010 at 18:25
1
\$\begingroup\$

While I agree with the above that I wouldn't do it this way, and that you should measure actual performance hit, it's beside the discussion.

To me the cast kinda tells me your setup is wrong. For one, what if the cast fails?

I'd definitely advise you to look into interfaces and/or 'observer/visitor pattern'.

Alternatively wonder about a class Modifiable, where then that vector2 can derive from (instead of entity), so you know you're type-safe. Have your entity have a ModifiableVector2 as a member and work on that?

\$\endgroup\$
0
\$\begingroup\$

Speed it up:

internal override void Apply(Entity entity)
{
    Entity2D entity2d = entity as Entity2D;
    if (entity2d)
    {
        entity2d.X += this.Position.X;
        entity2d.Y += this.Position.Y;
    }
}

The "as" cast is faster and returns null if the object can't be casted. You also avoid the second cast but don't ask me if the if statement is faster, slower or equal than the cast. Honestly, I couldn't care less unless you know this to be an issue. Which it won't. That I'm 99.9% sure of.

Anyway, the "as" cast with null-pointer check is a C# best practice. It won't crash if at one time the entity really is just an Entity, not a Entity2D.

You could also write a Modifier class which runs Apply only on Entity2D objects if you're that worried about performance. Or change all your game entities to be of Entity2D and also change the Modifier class. It's a matter of trading off memory vs. speed.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .