Я впервые пытаюсь сделать мобильную игру с сенсорным управлением в Unity. Я в основном получил это работает. Но есть проблема, как вы понимаете, что удар - это не касание?
Как работает мой код, который я частично нашел в обучающих материалах, заключается в том, что для регистрации касания я смотрю, если у пользователя есть сенсорный экран в течение минимального промежутка времени, в данном случае 0,05 секунды. И для просмотра, я смотрю, перемещается ли касание пользователя на минимальное расстояние.
Проблема в том, что довольно часто начало пролистывания регистрируется как касание, поскольку пользователь не двигает пальцем в течение 0,05 секунды. Я мог бы просто сделать минимальное стационарное время, чтобы зарегистрировать нажатие выше, но это означало бы, что в игре будет больше задержки между моментом, когда пользователь касается экрана, и действие будет выполнено ...
Есть ли идеальное решение моей проблемы? В мобильной игре Rayman Adventures тап заставляет игрока прыгать, а смахивание меняет его направление, и оно работает довольно плавно, лишь в очень редких случаях игрок прыгает, когда вы пытаетесь сменить направление. Я понятия не имею, как они это сделали.
Заранее спасибо за ваше время!
Вот мой код:
public static event Action<SwipeData> OnSwipe = delegate { };
public static event Action OnTap = delegate { };
[Header("Swipe parameters")]
[SerializeField]
bool m_DetectSwipeOnlyAfterRelease;
[SerializeField]
float m_MinDistanceForSwipe;
[Header("Tap parameters")]
[SerializeField]
float m_TapTimeMinThreshold;
private Vector2 m_FingerDownPosition;
private Vector2 m_FingerUpPosition;
private float m_TouchTime;
private bool m_StationaryTouch;
private bool m_TapRegistered;
private bool m_SwipeRegistered;
void Start() {
m_TapRegistered = true;
m_SwipeRegistered = true;
}
void Update() {
if (Input.touchCount == 1) {
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began) {
m_FingerUpPosition = touch.position;
m_FingerDownPosition = touch.position;
m_TouchTime = Time.time;
m_StationaryTouch = true;
m_TapRegistered = false;
m_SwipeRegistered = false;
}
if(!m_SwipeRegistered && touch.phase == TouchPhase.Moved) {
m_StationaryTouch = false;
m_FingerDownPosition = touch.position;
SwipeDirection swipeDirection = DetectSwipe();
// If a swipe was registered
if (!swipeDirection.Equals(SwipeDirection.NONE)) {
// And it was horizontal, we reset the swipe detection
if (swipeDirection.Equals(SwipeDirection.LEFT) || swipeDirection.Equals(SwipeDirection.RIGHT))
m_FingerUpPosition = touch.position;
else
m_SwipeRegistered = true;
}
}
// If the touch was stationary for the min threshold amount of time we register it as a tap
if (m_StationaryTouch && !m_TapRegistered && Time.time - m_TouchTime > m_TapTimeMinThreshold) {
m_TapRegistered = true;
OnTap();
}
if (!m_SwipeRegistered && touch.phase == TouchPhase.Ended && !m_TapRegistered) {
m_FingerDownPosition = touch.position;
DetectSwipe();
}
}
}
private SwipeDirection DetectSwipe() {
if (SwipeDistanceCheckMet()) {
SwipeDirection direction;
if (IsVerticalSwipe()) {
direction = m_FingerDownPosition.y - m_FingerUpPosition.y > 0 ? SwipeDirection.UP : SwipeDirection.DOWN;
SendSwipe(direction);
}
else {
direction = m_FingerDownPosition.x - m_FingerUpPosition.x > 0 ? SwipeDirection.RIGHT : SwipeDirection.LEFT;
SendSwipe(direction);
}
m_FingerUpPosition = m_FingerDownPosition;
return direction;
}
return SwipeDirection.NONE;
}
private bool IsVerticalSwipe() {
return VerticalMovementDistance() > HorizontalMovementDistance();
}
private bool SwipeDistanceCheckMet() {
return VerticalMovementDistance() > m_MinDistanceForSwipe || HorizontalMovementDistance() > m_MinDistanceForSwipe;
}
private float VerticalMovementDistance() {
return Mathf.Abs(m_FingerDownPosition.y - m_FingerUpPosition.y);
}
private float HorizontalMovementDistance() {
return Mathf.Abs(m_FingerDownPosition.x - m_FingerUpPosition.x);
}
private void SendSwipe(SwipeDirection direction) {
SwipeData swipeData = new SwipeData()
{
Direction = direction,
StartPosition = m_FingerDownPosition,
EndPosition = m_FingerUpPosition
};
OnSwipe(swipeData);
}