• SilverXna初体验:通用鼠标输入设备


    游戏中每一个逻辑实体都是一个小型的状态机,它们在游戏主循环的驱动之下不停的变换自身状态,游戏世界大千万物盛衰轮回由此产生。

    习惯了Xna架构的程序员大都习惯这样定义一个生命体:

    Class Being

    {

      public Being(){}            // 构造函数

      public bool Init(){}        // 初始化

      public void Update(){}   // 逻辑驱动

      public void Draw(){}      // 渲染驱动

      public void Dispose(){}  // 释放对象

    }

    我们在Update中单独处理有关该生命体针对外部输入设备的响应动作,或者由update分离出一个

    bool HandleInput(){}

    方法来处理所有的输入设备响应。这样一来生命体之间则彼此独立,互不侵犯。

    Silverlight中没有为我们提供必要的输入设备封装,而如果依赖于Sliverlight控件本身的应用特性,则我们将不得不把整个游戏世界绝大部分输入处理耦合到Sliverlight根容器中。——这显然不符合我们的要求。

    在Xna中,我们可以很方便的使用

                MouseState mousestate = Mouse.GetState();
                KeyboardState keystate = Keyboard.GetState();

    来获取鼠标和键盘设备状态。而封装相应的GUI时,则必须在此基础上人为的构建诸如控件的单击事件、拖动事件等等。——这个过程其实很繁琐。

    而相对的,收集控件各个事件反推输入设备状态,却是一个相对容易的过程。

    本节,我们就以这种思路构建一个通用于Xna状态机与Sliverlight事件响应二重机制的鼠标输入设备。

    思路其实很简单。首先,声明通用枚举:

        // 鼠标设备动作
        public enum MouseAction
        {
            None,

            MouseLeftButtonDown,
            MouseLeftButtonUp,
            MouseRightButtonDown,
            MouseRightButtonUp,

            LostMouseCapture,
            MouseEnter,
            MouseLeave,
            MouseMove,

            MouseWheel
        }
        // 鼠标键状态
        public enum ButtonState
        {
            Released = 0,
            Pressed = 1
        }
        // 鼠标设备委托定义
        public delegate void MouseButtonHandler(MouseAction act, MouseButtonEventArgs e);
        public delegate void MouseCommonHandler(MouseAction act, MouseEventArgs e);
        public delegate void MouseWheelHandler(MouseAction act, MouseWheelEventArgs e);

    比较好理解。接下来是一个可以容纳全部鼠标设备状态信息的类实体MouseState,我们可以完全仿Xna内部定义:

    MouseState.cs
    /*-------------------------------------

    代码清单:MouseState.cs
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace Microsoft.Xna.Framework.Input
    {
        /// <summary>
        
    /// 鼠标设备状态
        
    /// </summary>
        public class MouseState
        {
            // 横坐标
            double _X;
            public double X
            { get { return _X; } }

            // 纵坐标
            double _Y;
            public double Y
            { get { return _Y; } }

            // 滚轮位移
            int _ScrollWheel;
            public int ScrollWheel
            { get { return _ScrollWheel; } }

            // 左键状态(按下/弹起)
            ButtonState _LeftButton;
            public ButtonState LeftButton
            { get { return _LeftButton; } }

            // 右键状态(按下/弹起)
            ButtonState _RightButton;
            public ButtonState RightButton
            { get { return _RightButton; } }

            // 鼠标状态构造函数
            public MouseState(double x, double y, int scrollWheel, ButtonState leftButton, ButtonState rightButton)
            {
                _X = x;
                _Y = y;
                _ScrollWheel = scrollWheel;
                _LeftButton = leftButton;
                _RightButton = rightButton;
            }

            // 重载 != 运算符
            public static bool operator !=(MouseState left, MouseState right)
            {
                return !(left == right);
            }

            // 重载 == 运算符
            public static bool operator ==(MouseState left, MouseState right)
            {
                return left._X == right._X &&
                    left._Y == right._Y &&
                    left._ScrollWheel == right._ScrollWheel &&
                    left._LeftButton == right._LeftButton &&
                    left._RightButton == right._RightButton;
            }
        }
    }

    之后就是最关键的一环了:如何通过控件的应用事件还原得到鼠标设备状态信息。

    Silverlight中,各类控件通用的鼠标事件无外乎9种:鼠标左键按下、鼠标左键弹起、鼠标右键按下、鼠标右键弹起、丢失鼠标、鼠标进入、鼠标离开、鼠标移动、滚轮移动。

    只要我们针对这9种事件分别处理,即可还原得到鼠标设备的全部状态信息:

    MouseInput.cs
    /*-------------------------------------

    代码清单:MouseInput.cs
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace Microsoft.Xna.Framework.Input
    {
        /// <summary>
        
    /// 鼠标输入设备
        
    /// </summary>
        public class MouseInput
        {
            // 侦听根容器
            static UIElement _Handle;
            static public UIElement Handle
            { get { return _Handle; } }

            // Button类事件
            static public event MouseButtonHandler MouseButtonEvent;
            // Common类事件
            static public event MouseCommonHandler MouseCommonEvent;
            // Wheel类事件
            static public event MouseWheelHandler MouseWheelEvent;

            // 鼠标左键状态
            static ButtonState _LeftButton;
            // 鼠标右键状态
            static ButtonState _RightButton;
            // 鼠标横坐标
            static double _PosX;
            // 鼠标纵坐标
            static double _PosY;
            // 滚轮移动位移
            static int _ScrollWheel;

            // 鼠标输入设备初始化
            static public void InitDevice(UIElement handle)
            {
                _Handle = handle;

                // Button类事件响应:
                
    // 左键按下
                _Handle.MouseLeftButtonDown += new MouseButtonEventHandler(_Handle_MouseLeftButtonDown);
                // 左键弹起
                _Handle.MouseLeftButtonUp += new MouseButtonEventHandler(_Handle_MouseLeftButtonUp);
                // 右键按下
                _Handle.MouseRightButtonDown += new MouseButtonEventHandler(_Handle_MouseRightButtonDown);
                // 右键弹起
                _Handle.MouseRightButtonUp += new MouseButtonEventHandler(_Handle_MouseRightButtonUp);

                // Common类事件相应:
                
    // 丢失鼠标
                _Handle.LostMouseCapture += new MouseEventHandler(_Handle_LostMouseCapture);
                // 鼠标进入
                _Handle.MouseEnter += new MouseEventHandler(_Handle_MouseEnter);
                // 鼠标离开
                _Handle.MouseLeave += new MouseEventHandler(_Handle_MouseLeave);
                // 鼠标移动
                _Handle.MouseMove += new MouseEventHandler(_Handle_MouseMove);

                // Wheel类事件相应
                _Handle.MouseWheel += new MouseWheelEventHandler(_Handle_MouseWheel);
            }

            // 获得鼠标设备状态
            static public MouseState GetState()
            {
                return new MouseState(_PosX, _PosY, _ScrollWheel, _LeftButton, _RightButton);
            }

            // 设备内置左键按下事件处理
            static void _Handle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                // 左键状态置为按下
                _LeftButton = ButtonState.Pressed;
                // 支持外链左键按下事件
                if (MouseButtonEvent != null)
                    MouseButtonEvent.Invoke(MouseAction.MouseLeftButtonDown, e);
            }

            // 设备内置左键弹起事件处理
            static void _Handle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                // 左键状态置为弹起
                _LeftButton = ButtonState.Released;
                // 支持外链左键弹起事件
                if (MouseButtonEvent != null)
                    MouseButtonEvent.Invoke(MouseAction.MouseLeftButtonUp, e);
            }

            // 设备内置右键按下事件处理
            static void _Handle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                // 右键状态置为按下
                _RightButton = ButtonState.Pressed;
                // 支持外链右键按下事件
                if (MouseButtonEvent != null)
                    MouseButtonEvent.Invoke(MouseAction.MouseRightButtonDown, e);
            }

            // 设备内置右键弹起事件处理
            static void _Handle_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
            {
                // 右键状态置为弹起
                _RightButton = ButtonState.Released;
                // 支持外链右键弹起事件
                if (MouseButtonEvent != null)
                    MouseButtonEvent.Invoke(MouseAction.MouseRightButtonUp, e);
            }

            // 设备内置鼠标丢失事件处理
            static void _Handle_LostMouseCapture(object sender, MouseEventArgs e)
            {
                // 支持外链鼠标丢失事件
                if (MouseCommonEvent != null)
                    MouseCommonEvent.Invoke(MouseAction.LostMouseCapture, e);
            }

            // 设备内置鼠标进入事件处理
            static void _Handle_MouseEnter(object sender, MouseEventArgs e)
            {
                // 支持外链鼠标进入事件
                if (MouseCommonEvent != null)
                    MouseCommonEvent.Invoke(MouseAction.MouseEnter, e);
            }

            // 设备内置鼠标离开事件处理
            static void _Handle_MouseLeave(object sender, MouseEventArgs e)
            {
                // 支持外链鼠标离开事件
                if (MouseCommonEvent != null)
                    MouseCommonEvent.Invoke(MouseAction.MouseLeave, e);
            }

            // 设备内置鼠标移动事件处理
            static void _Handle_MouseMove(object sender, MouseEventArgs e)
            {
                // 获取鼠标位置
                System.Windows.Point pos = e.GetPosition(_Handle);
                // 更新设备横坐标
                _PosX = pos.X;
                // 更新设备纵坐标
                _PosY = pos.Y;
                // 支持外链鼠标移动事件
                if (MouseCommonEvent != null)
                    MouseCommonEvent.Invoke(MouseAction.MouseMove, e);
            }

            // 设备内置鼠标滚轮事件
            static void _Handle_MouseWheel(object sender, MouseWheelEventArgs e)
            {
                // 更新滚轮位移
                _ScrollWheel = e.Delta;
                // 支持外链鼠标滚轮事件
                if (MouseWheelEvent != null)
                    MouseWheelEvent.Invoke(MouseAction.MouseWheel, e);
            }
        }
    }

    之后,我们便可如Xna一样,通过调用GetState()方法即时获得鼠标设备状态信息。

    除此之外,该类的设计依然保留了Silverlight事件响应的特性。原本9种事件被重新归为3类,以静态化方式提供全局事件注册。——这样做无疑是有意义的,即使在任何一个小型的子类甚至子容器中,我们都可以随时注册并侦听根容器的全部事件。

    接下来我们将Silverlight工程默认生成的根容器注册给刚刚构建好的鼠标输入设备:

    /*-------------------------------------

    代码清单:MainPage.xaml.cs
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media.Animation;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;

    namespace SilverXna
    {
        public partial class MainPage : UserControl
        {
            Game _Game;
            public MainPage()
            {
                InitializeComponent();
                _Game = new Game(_GameSurface);
                // 初始化鼠标输入设备
                MouseInput.InitDevice(this);
            }
        }
    }

    最后是主体代码:

    /*-------------------------------------

    代码清单:Game.cs
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;
    using System.Windows.Media.Animation;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using System.IO;

    namespace SilverXna
    {
        public class Game : SilverGame
        {
            SpriteBatch _SpriteBatch;
            Texture2D texture;

            public Game(DrawingSurface GameSurface)
                : base(GameSurface)
            { }

            public override void Initialize()
            {
                base.Initialize();
            }

            public override void LoadContent()
            {
                _SpriteBatch = new SpriteBatch(this);

                Stream imageStream = Content.OpenResourceStream("SilverXna","Content/SLXNA.png");
                texture = Content.LoadTexture2D(imageStream);
                base.LoadContent();
            }

            public override void UnloadContent()
            {
                base.UnloadContent();
            }

            Vector2 pos = new Vector2(100100);
            public override void Update(TimeSpan DeltaTime, TimeSpan TotalTime)
            {
                // 获得鼠标设备状态
                MouseState mouseState = MouseInput.GetState();
                // 更新纹理位置到鼠标左键单击点
                if (mouseState.LeftButton == ButtonState.Pressed)
                {
                    pos = new Vector2((float)mouseState.X, (float)mouseState.Y);
                }
                base.Update(DeltaTime, TotalTime);
            }

            public override void Draw(TimeSpan DeltaTime, TimeSpan TotalTime)
            {
                GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Color(100149237255), 1.0f0);

                _SpriteBatch.Begin(BlendState.AlphaBlend);
                _SpriteBatch.Draw(texture, pos, new Color(255255255255));
                _SpriteBatch.End();

                base.Draw(DeltaTime, TotalTime);
            }
        }
    }

    单击鼠标左键,纹理会自动移动到相应的位置。按住鼠标左键不放,则呈现拖动效果。大家不妨一试~

    以上,谢谢 ^ ^





  • 相关阅读:
    Bash Shell 快捷键
    vector-swap
    vector-swap
    vector-size
    Android网络篇
    应用 Valgrind 发现 Linux 程序的内存问题
    树莓派初学者?先做做这十个项目吧
    树莓派 (为学习计算机编程教育设计的一种微型电脑)
    微软windows10 IOT支持PI3之后,树莓派3更是将获得Android官方原生支持
    Linux基金会宣布JS Foundation基金会成立 前身为jQuery团队
  • 原文地址:https://www.cnblogs.com/kenkao/p/2285353.html
Copyright © 2020-2023  润新知