動作環境
Mac OS Monterey
Unity2020.3.22f
Unity Universal Render Pipeline プロジェクト
インプット機能(スワイプ、タップ)関連初心者です。
現在モバイルアプリを作っているのですが、スマホスクリーンに対しての機能の導入が上手くいっていないので質問を投稿しました。
概要
スマホスクリーンに対して指が触れている間、動的(毎フレーム)に指が触れているポジション(x,y座標)をVector2で取得し、下記のスクリーンショット内に配置されている四角イメージのx,y座標を予めスクリプト内にVector2リストで保存しておいて、指が触れた際に当たり判定を取得する機能を実装しようとしています。
Unityで新しいinput systemが導入されている為、それを利用し2 - 3枚目のスクリーンショットの様にタップとスワイプが出来る様に試みたのですが、指が触れている場所を動的に取り続ける機能の実装が頭の中で上手く組み立てられないので、何方か似たような機能を既に実装された経験のある方居ましたらアドバイスして頂けないでしょうか?? この投稿の最下部に新しいinput systemに対して使用しているスクリプトを記載しておきます。
実装を試みている方法1
指のポジションを常に動的に取得し、スクリプト内で四角イメージの(x,y座標 + 四角イメージの半径をx,yに足し引きし)の合計を用いて、指がそのエリアを通過(スワイプ)した際に当たり判定を取る方法。
実装が出来ていない部分
・新しいinput system上で常に指の座標を取得する方法が分からないという事。(必ずしも新しいinput systemを使わなければいけないという事ではないです。)
下記の動画を参照したのですが、このスクリプトで指の座標をDebug.Logに出力すると常に0 - 1の座標しか表示されません。
スワイプ機能導入参照動画
タップ機能導入参照動画
———————————————
実装を試みている方法2
また上記の実装方法が上手くいかなかった場合に備えて以下の方法も考えています。入力機能に関して知識が浅いので、別に良い方法があったり、これら2つの方法の不備・欠点がある場合は指摘なども同時にして頂けると幸いです。
2dコライダーが付いた透明GameObjectを指が触れた場所にinstantiateして指の動きと共に付随させ、同じく2dコライダーが付いた四角のイメージUIにぶつけて(同じ座標を通過した際に)当たり判定を取る。指が離れたらInstantiateされたGameObjectは破棄。
実装方法が不明な部分
・スワイプの動きに上記のコライダー付きGameObjectを付随させる事。
1st Contact(中身のBindingはPathがTouch#0/Touch Contact?[Touchscreen], Trigger BehaviourはPress Only)
2nd - 4thと同じ構造です。(Touch#1-3に変わるだけです)
1st Position(中身のBindingはPathがTouch#0/Position[Touchscreen]、以下他の設定はなし)
2nd -4thと同じ構造です。(Touch#1-3に変わるだけです)
Input Systemに使用しているスクリプト
InputManager.cs,
Utils.cs,
SwipeDection.cs
using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.EnhancedTouch; [DefaultExecutionOrder(-1)] public class InputManager : Singleton<InputManager> { #region Events public delegate void SwipeStart(Vector2 position, float time); public event SwipeStart OnSwipeStart; public delegate void SwipeEnd(Vector2 position, float time); public event SwipeEnd OnSwipeEnd; #endregion private TouchControl touchControl; private Camera mainCamera; private void Awake() { touchControl = new TouchControl(); mainCamera = Camera.main; } private void OnEnable() { touchControl.Enable(); TouchSimulation.Enable(); } private void OnDisable() { touchControl.Disable(); TouchSimulation.Disable(); } private void Start() { touchControl.Touch.PrimaryContact.started += ctx => StartTouchPrimary(ctx); touchControl.Touch.PrimaryContact.canceled += ctx => EndTouchPrimary(ctx); } private void StartTouchPrimary(InputAction.CallbackContext context) { if (OnSwipeStart != null) OnSwipeStart(Utils.ScreenToWorld(mainCamera, touchControl.Touch.PrimaryPosition.ReadValue<Vector2>()), (float)context.startTime); } private void EndTouchPrimary(InputAction.CallbackContext context) { if (OnSwipeEnd != null) OnSwipeEnd(Utils.ScreenToWorld(mainCamera, touchControl.Touch.PrimaryPosition.ReadValue<Vector2>()), (float)context.time); } public Vector2 PrimaryPosition() { return Utils.ScreenToWorld(mainCamera, touchControl.Touch.PrimaryPosition.ReadValue<Vector2>()); } }
using UnityEngine; public class Utils : MonoBehaviour { public static Vector3 ScreenToWorld(Camera camera, Vector3 position) { position.z = camera.nearClipPlane; return camera.ScreenToWorldPoint(position); } }
using System.Collections; using UnityEngine; public class SwipeDetection : MonoBehaviour { [SerializeField] private float minimumDistance = .2f; [SerializeField] private float maximumTime = 1f; [SerializeField, Range(0f, 1f)] private float directionThreshhold = .9f; [SerializeField] private GameObject trail; private Coroutine coroutine; private InputManager inputManager; private Vector2 startPosition; private float startTime; private Vector2 endPosition; private float endTime; private void Awake() { inputManager = InputManager.Instance; } private void OnEnable() { inputManager.OnSwipeStart += SwipeStart; inputManager.OnSwipeEnd += SwipeEnd; } private void OnDisable() { inputManager.OnSwipeStart -= SwipeStart; inputManager.OnSwipeEnd -= SwipeEnd; } private void SwipeStart(Vector2 position, float time) { startPosition = position; startTime = time; trail.SetActive(true); trail.transform.position = position; coroutine = StartCoroutine(Trail()); } private IEnumerator Trail() { while (true) { trail.transform.position = inputManager.PrimaryPosition(); //0 - 1の値でしか座標を取得出来ない。 Debug.Log("_M " + inputManager.PrimaryPosition()); yield return null; } } private void SwipeEnd(Vector2 position, float time) { trail.SetActive(false); StopCoroutine(coroutine); endPosition = position; endTime = time; DetectSwipe(); } private void DetectSwipe() { if(Vector3.Distance(startPosition, endPosition) >= minimumDistance && (endTime - startTime) <= maximumTime) { Debug.Log("Swipe Detected"); Debug.DrawLine(startPosition, endPosition, Color.red, 5f); Vector3 direction = endPosition - startPosition; Vector3 direction2D = new Vector2(direction.x, direction.y).normalized; SwipeDirection(direction2D); } } private void SwipeDirection(Vector3 direction) { if(Vector2.Dot(Vector2.up, direction) > directionThreshhold) { Debug.Log("Swipe up"); } else if (Vector2.Dot(Vector2.down, direction) > directionThreshhold) { Debug.Log("Swipe down"); } else if (Vector2.Dot(Vector2.left, direction) > directionThreshhold) { Debug.Log("Swipe left"); } else if (Vector2.Dot(Vector2.right, direction) > directionThreshhold) { Debug.Log("Swipe right"); } } }
あなたの回答
tips
プレビュー