【问题标题】:MonoGame/XNA Mouse OffsetsMonoGame/XNA 鼠标偏移
【发布时间】:2016-05-27 06:24:00
【问题描述】:

我正在尝试使用Mouse.GetState() 进行菜单选择。目前,只有当我将鼠标悬停在菜单所在区域的左侧和上方时,它才会突出显示。我使用 DrawString 显示鼠标坐标,发现 0,0 点不在显示器的左上角或游戏窗口的左上角。它距离屏幕左上角大约 100,100 像素。此外,每次运行程序时,0,0 点都会移动。

我查看了其他遇到相同问题但无法解决的人。我尝试在我的Initialize() 中使用Mouse.WindowHandle = this.Window.Handle;,但它没有任何效果。我有两台显示器,当我强制全屏游戏时,它会在我的第二台显示器上打开,所以我禁用了它,但问题仍然存在。

这是我的代码http://pastebin.com/PNaFADqp的链接

Game1 类:

public class Game1 : Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    SpriteFont spriteFont;

    public const int WINDOW_HEIGHT = 800;
    public const int WINDOW_WIDTH = 600;

    public int tree;

    public TitleScreen titleScreen;
    public SATDemo satDemo;
    public SeparatingAxisTest separatingAxisTest;
    public SATWithAABB sATWithAABB;

    GameState currentState;

    public static Dictionary<string, Texture2D> m_textureLibrary = new Dictionary<string, Texture2D>();
    public static Dictionary<string, SpriteFont> m_fontLibrary = new Dictionary<string, SpriteFont>();

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        graphics.PreferredBackBufferHeight = WINDOW_HEIGHT;
        graphics.PreferredBackBufferWidth = WINDOW_WIDTH;
    }

    protected override void Initialize()
    {
        Mouse.WindowHandle = this.Window.Handle;
        //enable the mousepointer
        IsMouseVisible = true;
        currentState = GameState.TitleScreen;
        //sets the windows mouse handle to client bounds handle

        base.Initialize();
    }

    public void RequestSATDemo()
    {
        currentState = GameState.RequestSATDemo;
    }

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);


        m_textureLibrary.Add("Pixel", Content.Load<Texture2D>("White_Pixel"));
        m_fontLibrary.Add("Font", Content.Load<SpriteFont>("MotorwerkOblique"));

        titleScreen = new TitleScreen();
        satDemo = new SATDemo();
        separatingAxisTest = new SeparatingAxisTest();
        sATWithAABB = new SATWithAABB();
     }

    public void RequestSeparatingAxisTest()
    {
        currentState = GameState.SeparatingAxisTest;
    }

    public void RequestSATWithAABB()
    {
        currentState = GameState.SATWithAABB;
    }

    protected override void Update(GameTime gameTime)
    {
        MouseTestState = Mouse.GetState();
        switch (currentState)
        {
            case GameState.TitleScreen:
                {
                    titleScreen.Update(gameTime);
                    break;
                }
            case GameState.SeparatingAxisTest:
                {
                    separatingAxisTest.Update(gameTime);
                    break;
                }
            case GameState.SATWithAABB:
                {
                    sATWithAABB.Update(gameTime);
                    break;
                }
            case GameState.Exit:
                {
                    Exit();
                    break;
                }
            default:
                {
                    titleScreen.Update(gameTime);
                    break;
                }
        }

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        spriteBatch.Begin();

        spriteBatch.DrawString(m_fontLibrary["Font"], MouseTestState.ToString(), new Vector2(0, 0), Color.White);
        switch (currentState)
        {
            case GameState.TitleScreen:
                {
                    titleScreen.Draw(spriteBatch, spriteFont);
                    break;
                }
            case GameState.SeparatingAxisTest:
                {
                    separatingAxisTest.Draw(gameTime, spriteBatch);
                    break;
                }
            case GameState.SATWithAABB:
                {
                    sATWithAABB.Draw(gameTime, spriteBatch);
                    break;
                }
            case GameState.Exit:
                {
                    Exit();
                    break;
                }
            default:
                {
                    titleScreen.Update(gameTime);
                    break;
                }
        }

        spriteBatch.End(); 
        base.Draw(gameTime);
    }
}

TitleScreen 类:

public class TitleScreen : Screen
{ 
    List<Button> buttonList = new List<Button>();
    public Menu mainMenu;
    public TitleScreen()
    {
        mainMenu = new Menu(new Vector2(200, 100), buttonList, 0); 
        buttonList.Add(new PushButton("Separating Axis Test"));
        buttonList.Add(new PushButton("SAT With AABB"));
        buttonList.Add(new PushButton("Awesome"));
        buttonList.Add(new PushButton("Awesomere"));
        buttonList.Add(new PushButton("Awesomere")); 
    }

    public override void Update(GameTime gametime)
    {
        mainMenu.Update(gametime);
    }

    public void Draw(SpriteBatch sB, SpriteFont sF)
    {
        mainMenu.Draw(sB, sF); 
    } 
}

PushButton 类:

public class PushButton : Button
{
    string m_text;
    SpriteFont m_font;
    Color m_static, m_onClick, m_onHover;
    Texture2D m_sprite2D, m_onClick2D;

    static public int Pbuttoncount;

    //click processing
    bool m_clickedInside =  false,
         m_releasedInside = false,
         m_OnClicked =      false,
         selected =         false;

    Rectangle drawRectangle;

    public PushButton(string Text)
    {
        m_text = Text;

        drawRectangle = new Rectangle((int)Menu.m_position.X, (int)Menu.m_position.Y + (15 * Pbuttoncount), 200, 15);
        ButtonRegion = new Rectangle((int)Position.X, (int)Position.Y, 200, 15);
        Pbuttoncount++;
    }

    public PushButton(Rectangle ButtonRegion, SpriteFont Font, string Text, Color Static, Color OnClick, Color OnHover)
    {
        m_buttonRegion = ButtonRegion;
        m_font = Font;
        m_text = Text;
        m_static = Static;
        m_onClick = OnClick;
        m_onHover = OnHover;
        // drawRectangle = ButtonPosition(m_buttonRegion);
     }

    public PushButton(Rectangle ButtonRegion, Texture2D Sprite2D, Texture2D OnClick2D)
    {
        m_buttonRegion = ButtonRegion;
        m_sprite2D = Sprite2D;
        m_onClick2D = OnClick2D;
        //drawRectangle = ButtonPosition(m_buttonRegion);
    }

    public override void Update(GameTime gameTime)
    {
        MouseState currentMouse = Mouse.GetState();

        selected = MouseState(drawRectangle, currentMouse);
        m_clickedInside = ClickInside(currentMouse, m_lastMouseState);
        ReleaseInside(currentMouse, m_lastMouseState);

        if (selected && m_clickedInside && m_releasedInside)
            m_OnClicked = true;
        else
            m_OnClicked = false;

        m_lastMouseState = currentMouse;
    }

    public override void Draw(SpriteBatch spriteBatch, SpriteFont spriteFont, int buttonCount, Vector2 Position)
    {
        spriteBatch.Draw(Game1.m_textureLibrary["Pixel"], new Rectangle((int)Position.X + 10, (int)(Position.Y + 15 * buttonCount), 180, 15), Color.Wheat);

        if (selected)
            spriteBatch.DrawString(Game1.m_fontLibrary["Font"], m_text, new Vector2(Position.X + 15, Position.Y + 15 * buttonCount), Color.Orange);
        else
            spriteBatch.DrawString(Game1.m_fontLibrary["Font"], m_text, new Vector2(Position.X + 15, Position.Y + 15 * buttonCount), Color.Black);
    }
}

菜单类:

public class Menu
{
    List<Button> m_buttonList;
    float m_transparency;
    public int n = 0;
    public Rectangle buttonRegion, m_menuRegion, m_dimensions;
    static public Vector2 m_position;
    int m_WINDOW_HEIGHT = Game1.WINDOW_HEIGHT;
    int m_WINDOW_WIDTH = Game1.WINDOW_WIDTH;
    private Game1 m_managerClass;

    public Menu(Vector2 Position, List<Button> ButtonList, float Transparency)
    {
        m_position = Position;
        m_buttonList = ButtonList;
        m_transparency = Transparency;
        m_managerClass = new Game1();
    }

    public Rectangle MenuRegion
    {
        get { return m_menuRegion; }
        set { m_menuRegion = value; }
    }

    static public Vector2 Position
    {
        get { return m_position; }
    }

    public void Update(GameTime gametime)
    {
        for (int i = 0; i < m_buttonList.Count; i++)
        {
            m_buttonList[i].Update(gametime);
            if (m_buttonList[0].OnClicked)
            {
                SeperatingAxisTest();
            }
        }
    }

    public void Draw(SpriteBatch sB, SpriteFont sF)
    {
        sB.Draw(Game1.m_textureLibrary["Pixel"], new Rectangle((int)m_position.X - 5, (int)m_position.Y - 10, (m_buttonList[0].ButtonRegion.Width + 10), (m_buttonList[0].ButtonRegion.Height * m_buttonList.Count) + 20), Color.Blue);
        for (int i = 0; i < m_buttonList.Count; i++)
        {
            m_buttonList[i].Draw(sB, sF, i, new Vector2(Position.X, Position.Y));
        } 
    }

    private void SeperatingAxisTest()
    {
        m_managerClass.RequestSeparatingAxisTest();
    }
}

程序类:

public static class Program
{
    [STAThread]
    static void Main()
    {
        using (var game = new Game1())
            game.Run();
    }
}

如果您还需要什么,请告诉我。我还在学习,我会把我的灵魂卖给你以获得答案。

【问题讨论】:

  • 链接未找到。将您的代码添加到您的问题中。 (仅相关的最小样本)
  • 抱歉,我不知道与问题相关的内容。我是新手。
  • 您也可以发布您的入口点吗? Program.cs 之类的,包含Main 方法的那个。

标签: xna mouse offset monogame getstate


【解决方案1】:

您的Menu 类正在创建Game1 的新实例。这很可能不是您想要的,因为Game1 在您的应用程序的入口点中被实例化。 Game1 实例有一个TitleScreen 实例,而Menu 类的实例又是一个Menu 类的实例,因此Menu 应该没有创建自己的游戏的业务。

创建此(其他)实例时,它会调用特定于平台的 (Windows) 方法,创建额外的窗口句柄(从未显示)并配置 Mouse.WindowHandle

顺便说一句,手动设置WindowHandle does absolutely nothing in Monogame,所以所有这些提到的消息来源都在谈论 XNA。

所以,有几点说明:

  1. 您可能应该有一个包含当前屏幕的“屏幕管理器”类。在你的游戏类中有一个TitleScreen 类型的字段很奇怪,它至少应该是基本类型(Screen),这样游戏类才能透明地绘制和更新每个屏幕。

    李>
  2. 如果您需要在任何地方引用游戏类,请不要实例化新的,而是通过构造函数传递它。

  3. m_managerClass 对于实际上是 Game 的字段来说是一个坏名称。还 google 了 C# 命名约定。也许您甚至可能想要下载现有的单人游戏模板,例如检查一些samples onlineNetRumble sample 似乎实现了屏幕管理器。

  4. 去掉Mouse.WindowHandle这一行,它应该默认设置为你的唯一游戏窗口。

tl;drGame1 作为参数添加到您可能需要的任何位置(但仅限于您需要的位置)。

abstract class Screen
{
     private readonly Game1 _game;
     public Game1 Game 
     { get { return _game; } }

     public Screen(Game1 game)
     {
         _game = game;
     }
}

class TitleScreen : Screen 
{
     public TitleScreen(Game1 game)
         : base(game)
     { ... }
}

class Menu 
{
     private readonly Screen _screen;

     public Menu(Screen parentScreen, Vector2 pos, List<Button> list, float alpha)
     {
          _screen = parentScreen;
          ...

          // if you need the game instance, just use _screen.Game
     }
}

【讨论】:

  • 谢谢,格鲁。那修复了它。今晚我会多看看。如您所见,我目前在我的 game1 类中使用 switch 语句来切换公共枚举 GameState 以更改当前屏幕。如果我要创建一个屏幕管理器类,我应该将 switch 语句移到该类吗?将观看此视频系列以了解更多信息youtube.com/watch?v=TOAGy2S8MC8。还要复习我的 C# 命名约定
  • @Cody:OOP 背后的想法(即拥有一个基本的Screen 类或IScreen 接口)是为了消除对 switch 语句的需要。这意味着您有一个“当前屏幕”字段(例如currentScreen),并将其设置为某个屏幕实例(例如titleScreen)。如果所有屏幕都继承自Screen,那么您的更新/绘制方法并不关心它是哪个屏幕,即您只有currentScren.Update(gameTime);currentScreen.Draw(gameTime);,没有开关。
  • 这也意味着你不需要一个单独的“游戏状态”变量(至少对于屏幕来说不需要,也许对于单个屏幕中的一些实际状态机来说),因为你的状态(就当前屏幕)完全由 currentScreen 指向的任何内容定义。
猜你喜欢
  • 2018-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多