开发者

Approaches for animating a C# property over time?

开发者 https://www.devze.com 2023-02-02 00:38 出处:网络
I\'m currently trying to animate a bunch of public properties on certain objects. Usually they are of type float or vectors of floats (the type is known at compile-time). I want to be able to:

I'm currently trying to animate a bunch of public properties on certain objects. Usually they are of type float or vectors of floats (the type is known at compile-time). I want to be able to:

  1. assign a static value to them (MyObject.Duration = 10f;) or
  2. assign a random value to them by specifying a minimum and maximum value and optionally also a weight (MyObject.Duration = new RandomFloat(5f, 20f, 2f);) or
  3. "bind" this property to the property of another object (think of a child object binding some of its properties to its parent object, like its color or size or sth.) or
  4. assign sort of a keyframe animation to them, specifying a variable number of keyframes with timecode and the property's value at that specific point in time as well as information about how to interpolate between these frames

The keyframes should be able to accept random values for each frame, both for the time and the property's value.

What would be a practical approach for this kind of system? Currently I'm thinking about polymorphism: implement a base class or interface with a public Value-property and/or GetValue(float time)-method and then creating dif开发者_C百科ferent sub classes like StaticValue, RandomValue, BindingValue and AnimatedValue implementing this base class or interface. Doesn't seem very elegant, though, and the initialization of even simple objects becomes a bit tedious.

Another idea would be to implement these properties just as regular floats or vectors and create special "Modifier"-types binding to these properties. To retrieve the "real" value of the property, I'd first call any Modifier bound to the property, which would in turn update the actual object's property for me to retrieve later on. That would most likely mean using reflection at some point, which could be quite bad for performance as I'll probably have thousands of properties to update dozens of times per second.

Any suggestions on this? Being a novice I'm (hopefully) missing some far more elegant and/or practical solution than I'm already playing around with :(

Edit: Probably should have mentioned this earlier, but WPF isn't an option - it's not available on all targetted platforms, so I can't rely on it. I'm aware of its powerful databinding and animation capabilities, but I need to roll my own (or find some other lightweight alternative meeting my needs).


I think the polymorphic solution that you describe is the most elegant OO-way to do this. What do you find inelegant about it?

As for using the actual data type and modifier types, I suggest that you look at using implicit operator overloads.

You can define your class with all of the behaviour you need, but provide a conversion to/from the "value" type, so you can get/assign values as though it is that type. An example will help:

public class MyFloat
{
    float innerValue;

    // private constructor; instantiate using a float directly
    private MyFloat(float innerValue) { this.innerValue = innerValue; }

    public string Description { get { return "some metadata"; } }

    public int NumberOfFrames { get; set; }

    // conversion from MyFloat to float
    public static implicit operator float(MyFloat mine)
    {
        return mine.innerValue; // you can access private members here
    }

    // conversion from float to MyFloat
    public static implicit operator MyFloat(float val)
    {
        return new MyFloat(val); // use the private constructor
    }
}

In usage, then, you can do things like this:

MyFloat mine = 9f; 
mine.NumberOfFrames = 15;

or…

if(mine > 0f)…

As for the tedium of instantiation, I think this sort of scenario is the perfect candidate for an internal DSL/fluent interface.

You could make up something expressive and terse, like:

var animatedObject = Sprite.with(RandomMotion.animatated_between(0f).and(10f))
    .lasts(4).seconds;
var otherObject = Sprite.with<NoMotion>().starts_at(100, 0);
var yetAnother = Sprite.with(SteadyMotion.at(7f))
    .starts_at(100, 200)
    .weighing(.5f)
    .lasts(15).frames;
0

精彩评论

暂无评论...
验证码 换一张
取 消