2012-04-10 15 views
1

を実行するクラスを一般化し、線形補間の結果に基づいて、スプライトのアルファレベルを更新し、次のコードがあります。C#クラス編成/構造は - 私はC#のXNAゲームに取り組んでいますルーピング線形補間

class AlphaProcess : GameProcess { 

    Sprite sprite; 
    public Sprite Sprite { 
     get { return sprite; } 
     set { sprite = value; } 
    } 

    float start; 
    public float Start { 
     get { return start; } 
     set { start = value;} 
    } 

...<snip>... 

    public override void Update(float elapsed) { 
     if (FirstUpdate) { 
      Start = sprite.Alpha; 
      FirstUpdate = false; 
     } 

     Time += elapsed; 
     if (Time >= Duration) 
      Finished = true; 

     sprite.Alpha = MathHelper.Lerp(start,end,Time/Duration); 
    } 
} 

'Start'(float)、 'FirstUpdate'(bool)、 'Time'(float)、 'Duration'(float)はAlphaProcessクラスのすべてのフィールドです。 'Sprite'は、スケール、位置、方向、回転などの詳細を含むクラスです。

'Update'メソッドは、指定された期間に渡ってスプライトの新しいアルファ値を1秒間に60回呼び出されます。ゲームプロセスが終了すると、GameProcessはキューから削除されます。

このコードは正常に動作しますが、非常に具体的です。私が持っているSpriteクラスには、一定の時間(回転、位置(イージーイン/アウトのため))にわたって移動するのに便利な多くのプロパティが含まれています。これらの変数の多くはフロートです。異なる変数上で、まったく同じことをする複数の 'GameProcess'拡張クラスを作成することは馬鹿馬鹿しいようです。しかし、私はどのように最良のリファクタリングを行うかを考えることができないので、特定のスプライトでなく、変更されている浮動小数点値へのポインタを持つことができ、アルファ/回転/スケール/任意の値です。

私はC#の参照/値/パラメータを使用しているので、あなたはフィールドとして参照を保存することはできません。 Updateを呼び出す 'GameProcessQueue'は更新されている 'GameProcess'の内部構造を何も知らない。 これを行うよりスマートな方法があるので、クラスを一般化/抽象化して別のクラスのフィールドを更新することができます(ここでは 'Sprite'の 'Alpha'フィールド)。

答えて

2

... CALCSと...すべての問題を与えるが、汎用デリゲートを避けるべきです。これには、Tweening、Lerping、Sprite Alpha Valueの取得/設定の3つの主要な役割があります。設計を改善するには、これらを分離した分離クラスに分割する必要があります。

ゴール: AlphaProcessをTweenProcessに変更します。

スプライトを渡す代わりに、操作したいフロートを取得して設定できるインターフェイスを渡します。そして、Lerpを直接呼び出すのではなく、インターフェイスに渡すかTween関数に委譲します。 (私は代表者が頻繁にあなたのゲームが吃音を引き起こすことができますゴミを作成見つけたので、私は代わりに、デリゲートのインタフェースを使用しました。)

トゥイーンクラスは次のとおりです。

interface IFloatPropertySource 
{ 
    float FloatProperty { get; set; } 
} 

interface ITweenFunction 
{ 
    float Tween(float start, float end, float t); 
} 

class TweenProcess : GameProcess 
{ 
    float start; 
    IFloatPropertySource floatSource; 
    ITweenFunction tweenFunction; 

    public TweenProcess(IFloatPropertySource floatSource, ITweenFunction tweenFunction) 
    { 
     this.floatSource = floatSource; 
     this.tweenFunction = tweenFunction; 
    } 

    public override void Update(float elapsed) { 
     if (FirstUpdate) { 
      start = floatSource.FloatProperty; 
      FirstUpdate = false; 
     } 

     Time += elapsed; 
     if (Time >= Duration) 
      Finished = true; 

     floatSource.FloatProperty = tweenFunction.Tween(start, end, Time/Duration); 
    } 
} 

取得/アルファを設定するためのクラスがある:

class SpriteAlphaSource : IFloatPropertySource 
{ 
    Sprite sprite; 

    public SpriteAlphaSource(Sprite sprite) 
    { 
     this.sprite = sprite; 
    } 

    public float FloatProperty 
    { 
     get 
     { 
      return sprite.Alpha; 
     } 
     set 
     { 
      sprite.Alpha = value; 
     } 
    } 
} 

私はあなたが一種のこのクラスを避けるためにしようとしている知っています。しかし、反射を経由するような、その周りのすべての方法は本当に高価です。スプライトだけでなくレンダラブルが多いプロジェクトではスプライトからデカップリングし、代わりにIRenderableのようなベースインターフェイスで動作させることができます。

lerpingメカニズムは次のとおりです。このような代表団の*トン*のようにあなたのために事前に定義されていることに留意すべきである

class Lerp : ITweenFunction 
{ 
    public float Tween(float start, float end, float t) 
    { 
     return MathHelper.Lerp(start, end, t); 
    } 
} 
+0

あなたは正しいです - 「あなたがこのクラスを持たないようにしようとしていることはわかっていますが」 - これはまだ私が持っているものを構造化するもっと良い方法です。ちなみに、私は既に 'Animation'のクラスを持っています(基本的には、 'ITweenFunction'を実装しています.AlphaProcess(とSOの簡潔さではない)。 – codinghands

+1

また、好奇心の理由から、 m_ 'プレフィックス? – codinghands

+0

心配ありません。素晴らしい質問。m_(メンバ変数)プレフィックスはC++の遺産であり、ここではベストプラクティスではありません。 – Empyrean

2

基本的には、コールバック関数をUpdateクラスに渡します.C#用語では、デリゲート関数を使用します。クライアントコードでは、

public delegate SetThis(float value) { get; set; } 

はそれを設定するようになりますあなたのクラスにプロパティを追加し、あなたは、あなたが

myAlphaProcess.SetThis = (x => sprite.Alpha = x;) 

好きで、更新()関数で何かを持っている

SetThis(MathHelper.Lerp(start,end,Time/Duration)); 

私はこのコンピュータにコンパイラを持っていないので、この回答の文法はで、ですが、これはあなたのやり方です。良いgoogle検索は "lambda C#"または "delegate C#"となります。

+2

: 'アクション'、 'アクション' ...と ' Func '、' Func '、' Func ''アクション 'はvoidを返すデリゲートであり、' Func'sは最後の型パラメータを返します。 – Crisfole

+0

実際には、申し訳ありませんが、これに少し問題があります。あなたはどこに行くのかを詳しく説明できますか? – codinghands

1

これは

これは右でなければなりません...多分あなたはTweenManagerを行うと更新のみアクティブトゥイーンのためのコレクションにトゥイーンを追加する必要があります...その問題への一般的なアプローチすることができますが、私はそうではありませんそれを確認...多分ジェネリック医薬品は、あなたの主な問題は、あなたのAlphaProcessクラスが低い結束を持っているということです:)

Tweenable<float> Alpha = new Tweenable(defaultvalue); 

public class Tweenable<T> 
{ 
    public T Value { 
      get { return Function(elapsed, source, target-source, duration);} 
      private set { source = value; elapsed = 0;} 
    } 

    public TweeningFunction<T> Function; 

    float elapsed, duration; 
    T source, target; 

    public void Update(float Elapsed) 
    { 
      if (elapsed<duration) 
      { 
       elapsed+= Elapsed; 
       if (elapsed > duration) elapsed = duration; 
      } 
    } 

    public void Start(T Source, T Target, float Duration) 
    { 
     ... 
    } 
} 

public delegate T TweeningFunction(float timeElapsed, 
              T start, 
              T change, 
              float duration); 


public static partial class Tweening {  
     public static class Quartic { 
      public static float EaseIn(float t, float b, float c, float d) { 
       return c * (t /= d) * t * t * t + b; 
      } 
      public static float EaseOut(float t, float b, float c, float d) { 
       return -c * ((t = t/d - 1) * t * t * t - 1) + b; 
      } 
      public static float EaseInOut(float t, float b, float c, float d) { 
       if ((t /= d/2) < 1) { 
        return c/2 * t * t * t * t + b; 
       } 
       return -c/2 * ((t -= 2) * t * t * t - 2) + b; 
      } 
     } 
    } 
関連する問題