To create lightweight Windows Phone7 game engine -Samurai fourth Button (on)

Recommended for you: Get network issues from WhatsUp Gold. Not end users.
I'm going to Button module is divided into two parts to introduce the first part is the introduction, draw sprites, second part is the official Button.
First, what is the Button? Or that Button should be what it's like?
Of course, in our ordinary experience, Button is not a button you can be clicked, and the realization of the corresponding function. It is usually a rectangular area, inside to write on related functions, click seems to be pressed. Generally the case.
The essence of Button in Samurai is more interaction with the SAInput interface class Sprite.
What is genius? Is a series of actions we used to draw the game character class.
We first defined in the base class SASprite sprite class (of course or abstract class)

 public abstract class SASprite
    {
        public Texture2D texture;
        public Color color;
        public Vector2 position;

        public virtual Vector2 Size { get { return new Vector2(rectangle.Width, rectangle.Height); } } //Gets the size of the Sprite
        public virtual Rectangle rectangle { get { return new Rectangle((int)position.X, (int)position.Y, (int)Size.X, (int)Size.Y); } }//Collision rectangular access Sprite
        public virtual Rectangle sourceRectangle { get; set; } //Image rendering interception

        public SASprite() { }
        public SASprite(Texture2D texture) : this(texture, Vector2.Zero) { }
        public SASprite(Texture2D texture, Vector2 positon) : this(texture, (int)positon.X, (int)positon.Y) { }
        public SASprite(Texture2D texture, int pos_x, int pos_y)
        {
            this.texture = texture;
            this.position = new Vector2(pos_x, pos_y);
            this.color = Color.White;
        }
        //Judge whether the intersection
        public virtual bool IfCollide(Rectangle rect)
        {
            return rectangle.Intersects(rect);
        }
        //Draw interface for external calls
        public void Draw()
        {
            Draw(SAGlobal.spriteBatch);
        }
        public virtual void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, color);
        }
    }
This is the most simple a sprite class the most basic, it is only one texture (image), the relevant color, position information (here why attribute, and virtual? Look behind you know)
It contains the basic "collision" and "mapping" method.
SASprite has two sub class, one can only draw a frame of image SASimpleSprite, a mapping can be multi frame animation SAActionSprite (well, he was the grandson of SASprite class):
Have a look first to SASimpleSprite:

 public class SASimpleSprite:SASprite
    {
        public SASimpleSprite() { }
        /// <summary>
        /// In drawing the whole texture specified location
        /// </summary>
        /// <param name="texture">Texture</param>
        /// <param name="postion">Position</param>
        public SASimpleSprite(Texture2D texture, Vector2 postion)
        {
            this.texture = texture;
            this.sourceRectangle = new Rectangle(0,0,texture.Bounds.Width,texture.Bounds.Height);
            this.position = position;
            this.color = Color.White;
        }
        /// <summary>
        /// Draw a texture
        /// </summary>
        /// <param name="texture">Texture</param>
        public SASimpleSprite(Texture2D texture)
            : this(texture, Vector2.Zero)
        { }
        /// <summary>
        /// Draws the specified range of sourceRectangle texture in the specified position
        /// </summary>
        /// <param name="texture">Texture</param>
        /// <param name="sourceRectangle">Texture rectangle</param>
        /// <param name="position">Position</param>
        /// <param name="color">The specified color</param>
        public SASimpleSprite(Texture2D texture,Rectangle sourceRectangle,Vector2 position,Color color)
        {
            this.texture = texture;
            this.sourceRectangle = sourceRectangle;
            this.position = position;
            this.color = color;
        }
        public SASimpleSprite(string resource, Vector2 position)
            : this(SAGraphicUtil.GetImage(resource), position) { }
        public SASimpleSprite(string resource)
            : this(SAGraphicUtil.GetImage(resource)) { }
        public SASimpleSprite(string resource, Rectangle sourceRectangle, Vector2 position, Color color)
            : this(SAGraphicUtil.GetImage(resource), sourceRectangle, position, color) { }

        public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, sourceRectangle, color);
        }
    }

Come have a look SAActionSprite:

    public class SAActionSprite:SASimpleSprite
    {
        /// <summary>
        /// The recommended practice is: 
        /// These data will be a static method in a subclass of initialization (of course to static variables corresponding to another set of)
        /// In constructing method directly on the _sourceRectangles & _sizes Fuvalue
        /// </summary>
        public Rectangle[] _sourceRectangles;
        public Vector2[] _sizes;
        public int index;
        public int Count { get { return _sourceRectangles.Length; } }
        /// <summary>
        /// Up until now, I truly know that Prop is so convenient, also can be overridden method like. 
        /// </summary>
        public override Vector2 Size { get { return _sizes[index]; } } //Gets a index Sprite frame size
        public override Rectangle rectangle { get { return new Rectangle((int)position.X, (int)position.Y, (int)Size.X, (int)Size.Y); } }//Gets the index collision rectangular frame Sprite
        public override Rectangle sourceRectangle { get { return _sourceRectangles[index]; } } //Image rendering interception
        /// <summary>
        /// The trouble with the default constructor
        /// </summary>
        public SAActionSprite() { }
        /// <summary>
        /// The default action of the zero frame constructor
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="sourceRectangles"></param>
        /// <param name="sizes"></param>
        /// <param name="position"></param>
        /// <param name="color"></param>
        public SAActionSprite(Texture2D texture, Rectangle[] sourceRectangles, Vector2[] sizes, Vector2 position, Color color) 
            : this(texture, sourceRectangles, sizes, position, color, 0) { }
        /// <summary>
        /// Most of the constructor.
        /// </summary>
        /// <param name="texture">Texture</param>
        /// <param name="sourceRectangles">A rectangular array of texture</param>
        /// <param name="sizes">The size of the array</param>
        /// <param name="position">Plotting position</param>
        /// <param name="color">Drawing color</param>
        /// <param name="index">The first few frames action</param>
        public SAActionSprite(Texture2D texture, Rectangle[] sourceRectangles, Vector2[] sizes, Vector2 position, Color color, int index)
        {
            this.texture = texture;
            this._sourceRectangles = sourceRectangles;
            this._sizes = sizes;
            this.position = position;
            this.color = color;
            this.index = index;
        }
        public SAActionSprite(string resource, Rectangle[] sourceRectangles, Vector2[] sizes, Vector2 position, Color color, int index)
            : this(SAGraphicUtil.GetImage(resource), sourceRectangles, sizes, position, color, index) { }
        public SAActionSprite(string resource, Rectangle[] sourceRectangles, Vector2[] sizes, Vector2 position, Color color)
            : this(SAGraphicUtil.GetImage(resource), sourceRectangles, sizes, position, color, 0) { }
        //Because the attribute is Override, the Draw method but not override
    }

In fact, is the index, and then several properties of the original Override, have to agree a Prop or use up all.
Look carefully will find, nano how, only one Texture and a bunch of sourceRectangle!!! Do not excited, because I usually compare love a Texture loading, which are far less efficient than in a big Texture, all image loading efficiency is high, so here to remind yourself, even if it is loaded multiple Texture, at least in a Action or not to load multiple Texture.~

Then back on track, extended Button is actually to the SAActionSprite:
(because Button actually have the image Button, pure have image + Button text, even pure text Button, so the base class, you define a Button called SAControl)

public enum ControlStatus
    {
        Normal,
        Touch,
        Release
    }
    /// <summary>
    /// Base class, inherit from ActionSprite
    /// </summary>
    public abstract class  SAControl:SAActionSprite
    {
        //Control of the state, the initial Normal
        protected ControlStatus controlStatus;
        //Commission on response Click
        public delegate void ClickDelegate();
        protected ClickDelegate  ClickHandler;
        //Controls whether to open, enabled by default
        public bool Enable { get; set; }

        #Region initialization
        public void Init()
        {
            this.index = 0;
            this.controlStatus = ControlStatus.Normal;
            this.Enable = true;
            this.color = Color.White;
        }
        #endregion

        #Region registration and cancellation (careful not to call, in response to changes in because can not Foreach)
        public void Add()
        {
            SAInput.AddButton(this);
        }
        public void Remove()
        {
            SAInput.RemoveButton(this);
        }
        #endregion
        
        #Between region and SAInput interface
        /// <summary>
        /// Update, the first reset state is Normal, but the sub class to override (index changes)
        /// </summary>
        public virtual void Update()
        {
            this.controlStatus = ControlStatus.Normal;
        }
        /// <summary>
        /// When the update was touched
        /// </summary>
        public virtual void OnTouch(Vector2 touchPos)
        {
            if (IfOnTouch(touchPos))
            {
                this.controlStatus = ControlStatus.Touch;
            }
        }

        /// <summary>
        /// Supplementary judging whether to be touched
        /// </summary>
        /// <param name="touchPosition"></param>
        /// <returns></returns>
        public bool IfOnTouch(Vector2 touchPosition)
        {
            if (touchPosition.X >= position.X && touchPosition.X <= position.X + Size.X
                && touchPosition.Y >= position.Y && touchPosition.Y <= position.Y + Size.Y)
            {
                return true;
            }
            return false;
        }
        public bool IfOnTouch(GestureSample gesture)
        {
            return IfOnTouch(gesture.Position);
        }
        #endregion

        #The region response click event
        public virtual void OnClick()
        {
            if (this.Enable)
            {
                if (ClickHandler != null)
                {
                    this.controlStatus = ControlStatus.Release;
                    ClickHandler.Invoke();
                }
            }
        }
        #endregion
    }
So SAButton just say:

    public class SAButton:SAControl
    {
        /// <summary>
        /// The most simple, a picture of all the
        /// </summary>
        public SAButton(string resource,Rectangle sourceRect,Vector2 pos,ClickDelegate clickDel)
        {
            Init();
            //TODO
            this.texture = SAGraphicUtil.GetImage(resource);
            this._sourceRectangles = new Rectangle[3];
            this._sourceRectangles[2] = this._sourceRectangles[1] = this._sourceRectangles[0] = sourceRectangle;
            this._sizes = new Vector2[3];
            this._sizes[2] = this._sizes[1] = this._sizes[0] = new Vector2(rectangle.Width, rectangle.Height);
            this.position = pos;
            this.ClickHandler = clickDel;
            Add();
        }
        /// <summary>
        /// The most comprehensive
        /// </summary>
        public SAButton(string resource, Rectangle[] sourceRects, Vector2 pos, ClickDelegate clickDel)
        {
            Init();
            //TODO
            this.texture = SAGraphicUtil.GetImage(resource);
            this._sourceRectangles = new Rectangle[3];
            this._sizes = new Vector2[3];
            this.position = pos;
            this.ClickHandler = clickDel;
            #The number of region with different
            if (sourceRects.Length == 3)
            {
                this._sourceRectangles = sourceRects;
                for (int i = 0; i <3; i++)
                {
                    this._sizes[i] = new Vector2(_sourceRectangles[i].Width,_sourceRectangles[i].Height);
                }
            }
            else if (sourceRects.Length == 2)
            {
                this._sourceRectangles[2] = this._sourceRectangles[0] = sourceRects[0];
                this._sourceRectangles[1] = sourceRects[1];
                for (int i = 0; i <3; i++)
                {
                    this._sizes[i] = new Vector2(_sourceRectangles[i].Width, _sourceRectangles[i].Height);
                }
            }
            else
            {
                for (int i = 0; i <3; i++)
                {
                    this._sourceRectangles[i] = sourceRects[0];
                    this._sizes[i] = new Vector2(_sourceRectangles[i].Width, _sourceRectangles[i].Height);
                }
            }
            #endregion
            Add();
        }

        #Region flow control
        public override void Update()
        {
            //TODO
            index = 0;
            //Cannot delete, update status
            base.Update();
        }
        public override void OnClick()
        {
            //TODO
            if (this.Enable)
            {
                index = 2;
            }
            //Cannot delete
            base.OnClick();
        }
        public override void OnTouch(Vector2 touchPos)
        {
            //TODO
            if (IfOnTouch(touchPos))
            {
                index = 1;
            }
            //Cannot delete
            base.OnTouch(touchPos);
        }
        /// <summary>
        /// Because of the changes and the changes of index were modified, so there is no need to rewrite Draw
        /// </summary>
        public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) 
        {
            base.Draw(spriteBatch);
        }
        #endregion
    }

I'm actually on that old long constructor more disgusted, but because we usually use Button when the lazy, although Button has a "normal", "touch but fingers left", "touch fingers left" three kinds of state, but often we default the first and third state with the same image display, so...
We can also see some interact with the SAInput place, SAButton then, exactly is how they interact.?
We joined the following content in the original SAInput:
First we registered in gesture before it has opened the door for Button, have been secretly registered Tap gesture:


        static SAInput()
        {
            TouchPanel.EnabledGestures = GestureType.Tap;       //The default initial can handle Tap, for Button
            enable = true;
        }
We add a Button list:

        private static List<SAControl> buttonList = new List<SAControl>();
Before the registered in the processing of TouchCollection and Gesture, in fact we have secretly to handle all of the Button.:

        public static void UpdateGesture()
        {
            if (enable)
            {
                while (TouchPanel.IsGestureAvailable)
                {
                    GestureSample gestureSample = TouchPanel.ReadGesture();
                    //To deal with the predefined Button
                    if (gestureSample.GestureType == GestureType.Tap)
                    {
                        foreach (SAControl b in buttonList)
                        {
                            if (b.IfOnTouch(gestureSample.Position))
                            {
                                b.OnClick();
                                break;//ATTENTION can remove Button in
                            }
                        }
                    }

                    //Processing gesture events
                    foreach (GestureType g in inputDictionary.Keys)
                    {
                        if (gestureSample.GestureType == g)
                        {
                            inputDictionary[g].Invoke(gestureSample);
                            break;  //ATTENTION
                        }
                    }
                }
            }
        }

        public static void UpdateTouchCollection()
        {
            if (enable)
            {
                touchCollection = TouchPanel.GetState();
                //To deal with Button
                if (touchCollection.Count == 1)
                {
                    foreach (TouchLocation t in touchCollection)
                    {
                        if (t.State == TouchLocationState.Pressed || t.State == TouchLocationState.Moved)
                        {
                            foreach (SAControl b in buttonList)
                            {
                                b.OnTouch(t.Position);
                            }
                        }
                    }
                }

                if (OnTouchCollection != null)
                {
                    OnTouchCollection.Invoke(touchCollection);
                }
            }
        }
Of course, there are some very easy interface of Button and SAInput:

        #Region Button
        public static void AddButton(SAControl button)
        {
            buttonList.Add(button);
        }

        public static void CleanButton()
        {
            buttonList.Clear();
        }

        public static void RemoveButton(SAControl button)
        {
            if (buttonList.Contains(button))
            {
                buttonList.RemoveAt(buttonList.IndexOf(button));
            }
        }
        #endregion
Above, this is Button and SAInput integration.


The first part of the Button wrote here, another part is about "text Button" drawn content, please look. In addition, can finally began to write SAInput problem solving two.~Yes!
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Sabrina at December 28, 2013 - 4:31 PM