【问题标题】:XNA 2D Camera Drag Mouse Zoom ends up zooming out more then zooming inXNA 2D 相机拖动鼠标缩放最终缩小更多然后放大
【发布时间】:2012-08-10 13:16:33
【问题描述】:

我做了这个相机类来“调试”我的图形,它工作正常,但我不明白为什么它最终会缩小而不是缩小。

我实现了一个缩放功能,它通过用鼠标右键(RMB)拖动屏幕来工作(用左边你真的拖动屏幕),它就像Unity编辑器缩放(当你按住alt并使用RMB时,它具有缩放功能)

问题是,如果我拿着人民币像个白痴一样摇晃它,放大会比放大更多,最终让一切变得微不足道……我知道我的担心有点愚蠢,但意味着有那里的东西不是很精确..在统一编辑器中,像白痴一样摇晃它不会使事情最终变得超级缩小...

谁能告诉我是什么导致了这种行为?有点棘手..这是我的课,不要介意简单,我只是把它扔给调试:

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;

namespace Shooter

{

/// <summary>
/// Provides a camera controllable by mouse.
/// Controls include dragging the "screen"...
/// </summary>
class MouseCamera2D
{

    private Matrix m_mView;       // stores the camera state (position, scale/zoom, rotation)
    public Matrix ViewMatrix { get { return m_mView; }  }
    public Vector3 GetPosition() { return m_mView.Translation;  }

    public float m_scaleProportion = 0.01f; // the "speed" to scale, multiplies the offset from mouse drag

    // input data

    private MouseState m_mouseStateRef;
    private MouseState m_mouseStatePreviows = new MouseState();
    private KeyboardState m_kbStateRef;
    private KeyboardState m_kbStatePreviows = new KeyboardState();

    public Keys m_resetZoomKey = Keys.Z;


    //private GraphicsDevice m_graphicsDeviceRef;

    // ctor
    public MouseCamera2D(MouseState mouseState_p, KeyboardState kbState_p/*, GraphicsDevice graphicsDevice_p*/){

        if (mouseState_p == null ||kbState_p == null /*|| graphicsDevice_p == null*/) throw new Exception("cant be null"); // needs the reference

        //m_graphicsDeviceRef = graphicsDevice_p;

        m_mouseStateRef = mouseState_p; // init the reference
        m_kbStateRef = kbState_p;

        m_mView = Matrix.Identity; // set a valid matrix

        //zoomPivot = new Vector2(m_graphicsDeviceRef.Viewport.Width * 0.5f, m_graphicsDeviceRef.Viewport.Height * 0.5f);
    }



    public void InputUpdate()
    {
        m_mouseStatePreviows = m_mouseStateRef;
        m_mouseStateRef = Mouse.GetState();

        m_kbStatePreviows = m_kbStateRef;
        m_kbStateRef = Keyboard.GetState();

        InputDragControl();
        InputScaleControl();
        InputZoomOriginal();
    }

    private void InputDragControl()
    {
        //mouseStatePreviows = mouseStateRef;
       // mouseStateRef = Mouse.GetState();

        if (m_mouseStateRef.LeftButton == ButtonState.Pressed)
        {
            // check if its a drag or a new pivot point

            if (m_mouseStatePreviows.LeftButton == ButtonState.Pressed)
            {
                m_mView.M41 += (m_mouseStateRef.X - m_mouseStatePreviows.X);
                m_mView.M42 += (m_mouseStateRef.Y - m_mouseStatePreviows.Y);
            }
        }

    }

    Vector3 zoomPivot;
    private void InputScaleControl()
    {

        if (m_mouseStateRef.RightButton == ButtonState.Pressed)
        {
            // check if its a drag or a new pivot point

            if (m_mouseStatePreviows.RightButton == ButtonState.Pressed)
            {

                float scale = ((m_mouseStateRef.X - m_mouseStatePreviows.X) + (m_mouseStateRef.Y - m_mouseStatePreviows.Y)); //compute distance with "1d direction"(not abs)

                if (scale != 0.0f)
                {

                    scale *= m_scaleProportion;                       

                    //center zoom on mouse cursor:
                    m_mView *=

                                Matrix.CreateTranslation(-zoomPivot)
                                *
                                Matrix.CreateScale(1.0f + scale)
                                *
                                Matrix.CreateTranslation(zoomPivot)
                                ;

                    Console.WriteLine(scale.ToString());
                    Console.WriteLine(m_mView.M11.ToString());
                    Console.WriteLine("");
                }
            }
            else
            {
                // new press, get pivot point:

                zoomPivot.X = m_mouseStateRef.X;
                zoomPivot.Y = m_mouseStateRef.Y;
            }
        }
    }


    private void InputZoomOriginal()
    {
        if( m_kbStateRef.IsKeyDown(m_resetZoomKey) )
        {

            m_mView *=

                       Matrix.CreateTranslation(-zoomPivot)
                       *
                       Matrix.CreateScale(1.0f/m_mView.M11)
                       *
                       Matrix.CreateTranslation(zoomPivot)
                       ;

            Console.WriteLine(m_mView.M11.ToString());
                    Console.WriteLine("");
        }
    }
}

}

【问题讨论】:

    标签: xna camera 2d zooming


    【解决方案1】:

    你的问题来自这段代码:

    1.0f + scale

    让我们以单个像素的移动为例。使用m_scaleProportion = 0.01,正如您所拥有的那样,当您缩小时,您乘以 0.99。当您放大时,您乘以 1.01

    如果您先放大一个像素,然后再缩小一个像素,会发生什么?好吧,本质上,您将这两个值相乘。像这样:0.99 × 1.01 = 0.9999。这小于 1。重复此操作,最终您的缩放量会越来越小。


    如何正确实现缩放:

    首先:我建议不要在大多数情况下通过乘法来累加值(即:根据输入修改多帧的值)。在您的代码中,您不断地乘以矩阵(就像您对 *= 所做的那样) - 这可能会慢慢导致浮点问题。 (所以:不要使用矩阵,也不要使用常规的float

    你应该做的是通过加法来累积鼠标移动。然后根据到目前为止的整体运动更新矩阵。像这样的东西(伪代码):

    if(mouseWentDown)
    {
        // store the starting matrix:
        this.originalMatrix = this.currentMatrix;
        int zoomAmount = 0;
    }
    else if(mouseIsDown)
    {
        // Accumulate the mouse movment:
        zoomAmount += (how far the mouse moved this frame);
    
        // Recalculate the matrix based on the starting matrix:
        this.currentMatrix = this.originalMatrix * 
                Matrix.CreateScale((float)Math.Pow(2, zoomAmount * zoomRate));
    }
    

    注意使用Math.Pow 函数来提供实际的比例因子。这个函数很好,因为它为负输​​入提供小于 1 的值,为正输入提供大于 1 的值。对于零输入,它给出 1(无缩放)。

    当然,您可能还想在上面添加您的数据透视代码。这将是相似的。您可能还需要调整缩放率。

    注意:如果您使用SpriteBatch 将此矩阵用于二维工作,请不要缩放 Z 轴。仅缩放 X 和 Y 轴并保留 Z = 1。


    旁白:您可能会注意到技术上我上面的代码是通过乘法累加的,但仅在缩放完成时(所以它几乎没有那么糟糕)。在我自己的代码中,我通常会始终存储缩放量(从不将其重置为零)并重新生成完整的矩阵——它更健壮一些。

    【讨论】:

      猜你喜欢
      • 2020-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 2014-05-23
      相关资源
      最近更新 更多