zoukankan      html  css  js  c++  java
  • 如何在WP7上用XNA写2D游戏(四)


                                              3 章 创建XNA 游戏菜单
    3.1 WP7XNA游戏的触控操作
          上一章节,我们了解了制作XNA 2D游戏的常用组件已及使用ScreenManage管理场景。可以说对XNA 2D游戏有了入门,不过我们玩游戏不会一开始就进入到游戏场景里的,总是会有启动界面,loading界面,然后到了游戏菜单。然后让用户选择开始继续帮助等选项,如下图3-1,就是一个常见的游戏界面。

             

    3-1

     

    PC上的运行的XNA游戏不同,我们在WP7上是靠触摸屏操作的,这和用鼠标操作还是不同的。那么我们就需要先了解WP7XNA的触控操作。

                                                             

    现在的触摸屏手机基本都支持多点触控,比如拉伸,缩放,玩过Iphone上《愤怒的小鸟》就明白游戏画面可以用两个手指拉伸和缩放。还有很有名的《水果忍者》也是多点触控的好游戏,你用三个手指在屏幕上划拉,屏幕上就显出三个爪子印。

    当然啦"单点触摸"也是支持的,你用一个指头也能操作的,比如你用一个指头在《愤怒的小鸟》里拉动弹弓。我们就从简单的单点触控开始了解吧。

    当我们把一个指头在屏幕上操作,可能会有这样三种动作:按,移动,移开。就拿《愤怒的小鸟》里拉动弹弓这个动作,首先我们是按下一个指头,然后向后移动,然后在屏幕上移开这个手指。

    那么这三个操作在WP7XNA里如何获取呢?我们就需要了解XNA里的TouchPanelTouchCollection这两个类。

     

    TouchCollection touchState= TouchPanel.GetState();
    Foreach(TouchLocation location in touchState)
    {
            switch(location.State)
            {
                case TouchLocationState.Pressed://按下
                 ……
                break;
    case TouchLocationState.Moved://移动
                 ……
                break;
    case TouchLocationState.Released://释放
                 ……
                break;
     
    }
     
    }

     

    和触控操作类似的还有叫“手势”的,也算复杂的触控吧。

    TouchPanel.EnabledGestures = GestureType.FreeDrag;//用来指定手势,必须要先设定,否则报错

    if (TouchPanel.EnabledGestures != GestureType.None)

    {

    switch (TouchPanel.ReadGesture())

    {

    case GestureType.Tap: //单击

    break;

    case GestureType.DoubleTap://双击

    break;

    case GestureType.FreeDrag://自由拖动

    break;

    case GestureType.DragComplete://拖动完成

    break;

    case GestureType.Flick://轻弹

    break;

    case GestureType.Hold://按住不动

    break;

    case GestureType.HorizontalDrag://横向拖动

    break;

    case GestureType.None://无手势

    break;

    case GestureType.Pinch://

    break;

    case GestureType.PinchComplete://捏完

    break;

    case GestureType.VerticalDrag://纵向拖动

    break;

    }

    }

     

    3.2        编写MenuEntry

    如图3-1每一个菜单界面里都有多个菜单项,为了表示单个菜单项,我们就需要写一个MenuEntry类。

        菜单项可以在屏幕上输出文字来表示,为了美化还可以绘制图片来完成。菜单项一般都是纵向排列的,每个菜单项的坐标都不同,所以有这样两个属性:

            /// <summary>

            /// 菜单项文本内容

            /// </summary>

            public string Text

            {

                get { return text; }

                set { text = value; }

            }

     

            /// <summary>

            /// 菜单项文本的位置

            /// </summary>

            public Vector2 Position

            {

                get { return position; }

                set { position = value; }

            }

     

      由于每个菜单项都会响应点击事件,所以我们需要声明一个事件:

            /// <summary>

            ///菜单项的选中事件

            /// </summary>

            public event EventHandler Selected;

     

            /// <summary>

            ///选中菜单项函数

            /// </summary>

            internal void OnSelectEntry()

            {

                if (Selected != null)

                {

                    isPress = true;

               

                }

            }

     

    如果菜单项是图片构成的,为了让菜单项有按下动感,我们用图3-2里的三个图片来做一个三帧动画。


     

                                                        图3-2

          所以我们要用到四个变量:public Texture2D menuTexture,showTexture,pressTexture,releaseTexture;

          在菜单项的update函数里要做这样的处理

       private TimeSpan duration = TimeSpan.FromSeconds(0.4);//菜单动画的执行时间为0.2

       public void Update(bool isSelected, GameTime gameTime)

            {

                if(isPress)

                {

                    duration -=gameTime.ElapsedGameTime;

                   if (duration <= TimeSpan.FromSeconds(0.2)&& duration > TimeSpan.FromSeconds(0.1))

                    {

                        showTexture = pressTexture; //0.2-0.1秒之间显示三张图片中第二个图片

                    }

                    else  if (duration<= TimeSpan.FromSeconds(0.1) &&duration>TimeSpan.Zero)

                    {

                        showTexture =eleaseTexture;//0.1-0秒间显示三张图片中第三个图片

                    }

                    else if (duration <= TimeSpan.Zero)

                    {

                        Selected(this, new PlayerIndexEventArgs(playerIndex));//菜单项按下动画完成触发Selected事件

                        duration = TimeSpan.FromSeconds(0.4);           

                        isPress = false;

                    }

                }

            }

    3.3 编写MenuScreen

          由于菜单界面也是一个特殊的场景,所以MenuScreen继承于GameScreen

       如图3-3MenuScreen类结构如下:



     

                           3-3

         我们着重分析下HandleInput方法:

    public override void HandleInput(InputHelper input)

            {

                    TouchCollection touchState =TouchPanel.GetState();

                    bool  touchDetected = false; //是否触碰菜单

                    Vector2 touchPosition = new Vector2();

                   foreach(TouchLocation location in touchState)

                   {

                         switch(location.State)

                        {

                                 case TouchLocationState.Pressed:

                                          touchDetected = true;

                                          touchPosition = location.Position;

                                          break;

                                 case TouchLocationState.Moved:

                                          break;

                                 case TouchLocationState.Released:

                                          break;

                      }

                   }

          if(touchDetected)

    {

    foreach (MenuEntrymenuEntry in menuEntries)

                        {

                                Rectangle    touchRect = new Rectangle((int)touchPosition.X - 5, (int)touchPosition.Y- 5,10, 10);

                                Rectangle entryRect = new Rectangle((int)menuEntry.Position.X- 5, (int)menuEntry.Position.Y -                 5,menuEntry.GetWidth(this), menuEntry.GetHeight(this));                             

                        if(entryRect.Intersects(touchRect)) //如果触摸点在菜单项的矩形区域内

                   menuEntry.OnSelectEntry();//触发菜单选中事件。

                    }

          }

          ………………….

    }

    3.4编写MainMenuScreen类

          对于游戏主菜单界面而言,点击“Play 菜单项意味着要切入到游戏主场景里,点击“Exit Game”菜单意味着退出游戏,那么就需要在MenuScreen扩展游戏场景切换的方法。在前一章节里我们简单介绍了游戏场景的管理类ScreenManager,在这里就派上用途了。

          首先我们让MainMenuScreen继承于MenuScreen:

    public class MainMenuScreen:MenuScreen

          {

    }

    然后我们添加了如下等方法:

    /// <summary>

               /// 增加菜单项

               /// </summary>

              /// <param name="name">菜单文字</param>

              /// <param name="screen">点击对应要启动的Screen</param>

              /// <param name="isExitItem">是否是退出菜单</param>

              /// <param name="isShowLoading">是否显示loading界面</param>

             /// <param name="position">菜单的坐标</param>
       public void AddMainMenuItem(string name, GameScreen screen, bool isExitItem, bool isShowLoading,Vector2 position)

           {

               this.isShowLoading= isShowLoading;

               MenuEntry entry = new MenuEntry(name,screen,isExitItem, position);

               entry.Selected += new System.EventHandler(entry_Selected);

               MenuEntries.Add(entry);

           }

           /// <summary>

           /// 菜单点击事件

           /// </summary>

           /// <param name="sender"></param>

           /// <param name="e"></param>

         void entry_Selected(object sender, EventArgs e)

           {

               MenuEntry menu = sender as MenuEntry;

               if(menu.IsExitItem) //如果是退出菜单

               {

                   ScreenManager.Game.Exit();

               }

               else

               {          
                    ScreenManager.AddScreen(menu.Screen,null);

               }

           }

    此外,我们还需要写上InputHelper,修改上一章节的GameScreen类,ScreenManager类,在这两个类里加上对输入的支持。

    GameScreen类里我们加上HandleInput方法:

                     public virtual void HandleInput(InputHelper input)

                     {
     

                     }

        ScreenManager里我们需要修改Update方法,增加对screen的输入响应:

           if(!otherScreenHasFocus)

            {

                  screen.HandleInput(input);

                  otherScreenHasFocus = true;

            }

          具体代码修改请看具体的XNAGameSample3这个Demo

         然后在Game1.cs里的Initialize()方法里我们就加上如下代码即可:

            MainMenuScreen mainMenu = newMainMenuScreen("Castle Defense");

            GameMainScreen main = new GameMainScreen();

            Vector2 position = new Vector2{ X = 0f, Y = 0f };

            mainMenu.AddMainMenuItem("Play", main, false,true, position);

            mainMenu.AddMainMenuItem("Exit", null,true, false,position);

            screenManager.AddScreen(mainMenu, null);
     

     最后的代码运行效果如图3-4



     

    demo 下载地址:/Files/wangergo/XNAGameSample3.rar

  • 相关阅读:
    js中setTimeout、setInterval、 clearInterval方法简介
    分享一个VS2008漂亮的黑色主题
    最简单的设计模式
    记一次查数据的需求
    Oracle常用存储过程写法
    关于域名解析
    使用PHP打造QQ空间神奇图片
    自制小工具含源码——SPTC上海交通卡余额查询
    自制小工具含源码——博客园图床ImageBed
    不可不知的mysql 常用技巧总结
  • 原文地址:https://www.cnblogs.com/wangergo/p/2255192.html
Copyright © 2011-2022 走看看