我想检测水平滑动,以便用户可以向左或向右滑动以切换一堆游戏角色。 1左滑动切换/显示前一个字符,右滑动切换/显示下一个字符。
Input.GetAxis("Horizontal")
会给我一个介于-1和1之间的范围,具体取决于您向左或向右滑动。
如果我将Debug.Log(Input.GetAxis("Horizontal"))
添加到void update()
,则会在每次滑动/按键时多次打印轴范围。
如何获得单个(第一个)值Input.GetAxis("Horizontal")
返回?
我想做这样的事情:
void Update() {
float swipe = Input.GetAxis("Horizontal");
if (swipe > 0) {
ToggleRight ();
} else if (swipe < 0) {
ToggleLeft();
}
}
这可能还是有办法实现水平滑动?
答案 0 :(得分:0)
您遇到的问题是,在滑动过程中,您的功能会在每个游戏周期中被调用,您的功能最终会被多次调用。基本上,您希望有一种方法来过滤更新事件流并仅选择相关事件。
您可以采用的方法是使用 Reactive Extensions 。您可以下载统一兼容的反应式扩展版本here。
完成后,您就可以将统一输入转换为可观察流。这是你如何做到的:
using UnityEngine;
// You'll need to include these namespaces.
using UniRx;
using System.Linq;
using System;
// This will be responsible for converting unity input
// into a stream of events.
public class SwipeListener : MonoBehaviour
{
// Rx Subjects allow you to create an observable stream of your
// own. You can push events to the stream by calling OnNext().
private Subject<float> _subject;
// We'll expose the above stream via this property for a couple reasons.
// 1) If we exposed the subject directly, other code could push events to
// our stream by calling OnNext(). Preventing that helps avoid bugs.
// 2) We'll be filtering the stream to avoid having too many swipe-events.
public IObservable<float> InputStream { get; private set; }
// Event values will be grouped by threes and averaged
// to smooth out noise.
[SerializeField]
private int _bufferCount = 3;
// Average displacement level below which no swipe event
// will be triggered.
[SerializeField]
private float _minimumThreshhold = 15;
// To prevent back-to-back swipe events.
[SerializeField]
private float _slidingTimeoutWindowSeconds = .25f;
private void Update()
{
// We push values to our stream by calling OnNext() on our
// Subject in each game step.
_subject.OnNext(GetInputValue());
}
// Here is where we get the value that will be pushed into the stream.
// For this demonstration, I'm using the mouse-position. You could easily
// override this and return touch positions instead.
protected virtual float GetInputValue()
{
return Input.mousePosition.x;
}
public SwipeListener()
{
_subject = new Subject<float>();
// This is where the real magic happens. IObservable supports many of the
// same LINQ operations as IEnumerable.
IObservable<float> filtered = _subject
// Convert stream of horizontal mouse positions into a stream of
// mouse speed values.
.Pairwise()
.Select(x => x.Current - x.Previous)
// Group events and average them to smooth out noise. The group size
// can be configured in the inspector.
.Buffer(_bufferCount)
.Select(x => x.Average())
// Filter out events if the mouse was not moving quickly enough. This
// can be configured in the inspector. You'll want to play around with this.
.Where(x => Mathf.Abs(x) > _minimumThreshhold);
// Now we'll apply a sliding timeout window to throttle our stream. this
// will help prevent multiple back-to-back swipe events when you swipe once.
// I've split the event stream into two separate streams so we can throttle
// left and right swipes separately. This will help ensure that there isn't
// unnecessary lag when swiping left after having swiped right, or vice-versa.
TimeSpan seconds = TimeSpan.FromSeconds(_slidingTimeoutWindowSeconds);
IObservable<float> left = filtered
.Where(x => x < 0)
.Throttle(seconds);
IObservable<float> right = filtered
.Where(x => x > 0)
.Throttle(seconds);
// Now that we've throttled left and right swipes separately, we can merge
// them back into a single stream.
InputStream = left.Merge(right);
}
}
现在你所要做的就是编写一个使用上述脚本的脚本。这是一个如何做到这一点的例子:
using UnityEngine;
using System.Collections;
using UniRx;
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(SwipeListener))]
public class ColorFlasher : MonoBehaviour
{
[SerializeField]
private Material _left;
[SerializeField]
private Material _right;
private Material _normal;
[SerializeField]
private float _flashPeriod = .1f;
private MeshRenderer _meshRenderer;
private SwipeListener _inputListener;
void Start()
{
_meshRenderer = GetComponent<MeshRenderer>();
_normal = _meshRenderer.material;
_inputListener = GetComponent<SwipeListener>();
_inputListener.InputStream
.Subscribe(x => StartCoroutine(FlashColor(x)));
_inputListener.InputStream.Subscribe(x => Debug.Log(x));
}
private IEnumerator FlashColor(float swipe)
{
Material material = _normal;
if (swipe > 0)
material = _right;
else if (swipe < 0)
material = _left;
_meshRenderer.material = material;
yield return new WaitForSeconds(_flashPeriod);
_meshRenderer.material = _normal;
}
}
上述脚本只有一个立方体,每当检测到滑动时,它会短暂地闪烁不同的颜色。
on my github上提供了上述示例的完整版本。