Требуется ли ненулевой порог, чтобы предотвратить щелчки при чтении миниатюры Xbox360 для меню XNA? - PullRequest
0 голосов
/ 22 февраля 2011

Вертикальные меню в моей игре позволяют нажимать на джойстик вверх или вниз, чтобы перейти к следующему (или предыдущему) пункту меню. Я реализую это, сохраняя старое состояние большого пальца. Если состояние было нулевым и теперь ненулевым, выбирается следующий (или предыдущий) пункт меню.

Я никогда не замечал никаких «щелчков» этой реализацией ни на контроллере Xbox, подключенном к ПК, ни на Xbox. Я проверил с несколькими контроллерами.

Однако, когда я ответил на вопрос, вопрос XNA - как определить, «палка для большого пальца» «дернулась» в определенном направлении , Эндрю Рассел прокомментировал:

Хотя это правильная идея, порог должен быть выше нуля (для использовать в меню), и там должно быть разница между активацией и деактивация, чтобы предотвратить щелчок.

Насколько я понимаю, Xna уже обеспечивает фильтрацию и "мертвую зону" на входе большого пальца, и что для предотвращения щелчков не требуется никаких порогов или полей. Заявление Эндрю беспокоило меня.

Существуют ли какие-либо контроллеры, которым необходим порог или запас для предотвращения "щелчков"?

Должен ли я кодировать с порогом и запасом только для безопасности?

Следующий код является минимальной реализацией моего метода опроса ввода для меню XNA. Единственное отличие состоит в том, что мои актуальные меню автоматически прокручиваются после того, как значение элемента управления ненулевое в том же направлении в течение короткого времени. Логика, связанная с этим вопросом, находится в функции ProcessUserInput.

Мяч представляет собой активный пункт меню. Нажмите левую ручку вверх или вниз, чтобы перейти к следующему / предыдущему пункту меню. Я не могу заставить его "мерцать".

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace WindowsGame
{
    public class Ball
    {
        public float RADIUS = DIAMETER * 0.5f;
        const int DIAMETER = 40;
        static readonly uint WHITE = Color.White.PackedValue;
        static readonly uint BLACK = new Color(0, 0, 0, 0).PackedValue;

        Texture2D m_texture;

        public Ball(GraphicsDevice graphicsDevice)
        {
            m_texture = new Texture2D(graphicsDevice, DIAMETER, DIAMETER);

            uint[] data = new uint[DIAMETER * DIAMETER];

            for (int i = 0; i < DIAMETER; i++)
            {
                float iPosition = i - RADIUS;

                for (int j = 0; j < DIAMETER; j++)
                {
                    data[i * DIAMETER + j] = new Vector2(iPosition, j - RADIUS).Length() <= RADIUS ? WHITE : BLACK;
                }
            }

            m_texture.SetData<uint>(data);
        }

        public Vector2 Position { get; set; }

        private Rectangle DrawRectangle
        {
            get
            {
                return new Rectangle((int)Math.Round(Position.X - RADIUS), (int)Math.Round(Position.Y - RADIUS), DIAMETER, DIAMETER);
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(m_texture, DrawRectangle, Color.White);
        }
    }

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Matrix viewMatrix;
        Matrix inverseViewMatrix;
        Ball ball;
        GamePadState m_lastGamePadState;

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

        protected override void Initialize()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            ball = new Ball(GraphicsDevice);
            viewMatrix = Matrix.CreateTranslation(Window.ClientBounds.Width * 0.5f, Window.ClientBounds.Height * 0.5f, 0.0f);
            inverseViewMatrix = Matrix.Invert(viewMatrix);
            m_lastGamePadState = GamePad.GetState(PlayerIndex.One);
            base.Initialize();
        }

        private void ProcessUserInput()
        {
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            if (m_lastGamePadState.ThumbSticks.Left.Y == 0.0f)
            {
                ball.Position += Vector2.UnitY * (-Math.Sign(gamePadState.ThumbSticks.Left.Y) * ball.RADIUS * 2.0f);
            }

            m_lastGamePadState = gamePadState;
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            ProcessUserInput();
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, viewMatrix);
            ball.Draw(spriteBatch);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

Ответы [ 2 ]

1 голос
/ 22 февраля 2011

Речь идет, в основном, о том, чтобы элементы управления чувствовали себя «хорошо».

Требуется установка порога выше нуля (потому что палочки никогда не бывают точно на нуле).Мертвая зона считается порогом, но она очень мала.Я думаю, что мертвая зона XNA по умолчанию составляет около 0,24.Это слишком мало, чтобы использовать его в меню.

I подозреваю - но я не в состоянии проверить это прямо сейчас - что XNA интерпретирует кнопки большого пальца как кнопкикод использует ту же крошечную, неудовлетворительную мертвую зону в качестве порога активации.

Как видно из моего ответа, который вы связали, я установил порог активации на 0,85, что значительно выше.Правда, мой код не для меню.Настройка для меню может быть немного меньше, но все же не такой маленькой, как в мертвой зоне по умолчанию.

Что касается поля (например: активировать при 0,85, деактивировать при 0,75).Это особенно необходимо для того, чтобы вы почувствовали удовлетворение, когда конкретно реагируете на переход «выключено».На самом деле в этом нет необходимости, когда вы просто обнаруживаете состояние «включено».

Это также предотвращает ситуацию, когда вы интерпретируете движение ручки при нажатии кнопки (как вы могли бы для меню) и может, еслиредкий случай, получить поддельное двойное нажатие.

1 голос
/ 22 февраля 2011

Вы, вероятно, хотите

GamePad.GetState(PlayerIndex.One, GamePadDeadZone.IndependentAxes);

Это должно быть все, что тебе нужно. См. GamePadDeadZone . ( Edit: только что заметил, что это по умолчанию - у вас уже должно быть все в порядке. )

Лично я использую Buttons.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...