【Unity】ボタンが押されたことにしたい。スクリプトからボタンを押す方法【それスク】
Unityの「それスクリプトでどうやるの?シリーズ」ボタンを押した時に何かが動くように作るのは出来ても、他のプログラム処理の中で、ボタンを押された時と同じ挙動をして欲しい時ってありますよね。UnityEngine.UI.Button.Invokeを使うと簡単に実現可能です。
ボタンをスクリプトから押されたことにする
前提として、ボタンを押して何かの処理が出来ているとします。その上で、他のスクリプトから押されたときと同様の処理を実行させたい場合にどうすればよいかを説明します。
ピンとくる人用
以下のスクリプトを見て思い出した人は早くプログラムの修正に戻るが良い。ただ、ブログ的には寂しいので、別の記事1つぐらいチラ見して帰ってくれると嬉しい。
using UnityEngine;
using UnityEngine.UI;
public class ForceButtonPush : MonoBehaviour {
public Button push_button;
void Start()
{
push_button.onClick.Invoke();
}
}
UI.ButtonのonClickを呼び出す
ボタンにはonClickイベントが存在しており、これを強制的に呼び出すことで、スクリプトからボタンを押したように振る舞います。
通常のボタンで押されるまでの下準備。
スクリプトでボタンを押したことにする前に、通常のボタンを押されたときの処理を用意します。そのうえで、どのように手を加えることでスクリプトから呼び出すことができるのかを追記する形で説明します。
まずは以下のようなスクリプトを準備します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TestScript : MonoBehaviour
{
public void ButtonPushed()
{
Debug.Log("ボタンが押されました");
}
}
スクリプトが用意できたら、シーン内にボタンと、上記のスクリプトをAddComponentしたオブジェクトを用意します。
下図では、TestScriptと名したゲームオブジェクトに同名のスクリプトがAddComponentされています。ボタンは新規に用意しました。
2つが用意出来たら、ButtonのOnClick()の+ボタンで新しいイベントを追加してヒエラルキーにあるTestScriptを指定します。
うまくアタッチできていれば、No Functionをクリックして、TestScript>ButtonPushedが選択可能になっているはずなので、指定して下さい。
関数がpublicで宣言されていないと表示されませんので、見つからない場合はスクリプトを確かめるか、アタッチしているゲームオブジェクトにTestScriptがAddComponentされているかを確認してみて下さい。
関数が指定できていれば、実行してボタンを押すと、Consoleにログが表示されると思います。これで人まずは通常のボタンからの関数呼び出しが出来ている状態です。押した回数ログが表示されます。
スクリプトからボタンを押す処理
ここからが一応本題です。作業手順としては以下になります。
1.ボタンを押したいスクリプトが、対象のボタンを制御できる変数を用意
2.(今回は)インスペクターでセット
3.呼び出し用の処理を追記
4.実行して確認
このような流れで行きます。最後の呼び出し用の処理に関しては、適宜プログラムに合わせて下さい。
1.ボタンを押したいスクリプトが、対象のボタンを制御できる変数を用意
今回は先程のTestScriptに追記する形で対応します。どこでも良いので、以下の変数を追加して下さい。
[SerializeField]
private Button btn;
シリアライズフィールド+プライベートの組み合わせは、「インスペクターでセットするけど、スクリプトからのセットはしないでね!」という意思表明です。これを見た場合、インスペクターでセットされているのを期待して下さい(もしくはセット関数からのセットのみを監視する)。
2.(今回は)インスペクターでセット
先程のスクリプト修正を行うと、インスペクター側にボタンをあてがうことができるフィールドが追加されていると思います。
このBtn(Button btn;)に先程用意したUIのボタンをセットして下さい。Buttonの型で指定してあるので、ここまでの工程でシーンを作っている場合、入れることができるのは今しがた作ったボタンのみになっているので入れることができるものを入れて下さい。
今回はインスペクターでセットしていますが、変数で渡したり、どこかからか取得できる場合はスクリプト経由でも同じです。Button変数に押したいボタンが入っていれば代用可能です。
3.呼び出し用の処理を追記
実際にボタンを押されたことにする処理を追加します。少し味気ないですが、Start関数で呼び出すとしましょう。
void Start()
{
btn.onClick.Invoke();
}
変数名などは同じでお願いします。(変更している場合はbtnを対象の変数に変更して下さい)
Assets\TestScript.cs: warning CS0649: Field 'TestScript.btn’ is never assigned to, and will always have its default value null
Unityのバージョンによってはこんな警告が出るかもしれません。2019系で確かめているとこの警告が出ますが、SerializeFieldで宣言している意味をUnityが分かってないのかも。内容としては変数がアサインされてないからいつもデフォルト値のnullだぜ?とのこと。スクリプトでのアサインを拒否するプログラムなので、特に気にしなくても問題ありません。
当然ですがSerializeField>Privateの宣言はインスペクタでの設定を強要しているので、セットし忘れにはお気をつけ下さい。
4.実行して確認
この状態でUnityを実行してみて下さい
ボタンを押してないのに、ログが表示されたら成功です。
まとめ
ボタンをスクリプトから押したことにするためには、UI.Button.onClick.Invoke()関数を呼び出すことで実現可能です。
実際に呼び出すには、呼び出したいスクリプトにButton変数を用意して、対象のボタンを認識させることが必要ということが分かりました。
今回はインスペクターでセットしましたが、プログラム経由でボタンを取得しても同じことが出来ます。利用箇所としては、プログラム上でキャンセルボタンなどをタイムアウトなどで押したことにしたい時なんかに便利です。タイムアウトでタイムアウト用の処理を別途書くより、ボタンを押したことにしてあげたほうが、独自の処理が減るため、バグも少なくなりやすいです。
修正する箇所も1つで済むので、こういうプログラムをできるだけ作れるようになると、スマートなプログラムが作れるようになりますよ。