1

我在使用 XNA 框架时遇到了问题,我在这里有一个精简版的代码来演示。单击鼠标时,会在该鼠标单击点创建一个对象,并通过其自己的 draw 方法显示该对象。

发生的情况是第一个对象是在正确的位置创建的(当前鼠标坐标显示为文本)但是当创建第一个对象时,当前鼠标坐标相对于窗口位置偏移。随后创建的对象再次偏移它,直到我在屏幕上得到一个漂亮的对象对角线。如果我删除创建对象的方法,那么一切都很好-鼠标坐标相对于窗口保持良好。

这是代码,有基本方法、创建对象的方法、对象的类和查找鼠标输入的类。有没有其他人遇到过这个问题或者可以看到我做错了什么?

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace mousetest
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    public SpriteFont defaultFont;

    public static Vector2 mousepos;

    public Texture2D anobjectTexture;

    public List<anobject> anobjectList = new List<anobject>();

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

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here

        //make the mouse pointer visible 
        this.IsMouseVisible = true;

        base.Initialize();
    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        // TODO: use this.Content to load your game content here

        defaultFont = Content.Load<SpriteFont>(@"fonts\arial");

        anobjectTexture = Content.Load<Texture2D>("reddot");
    }

    /// <summary>
    /// UnloadContent will be called once per game and is the place to unload
    /// all content.
    /// </summary>
    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here

        mouseUpdate();

        base.Update(gameTime);
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        // TODO: Add your drawing code here

        //draw the mouse coords
        //Draw the debug text 
        //
        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.FrontToBack, SaveStateMode.None);

        spriteBatch.DrawString(defaultFont, "mousex: " + mousepos.X + " mousey: " +mousepos.Y,
            new Vector2(10, 10), Color.Black, 0, Vector2.Zero, 1, SpriteEffects.None, 1);


        int i = 0;
        foreach (anobject theobject in anobjectList)
        {
            theobject.drawObject(spriteBatch);
            i++;
        }

        spriteBatch.DrawString(defaultFont, "objects: " + i,
        new Vector2(10, 20), Color.Black, 0, Vector2.Zero, 1, SpriteEffects.None, 1);

        spriteBatch.End();

        base.Draw(gameTime);
    }

    //mouse test method
    public Vector2 mouseUpdate()
    {
        MouseInput.CheckMouse(800, 600);
        mousepos.X = MouseInput.mouseState.X;
        mousepos.Y = MouseInput.mouseState.Y;

        if (MouseInput.ismouse_leftbuttonpressed == 1)
        {
            if (MouseInput.ismouse_leftbuttonheld == 0)
            {
                doSomething();
            }
        }

        return mousepos;
    }


    public void doSomething()
    {
        //create an instance of the 'anobject' class when the mouse is clicked

        anobject testobject = new anobject(mousepos, anobjectTexture);
        anobjectList.Add(testobject);

    }
}


public class anobject : Game1
{
    public Vector2 position;
    public Texture2D anobjectTexture;

    //constructor
    public anobject(Vector2 inpos, Texture2D inTexture)
    {
        position = inpos;
        anobjectTexture = inTexture;

    }

    public void drawObject(SpriteBatch inspritebatch)
    {

        inspritebatch.Draw(anobjectTexture,
                    new Vector2(
                    (position.X),
                    (position.Y)),
                    null, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0.99f); 
    }

    }//end of class
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

namespace mousetest
{
    class MouseInput: Game1
    {
        public static MouseState mouseState;

        // might need this just cause the way the api mouse call works  
        public static Vector2 mouseLocation;
        // these are Mouse position values  
        public static int mousePosition_X = 0;
        public static int mousePosition_Y = 0;
        public static float virt_mousePosition_X = 0.0f; // this is calculated to were the mouse is as a percentage of screen width height  
        public static float virt_mousePosition_Y = 0.0f; // this is very useful for seting positions of boxes and buttons ect...  
        // left mouse button  
        public static int ismouse_leftbuttonpressed = 0; // is left being pressed at this moment  
        public static int leftmouselastpressedatX = 0;
        public static int leftmouselastpressedatY = 0;
        public static int leftmouselastdragreleasedX = 0;
        public static int leftmouselastdragreleasedY = 0;
        public static int ismouse_leftbuttonheld = 0; // is left being held down  
        // right mouse button  
        public static int ismouse_rightbuttonpressed = 0; // is right being pressed at this moment  
        public static int rightmouselastpressedatX = 0;
        public static int rightmouselastpressedatY = 0;
        public static int rightmouselastdragreleasedX = 0;
        public static int rightmouselastdragreleasedY = 0;
        public static int ismouse_rightbuttonheld = 0;  // is right being held down  
        // this is the scroll wheel  
        public static int mousewheel_value = 0; // this will mainly affect the zoomvalue its multiplyed by a small number to get the below  
        public static int mouseoldwheel_value = 0;
        public static float zoomwheel_value = 0; // this is a value that relects the % of zoom  
        public static float zoomvalue = 1.0F; // this we modify later on for mouse scrolling zooming  


        /// <summary>  
        /// one lil problem this is still in this function SGMKS.screenWidth; so ill have to deal with that later on  
        /// as the screen size might change and thus ruin alot of info if we dont update that  
        ///   
        ///  get the mouse values and save them into a static class to track those variables  
        /// </summary>  
        public static void CheckMouse(int sW, int sH)
        {
            // grab the mouse state from the input class  
            mouseState = Mouse.GetState();
            // save the current mouse position into another variable for later use  
            mousePosition_X = mouseState.X;
            mousePosition_Y = mouseState.Y;
            virt_mousePosition_X = (float)mousePosition_X / (float)sW;
            virt_mousePosition_Y = (float)mousePosition_Y / (float)sH;
            // or we could put this in a vector instead  
            mouseLocation = new Vector2(mousePosition_X, mousePosition_Y);

            // Processing when carrying out the left click of the mouse  
            //_______________________________________________  
            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                //NOTE THESE ARE PLACED IN A SPECIFIC ORDER TO ENSURE THAT DRAG CLICK LOGIC IS CORRECT  
                // Never *** it up note to self thanks  
                // on the first pass the below will set the lastposmousepressed to the current position  
                if (ismouse_leftbuttonheld == 0) // this executes on the first pass and the second pass but not the third pass  
                {
                    if (ismouse_leftbuttonpressed == 1) // this condition will not execute untill the second pass thru the function  
                    {
                        ismouse_leftbuttonheld = 1; // now we mark it as being held on the second pass                         
                    }
                    else  // this executes on the first pass only  
                    {
                        leftmouselastpressedatX = mousePosition_X; // and we save the click of the first point of holding   
                        leftmouselastpressedatY = mousePosition_Y; // so when released we know were we draged from  
                    }
                }
                // set at the end of but still in the first pass  
                ismouse_leftbuttonpressed = 1;// we SET this after the call to is leftbutton pressed now to to ensure next pass its active  
            }
            else
            { // mouse itself is no longer registering the button pressed so.. toggle held and button pressed off  
                ismouse_leftbuttonpressed = 0;
                if (ismouse_leftbuttonheld == 1)
                {
                    leftmouselastdragreleasedX = mousePosition_X;
                    leftmouselastdragreleasedY = mousePosition_Y;
                }
                ismouse_leftbuttonheld = 0;
            }

            // Processing when carrying out the right click of the mouse  
            //________________________________________________  
            if (mouseState.RightButton == ButtonState.Pressed)
            {
                //NOTE THESE ARE PLACED IN A SPECIFIC ORDER TO ENSURE THAT DRAG CLICK LOGIC IS CORRECT  
                // on the first pass the below will set the lastposmousepressed to the current position  
                if (ismouse_rightbuttonheld == 0) // this executes on the first pass and the second pass but not the third pass  
                {
                    if (ismouse_rightbuttonpressed == 1) // this condition will not execute untill the second pass thru the function  
                    {
                        ismouse_rightbuttonheld = 1; // now we mark it as being held on the second pass  
                    }
                    else  // this executes on the first pass only  
                    {
                        rightmouselastpressedatX = mousePosition_X; // and we save the click of the first point of holding   
                        rightmouselastpressedatY = mousePosition_Y; // so when released we know were we draged from  
                    }
                }
                // set at the end of the first pass  
                ismouse_rightbuttonpressed = 1;// we SET this after the call to is rightbutton pressed now to to ensure next pass its active  
            }
            else
            { // right mouse button itself is no longer registering the button pressed so.. toggle held and button pressed off  
                ismouse_rightbuttonpressed = 0;
                if (ismouse_rightbuttonheld == 1)
                {
                    rightmouselastdragreleasedX = mousePosition_X;
                    rightmouselastdragreleasedY = mousePosition_Y;
                }
                ismouse_rightbuttonheld = 0;
            }

        }//endof method  


    }
}
4

1 回答 1

1

您的 MouseInput 和 AnObject 类是您的 Game1 类的后代,因此每次创建 AnObject 的实例时,您都在创建一个 Game 实例。

Mouse.GetState() 的一部分如下所示:

if (hHookedHandle != null)
{
    ScreenToClient(hHookedHandle, &gpoint);
}

因此,无需深入研究,Game 类将鼠标屏幕坐标转换为窗口坐标。因此,每次您创建一个新的 Game 实例时,它都可能是前一个实例的子实例,因此它的窗口坐标位于其父实例内。

解决方案是从您的课程中删除“:Game1”。您通常只想在项目中拥有一个 Game 类。

于 2010-02-05T21:45:10.880 回答