- 投稿日:2020-08-05T20:45:49+09:00
UnityのC#からGitを叩く
UnityのC#からGitを叩く
UnityのC#のEditor拡張スクリプトからGitコマンドを叩く機会があったので、忘れないうちにまとめます。
サンプルコマンド
今回、例として、UnityのC#から以下のコマンドを叩いてみます。
git config core.autocrlf改行コードを自動で変換する機能が有効になっているか確認できるコマンドです。
サンプルコード
以下がサンプルコードです。外部から
GetAutocrlf
を叩けばコマンドが実行されます。using System; using System.Diagnostics; using System.IO; using UnityEditor; using UnityEngine; using Debug = UnityEngine.Debug; public class GitCommandPractice { /// <summary> /// Gitのautocrlfを確認する。 /// </summary> public void GetAutocrlf() { // gitのパスを取得する。 string gitPath = GetGitPath(); // gitのコマンドを設定する。 string gitCommand = "config core.autocrlf"; // コマンドを実行して標準出力を取得する。 string autocrlf = GetStandardOutputFromProcess(gitPath, gitCommand).Trim(); Debug.Log(autocrlf); } /// <summary> /// Gitの実行ファイルのパスを取得する。 /// </summary> /// <returns>Gitのパス</returns> private string GetGitPath() { // Macのとき if (Application.platform == RuntimePlatform.OSXEditor) { // パスの候補 string[] exePaths = { "/usr/local/bin/git", "/usr/bin/git" }; // 存在するパスで最初に見つかったもの return exePaths.FirstOrDefault(exePath => File.Exists(exePath)); } // Windowsはこれだけで十分 return "git"; } /// <summary> /// コマンドを実行して標準出力を取得する。 /// </summary> /// <param name="exePath">実行ファイルのパス</param> /// <param name="arguments">コマンドライン引数</param> /// <returns>標準出力</returns> private string GetStandardOutputFromProcess(string exePath, string arguments) { // プロセスの起動条件を設定する。 ProcessStartInfo startInfo = new ProcessStartInfo() { FileName = exePath, Arguments = arguments, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardOutput = true, }; // プロセスを起動する。 using (Process process = Process.Start(startInfo)) { // 標準出力を取得する。 string output = process.StandardOutput.ReadToEnd(); // プロセスが終了するかタイムアウトするまで待つ。 process.WaitForExit(TimeoutPeriod); return output; } } }解説
C# の
Prosess
を使って、Gitコマンドを叩き、その標準出力を読み取るという仕組みです。
GetGitPath()
では、Gitの実行ファイルのパスを取得しています。Gitの実行ファイルのパスは、環境変数Pathに登録されていることが一般的だと思うので、単に
git
と記述してもほとんどの場合、問題ないと思います。ただし、私のMac環境ではそれではうまく行かなかったので、
/usr/local/bin/git
とusr/bin/git
の2種類を明示的にハードコーディングし、どちらか見つかった方を実行ファイルとして利用するようにしました。さいごに
本記事作成にあたり、以下を参考にしました。ありがとうございました。
- 投稿日:2020-08-05T16:30:25+09:00
uGUIにおけるポインターイベントの伝播 (Unity)
前提
環境
- Unity 2019.4.6 (LTS)
目的
- uGUIにおける主なポインターイベントのバブリングを研究します。
公式ドキュメント
イベントの伝播を確認する
準備
- ▼♻Scene
- ▼?Canvas
- ▼?Obj (0)
- ▼?Obj (1)
- ?Obj (2)
- ?EventSystem
※
Obj (0~2)
には、イベントを受け取るImage
と、受け取ったイベントとhovered
を報告するCheckPointerEvent
をアタッチ
CheckPointerEvent
の内容CheckPointerEvent.csusing System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.EventSystems; public class CheckPointerEvent : MonoBehaviour , IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler // ドラッグ , IPointerEnterHandler, IPointerExitHandler // 領域出入 , IPointerUpHandler, IPointerDownHandler, IPointerClickHandler // クリック { public void OnBeginDrag (PointerEventData eventData) { Debug.Log ($"{name}.OnBeginDrag [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } public void OnEndDrag (PointerEventData eventData) { Debug.Log ($"{name}.OnEndDrag [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } public void OnDrop (PointerEventData eventData) { Debug.Log ($"{name}.OnDrop [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } private List<GameObject> lastDragHoverd; // 最後のドラッグ・ログ public void OnDrag (PointerEventData eventData) { if (lastDragHoverd == null || !lastDragHoverd.SequenceEqual (eventData.hovered)) { // 異なるときだけ Debug.Log ($"{name}.OnDrag [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); lastDragHoverd = new List<GameObject> (eventData.hovered); } } public void OnPointerEnter (PointerEventData eventData) { Debug.Log ($"{name}.OnPointerEnter [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } public void OnPointerExit (PointerEventData eventData) { Debug.Log ($"{name}.OnPointerExit [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } public void OnPointerUp (PointerEventData eventData) { Debug.Log ($"{name}.OnPointerUp [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } public void OnPointerDown (PointerEventData eventData) { Debug.Log ($"{name}.OnPointerDown [{string.Join(", ", eventData.hovered.ConvertAll (o => o.name))}]"); } public void OnPointerClick (PointerEventData eventData) { Debug.Log ($"{name}.OnPointerClick [{string.Join (", ", eventData.hovered.ConvertAll (o => o.name))}]"); } }試行と結果
親「エンター、ダウン、ドラッグ、アップ、イグジット」Obj (0).OnPointerEnter [] Obj (0).OnPointerDown [Obj (0), Canvas] Obj (0).OnBeginDrag [Obj (0), Canvas] Obj (0).OnPointerUp [Obj (0), Canvas] Obj (0).OnPointerClick [Obj (0), Canvas] Obj (0).OnEndDrag [Obj (0), Canvas] Obj (0).OnPointerExit [Obj (0), Canvas]親「エンター、ダウン、ドラッグ、イグジット、ドラッグ、アップ」Obj (0).OnPointerEnter [] Obj (0).OnPointerDown [Obj (0), Canvas] Obj (0).OnBeginDrag [Obj (0), Canvas] Obj (0).OnDrag [Obj (0), Canvas] Obj (0).OnPointerExit [Obj (0), Canvas] Obj (0).OnDrag [] Obj (0).OnPointerUp []子「エンター、ダウン、ドラッグ、アップ、イグジット」Obj (1).OnPointerEnter [] Obj (0).OnPointerEnter [Obj (1)] Obj (1).OnPointerDown [Obj (1), Obj (0), Canvas] Obj (1).OnBeginDrag [Obj (1), Obj (0), Canvas] Obj (1).OnDrag [Obj (1), Obj (0), Canvas] Obj (1).OnPointerUp [Obj (1), Obj (0), Canvas] Obj (1).OnPointerClick [Obj (1), Obj (0), Canvas] Obj (1).OnEndDrag [Obj (1), Obj (0), Canvas] Obj (1).OnPointerExit [Obj (1), Obj (0), Canvas] Obj (0).OnPointerExit [Obj (1), Obj (0), Canvas]子「エンター、ダウン、ドラッグ、イグジット、ドラッグ、アップ」Obj (1).OnPointerEnter [] Obj (0).OnPointerEnter [Obj (1)] Obj (1).OnPointerDown [Obj (1), Obj (0), Canvas] Obj (1).OnBeginDrag [Obj (1), Obj (0), Canvas] Obj (1).OnDrag [Obj (1), Obj (0), Canvas] Obj (1).OnPointerExit [Obj (1), Obj (0), Canvas] Obj (0).OnPointerExit [Obj (1), Obj (0), Canvas] Obj (1).OnDrag [] Obj (1).OnPointerUp [] Obj (1).OnEndDrag []孫「エンター、ダウン、ドラッグ、アップ、イグジット」Obj (2).OnPointerEnter [] Obj (1).OnPointerEnter [Obj (2)] Obj (0).OnPointerEnter [Obj (2), Obj (1)] Obj (2).OnPointerDown [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnBeginDrag [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnDrag [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnPointerUp [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnPointerClick [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnEndDrag [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnPointerExit [Obj (2), Obj (1), Obj (0), Canvas] Obj (1).OnPointerExit [Obj (2), Obj (1), Obj (0), Canvas] Obj (0).OnPointerExit [Obj (2), Obj (1), Obj (0), Canvas]孫「エンター、ダウン、ドラッグ、イグジット、ドラッグ、アップ」Obj (2).OnPointerEnter [] Obj (1).OnPointerEnter [Obj (2)] Obj (0).OnPointerEnter [Obj (2), Obj (1)] Obj (2).OnPointerDown [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnBeginDrag [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnPointerExit [Obj (2), Obj (1), Obj (0), Canvas] Obj (1).OnPointerExit [Obj (2), Obj (1), Obj (0), Canvas] Obj (0).OnPointerExit [Obj (2), Obj (1), Obj (0), Canvas] Obj (2).OnDrag [] Obj (2).OnPointerUp [] Obj (2).OnEndDrag []
- 他に、ドラッグして他のオブジェクトにドロップすると、落とされたオブジェクトにのみ
OnDrop
が届く様子を確認できました。考察
結果の解釈
OnPointerEnter
とOnPointerExit
はターゲット以降もバブルアップ(親へ伝播)されます。
- その他(クリック、ドラッグ)はターゲットで留められてバブルアップされません。
- このイベントによる違いは、ボタンを親子に配置することでも確認できます。
- 子ボタンをポインターで指すと、親ボタンも
Highlighted
状態になりますが、クリックしても親ボタンには伝わりません。hovered
は、「マウスが上にのっているオブジェクトのスタックリスト」と説明されていますが、イベント発生直前の親を辿るようです。
- 特に、
OnPointerEnter
では侵入直前の状態を示すため、ポインターが孫に侵入した場合、孫では侵入前なので何もなし、バブルアップされた子では孫に侵入済み、さらにバブルアップされた親では孫と子に侵入済みとなるようです。- 他のイベントの多くは、直前が既にオブジェクトに乗った状態なので、総親の
Canvas
まで辿られています。- 対して、オブジェクトから外れてからドラッグを終えると、何にも乗っていないことになります。
疑問
- イベントによって、ターゲットがイベントを受け取った後のバブルアップの有無が異なるようですが、どのようなルールなのでしょうか?
- 固定的なものなのか、設定あるいは制御可能なものなのでしょうか?
- いろいろ調べて見ましたが、関係するような記述は発見できませんでした。
- 制御できても良さそうなものですが、「そういうもの」として設計されているということでしょうか。
- 投稿日:2020-08-05T16:01:07+09:00
Distance Joint 2Dの解説
今回はphysics2Dの中にあるDistance Joint 2Dについて解説していこうと思います。
Distance Joint 2Dとは
Distance Joint 2Dは、2つのオブジェクト間の距離を保たせるための機能です。
近づきもせず、離れもせず。そんな感じの機能です。
jointというのは「関節」や「付け根」などの意味を持っているそうです。Distance Joint 2Dの各パラメータ
所々パラメータの名前が見切れていてすみません。
パラメータが多いですが頑張って1つずつ見ていきましょう。・Enable Collision
このパラメータは、アタッチしたオブジェクトと当たり判定をするかどうかというのを決める為のものです。
これのチェックボックスにチェックをすると衝突する
ようになります。
チェックを外すと、衝突判定をせずにアタッチしたオブジェクトをすり抜けられるようになります。・Connected Rigid Body
ここにオブジェクトをアタッチすると、そのオブジェクトとつながった状態になります。
ここにオブジェクトをアタッチしない場合、ワールド空間とつながった状態になります。・Auto Configure Connected Anchor
2つ下の「Connected Anchor」を自動的に決めるためのものです。
あまりこれを使うのはオススメしません。これを使うとオブジェクトが変な挙動をする可能性があるからです。・Anchor
このオブジェクト側の基準点を決めるところです。
ワールド座標ではなく、このオブジェクトのローカル座標になっているので注意してください。
私はX、Yともに0にすることをオススメします。・Connected Anchor
アタッチしたオブジェクト側の基準点を決めるところです。
ここで使われている座標はアタッチしたオブジェクトのローカル座標です。
こちらもX、Yともに0にすることをオススメします。・Auto Configure Distance
ここのチェックボックスにチェックを入れると二つのアンカーの距離が下のDistanceに入力されます。
注意点として、このチェックボックスにチェックを入れたままプロジェクトを実行して、どちらかのオブジェクトの座標を直接いじると、Distanceの値が変わってしまいます。もしかしたら他にもDistanceの値が変わってしまうやり方があるかもしれないので、チェックは1回付けたら外しておきましょう
。・Distance
ここでは、2つのアンカーの距離を決めます。
2つのオブジェクトの距離がここで決められた距離よりも離れていた場合、両方のオブジェクトが決められた距離まで近づいていきます。・Max Distance Only
ここのチェックボックスにチェックを入れると、2つのオブジェクトはDistanceで決められた距離よりも近づくことができるようになります。
ロープで繋がっているようなイメージです。・Break Force
二つのオブジェクトのつながりを断ち切り、
Distance Joint 2Dを削除する
ために必要な力を決めます。
infinityだと絶対に切れることはありません。
また、infinityに戻したいときは「inf」と入力してください。スクリプトの一例
private void OnCollisionEnter2D(Collision2D collision)
{
this.GetComponent().enableCollision = true;
this.GetComponent().connectedBody = collision.rigidbody;
this.GetComponent().anchor = new Vector2(0, 0);
this.GetComponent().connectedAnchor = new Vector2(0, 0);
this.GetComponent().distance = 2;
this.GetComponent().maxDistanceOnly = true;
this.GetComponent().breakForce = Mathf.Infinity;
}これはぶつかってきたオブジェクトを捕まえる的なプログラムです。
あらかじめこのオブジェクトのBody Type(Rigid Body2dのパラメータ)をkinematicにして床とかに触れないようにするか、if文を使って捕まえられるオブジェクトを限定する必要があります。おわりに
今回は前回よりもパラメータが多いうえにややこしいのも結構あって大変でした。
Joint系は恐らく全部こんな感じだと思いますが、あと8個あるのでそれは全部記事にしていこうと思います。
私もまだまだ理解できていないところが多いので、記事も書きながら勉強していく所存です。なので、この記事を読んでくださった皆様のなかで間違いなどを見つけたら、ご指摘いただけるとこちらとしても嬉しいです。
- 投稿日:2020-08-05T00:04:12+09:00
【Unity】UnityWebRequestで画像ファイルを送信してPHPで受け取る最小実装
UnityWebRequestで画像ファイルを送信しPHPで受け取る最小の実装を備忘録として残します。
Unity側
前提条件として画像ファイルはバイト配列として取得している状態を作ります。
以前執筆したコチラの記事でTextureをPNGにエンコードしたバイト配列作成までを紹介しているので、参考になるかもしれません。
【Unity】RawImageのTextureをPNGにエンコードする方法IEnumerator Send(byte[] bytes) { var form = new WWWForm(); // "file"はPHP側で$_FILESから取得するキー ex)$_FILES["file"] form.AddBinaryData("file", bytes, "image.png", "image/png"); var req = UnityWebRequest.Post("http://localhost:8080/api.php", form); yield return req.SendWebRequest(); }PHP側
api.php$fileName = $_FILES["file"]["name"]; // api.phpと同じディレクトリに保存されます move_uploaded_file($_FILES["file"]["tmp_name"], $fileName);最後に
エラーハンドリングを考慮するとUnityもPHPも記述することはまだまだありますが、本記事では肝となる部分の実装のみを紹介しました。
環境
- Unity2019.4.4f1
- PHP 7.2.16