質問

I'm pulling my hair out trying the figure this out. I have a simple button, that checks for the mouse to be over, and then changes the texture if it is. It works fine. However, when I add a camera into the mix, it breaks everything. I've tried transforming both the mouse and rectangle I use for bounding-box collision, and it won't work. Here's my code for the button:

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

namespace x.Graphics.UI
{
    public enum ButtonStates
    {
        Normal,
        Hover,
        Pressed
    }
    public delegate void ButtonPress();
    public class Button
    {
        public Texture2D Texture
        {
            get
            {
                Texture2D result = null;

                switch (ButtonState)
                {
                    case ButtonStates.Normal:
                        result = NormalTexture;
                        break;

                    case ButtonStates.Hover:
                        result = HoverTexture;
                        break;

                    case ButtonStates.Pressed:
                        result = DownTexture;
                        break;
                }

                return result;
            }
        }
        public Vector2 Position { get; set; }
        public event ButtonPress ButtonPressed;
        public ButtonStates ButtonState { get; set; }
        public Rectangle CollisionRect { get; set; }

        private Texture2D NormalTexture;
        private Texture2D HoverTexture;
        private Texture2D DownTexture;
        private MouseState mouseState;
        private MouseState previousMouseState;

        public Button(Texture2D normalTexture, Texture2D hoverTexture, Texture2D downTexture,
            Vector2 position)
        {
            NormalTexture = normalTexture;
            HoverTexture = hoverTexture;
            DownTexture = downTexture;
            Position = position;

            mouseState = Mouse.GetState();
            previousMouseState = mouseState;

            CollisionRect = new Rectangle((int)Position.X, (int)Position.Y,
                    Texture.Width,
                    Texture.Height);
        }

        public void Update (MouseState currentState)
        {
            mouseState = currentState;

            if (CollisionRect.Contains(new Point(mouseState.X, mouseState.Y)))
            {
                if (mouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                {
                    ButtonState = ButtonStates.Pressed;
                    ButtonPressed();
                }
                else
                    ButtonState = ButtonStates.Hover;
            }
            else
                ButtonState = ButtonStates.Normal;
        }

        public void Update(MouseState currentState, Camera camera)
        {
            Vector2 mouse = new Vector2(mouseState.X, mouseState.Y);
            mouse = Vector2.Transform(mouse, camera.InverseTransform);
            CollisionRect = CalculateTransformedBoundingBox(CollisionRect, c.InverseTransform);

            Console.WriteLine("Rectangle[X: {0}, y: {1}], Mouse:[X: {2}, Y: {3}]", CollisionRect.X, CollisionRect.Y, mouse.X, mouse.Y);

            if (CollisionRect.Contains(new Point((int)mouse.X, (int)mouse.Y)))
            {
                if (mouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                {
                    ButtonState = ButtonStates.Pressed;
                    ButtonPressed();
                }
                else
                    ButtonState = ButtonStates.Hover;
            }
            else
                ButtonState = ButtonStates.Normal;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(Texture, Position, null, Color.White, 0.0f,
                Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
        }

        private Rectangle CalculateTransformedBoundingBox(Rectangle local, Matrix toWorldSpace)
        {
            Vector2 leftTop = new Vector2(local.Left, local.Top);
            Vector2 rightTop = new Vector2(local.Right, local.Top);
            Vector2 leftBottom = new Vector2(local.Left, local.Bottom);
            Vector2 rightBottom = new Vector2(local.Right, local.Bottom);

            Vector2.Transform(ref leftTop, ref toWorldSpace,
                             out leftTop);
            Vector2.Transform(ref rightTop, ref toWorldSpace,
                             out rightTop);
            Vector2.Transform(ref leftBottom, ref toWorldSpace,
                             out leftBottom);
            Vector2.Transform(ref rightBottom, ref toWorldSpace,
                             out rightBottom);

            // Find the minimum and maximum extents of the
            // rectangle in world space
            Vector2 min = Vector2.Min(Vector2.Min(leftTop, rightTop),
                                     Vector2.Min(leftBottom, rightBottom));
            Vector2 max = Vector2.Max(Vector2.Max(leftTop, rightTop),
                                     Vector2.Max(leftBottom, rightBottom));

            // Return that as a rectangle
            return new Rectangle((int)min.X, (int)min.Y,
                                (int)(max.X - min.X), (int)(max.Y - min.Y));
        }
    }
}

And my code for the camera:

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

namespace x.Graphics
{
    public class Camera
    {
        protected float _zoom;
        protected Matrix _transform;
        protected Matrix _inverseTransform;
        protected Vector2 _pos;
        protected float _rotation;
        protected Viewport _viewport;
        protected MouseState _mState;
        protected KeyboardState _keyState;
        protected Int32 _scroll;

        public float Zoom
        {
            get { return _zoom; }
            set { _zoom = value; }
        }
        public Matrix Transform
        {
            get { return _transform; }
            set { _transform = value; }
        }
        public Matrix InverseTransform
        {
            get { return _inverseTransform; }
        }
        public Vector2 Pos
        {
            get { return _pos; }
            set { _pos = value; }
        }
        public float Rotation
        {
            get { return _rotation; }
            set { _rotation = value; }
        }

        public Camera(Viewport viewport)
        {
            _zoom = 1.0f;
            _scroll = 1;
            _rotation = 0.0f;
            _pos = Vector2.Zero;
            _viewport = viewport;
        }

        public void Update()
        {
            Input();
            MathHelper.Clamp(_zoom, 0.01f, 10.0f);
            _rotation = ClampAngle(_rotation);
            _transform =    Matrix.CreateRotationZ(_rotation) *
                            Matrix.CreateScale(new Vector3(_zoom, _zoom, 1)) *
                            Matrix.CreateTranslation(_pos.X, _pos.Y, 0);
            _inverseTransform = Matrix.Invert(_transform);
        }

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

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

        protected float ClampAngle(float radians)
        {
            while (radians < -MathHelper.Pi)
            {
                radians += MathHelper.TwoPi;
            }
            while (radians > MathHelper.Pi)
            {
                radians -= MathHelper.TwoPi;
            }
            return radians;
        }
    }
}

I'm not 100% sure what's wrong, but the mouse position only changes when I press a button. I'm really confused, I've never worked with cameras before. Any help would be really appreciated. Thanks!

UPDATE: It detects the mouse as being over the button before I try and move the camera. After that, the coorindates of the rectangle are continually incremented.

役に立ちましたか?

解決

Don't transform bounding box... is easy to transform mouse coordinates ... ;)

Use the inverse transform of your camera matrix to transform mouse coords to the same space of your bounding box.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top