Вертикальные меню в моей игре позволяют нажимать на джойстик вверх или вниз, чтобы перейти к следующему (или предыдущему) пункту меню. Я реализую это, сохраняя старое состояние большого пальца. Если состояние было нулевым и теперь ненулевым, выбирается следующий (или предыдущий) пункт меню.
Я никогда не замечал никаких «щелчков» этой реализацией ни на контроллере 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);
}
}
}