CircleCI + Docker +Unity でクラウドビルドを試してみた(メモ書き)
メモ書きです。
参考にしたサイト様
Unityでテストを書いてCircleCIでコミットのたびにテストをチェックする | 測度ゼロの抹茶チョコ
neue cc - CircleCIでUnityをテスト/ビルドする、或いは.unitypackageを作るまで
・DockerにUnityのコンテナデータを取得します。
gableroux/unity3d/tags
( 最終更新は2年前となっており、最も最新のバージョンはUnity2020になります。)
今回はUnity2019を使用します。
Dockerにて以下のコメントを実行します。
docker run -it gableroux/unity3d:2019.1.14f1 bash
/opt/Unity/Editor/Unity -quit -batchmode -nographics -logFile -createManualActivationFile
cat Unity_v2019.1.14f1.alf
・ライセンスファイルの元となるxmlを、catでコピー&ペーストしてUnityv2019.1.14f1.alfという名前で保存します。
その後以下のURLにアクセスして保存したalfファイルをアップロードすると、Unity_v2019.x.ulf ファイルをもらえます。
Unity - Activation
・取得したライセンスファイルをcircleCIで承認されるように対応します
CricleCIのプロジェクト環境に登録する方法もありますが、筆者が試したところライセンス取得に失敗するため、別の方法を試します。
export UNITY_KEY=任意の英数字
openssl aes-256-cbc -d -base64 -A -in DLしたUnity_v2019.x.ulfを保存してあるファイルパス
こちらを実行してライセンスファイルを変換します。
opensslでBASE64エンコードされた文字列をdecryptしようとしたら769bytes以上になるとエラーになる件 - だいたいよくわからないブログ
・CircleCIにGithubの登録などを行う
CircleCIでUnityのTest&Buildを雰囲気理解で走らせた - Qiita
・config.ymlに記載する
commands:
unity_activation:
parameters:
unity_license: { type: string }
steps:
- checkout
- run: openssl aes-256-cbc -d -base64 -A -in .circleci/Unity_v2019.x.ulf-cipher -k ${UNITY_KEY} >> .circleci/Unity_v2019.x.ulf -md md5
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -manualLicenseFile .circleci/Unity_v2019.x.ulf || exit 0
・CircleCI → Project → Environment Variables で先ほど登録したUNITY_KEYを登録します。
上記を行うことで、CircleCI側でUnityライセンス認証に成功しました。
【UE5】フレームレートの設定をしないと危険
UE5を使っていた際、GPUの使用率がドエライことになり、クラッシュする事態が発生した。
解決策を探していたところ、フレームレートが無制限になっていたため、そちらの対応を行いました。
・UE5のプロジェクトから、「プロジェクト設定」→「基本設定」→「フレームレートのスムージング」にチェックをつけてください。
それでも重くなる場合はFPSを固定にしてみてください。
【GAS】UrlFetchApp.fetchを使ってWebサイトの中身を取得する
UrlFetchApp.fetch関数を使用して、指定したWebサイトのコンテンツデータを取得してみましょう。
GASを起動して、以下の処理を記載いたします。
function GetSelectURLContent(url) { var html = ""; try { html = UrlFetchApp.fetch(url).getContentText(); } catch (ex) { Logger.log("ex message {%s}",ex); return null; } return html; }
try catchを使用して Webサイトの情報が正常に取れなかった場合に備えております。
正常に受け取れれば その値を渡す仕組みです。
var urlContent = GetSelectURLContent(urls); if(urlContent == null) { Logger.log("指定URLのコンテンツ情報の取得に失敗しました。 ::URL:: {%s}",urls); continue; }
受け取った後の判定処理です。
今回は、失敗した場合はエラーメッセージを出すように対応しています。
【Unity】Githubの submodule を設定
・複数のプロジェクトで流用できる機能 ( 基盤など ) を使用する場合、サブモジュール登録を行うと便利です。
・git submodule add を使用した際に、以下のエラーが発生した時の対処法です。
また、submoduleを削除して、再度追加する際にもエラーが発生しやすいです。
複数の削除コードを入力しないといけないのが主な原因。
git submodule add --name
【Unity】 GitHubのPermission denied エラーで苦戦した話
mac OS を Montereyに更新した後、ソースツリーなどでGit のpushやClone時にエラーが発生するようになった。
(解決した方法)
1. sshキーを再生成し、秘密鍵登録を行なった
GitHubにSSH接続する方法(秘密鍵、公開鍵の作成) - Qiita
2. GitHubのバージョンアップでトークン作成が必要になったのでそちらを登録した
【Unity NodeJs】で簡単なAPIサーバーを作成する Get編
プログラミングには様々な言語やありますよね。
エンジニアの世界でも業種は多岐に渡ります。
私は今までフロントエンド(クライアント)エンジニアとしてやって来ましたが、元々サーバーサイドにも興味があり、いい機会なので「Nodejs 」をUnityと掛け合わせて「ハイスコアAPIサーバー」を作成したので、メモ感覚で記載してみました。
使用言語とソフト
・NodeJs
・NodeJs Express
・MySql
・Unity
1. NodeJs側のソースコード
require('date-utils'); var moment = require('moment'); var bodyParser = require('body-parser'); const exp = require("express"); const app = exp(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.listen(3000, function () { console.log("Start GetServer"); }) const mysql = require('mysql'); app.get("/GET", function (req, res, nex) { let con = mysql.createConnection({ host: 'localhost', user: 'root', port: 3306, database: 'playerRank' }); con.query("SELECT * FROM RANKPLAYER", function (e, r) { if (e) { console.error('error connecting: ' + e.stack); return; } console.log(r); response(res, "OK", r); }) })
事前にMySqlで「playerRank」データベースを作成して、RANKPLAYER という名前のテーブルを作成しています。
ネーミングセンス
次にUnity側の処理を記述します。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System; using System.IO; using UnityEngine.Networking; using System.Text; public class GetNodeJsBtn : MonoBehaviour { private const string URL = "http://localhost:3000/Get"; public void OnGetJson() { StartCoroutine("mOnSend", URL); } private IEnumerator mOnSend(string url) { UnityWebRequest webRequest = UnityWebRequest.Get(url); yield return webRequest.SendWebRequest(); //エラーが出ていないかチェック if (webRequest.isNetworkError) { //通信失敗 Debug.Log(webRequest.error); } Debug.Log(webRequest.downloadHandler.text); //受信したテキスト(json)を変換 Json jsonClass = JsonUtility.FromJson<Json>(webRequest.downloadHandler.text); //通信失敗 foreach(var data in jsonClass.data) { Debug.Log($"jsonClass {data.id}"); } }
UnityWebRequestを使用して、先ほど作成したNodeJsのGetAPIにアクセスしています。
そのあとJsonUtilityでJsonクラスに変更しています。
【Unity】AssetStoreがセールだったので、オススメのAssetを紹介してみる
AssetStoreが日替わりセールをやっていたので、自分がよく使っている or 欲しい!Assetを紹介します!。
Editor Console Pro
価格 : $30
多機能なコンソールウィンドウを使用できるアセットです。
デフォルトのConsoleより高機能で、関数名や文字色の変更などめっちゃ豪華なコンソール画面を活用できます。
デバッグ時にバリバリ活用できるのでオススメです。
Odin Inspector and Serializer
価格 : $55
Inspectorを劇的にパワーアップさせるAssetです!
値段は張りますがパフォーマンスは圧倒的で、例えば「Dictionary」をInpspector上で編集することができるようになります。
開発効率は爆速に上がると思うので、是非活用してみてください!。
今回は上記2点ですが、今後も紹介していきたいと思います。
【Unity】ECSをUnityで使うための事前準備 (Unity-2019.2.11f)
巷で話題のECSを軽く勉強したので数回に渡って記事にして行きます。
<注意>今回の記事は 2019.2.11f バージョン時点での内容になります。
というのも、ECSやJobSystemなどはまだまだ開発途中の状態だからです。
そのため、この記事内で記載している内容が今後のアップデート次第で使用不可能になるかも知れません。。。
参考にしたサイト様
今回、ECSを勉強するに当たって、先人様方の偉大な記事を参考にいたしました。
どれも素晴らしい内容であり、本当にありがとうございま
ECSをさわってみた感想
まず初めてにECSを軽くさわってみた感想ですが、
・JobComponentSystem や Entity の動作に慣れる必要がある
・CollisionやTranslate ( オブジェクトの移動 ) は自作する必要があり、まだまだ導入コストは高い
ざっくりまとめると「作品の幅は広がり、今後のスタンダートな技術になるがまだまだ実装コストは高い」となります。
今後のアップデートで Unity ECS用のRigidbodyなどが実装されればより使いやすい機能になると思います。
Unity ECSを使う前の準備
Unityの 「Window → Package Manager → Show preview packages 」をチェックしましょう。
そうすると左側に Entities が表示されるのでimportしましょう。
同様に 「hybrid renderer」も導入しておきましょう。
導入が終わったらUnityを再起動してください。
これでECSを使う準備が整いました。
次はECSで実際にゲームを作ってみようと思います。
【Unity】UnityHubは使いやすい
お久しぶりです。2週間ぶりにブログを更新します。
先週は風邪でダウンしてしまい、1週間ほど体調不良が続きました。
今回はちょうど1年ほど前にリリースされたUnityのバージョン管理ツール UnityHub について解説します。
UnityHubとは
UnityHubの最大の利点は「バージョンが異なるUnityを一括管理できる」これにつきます!
また モジュールの途中インストールが可能になったことも大きいです!
今まではインストール時に取りこぼしがあると再インストールしなければならなかったため、その手間がなくなりました。
バージョン管理に最適
UnityHubを使用すると「プロジェクトのUnityバージョンを切り替える」際に非常に役立ちます。
最近ですと某ソーシャルゲームのUnityバージョンが Unity5.xx から Unity.2017 に変更されました。
Unityはバージョン更新ごとに仕様変更が発生するため、 Unity5で使っていた処理がUnity2017以降では使えなくなったー! なんてことはいくらでも起こります。
UnityHubを導入先
https://unity3d.com/jp/get-unity/download
上記URLから UnityHubをダウンロードしてください。
UnityHubで複数のバージョンをインストールした画面です。
1つ問題があって、UnityHubで選択できるバージョンはそのバージョンごと「2018xx」の最新正式バージョンが選択されます。
最新バージョン以外が欲しい場合は別途直接導入してからUnityHubに導入してください。
UnityHubを使って楽々なバージョン管理ライフを送っていきたいですね。
【Unity】GAS + スプレットシートで C#スクリプトを自動生成しよう! 【マスターデータに使える!】
Unity基盤を作っているのですが、そろそろマスターデータ関連に着手したいと思いました。
初めはスプレットシートにマスターデータを作って、それをcsvファイルにして読み込もオーソドックスな仕組みを作ってましたが、
ふと、csvファイルと一緒にcsスクリプトも自動生成しちゃえば楽じゃない? ということに気づきました。
今回はGASを使ってGoogleドライブにcsファイルを自動生成する方法を解説します。
スプレッドシートにマスターデータの値を記述する
次に作ったスプレッドシートの表をうめて行きます。
今回はマスターデータのスクリプトを自動生成するように作るため
・行にスクリプトで使う変数の名前
・2行にその変数の型名を記載します。
・3行 以降はその項目にあった値を記述します
今回は画像のような内容になります
ここまででスプレッドシートの順位が整いました。
次はスクリプトエディタの作成をしましょう
スクリプトエディタでファイルの自動生成を行おう
「ツール」→「スクリプトエディタ」からスクリプト作成に移ります。
スプレッドシートの値を取得する
function myFunction() {
// スプレッドシートから値を取得する
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
}
まずは現在開いているスプレッドシートを取得しましょう。
SpreadsheetApp.getActiveSpreadsheet() でシート情報を取得できます。
シートから値をとる範囲を設定する
function myFunction() { // スプレッドシートから値を取得する var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); //現在のシートを取得 var sheet = spreadsheet.getActiveSheet(); // シートの最後の行数を取得 var lastColume = sheet.getLastColumn(); //3. 指定するセルの範囲(A1)を取得 var range = sheet.getRange(1,1,2,lastColume); //4. 値を取得する var value = range.getValues(); }
spreadsheet.getActiveSheet() で 現在開いているシートを取得します。
sheet.getLastColumn(); で 何かが記載されているシートの最大数が取得できます。
sheet.getRange() で取得する範囲を設定できます。
今回は 1行目の 変数名と 2行目の 変数の型 を取得したいので sheet.getRange(1,1,2,lastColume); という形になります。
csスクリプトのクラス名とusing を記述する
// 選択中のシート名を取得する var sheetName = sheet.getSheetName(); // 先頭文字を大文字にする var scriptName = sheetName.charAt(0).toUpperCase() + sheetName.slice(1); // 使用する using を設定する var scrpitUsings = "using UnityEngine;\n" + "using System;\n"; // csスクリプトのclass生成用の文字列を設定する var scriptClassName = scrpitUsings + "\n" + "public class " + scriptName + " {";
sheet.getSheetName(); で現在のシート名を取得します。
マスターデータごとの名前をシートの名前にして、csスクリプトに連動する形式にしています。
そちらの方が分かりやすくで管理がとても楽になりますね。
sheetName.charAt(0).toUpperCase() + sheetName.slice(1); では、 先頭文字を大文字にしています。
.slice() は 文字列の開始、終了位置を設定できます。
今回は 2文字目から表示される様に設定しています。
scrpitUsings では csファイルで使う using を文字列で設定しています。
ここは好きなusingを入れていただいて構いません。 ここを自動化しても面白そうですね。
最後の scriptClassName では csファイルの class 宣言文章を文字列で設定しています。
csスクリプトで使用する変数やメソッドの文字列を作成しよう!
// プロパティ配列 var propertyArray = []; // スプレットシートの値を代入する for(var i = 0 ; i < value.length ; i++) { // 変数orメソッド用の文字列を設定 var property = "public" + " " + value[1][i] + " " + value[0][i] + ";"; // 配列に追加 propertyArray.push(property); // 改行する(任意) propertyArray.push("\n"); }
propertyArray は csスクリプトの変数群を追加する配列です。
value.length は 先ほど取得した sheet.getRange() の内容が入っています。
二次元配列で構成されているのがポイントです ( dictionary 見たいになっています。)
// 変数orメソッド用の文字列を設定 var property = "public" + " " + value[1][i] + " " + value[0][i] + ";";
ここが 変数orメソッドの生成箇所です。
今回は 変数 のみに対応しています。
public value[1][i] ( 変数の型 ) + value[0][i] (変数の名前) + ";" となっています。
これでスプレッドシートに記載した変数名と型を文字列としてスクリプトに設定することができる様になりました。
propertyArray.push(property) で作った文字列を配列に追加しています。
csスクリプトに記載する文字列を完成される
// ,を消す var resultProperty = propertyArray.join(""); // クラス内部の文字列を完成させる var scripts = scriptClassName + "\n" + resultProperty + "}";
propertyArray.join(""); で 配列内の , を消しています。
最後に classの文面を仕上げれば、クラス内部の設計は完成です。
ドライブにcsファイルを出力しよう!
// 出力先のフォルダを設定する var myFolder = DriveApp.getFolderById('XXXXXXXXXXXXXXXXXXXXXXXXXX'); // ファイルを出力する myFolder.createFile(scriptName + ".cs",scripts);
いよいよ先ほど作ったgoogleドライブにcsファイルを出力しましょう。
まず DriveApp.getFolderById で出力するフォルダを設定します。
XXXXX.... の部分はドライブフォルダDを入力してください。
フォルダのID は ドライブから任意のフォルダを開いた後のURLに乗っています。
drive/u/0/folders/XXXXXXXXXXXXXXXXXXXXXXXXXXX
のXXXX の部分です。
createFile(scriptName + ".cs",scripts); では ファイルを生成します。
scriptName + ".cs" では スクリプトの名前と拡張子を設定しています。
第2引数では scripts を設定しています。
これでcsファイルの生成の準備が整いました。
ファイルを生成しよう!
それでは作ってきたGASスクリプトを起動しましょう。
左上の矢印ボタンを押して起動してください。
成功すれば 冒頭で作成したドライブに csファイルが生成されています。
csファイルもこのように出来上がりました。
using System; using UnityEngine; public class Temp { public int id { get; private set; } public string serihu { get; private set; } public float power { get; private set; } }
いかがだったでしょうか。
今回の処理は様々な箇所で対応できると思うので、是非試してみてください!
【Unity C# 】Dictionaryとキャッシュな保管クラスを作ってみた
作成中のUnity基盤に取り入れてみました。
内容は大したことはしていなく、Dictionaryでデータを保存し、メソッドで「特定のデータを保管しているか」「保管してる特定のデータを取得する」機能を実装して外部で対応する形になっています。
1. キャッシュ用のDictionaryを作成する
今回は PrefabのPath(情報)を保管するクラスを作成しました。
/// <summary> /// Prefabのパスを保持するクラス /// </summary> public sealed class PrefabPathHolder { //=============================================== // 変数 //=============================================== /// <summary> PrefabのPathの保管</summary> private Dictionary<string, PrefabPathProperty> mPaths = new Dictionary<string, PrefabPathProperty> ();
private で Dictionary mPaths を宣言しています。
このmPaths に Unityで使用する全てのPrefab情報を保管して、必要な時に引き出す仕組みになっています。
例えば、「XXってPrefab情報って保管されてるか知りたい」状態になったとします。
その時に備えて「指定されたPrefabが保管されているか調べて返答する」関数を作ってみました。
type.FullName と ConstainsKey() で Dictionaryを調べる
/// <summary> /// 指定したPathが保持されているか判定する /// </summary> /// <returns></returns> public bool HasPrefabPath (Type prefabType) { return this.mHasPrefabPath (prefabType.FullName)); } private bool mHasPrefabPath (string tagName) { // 保持して入ればローカルに存在しているか判定する if (mPaths.ContainsKey (tagName)) { return true; } return false; }
HasPrefabPath は 指定された type が保管されているのかbool型で返答します。
mHasPrefabPathに type.FullName を渡していますが、FullName は そのtype の正式名称を送信します。
このクラスの場合だと 「PrefabPathHolder 」 namespace があれば 「namespace.PrefabPathHolder」 として表示されます。
mHasPrefabPathの 「mPaths.ContainsKey」は Dictionary の Key に 先ほど指定したFullName が含まれているか判定しています。
この他にも「指定したPrefab情報を渡す」や「指定したPrefabは ローカル? or AssetBundle? 」などの機能を作ると、よりスムーズな開発ライフを遅れると思います。
Python \n (改行コード) がついた文字列を削除したい (replace)
前回のBot作成中に起こったできごとを赤裸々に書いていきます。
ある文字列から特定の文字を削除したい! って思うときあると思います。
私は「Androidストアから引っ張ってきた最新のアプリバージョン」を文字列で取得する処理を実装しました。
ですが、引っ張ってきた文字列には「不要なモノ」が含まれていました。
文字列を分割できないか調べる
pythonでの文字列の分割方法ザッとをまとめてみました。
- split ・・・ 区切り文字を設定し分割する
- rsplit・・・ 右側 ( 文字列後部 ) から分割する
- splitlines ・・・ 改行コードがあったら分割
これを見るに splitlines を使うのが正しいと思いますが、改行コードで文字列が分割された後の処理が面倒だったため、
今回は replace を使って文字列から改行コードを削除しようと思います。
replace で改行コードを消す!
replace の使い方は以下のように記述します
文字列.replace. ("削除 (置換) する前の文字列 " , "削除(置換)した後の文字列 " , 最大回数)
最大回数 については未設定で大丈夫です。
今回は改行コードの変更のためこのように記述しました!
var text = appVersionText.replace("\n","")
これで text に appVersionの文字列から改行コードが削除された文字列が代入されます!
アプリバージョンの文字列だけ取得できるようになりました!
replace を使っても \n が削除されない場合
先ほどの設定を行っても文字列から改行コードが消えない人へ
私も同じ症状に悩まされました。
というのも、\n(改行コード)としてでなくただの文字列としてだった場合、replace や splitを使っても削除、分割はできません!
その場合の対象法は以下の通りです
var text = appVersionText.replace("\\",""). replace("n","")
\ と n の2つを別々に選択しなければなりません。
これで試してみてください。
python初心者がslackbotを使って通知Botを作成!
ある日同僚から「ストアのアプリバージョンが更新されたら知らせてくれるBotとか作れる?」との要望をいただきました。
ちょうどAPIトークンやBotの勉強をしたいと思っていたので2つ返事で挑戦することにしました。
まずは python slackbot を導入する!
slackbot で調べたらちょうど良さそうなのが出てきたので導入。
参考にした記事様
PythonのslackbotライブラリでSlackボットを作る - Qiita
上記の記事通りに導入を行い、slackでbotの動作が確認できたら完了です。
ただし、上記のレスポンスbotは一度起動するとそれ以外の処理を受け付けなくなります。
pythonでバッチ(bat .cmd ) ファイルの動かし方を調べる
slackbotがちゃんと動いたので、次はbotに処理させる機能を作成します。
今回の要望は「ストアから特定のアプリバージョンを取得する」だったので、
私はシェルコマンドでストアからバージョンを取得する処理を作成しました。
ターミナルで動作を確認済み。
ここまでは良かったのですが、どうやってpythonにshellコマンドを呼ばせるかに悪戦苦闘しました。
初めは system.os を使ってみたのですが、最新のverですと非推奨扱いになっていて断煙。
その後行き着いたのが 「subprocess.check_output()」です。
これを使うとシェルコマンドでの結果もpythonで取得できるので、まさに最高の機能と出会えたと思えました。
そしてこのsubprocess.check_output()、なんとバッジファイルも起動できる優れもの。
そこでバッチファイルを作ることにしました。
bat(cmd)ファイルを作成してpythonで起動させる!
私はmacで作業しているので、cmdファイルを作成しました。
注意: bat(cmd)ファイルのアクセス権限を与えていたいと動作しません!
Macでバッチファイルを作成する方法
https://www.dafuku.com/2014/11/mac-bat-file.html
こちらのサイト様を参考にして、バッチファイルにアクセス権限を付与してください。
アクセス宣言を付与したらこのバッチファイルへのパスをpythonに設定し、subprocess.check_output()で読んでみましょう。
まとめ
長々と話しましたがまとめとして実際に作成したソースコードを記載します
python入門1日目の私が作成したので、かなり荒削りですがそこはご了承ください。
#!/usr/bin/env python # -*- coding: utf-8 -*- from slackbot.bot import Bot import subprocess import os import time from slacker import Slacker def main(): # bot = Bot() # bot.run() # アプリバーション記載テキストの更新 def writeVersion( newAppVersion): # newAppVersion 最新バージョン # アプリバージョン記載テキストを読み込む path = "記載テキストのパス" # ファイルのアプリバージョンを書き換える with open(path , mode= 'w') as f: f.write(newAppVersion) slack = Slacker("slackのapitoken"") slack.chat.post_message('チャンネル名', " 色々書いてね! ", as_user=True) # ストアのiosアプリバージョンが変更されたか確認する def checkAppVersion(): print('checkAppVersion') # アプリバージョンを記載するテキストファイル path = "パス" f = open(path) prev_version = f.readline() f.close() # ストアからアプリバージョンをひっぱて来るcommand cmd_file = "バッチファイルへのパス" # コマンドを起動する a = subprocess.check_output(cmd_file,shell=True) # 不要な文字を削除 version = str(a) print(version) # 保管してあるバージョンと最新のストアアプリバージョンを比較 if prev_version != version: # バージョンが違う場合、Slackへの告知とAppVersion.txtの更新を行う writeAppVersion(version) # バージョンチェック def schedule_version_check(): while True: checkAppVersion() time.sleep(5)# 5秒間待機 if __name__ == "__main__": print('start slackbot') schedule_version_check() # main()
time.sleep(5) で5秒間ごとにストアのアプリバージョンチェックが走るようにしています。
bot.run()の部分は使わないのでコメントアウトしてますね。
pythonは上から書かないと行けなかったりして慣れが必要だと思いましたが、他にもやりたいことが増えたので
どんどんやって行きたいと思います!
Unity Objectを任意の型に変換する拡張メソッドを作ってみました
最近はResources生成用のコントローラクラスを作っているのですが、その最中で出来上がったものをブログに書き起こしました。
というのも、指定したクラス (Prefab) を自動でInstantiate する処理を作っていたときに、オブジェクトの型変更をスムーズと思い、サクッと作ってみました。
ソースコード
using System.Collections.Generic; using System.Collections; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using UnityEngine; /// <summary> /// UnityEngine.Objectの拡張クラス /// </summary> public static class ObjectExtension { /// <summary> /// UnityEngine.Objectを任意の型に変更する /// </summary> /// <param name="selfObj"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static T ConvertAsObject<T> (this Object selfObj) where T : Object { // ObjectがNullの場合 if (selfObj == null) { return null; } // 取得した情報がComponentの場合 if (typeof (T).IsSubclassOf (typeof (Component))) { // GameObjectに変換する GameObject obj = (selfObj as GameObject); // GameObjectであった場合、Componentを返す if (obj != null) { return obj.GetComponent<T> (); } } // Objectの型を変更して返す return (selfObj as T); } }
説明
まずC#の拡張クラスを使っています。
this Object selfObj でこの関数を読んだオブジェクトの型を変換できるようになりました。
/ ObjectがNullの場合 if (selfObj == null) { return null; }
ではこの関数を読んだオブジェクトがnullだった場合、nullを変換するifを読んでいます。
Nullチェックは本当に大事で、特にObject系は必ず行いましょう。
// 取得した情報がComponentの場合 if (typeof (T).IsSubclassOf (typeof (Component))) { // GameObjectに変換する GameObject obj = (selfObj as GameObject); // GameObjectであった場合、Componentを返す if (obj != null) { return obj.GetComponent<T> (); } }
この部分はテンプレート先のクラスがComponent型の場合、ObjectをGameObjectに変換します。
GameObjectだった場合のみ、型変換先のクラスをGameObjectにアタッチする仕組みです。
Component型でなかったらそのまま型変換したObjectを変換されています。
使い方
個人的には Instantiateを行うときに使用しています。
Instantiateする際の型変換時に行うと、汎用的に使えてとても便利です。
是非皆さんも試してみてください。