XNA使用2D相机查找鼠标位置

时间:2012-04-03 20:57:34

标签: c# xna camera mouse tile

我尝试过在网上找到的每一种方式来获得相对于相机的鼠标位置,但没有任何效果。选择图块总是远离鼠标。另外,我如何只更改我点击的图块而不是每个具有相同纹理的图块

相机类

public class Camera : Game1
{
    protected float _zoom;
    public Matrix _transform;
    public Vector2 _pos;
    protected float _rotation;

    public Camera()
    {
        _zoom = 1.0f;
        _rotation = 0.0f;
        _pos = Vector2.Zero;
    }

    public float Zoom
    {
        get { return _zoom; }
        set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image
    }

    public float Rotation
    {
        get { return _rotation; }
        set { _rotation = value; }
    }


    public void Move(Vector2 amount)
    {
        _pos += amount;
    }

    public Vector2 Pos
    {
        get { return _pos; }
        set { _pos = value; }
    }

    public Matrix get_transformation()
    {
        _transform = 
                     Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
                     Matrix.CreateRotationZ(Rotation) *
                     Matrix.CreateScale(_zoom) *
                     Matrix.CreateTranslation(new Vector3(1024 * 0.5f, 768 * 0.5f, 0));
        return _transform;
    }

    public void Update()
    {
        Input();
    }

    protected virtual void Input()
    {
        KeyboardState _keyState;
        _keyState = Keyboard.GetState();

        if (_keyState.IsKeyDown(Keys.A))
        {
            _pos.X -= 5f;
        }
        if (_keyState.IsKeyDown(Keys.D))
        {
            _pos.X += 5f;
        }
        if (_keyState.IsKeyDown(Keys.W))
        {
            _pos.Y -= 5f;
        }
        if (_keyState.IsKeyDown(Keys.S))
        {
            _pos.Y += 5f;
        }
    }
}

瓷砖等级

class TileGeneration
{
    public Block[] tiles = new Block[3];
    public int width, height;
    public int[,] index;
    public Texture2D grass, dirt, selection;
    bool selected;
    MouseState MS;
    Vector2 mousePos;

    Camera camera;

    public TileGeneration()
    {

    }

    public void Load(ContentManager content, GraphicsDevice g)
    {
        grass = content.Load<Texture2D>(@"Tiles/grass");
        dirt = content.Load<Texture2D>(@"Tiles/dirt");
        selection = content.Load<Texture2D>(@"Tiles/selection");

        tiles[0] = new Block { Type = BlockType.Grass, Position = Vector2.Zero, texture = grass};
        tiles[1] = new Block { Type = BlockType.Dirt, Position = Vector2.Zero, texture = dirt};

        width = 50;
        height = 50;

        index = new int[width, height];

        camera = new Camera();

        Random rand = new Random();
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                index[x,y] = rand.Next(0,2);
            }
        }
    }

    public void Update()
    {
        MS = Mouse.GetState();
        Matrix inverseViewMatrix = Matrix.Invert(camera.get_transformation());
        Vector2 mousePosition = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
        Vector2 worldMousePosition = Vector2.Transform(mousePosition, inverseViewMatrix);
        mousePos = worldMousePosition;
        Console.WriteLine(mousePos);

        if (MS.LeftButton == ButtonState.Pressed)
        {
            Console.WriteLine("Selected");
            selected = true;
        }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
              spriteBatch.Draw(tiles[index[x,y]].texture, new Rectangle(x * 64, y * 64, 64, 64), 
                    Color.White);
              if (selected && IsMouseInsideTile(x, y))
              {
                  if (tiles[index[x,y]].texture == grass)
                      tiles[index[x,y]].texture = dirt;
              }
              if(IsMouseInsideTile(x, y))
                  spriteBatch.Draw(selection, new Rectangle(x * 64, y * 64, 64, 64), Color.White);
            }
        }    
    }

    public bool IsMouseInsideTile(int x, int y)
    {
        return (mousePos.X >= x * 64 && mousePos.X <= (x + 1) * 64 &&
            mousePos.Y >= y * 64 && mousePos.Y <= (y + 1) * 64);
    }

Game1 Draw

protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, 
            camera.get_transformation());

        tile.Draw(this.spriteBatch);
        player.Draw(this.spriteBatch);
        spriteBatch.End();

        base.Draw(gameTime);
    }

enter image description here

2 个答案:

答案 0 :(得分:3)

可能有更好的方法,但是:

// absoluteMouseX will be the value from your MouseState, and camera will be an instance of your class
// You may need to convert your rotation to radians.

float relativeMouseX = absoluteMouseX + camera.Pos.X;

float relativeMouseY = absoluteMouseY + camera.Pos.Y;

答案 1 :(得分:1)

我现在没有XNA来测试它,但我记得有这个问题。

我的代码片段可能有所帮助:

        Vector2 mouse = new Vector2(ms.X, ms.Y);
        Matrix transform = Matrix.Invert(camera.ViewMatrix);

        Vector2.Transform(ref mouse, ref transform, out mouse);

        selectedRow = (int)(mouse.Y / Tile.SIZE);
        if (selectedRow < 0) selectedRow = 0;
        else if (selectedRow >= rows) selectedRow = rows - 1;

        selectedCol = (int)(mouse.X / Tile.SIZE);
        if (selectedCol < 0) selectedCol = 0;
        else if (selectedCol >= cols) selectedCol = cols - 1;

两件事:
1.注意行取决于鼠标的Y分量和X分量的列 2.请注意,直接获取鼠标放置的图块要快得多,而不是询问每个图块是否有鼠标“内部”。