Monday, January 14, 2019

c# - How do I set up my modifier system without casting?


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
{
/// Applies the modifier to this entity.
/// The modifier to apply.
public void ApplyModifier(Modifier modifier)
{

modifier.Apply(this);
}
}

/// Modifies an entities position
public class ModifyPosition : Modifier
{
/// /// Initializes a new instance of the
class.///

/// The position.

public ChangePosition(Vector2 position)
{
this.Position = position;
this.IsModifyingChildren = false;
}

/// Gets the position.
/// The position.
public Vector2 Position { get; private set; }


/// Applies this change to the specified entity.
/// The entity.
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?



Answer



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;
};
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...