C # generic with a little difference for types?

Notice the two extensions: one for float, one for Vector3.

Note that there is only a slight difference in calling var( .

In C #, could they be written as a unit?

The essence of my question:

in general, can you make changes to the character type?

 public static IEnumerator Tweeng( this float duration, System.Action<float> vary, float aa, float zz ) { float sT = Time.time; float eT = sT + duration; while (Time.time < eT) { float t = (Time.time-sT)/duration; vary( Mathf.SmoothStep(aa,zz, t) ); // slight difference here yield return null; } vary(zz); } public static IEnumerator Tweeng( this float duration, System.Action<Vector3> vary, Vector3 aa, Vector3 zz ) { float sT = Time.time; float eT = sT + duration; while (Time.time < eT) { float t = (Time.time-sT)/duration; vary( Vector3.Lerp(aa,zz, t) ); // slight difference here yield return null; } vary(zz); } 

(BTW for any reading of C # gurus, code example in Unity, where you access the frame system in a coroutine.)

For any reading by Unity developers, examples of how you call Tweeng

 // tweeng z to 20 degrees in .12 seconds StartCoroutine(.12f.Tweeng( (t)=>transform.Eulers(0f,0f,t), 0f,20f) ); // fade in alpha in .75 seconds StartCoroutine(.75f.Tweeng( (u)=>{ca=u;s.color=c;}, 0f,1f) ); 

(If you are new to Unity and not familiar with the basic concept of extensions, here is intro .)

+4
generics c #
source share
3 answers

You can do this if you make an extra Func<T,T> that does the conversion before invoking the var action (which you must rename because var is the C # keyword).

Here is one way you could take:

 public static IEnumerator Tweeng<T>( this float duration , System.Action<T> varAction , T aa , T zz ) { Func<T,T,float,T> transform = MakeTransform<T>(); float sT = Time.time; float eT = sT + duration; while (Time.time < eT) { float t = (Time.time-sT)/duration; varAction(transform(aa, zz, t)); yield return null; } varAction(zz); } private static Func<T,T,float,T> MakeTransform<T>() { if (typeof(T) == typeof(float)) { Func<float, float, float, float> f = Mathf.SmoothStep; return (Func<T,T,float,T>)(Delegate)f; } if (typeof(T) == typeof(Vector3)) { Func<Vector3, Vector3, float, Vector3> f = Vector3.Lerp; return (Func<T,T,float,T>)(Delegate)f; } throw new ArgumentException("Unexpected type "+typeof(T)); } 

It can even be done inline:

 public static IEnumerator DasTweeng<T>( this float duration, System.Action<T> vary, T aa, T zz ) { float sT = Time.time; float eT = sT + duration; Func<T,T,float,T> step; if (typeof(T) == typeof(float)) step = (Func<T,T,float,T>)(Delegate)(Func<float, float, float, float>)Mathf.SmoothStep; else if (typeof(T) == typeof(Vector3)) step = (Func<T,T,float,T>)(Delegate)(Func<Vector3, Vector3, float, Vector3>)Vector3.Lerp; else throw new ArgumentException("Unexpected type "+typeof(T)); while (Time.time < eT) { float t = (Time.time-sT)/duration; vary( step(aa,zz, t) ); yield return null; } vary(zz); } 

Perhaps a more natural idiom

  Delegate d; if (typeof(T) == typeof(float)) d = (Func<float, float, float, float>)Mathf.SmoothStep; else if (typeof(T) == typeof(Vector3)) d = (Func<Vector3, Vector3, float, Vector3>)Vector3.Lerp; else throw new ArgumentException("Unexpected type "+typeof(T)); Func<T,T,float,T> step = (Func<T,T,float,T>)d; 
+3
source share

You can define your method as follows:

 public static IEnumerator Tweeng<T>(this float duration, System.Action<T> var, T aa, T zz, Func<T,T,float,T> thing) { float sT = Time.time; float eT = sT + duration; while (Time.time < eT) { float t = (Time.time - sT) / duration; var(thing(aa, zz, t)); yield return null; } var(zz); } 

And then using it:

 float a = 5; float b = 0; float c = 0; a.Tweeng(q => {}, b, c, Mathf.SmoothStep); 

Or:

 float a = 0; Vector3 b = null; Vector3 c = null; a.Tweeng(q => {}, b, c, Vector3.Lerp); 

Alternatively, if you want to get rid of passing a method, you can have simple overloads to process it:

 public static IEnumerator Tweeng(this float duration, System.Action<float> var, float aa, float zz) { return Tweeng(duration, var, aa, zz, Mathf.SmoothStep); } public static IEnumerator Tweeng(this float duration, System.Action<Vector3> var, Vector3 aa, Vector3 zz) { return Tweeng(duration, var, aa, zz, Vector3.Lerp); } private static IEnumerator Tweeng<T>(this float duration, System.Action<T> var, T aa, T zz, Func<T,T,float,T> thing) { float sT = Time.time; float eT = sT + duration; while (Time.time < eT) { float t = (Time.time - sT) / duration; var(thing(aa, zz, t)); yield return null; } var(zz); } 

And then using it:

 float a = 5; float b = 0; float c = 0; a.Tweeng(q => {}, b, c); 

Or:

 float a = 0; Vector3 b = null; Vector3 c = null; a.Tweeng(q => {}, b, c); 

<h / "> Stub methods to compile in LINQPad / without unit:

 public class Mathf { public static float SmoothStep(float aa, float zz, float t) => 0; } public class Time { public static float time => DateTime.Now.Ticks; } public class Vector3 { public static Vector3 Lerp(Vector3 aa, Vector3 zz, float t) => null; } 
+3
source share

I liked the Tweeng thing, but why expand the float if Coroutine can only be used on MonoBehaviours? You have to make extensions for MonoBehaviour, so, for example, I made an extension for interpolation:

 public static void _Interpolate(this MonoBehaviour monoBehaviour, float duration, Action<float, bool> callback, float from, float to, Interpolator interpolator) { monoBehaviour.StartCoroutine(ExecuteInterpolation(interpolator, duration, callback, from, to)); } 

So, I just started Coroutine inside the extension:

 private static IEnumerator ExecuteInterpolation(Interpolator interpolator, float duration, Action<float, bool> callback, float from, float to) { float sT = Time.time; float eT = sT + duration; bool hasFinished = false; while (Time.time < eT) { float t = (Time.time - sT) / duration; // ----> my logic here with callback(to, false) yield return null; } hasFinished = true; callback(to, hasFinished); } 

Please note that I have a logical expression to say that the interpolation is complete, this is because it is not best to rely on a comparison with a floating point to check the end of the stream if it rounds the result to the maximum result to the last that we are going to to call a callback for the last interaction called twice.

0
source share

All Articles