【GAS】ウェブアプリーケーションとして使う場合にパラメーターを渡す方法
概要
よくWebのAPIを呼び出すときにパラメーターに応じて取得する内容を変えるのをGASでしたかったので、調べたことを忘備録の意味合いも含めて記事を書きます。
スクリプト準備
GASでHTTP通信が行われた際に、do◯◯系のコールバックが呼ばれます。
- GETの場合はdoGet()、POSTの場合はdoPOST()
このdo◯◯コールバックには引数を入れることができ、この引数のparameterというプロパティの中に渡されたパラメータが格納されてます。
function doGet(e){ //e.parameterに渡されたパラメーターが入る }
例としてuserNameという自身の名前を入れてもらうパラメーターを使用したい場合は、以下のようにすることで使用できます。
function doGet(e){ var userName = e.parameter.userName; //以降適当な処理 }
次に先程追加したパラメーターをURLに追記して渡せるようにします。
URL準備
まずはURLが必要になるので、GASをウェブアプリケーションとして実行できるようにします。
上のメニューから「公開」→「ウェブアプリケーションとして導入」を押すと設定のダイアログが出るので、よしなに設定します。
例
- Project Version : 1.0
- Execute the App as : Me
- Who has access to the app : Only myself
※注意点として既にウェブアプリケーションとして公開している場合は、プロジェクトのバージョン情報を新しくしないと反映されないので、コンボボックスからNewを選択してバージョンを新しくします。
設定が終わったらOK、もしくは更新を押すとURLが発行されるので、このURLにパラメーターを追加して渡すようにします。
先程のuserNameを渡したい場合は、以下のようになります。
発行されたURL?userName=入れたい名前
後はこのURLをブラウザなりcurlなりで開いて、入れた名前がうまく実行できていれば成功です。
今回は単体でしたが、複数のパラメーターを入れたい場合は&で繋げるようにします。
発行されたURL?パラメーター名1=パラメーター1&パラメーター名2=パラメーター2
参考
【UE4】DataTableに対してFill Data Table From JSON Stringをすると謎のメッセージが出る
現象
HTTP通信を用いてスプレッドシートをjsonに変換して、そのjsonを「Fill Data Table From JSON String」を使ってDataTableアセットに保存しようとしました。 すると以下のメッセージが出て保存されずに処理が終了しました。
データのフォーマットが違うのかエクスポートして確認してみましたが、フォーマットも同じだったので途方に暮れていましたが、メッセージの内容でぐぐったら暫定的にですが解決方法がわかったので、とりあえず解決したい人の参考になれば…と思い記事を書きました。
状況
環境は4.24.1です。
データの構造は以下のとおりです。
構造体
[ { "Name": "hoge", "Description": "ほげ" }, { "Name": "hogehoge", "Description": "ほげほげ" }, ]
- 確認方法
確認しやすいようにボタンを押したら「Fill Data Table From JSON String」をするように「Editor Utilities Widget」でBPを作ります。
が、上記のメッセージが出てデータはうまく保存されずに終了します。
解決方法
出力したいDataTableアセットを右クリックして、以下の様にします。
これで再び上記BPで実行するとちゃんと保存されるようになりました。
注意点
上記の方法で解決したと思ったのですが、エディタを立ち上げ直すと再び上記のメッセージが出るようになるので、再度インポートしないといけません…。
これやれば解決するよなどがあればご教授いただけると幸いです。
参考
GroupByの第2引数を使って、Selectで射影したインデックス付き配列を射影前の型だけ参照できるようにする
概要
以下の様に配列のインデックスによってGroupByでグループ分けしたいときがありました。 よくありそうな手法としてSelectでインデックス付き配列に変換してからグループ化するとします。
numbers = new int[]{0,1,2,3,4,5}; //数は適当です gridNumbers = numbers .Select((number,index) => new {Number = number, Index = index}) .GroupBy(numbers => numbers.Index / 2); //仮として2で割った値の数でグループを作ります foreach(var gridNumber in gridNumbers) { Consol.WriteLine(gridNumber); }
0 0 0 1 1 1
GroupByで分けてみたものの、グループ分けのためだけに作ったIndexをこれ以降使わないとしたら、インデックスだけなくして元に戻したくなりますよね。 そんなときに、GroupByの第2引数を使えばもとに戻せることを知ったので、上記のコードを改善してみようと思います。
改善
先程のGroupByのところを以下のように直してみます。
.GroupBy(numbers => numbers.Index / 2, numbers => numbers.number); //仮として2で割った値の数でグループを作って、第2引数で入れたnumberだけを抽出する
こうすることでインデックスは今後インテリジェンスで参照できなくなったので、スッキリしました。 小ネタ程度の記事ですが、ぐぐっても出てこなかったのでまとめてみました。
Hierarchyのコンテキストメニューから自作のゲームオブジェクトを生成する方法
やりたいこと
こんな感じに自作のゲームオブジェクトをHierarchyのコンテキストメニューから生成できるように作りたかったのでそれについてまとめます。
環境はUnity2018.4.4f1です
実装
必要な処理はMenuItemです。
[MenuItem("GameObject/TestGameObject", false, 0)]
・第1引数はHierarchyのコンテキストメニューに表示したいので「GameObject/」にし、表示したい名前をその後ろに入れます。
・第2引数は押せないようにチェックを入れるかのフラグですが、常に選択できるようにしたいのでtrueにします。
・第3引数は表示したい場所を指定します。0が一番上になり、Create Emptyが一番前に来るのでそれに下になります。
今回はわかりやすく一番上にします。
今回は生成するのが目的のため、他の処理はUndoだけできるようにしておけば元に戻せるのでそうします。
public class TestGameObjectMenuItem { [MenuItem("GameObject/TestGameObject", false, 0)] public static void CreateGameObject() { var go = new GameObject("TestGameObject"); //作成したゲームオブジェクトを選択状態にする Selection.activeObject = go; //Undoに登録 Undo.RegisterCreatedObjectUndo(go,"TestGameObject"); } }
これでベースが出来上がったので、後は特定のコンポーネントをAddComponentしたり、選択しているオブジェクトと組み合わせて親子構造を作ったり自由にカスタマイズしてみてください。
参考
選択したアセットを参照しているアセットを検索するエディタ拡張
概要
Unityの標準の機能にアセットを選択した状態で右クリックのメニューで「Select Dependencies」を選択すると、選択しているアセットが参照しているアセットの情報がインスペクターに表示されます。
今回はこれの逆のことがしたく、選択したアセットがどのアセットで参照されているのかが知れるように拡張してみました。
実装
環境はUnity2018.4.6f1
Script Runtime Versionは.NET 4.x Equivalentです。(文字連結を+でしたくないという我儘のため.NET3.5でも行けると思います`)
using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; public class ReverseSelectAssetsLookupFinder { [MenuItem("Assets/ReverseSelectAssetsLookupFinder")] private static void ReverseSelectAssetLookup() { //検索対象は全てのアセットにする var allAssetsPath = AssetDatabase.GetAllAssetPaths(); //今回は複数選択していた場合も検索できるようにループさせる var selectAssets = Selection.objects; foreach (var selectAsset in selectAssets) { var reverseSelectAssetsLookupList = new List<string>(); var targetAssetPath = AssetDatabase.GetAssetPath(selectAsset); for (var i = 0; i < allAssetsPath.Length; ++i) { //何も出ないのも寂しいのでプログレスバーで進捗を出す EditorUtility.DisplayProgressBar("reverse lookup", $"{selectAsset} is Search...{i}/{allAssetsPath.Length}", (float) i / allAssetsPath.Length); //アセットの参照対象に選択したアセットが含まれていたら逆引き対象としてみなす var assetPath = allAssetsPath[i]; var dependenciesAssets = AssetDatabase.GetDependencies(assetPath, false); if (dependenciesAssets.Contains(targetAssetPath)) { reverseSelectAssetsLookupList.Add(assetPath); } } EditorUtility.ClearProgressBar(); //とりあえず結果が知りたいのでDebug.Logに出す if (reverseSelectAssetsLookupList.Count == 0) { Debug.Log($"reverse {selectAsset} lookup result : no Dependencies"); } else { Debug.Log($"reverse {selectAsset} lookup result : {string.Join(",\n", reverseSelectAssetsLookupList)}"); } } } [MenuItem("Assets/ReverseSelectAssetsLookupFinder", true)] private static bool IsValidate() { //一つ以上アセットが選択されていたら選択可能にする return Selection.objects != null && Selection.objects.Length > 0; } }
あとがき
今回はやりたいこと優先のため簡易的なコードになりましたが、
機能性を考えると同じようにインスペクターで表示したくなりますね…努力目標で追加してみたい…。
MenuItemからインスペクターの表示ってスクリプト上でできるのかな…お詳しい方がいればお力をお借りしたい…。
参考
RectTransformを使ってButtonの当たり判定を複数持ちたかった話
概要
uGuiのButtonを特定の範囲だけ選択したら押せるようにしたかったため調べたことをまとめて記事にしようと思いました。
調べてみた所、大きさを変えたり範囲外にしたりするにはICanvasRaycastFilterを用いるのが良さそうなのがわかりました。
今回のやりたいことを実現するために考えられる方法として
1.Rectを使う
→GameObjectが一つで済むので処理負荷があまりなさそう
→複数解像度対応などCanvasScalerでやっている処理を自前で書かないといけない
→シーン上に表示されないのでエディタ拡張を用いてHandleなどシーン上で調整しやすいような環境を整えると作業が楽になる
Handleを用いたRectクラスをシーン上で視覚的に確認しやすくなっている記事を参考にしました。
light11.hatenadiary.com
2.RectTransformを使う
→GameObjectを必要な数分用意しないといけないので、処理負荷が1に比べて高そう
→複数解像度対応をCanvasScalerでやってくれるので気にしなくていい
→RectTransformで範囲を設定できるのでエディタ拡張をしなくて済む
今回は簡単に実装がしたかったため、2の方法で実装してみようと思います
実装
やることは、UIのワールド座標=スクリーン座標に変換して、変換した位置にタッチ座標が重なっていれば選択できるようにすることです。
using System.Collections.Generic; using System.Linq; using UnityEngine; public class RaycastRectangleFilter : MonoBehaviour, ICanvasRaycastFilter { //子オブジェクトからも設定したいと考えた場合のためにSerializedFieldで設定する [SerializeField] private List<RectTransform> _rectTransforms = new List<RectTransform>(); public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) { //各RectTransformのタッチ判定が一つでも成功したら許可する return _rectTransforms.Any(rectTransform => { //スクリーン座標が欲しいのでUI座標からワールド座標に変換する var worldCorners = new Vector3[4]; rectTransform.GetWorldCorners(worldCorners); var result = new Rect( worldCorners[0].x, worldCorners[0].y, worldCorners[2].x - worldCorners[0].x, worldCorners[2].y - worldCorners[0].y); //変換したスクリーン座標にタッチ座標が重なっていれば押せることを許可 return result.Contains(sp); }); } }
参考
アセットに設定されてあるアセットバンドル名をコンテキストメニューで取得できるようにしてみた
概要
プログラムでアセットバンドルからロードする際に、アセットに設定したAssetBundle名を取得したい時がありました。
Inspectorで設定できるのでそこから名前もコピーできるのかなと思っていましたが、 コピーみたいな項目がありませんでした。
なのでコンテキストメニューを利用して選択しているアセットのアセットバンドル名をコピーできるようにしました。
エディタ拡張のリハビリがてら登録されているAssetBundle名をコンテキストメニューで取得するスクリプトを書いた pic.twitter.com/b0FpgyQrXZ
— ダリア (@daria_nicht) July 25, 2019
環境はUnity2018.4.4.f1です。
実装
コードを見たほうが早いと思うのでコード載せます。
using System.Linq; using UnityEditor; using UnityEngine; public class SelectObjectAssetBundleNamesCopyToClipBoard { [MenuItem("Assets/SelectObjectAssetBundleNamesCopyToClipBoard")] private static void CopyToClipBoard() { //バンドル名はAssetImporterで取得できるので、選択しているアセットのパスを渡す var selectAssetsPath = Selection.objects.Select(AssetDatabase.GetAssetPath); var assetImporters = selectAssetsPath.Select(AssetImporter.GetAtPath); //スクリプトで使えるように引用符(')で囲んでおく //.NET 4.xだったらこの書き方で行けますが、それより下のバージョンなら+などで連結してください var assetBundleNames = assetImporters.Select(importer => $"\"{importer.assetBundleName}\""); //クリップボードにコピー GUIUtility.systemCopyBuffer = string.Join(",\n", assetBundleNames); } [MenuItem("Assets/SelectObjectAssetBundleNamesCopyToClipBoard", true)] private static bool IsValidate() { //選択しているオブジェクトがあればコピーできるようにする return Selection.objects != null && Selection.objects.Length > 0; } }
最後に
今は選択しているアセットのみですが、フォルダだった場合はフォルダ以下のアセットバンドル名も取得できれば便利になりそうですね。 機会があったら改良したいと思います。