1 module sbylib.graphics.action.animation; 2 3 public import std.datetime; 4 public import sbylib.graphics.action.interpolation : Interpolation; 5 import sbylib.graphics.action.action : IAction, ImplAction; 6 7 class Animation(T) : IAction { 8 private T delegate() getValue; 9 private void delegate(T) setValue; 10 private void delegate(float) updateFunction; 11 private Duration _period; 12 13 mixin ImplAction; 14 15 this(T delegate() getter, void delegate(T) setter) { 16 this.getValue = getter; 17 this.setValue = setter; 18 } 19 20 this(ref T value) { 21 this.getValue = () => value; 22 this.setValue = (T v) { value = v; }; 23 } 24 25 Animation to(T arrival) { 26 import std.typecons : Nullable, nullable; 27 28 Nullable!T departure; 29 updateFunction = (float t) { 30 if (departure.isNull) departure = getValue().nullable; 31 setValue(T(departure.get() + (arrival - departure.get()) * t)); 32 }; 33 34 return this; 35 } 36 37 Animation interpolate(Interpolation i) { 38 const b = updateFunction; 39 updateFunction = (float t) => b(i(t)); 40 return this; 41 } 42 43 Animation period(Duration period) { 44 this._period = period; 45 return this; 46 } 47 48 override void start() { 49 import std.datetime : Clock; 50 import sbylib.event : when, then, until, Frame, finish; 51 52 auto starttime = Clock.currTime; 53 54 auto event = when(Frame).then({ 55 auto t = cast(float)(Clock.currTime - starttime).total!("msecs") / _period.total!("msecs"); 56 updateFunction(t); 57 }) 58 .until(() => Clock.currTime > starttime + _period || killed); 59 60 when(event.finish).then({ 61 this.notifyFinish(); 62 }); 63 } 64 }