質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1524閲覧

Unityのスマホタッチ操作に関して(1本目に置いた指を2本目に引っ張られたくない)

jury

総合スコア18

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

1グッド

1クリップ

投稿2019/01/09 03:37

編集2019/01/09 06:02

こんにちは。
昨日に引き続きUnityに関して質問させて頂きます。

###解決したいこと
現在、以下画像のようにシューティングゲームを作成したいと思っています。
左下のUIが中央の青いオブジェクト(プレイヤー)を動かすジョイスティックで、右下のUIがプレイヤーから弾を発射させるボタンです。
イメージ説明

スティックで移動させながら弾を発射出来るようにしたのですが、発射ボタンを押すとタップ感知が反応してしまい、ジョイスティックが右側に持っていかれてしまいプレイヤーの挙動がおかしなことになってしまいます。

移動や発射自体はそれぞれ問題無くうごくのですが、両立させる方法が中々思いつきません…
もし何か良いアイディア等あればご教授頂ければと思います。

編集追記
方法として、タップ処理でタップできる箇所の範囲を制限する。
あるいはドラッグ中の場合のタップを受け付けないといった物を思いついたのですが、
上手く実装できません……

C#

1using UnityEngine; 2using UnityEngine.UI; 3using UnityEngine.EventSystems; 4using System.Collections; 5using System.Collections.Generic; 6 7/// <summary> 8/// ジョイスティック 9/// </summary> 10public class Joystick : Graphic, IPointerDownHandler, IPointerUpHandler, IEndDragHandler, IDragHandler 11{ 12 13 //実際に動くスティック部分 14 [SerializeField] 15 [Header("実際に動くスティック部分(自動設定)")] 16 private GameObject _stick = null; 17 private const string STICK_NAME = "Stick"; 18 19 //スティックが動く範囲の半径 20 [SerializeField] 21 [Header("スティックが動く範囲の半径")] 22 private float _radius = 100; 23 24 //指を離した時にスティックが中心に戻るか 25 [SerializeField] 26 [Header("指を離した時にスティックが中心に戻るか")] 27 private bool _shouldResetPosition = true; 28 29 //現在地(x,y共に値が-1~1の範囲になる) 30 [SerializeField] 31 [Header("現在地(自動更新)")] 32 private Vector2 _position = Vector2.zero; 33 public Vector2 Position { get { return _position; } } 34 35 //スティックの位置(Setter) 36 private Vector3 _stickPosition 37 { 38 set 39 { 40 _stick.transform.localPosition = value; 41 _position = new Vector2( 42 _stick.transform.localPosition.x / _radius, 43 _stick.transform.localPosition.y / _radius 44 ); 45 } 46 } 47 48 //================================================================================= 49 //初期化 50 //================================================================================= 51 52 protected override void Awake() 53 { 54 base.Awake(); 55 Init(); 56 } 57 58 //初期化 59 private void Init() 60 { 61 //スティックを生成する必要があれば生成し、位置を中心に設定 62 CreateStickIfneeded(); 63 _stickPosition = Vector3.zero; 64 65 //スティックのImage取得(なければ追加)、タッチ判定を取られないようにraycastTargetをfalseに 66 Image stickImage = _stick.GetComponent<Image>(); 67 if (stickImage == null) 68 { 69 stickImage = _stick.AddComponent<Image>(); 70 } 71 stickImage.raycastTarget = false; 72 73 //タッチ判定を受け取れるようにRaycastTargetをTrueに 74 raycastTarget = true; 75 76 //タッチ判定をとる範囲は表示されないように透明に 77 color = new Color(0, 0, 0, 0); 78 } 79 80 //スティックを生成する必要があれば生成 81 private void CreateStickIfneeded() 82 { 83 //スティックが設定されていれば終了 84 if (_stick != null) 85 { 86 return; 87 } 88 89 //スティックが子にあるか検索、あれば取得し終了 90 if (transform.Find(STICK_NAME) != null) 91 { 92 _stick = transform.Find(STICK_NAME).gameObject; 93 return; 94 } 95 96 //スティック生成 97 _stick = new GameObject(STICK_NAME); 98 _stick.transform.SetParent(gameObject.transform); 99 _stick.transform.localRotation = Quaternion.identity; 100 } 101 102 //================================================================================= 103 //タップ 104 //================================================================================= 105 106 //タップ開始時 107 public void OnPointerDown(PointerEventData eventData) 108 { 109 //タップした瞬間にドラッグを開始した事にする 110 OnDrag(eventData); 111 } 112 113 //タップ終了時(ドラッグ終了時には呼ばれない) 114 public void OnPointerUp(PointerEventData eventData) 115 { 116 //タップした終了した時にドラッグを終了した時と同じ処理をする 117 OnEndDrag(eventData); 118 } 119 120 //================================================================================= 121 //ドラッグ 122 //================================================================================= 123 124 //ドラッグ終了時 125 public void OnEndDrag(PointerEventData eventData) 126 { 127 if (_shouldResetPosition) 128 { 129 //スティックを中心に戻す 130 _stickPosition = Vector3.zero; 131 } 132 } 133 134 //ドラッグ中 135 public void OnDrag(PointerEventData eventData) 136 { 137 //タップ位置を画面内の座標に変換し、スティックを移動 138 Vector2 screenPos = Vector2.zero; 139 RectTransformUtility.ScreenPointToLocalPointInRectangle(GetComponent<RectTransform>(), 140 new Vector2(Input.mousePosition.x, Input.mousePosition.y), 141 null, 142 out screenPos 143 ); 144 145 _stickPosition = screenPos; 146 147 //移動場所が設定した半径を超えてる場合は制限内に抑える 148 float currentRadius = Vector3.Distance(Vector3.zero, _stick.transform.localPosition); 149 if (currentRadius > _radius) 150 { 151 152 //角度計算 153 float radian = Mathf.Atan2(_stick.transform.localPosition.y, _stick.transform.localPosition.x); 154 155 //円上にXとYを設定 156 Vector3 limitedPosition = Vector3.zero; 157 limitedPosition.x = _radius * Mathf.Cos(radian); 158 limitedPosition.y = _radius * Mathf.Sin(radian); 159 160 _stickPosition = limitedPosition; 161 } 162 163 } 164 165 //================================================================================= 166 //更新 167 //================================================================================= 168 169#if UNITY_EDITOR 170 //Gizmoを表示する 171 private void OnDrawGizmos() 172 { 173 //スティックが移動できる範囲をScene上に表示 174 UnityEditor.Handles.color = Color.green; 175 UnityEditor.Handles.DrawWireDisc(transform.position, transform.forward, _radius * 0.5f); 176 } 177#endif 178 179}
退会済みユーザー👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

大まかな方針だけになりますが
Input.touchesを使うと複数の指の座標がもとまるのでforで一本ずつ処理すると良いと思います
イメージとしては、Input.touches[指のinxex]の座標がJoyStickの範囲内にあるときはJoystickの位置を更新、ボタンの範囲内にあるときはボタンを更新という感じになると思います。UI座標からスクリーンに変換するところはstackoverflowのやり方で出来ると思います

追記
クラスの継承はMonoBehaviorだけにして
(Joystick:MonoBehavior)
イベント処理の関数は消してください
OnDragを以下のように、

C#

1 float _radius2=150;//ジョイスティックの最大半径 2 public bool OnDrag(Vector2 touch) 3 { 4 //タップ位置を画面内の座標に変換し、スティックを移動 5 Vector2 screenPos = Vector2.zero; 6 RectTransformUtility.ScreenPointToLocalPointInRectangle(GetComponent<RectTransform>(), 7 touch, 8 null, 9 out screenPos 10 ); 11 12 _stickPosition = screenPos; 13 14 //移動場所が設定した半径を超えてる場合は制限内に抑える 15 float currentRadius = Vector3.Distance(Vector3.zero, _stick.transform.localPosition); 16 if (currentRadius > _radius2) 17 {return false;} 18 19 if (currentRadius > _radius) 20 { 21 22 //角度計算 23 float radian = Mathf.Atan2(_stick.transform.localPosition.y, _stick.transform.localPosition.x); 24 25 //円上にXとYを設定 26 Vector3 limitedPosition = Vector3.zero; 27 limitedPosition.x = _radius * Mathf.Cos(radian); 28 limitedPosition.y = _radius * Mathf.Sin(radian); 29 30 _stickPosition = limitedPosition; 31 } 32 return true; 33 }

Updateを以下のようにしてください

C#

1public void Update(PointerEventData eventData) { 2 bool isInsideBoundary; 3 Touch[] touches = Input.touches; 4 for (int i = 0; i < Input.touchCount; i++) { 5 Touch touch=touches[i]; 6 if(touch.phase==TouchPhase.Began||touch.ohase==TouchPhase.Moved){ 7 isInsideBoundary=OnDrag(touch.position); 8 if(isInsideBoundary)break; 9 } 10 } 11 if(!isInsideBoundary){ 12 if (_shouldResetPosition) 13 { 14 //スティックを中心に戻す 15 _stickPosition = Vector3.zero; 16 } 17 } 18}

投稿2019/01/10 07:45

編集2019/01/16 10:51
bochan2

総合スコア2050

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jury

2019/01/16 06:29

返事が遅くなってしまい申し訳ございません… ご回答ありがとうございます! それっぽく作ってみたのですが、中々思うようにいきません… public void Update(PointerEventData eventData) { Touch[] myTouches = Input.touches; for (int i = 0; i < Input.touchCount; i++) { //ここに処理内容 if (Input.touchCount > 0) { myTouches[i] = Input.GetTouch(0); //Debug.Log(i); if (myTouches[i].fingerId == 0) { Rect rect = new Rect(x, y, w, h); bool contain = rect.Contains(myTouches[i].position); if (contain) { OnDrag(eventData); } } } } } 想定ではこのrect範囲内で制御できるかと思っていたのですが、実行してみると Script error (Joystick): Update() can not take parameters. と出てしまいます。 引き続き、解決方法などございましたらお願い致します。
bochan2

2019/01/16 09:50

public void Update(PointerEventData eventData) { を public void Update() { にすればそのエラーはなくなりますが 座標をジョイスティック側に与えるようにしないといけないですね 時間があれば書いてみようと思います
jury

2019/01/18 01:36

コードの記載までありがとうございます! お答えいただいて、エラーのある個所は修正してみたのですが、 以下の2か所のエラーがどうしても取り除けません… ・OnDrag(touch.position)でvoidをboolに暗示的には変換できません。 ```C# public void Update(PointerEventData eventData){ bool isInsideBoundary1 = true; Touch[] touches = Input.touches; for (int i = 0; i < Input.touchCount; i++){ Touch touch = touches[i]; if (touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved){ isInsideBoundary1 = OnDrag(touch.position); if (isInsideBoundary1) break; } } if (!isInsideBoundary){ if (_shouldResetPosition1){ //スティックを中心に戻す _stickPosition1 = Vector3.zero; } } } ``` ・return false; public void OnDrag(Vector2)はvoid型を返すため、キーワードreturnのあとにobject式を指定することはできません。 ```C# public void OnDrag(Vector2 touch){ //タップ位置を画面内の座標に変換し、スティックを移動 Vector2 screenPos = Vector2.zero; //Debug.Log(Input.mousePosition); RectTransformUtility.ScreenPointToLocalPointInRectangle(GetComponent<RectTransform>(), new Vector2(Input.mousePosition.x, Input.mousePosition.y), null, out screenPos ); _stickPosition1 = screenPos; //移動場所が設定した半径を超えてる場合は制限内に抑える float currentRadius = Vector3.Distance(Vector3.zero, _stick1.transform.localPosition); if (currentRadius > _radius3){ return false; } if (currentRadius > _radius1){ //角度計算 float radian = Mathf.Atan2(_stick1.transform.localPosition.y, _stick1.transform.localPosition.x); //円上にXとYを設定 Vector3 limitedPosition = Vector3.zero; limitedPosition.x = _radius1 * Mathf.Cos(radian); limitedPosition.y = _radius1 * Mathf.Sin(radian); _stickPosition1 = limitedPosition; } } private T GetComponent<T>() { throw new NotImplementedException(); } ``` 以上です。 どうかお答え頂ければと思いますm(_ _)m
bochan2

2019/01/18 09:06

public void OnDrag を public bool OnDragにしてください
jury

2019/01/22 02:07

確認が遅くなってしまいました… お答えいただきありがとうございます! 実装してみたところ、上手く作動しました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問