(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]



Sprite Renderer等のクリックやタップよりuGUIの操作を優先する【Unity】【uGUI】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 2019.2.21f1


はじめに

Unityはマウスのクリックやスマホでのタッチを簡単に取得する事できます。

private void Update(){
  if (Input.GetMouseButton(0)) {
    Debug.Log("マウスのクリック発生中");
  }
  if (Input.touchCount > 0) {
    Debug.Log("タッチ発生中");
  }
}
f:id:kan_kikuchi:20200218052324g:plain


ただ、uGUIのボタン等と被っていると両方のイベントが同時に発生してしまいます。

f:id:kan_kikuchi:20200219042731g:plain


今回はそんな時にuGUIの操作を優先する実装方法の紹介です!


なお、記事中の画像は以下のアセットを使っております。

2D Medieval Fantasy Character Pack | 2D Characters | Unity Asset Store



IsPointerOverGameObject

まずuGUIのタッチ等のイベントはEventSystemで管理されています。

f:id:kan_kikuchi:20200219043509j:plain


そしてこのEventSystemにはIsPointerOverGameObjectという、

uGUIのオブジェクトを選択しているかというフラグがあります。



これを使えばuGUIのボタン等を押しているかが分かるので、

そういう場合はマウスのクリックやタッチを無視すれば、uGUIの操作を優先できます。


具体的には以下のような感じ。

/*EventSystemを使うにはusing UnityEngine.EventSystems;が必要*/

private void Update(){
  //UIを触ってる場合はスルー
  if(EventSystem.current.IsPointerOverGameObject()){
    return;
  }
  //スマホなどのタッチの場合の判定
  if (Input.touchCount > 0){
    if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)){
      return;
    }
  }
  
  if (Input.GetMouseButton(0)) {
    Debug.Log("マウスのクリック発生中");
  }
  if (Input.touchCount > 0) {
    Debug.Log("タッチ発生中");
  }
}
f:id:kan_kikuchi:20200219044650g:plain



Event Trigger

もしSprite Rendererのクリック判定を実装したいのでRaycastを使ってる場合でも、

IsPointerOverGameObjectでuGUIを優先する実装は出来ますが、

private void Update(){
  //UIを触ってる場合はスルー
  if(EventSystem.current.IsPointerOverGameObject()){
    return;
  }
  //スマホなどのタッチの場合の判定
  if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began){
    if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)){
      return;
    }
  }

  //クリック or タッチが発生しているか判定、している場合はその座標を取得
  Vector2 clickOrTouchingPosition;
  if (Input.GetMouseButton(0)) {
    clickOrTouchingPosition = Input.mousePosition;
  }
  else if (Input.touchCount > 0) {
    clickOrTouchingPosition = Input.GetTouch(0).position;
  }
  else {
    return;
  }
    
  //メインカメラ上からRayを飛ばす
  Ray ray = Camera.main.ScreenPointToRay(clickOrTouchingPosition);
  RaycastHit2D hit = Physics2D.Raycast((Vector2)ray.origin, (Vector2)ray.direction);
  
  //レイが何かと衝突したかの判定
  if(hit.collider == null) {
    Debug.LogWarning("クリックした所に何もありません");
  }
  else {
    Debug.Log($"{hit.collider.gameObject.name}をクリック中");
  }
}
f:id:kan_kikuchi:20200219051222g:plain


こういう時はカメラにPhysics 2D Raycasterを付けた後、

f:id:kan_kikuchi:20200219051118j:plain


Sprite Rendererと同じオブジェクトにEvent Triggerを付けて、

そこにクリックした時の処理を登録すると、

f:id:kan_kikuchi:20200219051126j:plain


先程のUpdateの処理なしで実装出来るのでオススメです。

/// <summary>
/// キャラクターが押された時の処理
/// </summary>
public void OnClickCharacter(GameObject target) {
  Debug.Log($"{target.name}が押されました");
}

/// <summary>
/// ボタンが押されました
/// </summary>
public void OnClickButton() {
  Debug.Log("ボタンが押されました");
}
f:id:kan_kikuchi:20200219051247g:plain



参考