为阅读XNA菜单的Xbox360指拨时是否需要非零阈值以防止轻拂? [英] Is a non-zero threshold required to prevent flicking when reading the Xbox360 thumbstick for an XNA menu?
问题描述
我游戏中的垂直菜单允许您在指尖上按向上或向下以跳到下一个(或上一个)菜单项.我通过存储旧的指杆状态来实现这一点.如果状态为零,但现在不为零,则选择下一个(或上一个)菜单项.
The vertical menus in my game allow you to press up or down on the thumbstick to jump to the next (or previous) menu item. I implement this by storing the old thumbstick state. If the state was zero and is now non-zero, the next (or previous) menu item is selected.
我从未在连接到PC或Xbox的Xbox控制器上注意到此实现的任何轻弹".我已经测试了几个控制器.
I have never noticed any "flicking" with this implementation either on Xbox controller attached to a PC or an Xbox. I have tested with several controllers.
但是,当我回答问题,
However when I answered the question question XNA - how to tell if a thumb stick was "twitched" in a certain direction, Andrew Russell commented:
虽然这是正确的主意, 阈值必须高于零(对于 在菜单中使用),并且需要有一个 激活和激活之间的余量 停用以防止其滑动.
While this is the right idea, the threshold needs to be above zero (for use in menus), and there needs to be a margin between activation and deactivation to prevent it flicking.
我的理解是Xna已经在拇指输入上提供了过滤和死区",并且不需要阈值或裕量来防止轻拂.安德鲁的声明令我担心.
My understanding is that Xna already provides filtering and a "dead-zone" on the thumb-stick input and that no threshold or margin is necessary to prevent flicking. Andrew's statement worried me.
是否存在需要阈值或边距以防止轻拂"的控制器?
为了安全起见,我应该在阈值和边距中进行编码吗?
以下代码是我的XNA菜单输入轮询方法的最小实现.唯一的区别是,在控件的值在同一方向上短时不为零后,我的实际菜单会自动滚动.与该问题有关的逻辑在ProcessUserInput函数中.
The following code is a minimal implementation of my method of input polling for XNA menus. The only difference is that my actual menus autoscroll after the control's value has been non-zero in the same direction for a short while. The logic related to this question is in the ProcessUserInput function.
球代表活动菜单项.向上或向下按左拇指拨杆,将球跳到下一个/上一个菜单项.我无法将它变成闪烁".
The ball represents the active menu item. Press the left thumbstick up or down to jump the ball to the next/previous menu item. I can't get it to "flicker".
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);
}
}
}
推荐答案
基本上是让控件感觉好".
需要将阈值设置为零以上(因为摇杆永远不会精确地位于零上).死区算作一个阈值,但很小很小.我认为默认的XNA死区约为0.24.这太小了,无法在菜单中使用.
Setting a threshold above zero is required (because the sticks are never exactly on zero). The dead-zone counts as a threshold, but it's very small. I think the default XNA dead-zone is about 0.24. This is way too small to use in a menu.
我怀疑-但是我现在无法测试-XNA的按按钮解释"代码使用与激活相同的,微小的,不令人满意的死区阈值.
I suspect - but I am not in a position to test this right now - that XNA's interpret-the-thumbsticks-as-buttons code uses the same, tiny, unsatisfying dead zone as its activation threshold.
从您链接的答案中可以看到,我将激活阈值设置为0.85,这要高得多.诚然,我的代码不适用于菜单.菜单的调整可能要小一些,但仍不如默认的死区小.
As you can see from my answer you linked, I set an activation threshold at 0.85, which is considerably higher. Admittedly, my code is not for a menu. The tuning for a menu might be a bit smaller, but still not as small as the default dead-zone.
对于边距(例如:在0.85处激活,在0.75处停用).当您专门响应"off-on-off"过渡时,要获得令人满意的感觉,这是特别需要的.当您仅检测到"on"状态时,并没有必要.
As for the margin (eg: activate at 0.85, deactivate at 0.75). This is particularly required to get a satisfying feel when you're specifically responding to an "off-on-off" transition. It is not really necessary when you're simply detecting the "on" state.
这还可以防止您将摇杆运动解释为按下按钮(例如菜单),并且在极少数情况下可能会收到虚假的双击.
It also prevents the situation where you're interpreting stick movement as button presses (as you might for a menu) and may, on rare occasion, receive a spurious double-press.
这篇关于为阅读XNA菜单的Xbox360指拨时是否需要非零阈值以防止轻拂?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!