2Dテーブルゲーム作成時のEventTriggerを使用したクリック選択操作の実装(Unity2019.4.13f1)


(副題)【親が子に干渉する問題】「Event Trigger」の「Select」を使用した時の思わぬ弊害

作成したい機能イメージ

将棋のマスを進めるGUI

  1. 「駒(Imageオブジェクト)」をクリックしたら「移動可能マス(Imageオブジェクト)」が出てくる。
  2. さらに、「移動可能マス(Imageオブジェクト)」をクリックするとその方向に「駒」が移動できる

「Event Trigger」の「Select」と「Deselect」を使用した失敗例

結論:子オブジェクトをクリックすると

「親オブジェクトがクリックされた判定」になる!

そもそも「Event Trigger」とは?

こちらが分かりやすいです。参考にしてください。

3分でわかる!UnityのEvent Trigger(イベントトリガー)の使い方 | FREE SWORDER

では、Event Triggerの「Select」と「Deselect」とは?

Select:オブジェクトが選択されたとき(※Imageなどで使用する場合はSelectableコンポーネント等の追加が必要)

Deselect:選択中のオブジェクトで、選択状態が解除されたとき

よくわからないので、実装例を見ましょう。

このように、「Select」でオブジェクトを「選択」という状態にすることができ、「Deselect」でほかのオブジェクトが「選択」されたときに解除ができるようになっています。

スクリプトはこんだけ済むので実装が楽!(と思ってた。。。本実装では、失敗例として使ってます。)

【駒にアタッチしたスクリプト(失敗)】

using UnityEngine;
using UnityEngine.EventSystems;

public class koma_pointer_manager : MonoBehaviour, ISelectHandler, IDeselectHandler
{
  //ほかのオブジェクトが選択されたら、子オブジェクトを消す
    public void OnDeselect(BaseEventData eventData)
    {
        Debug.Log("You finished " + this.name);
        this.gameObject.transform.Find("can_move_area").gameObject.SetActive(false);
    }

    //このスクリプトをアタッチしてるオブジェクトが選択されたら、その子オブジェクトを表示する
    public void OnSelect(BaseEventData eventData)
    {
        Debug.Log("You clicked " + this.name);
        this.gameObject.transform.Find("can_move_area").gameObject.SetActive(true);
    }
}

余談ですが、本スクリプトは「ISelectHandler, IDeselectHandler」を実装しているので、UnityEngin.UIのオブジェクト(Imageなど)なら「Inspector」上で「Event Trigger」の設定をせずに「Select」、「Deselect」機能がつかえます。

【移動可能エリアにアタッチしたスクリプト(失敗)】

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using Koma;

public class area_pointer_manager : MonoBehaviour
{
        //クリックしたら親オブジェクトの駒を移動する
    public void OnPointerClick()
    {
        position_manager pm = new position_manager();
        pm.set_koma_select_position(this.gameObject.transform.parent.gameObject.transform.parent.gameObject , 4, 8);
        Debug.LogError("You Click Area");//※わかりやすいようにLogErrorにしてある
    }   
}

なぜ「Select」ではなにがダメなのか?

「駒」オブジェクトを「Select」を使って選択すると、表示した子オブジェクトをクリックしても親オブジェクトが反応してしまう。

  1. 親オブジェクト「駒」をクリック→子オブジェクトが表示される(親オブジェクトの「OnSelect」が呼ばれる。)
  2. 子オブジェクトをクリック→親オブジェクトが選択されているので、親オブジェクトが反応(一度、「OnDeselect」が呼ばれてから「OnSelect」が呼ばれる。

結論:駒が進まない。。。。

成功した方法【Event Triggerの「Click」で解決】

【駒にアタッチしたスクリプト(成功)】

using UnityEngine;
using UnityEngine.EventSystems;

public class koma_pointer_manager : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("You clicked " + this.name);
        this.gameObject.transform.Find("can_move_area").gameObject.SetActive(true);
    }
}

【移動可能エリアにアタッチしたスクリプト(成功)】

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using Koma;

public class area_pointer_manager : MonoBehaviour
{
    //クリックしたら親オブジェクトの駒を移動する
    public void OnPointerClick()
    {
        position_manager pm = new position_manager();
        pm.set_koma_select_position(this.gameObject.transform.parent.gameObject.transform.parent.gameObject , 4, 8);
        this.gameObject.transform.parent.gameObject.SetActive(false);
        Debug.LogError("You Click Area");
    }   
}
  1. 親オブジェクト「駒」をクリック→子オブジェクトが表示される(親オブジェクトの「OnPointerClick」が呼ばれる。)
  2. 子オブジェクトをクリック→親オブジェクト「駒」が移動する。(子オブジェクトの「OnPointerClick」が呼ばれる) 

※わかりやす用に子オブジェクトのDebugをLogErrorにしています。

最後に

Event Triggerの「Select」の使用例を解説している人があまりいないので、

面白い使い方があったら教えてほしいです。

他の「駒」をクリックしたときに「元の駒」の「移動範囲」を消すスクリプトは、
【駒にアタッチしたスクリプト(成功)】に「Active_false_selected_by_Tag」の指定タグをすべて非表示にするプログラムを追加したらできます。

using UnityEngine;
using UnityEngine.EventSystems;

public class koma_pointer_manager : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Active_false_selected_by_Tag("koma_area");
        Debug.Log("You clicked " + this.name);
        this.gameObject.transform.Find("can_move_area").gameObject.SetActive(true);
    }

    public void Active_false_selected_by_Tag(string tag)
    {
        // Hierarchy状のタグのついたオブジェクトをすべて格納
        GameObject[] tags = GameObject.FindGameObjectsWithTag(tag);

        // すべてのタグを非表示にする
        foreach (GameObject t in tags)
        {
            t.SetActive(false);
        }
    }
}

マウスが子オブジェクトのエリアに重なったときに色を変えるスクリプトは

【移動可能エリアにアタッチしたスクリプト(成功)】に「OnPointerExit」と「OnPointerEnter」を足したものです。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using Koma;

public class area_pointer_manager : MonoBehaviour
{

    //マウスが重なったら色を濃くする
    public void OnPointerExit()
    {
        // Imageの取得
        Image image = this.GetComponent<Image>();
        // 0=透明 1=不透明なので、1.0で完全に不透明になる
        image.color = new Color(1.0f, 0.1401087f, 0.0f, 0.3f);
    }

    //マウスが外れたら色を戻す
    public void OnPointerEnter()
    {
        // Imageの取得
        Image image = this.GetComponent<Image>();
        // 0=透明 1=不透明なので、1.0で完全に不透明になる
        image.color = new Color(1.0f, 0.1401087f, 0.0f, 0.8f);
    }

    //クリックしたら親オブジェクトの駒を移動する
    public void OnPointerClick()
    {
        position_manager pm = new position_manager();
        pm.set_koma_select_position(this.gameObject.transform.parent.gameObject.transform.parent.gameObject , 4, 8);
        this.gameObject.transform.parent.gameObject.SetActive(false);
        Debug.LogError("You Click Area");
    }   
}

最終動作