Silverlightを使って簡単なミニゲームを作る—Jewellery(Part 2)

7663 ワード

下一篇:Silverlightを使って簡単なミニゲームを作る—Jewellery(Part 1)
 
Jewelsからコードの作成を開始します.
まずはInitializeメソッド.スタート後、Jewel配列を埋めてCanvasに表示します.ここで注意したいのは、初期化のプロセスは、最終的な表示において、消去可能なJewelが存在しないことを保証することです.Jewelの種類はランダムに生成されるため、最も簡単な方法は、現在位置の行/列において、隣接位置に同じ種類のJewelが存在する場合、ランダムに生成される種類はこの種類ではない.コードは次のとおりです.
        private void Initialize()

        {

            for (int i = 0; i < this.RowCount; ++i)

                for (int j = 0; j < this.ColumnCount; ++j)

                {

                    this.JewelMap[i, j] = this.CreateJewel(i, j);

                }



            this.FillMap(this.KindCount);

        }



        private T CreateJewel(int x, int y)

        {

            T jewel = new T();

            jewel.IndexX = x;

            jewel.IndexY = y;

            jewel.Width = this.JewelWidth;

            jewel.Height = this.JewelHeight;

            jewel.Click += new EventHandler(jewel_Click);

            return jewel;

        }



        private void FillMap(int kindCount)

        {

            List<int> unallowed = new List<int>();



            for (int i = 0; i < this.RowCount; ++i)

                for (int j = 0; j < this.ColumnCount; ++j)

                {

                    T jewel = this.JewelMap[i, j];

                    if (i > 1 && this.JewelMap[i - 1, j].Kind == this.JewelMap[i - 2, j].Kind)

                    {

                        unallowed.Add(this.JewelMap[i - 1, j].Kind);

                    }

                    if (j > 1 && this.JewelMap[i, j - 1].Kind == this.JewelMap[i, j - 2].Kind)

                    {

                        unallowed.Add(this.JewelMap[i, j - 1].Kind);

                    }

                    int kind = rand.Next(kindCount);

                    while (unallowed.Contains(kind))

                        kind = rand.Next(kindCount);



                    jewel.Kind = kind;

                    unallowed.Clear();

                }

        }

各Jewelも初期化する必要があり、各Jewelを表示できるようにするには、JewelBaseにInitializeの虚メソッドを追加し、現在のCanvasに転送する必要があります.したがって、Jewelsを初期化した後、各JewelのInitializeメソッドを呼び出します.具体的な内容は、Jewelを実現する際に、またお話しします.
CreateJewelメソッドでは、JewelのClickイベントごとに、ユーザーのクリックを受信/選択するための統一的な処理方法をバインドします.これは、ユーザーのインタラクションを処理する鍵です.クリック処理があれば、次はSelectとUnselectで、現在選択されているJewelを記録する以外は、インタフェースIJewelSelectorを呼び出せばいいので、先にスキップします.ここでは主にExchangeメソッドと、Exchangeの後にTryToDestroyメソッドを扱うのがゲームの核心でしょう.これを言う前に、MoveでもDestroyでも、このプロセスはアニメーション表示のプロセスに違いないと説明したいと思います.SLでは、アニメーションの表示は一般的にthreadの問題です.アニメーション表示が終了したら、次の処理を行い、良い応答を得ることができます.だから、私たちはまずExchangeをして、2つのJewelのMoveアニメーションが終わるのを待って、TryToDestroyに来ます.Destroyもアニメーションであることを考慮して、ここでは単独でClassをしてEventを登録し、すべてのJewel応答が終わるのを待っています.大まかなコードは次のとおりです.
    public delegate bool EventCondition(string eventName);



    public static class JewelEvent

    {

        //  launch this method when a jewel finish its animation

        public static void Add(string name, JewelBase source)

        {

        }



        // get all jewels which has finished

        public static JewelBase[] GetSources(string name)

        {

        }



        public static T[] GetSources<T>(string name) where T : JewelBase

        {

        }



        public static void RegisterAndBegin(string name, int count, Action action)

        {

            RegisterAndBegin(name, (e) => GetSources(name).Length == count, action);

        }



        public static void RegisterAndBegin(string name, EventCondition condition, Action action)

        {

            RegisterAndBegin(name, condition, (Delegate)action);

        }



        // register a event, auto launch action depend on condition

        public static void RegisterAndBegin(string name, EventCondition condition, Delegate action, params object[] parameters)

        {

        }



        public static void Unregister(string name)

        {

        }



        public static bool HasRegistered(string name)

        {

        }



        public static void Begin(string name)

        {

        }



        public static void End(string name)

        {

        }



        public static void Reset(string name)

        {

        }

    }

このようにして、アニメーションがすべて終了したことを確認してから、次の判断を実行することができます.
private void Exchange(T source, T target)

{

    JewelEvent.RegisterAndBegin("Move", 2, this.ExchangeFinished);



    // launch JewelBase.MoveTo method

}



private void ExchangeFinished()

{

    if (!this.TryToDestroy())

    {

        // restore

        T[] jewels = JewelEvent.GetSources<T>(“Move”);

        this.Exchange(jewels[0], jewels[1]);

    }

}

これがExchangeメソッドの最も主要なことで、2つのJewelのMoveToメソッドを呼び出して、それらが新しい位置に移動できるようにし、移動が終了するのを待ってから、破棄できるJewelが存在するかどうかを判断し、存在しない場合、この2つのJewelの位置を回復します.
TryToDestroyという方法を見てみましょう.実は何も言うことはありません.横になってから、縦に破棄できるJewelを探して、3つ以上あれば破棄できます.ここでお話しするのは、やはりアニメーションの表示についてです.プログラムではまずすべてを巡り、破棄できるJewelを見つけて、重複していないことを確認し、リストに存在していることを確認し、最後にJewelのDestroyメソッドを呼び出します.やはりさっき言ったイベントのクラスを使います.大まかなコードは次のとおりです.
        private bool TryToDestroy()

        {

            List<T> jewels = new List<T>();



            // check row

            for (int y = 0; y < this.ColumnCount; ++y)

            {

                // ...

            }



            // check column

            for (int x = 0; x < this.RowCount; ++x)

            {

                // ...

            }



            if (jewels.Count == 0)

            {

                return false;

            }



            // destroy

            JewelEvent.RegisterAndBegin("Destroy", jewels.Count, this.DestroyFinished);

            jewels.ForEach((e) =>

                {

                    e.Destroy();

                    this.JewelMap[e.IndexX, e.IndexY] = null;

                });



            return true;

        }



        private void DestroyFinished()

        {

            T[] jewels = JewelEvent.GetSources<T>(JewelEventNames.Destroy);



            this.Fill(jewels); // fill empty location

        }

最後の方法は、Destroyの後、Jewelの補充作業をして、ゲームをずっと遊ぶことができます.:)やはり遍歴して、私はこの方法の中で、下から上へ遍歴して、nullの場所に出会って、私はメモして、それから上へ歩いて、Jewelを見つけた後に、このJewelのMoveTo方法を呼び出して、それを消えたJewelの位置に落とすことができます.見つからない場合は、転送された配列のJewelを先端に配置し、再初期化します.このような利点は、Jewelを新規作成する必要がなく、すべてのJewelインスタンスが重複して適用されることです.
        private void FillEmpty(T[] jewels)

        {

            List<T> sources = new List<T>();

            List<int> targetXs = new List<int>();  // save new location x

            List<int> targetYs = new List<int>();  // save new location y



            for (int x = 0; x < this.RowCount; ++x)

            {

                // ...

            }



            if (sources.Count == 0)

                return;



            JewelEvent.RegisterAndBegin("Move", sources.Count, this.FillFinished);

            for (int i = 0; i < sources.Count; ++i)

            {

                this.MoveTo(sources[i], targetXs[i], targetYs[i]);

            }



            sources.Clear();

        }



        private void FillFinished()

        {

            this.TryToDestroy();  // try to destroy again

        }

Fillを終えたら、TryToDestroyに行くことを忘れないでください.新しい充填のため、消去可能なJewelも存在するかもしれません.続けて消して、これもゲームの中で最も眩しいところでしょう.:)だから、ここは消去可能なJewelがなくなるまで循環します.
はい、これが核心の論理部分で、基本的にSLのものには触れません.次にJewelのアニメーションを処理し始め、本当に表示できるようにして、この論理を発揮させます.
 
未完待続...