気ままなUnityエンジニアブログ

新米Unityエンジニアが送る解説アウトプットブログです。Twitter : @UjinUnity

MENU

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 を使用した際に、以下のエラーが発生した時の対処法です。

scrapbox.io


また、submoduleを削除して、再度追加する際にもエラーが発生しやすいです。
複数の削除コードを入力しないといけないのが主な原因。

git submodule add --name XXX などで 新たな名前記入で回避できる方法もあるため、苦戦している方は試してみてください

qiita.com

【Unity】 GitHubのPermission denied エラーで苦戦した話

mac OS を Montereyに更新した後、ソースツリーなどでGit のpushやClone時にエラーが発生するようになった。

(解決した方法)

1. sshキーを再生成し、秘密鍵登録を行なった

GitHubにSSH接続する方法(秘密鍵、公開鍵の作成) - Qiita


2. GitHubのバージョンアップでトークン作成が必要になったのでそちらを登録した

【Unity NodeJs】で簡単なAPIサーバーを作成する Get編

f:id:Wojtek:20191205001601j:plain


プログラミングには様々な言語やありますよね。
エンジニアの世界でも業種は多岐に渡ります。

私は今までフロントエンド(クライアント)エンジニアとしてやって来ましたが、元々サーバーサイドにも興味があり、いい機会なので「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を紹介してみる

f:id:Wojtek:20191127220913j:plain


AssetStoreが日替わりセールをやっていたので、自分がよく使っている or 欲しい!Assetを紹介します!。


Editor Console Pro


f:id:Wojtek:20191127221308p:plain

価格 : $30


多機能なコンソールウィンドウを使用できるアセットです。

デフォルトのConsoleより高機能で、関数名や文字色の変更などめっちゃ豪華なコンソール画面を活用できます。

デバッグ時にバリバリ活用できるのでオススメです。

Odin Inspector and Serializer


f:id:Wojtek:20191127222101p:plain


価格 : $55


Inspectorを劇的にパワーアップさせるAssetです!

値段は張りますがパフォーマンスは圧倒的で、例えば「Dictionary」をInpspector上で編集することができるようになります。

開発効率は爆速に上がると思うので、是非活用してみてください!。


今回は上記2点ですが、今後も紹介していきたいと思います。

【Unity】ECSをUnityで使うための事前準備 (Unity-2019.2.11f)

f:id:Wojtek:20191124180809j:plain


巷で話題のECSを軽く勉強したので数回に渡って記事にして行きます。

<注意>今回の記事は 2019.2.11f バージョン時点での内容になります。

というのも、ECSやJobSystemなどはまだまだ開発途中の状態だからです。
そのため、この記事内で記載している内容が今後のアップデート次第で使用不可能になるかも知れません。。。

参考にしたサイト様

今回、ECSを勉強するに当たって、先人様方の偉大な記事を参考にいたしました。

qiita.com


qiita.com


qiita.com


どれも素晴らしい内容であり、本当にありがとうございま

ECSをさわってみた感想


まず初めてにECSを軽くさわってみた感想ですが、

・JobComponentSystem や Entity の動作に慣れる必要がある
・CollisionやTranslate ( オブジェクトの移動 ) は自作する必要があり、まだまだ導入コストは高い

ざっくりまとめると「作品の幅は広がり、今後のスタンダートな技術になるがまだまだ実装コストは高い」となります。

今後のアップデートで Unity ECS用のRigidbodyなどが実装されればより使いやすい機能になると思います。


Unity ECSを使う前の準備

f:id:Wojtek:20191124173150p:plain

Unityの 「Window → Package Manager → Show preview packages 」をチェックしましょう。


f:id:Wojtek:20191124173212p:plain


そうすると左側に Entities が表示されるのでimportしましょう。


f:id:Wojtek:20191124173319p:plain


同様に 「hybrid renderer」も導入しておきましょう。


導入が終わったらUnityを再起動してください。

これでECSを使う準備が整いました。

次はECSで実際にゲームを作ってみようと思います。

【Unity】UnityHubは使いやすい

f:id:Wojtek:20191120225052j:plain



お久しぶりです。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をダウンロードしてください。



f:id:Wojtek:20191120225156p:plain


UnityHubで複数のバージョンをインストールした画面です。

1つ問題があって、UnityHubで選択できるバージョンはそのバージョンごと「2018xx」の最新正式バージョンが選択されます。

最新バージョン以外が欲しい場合は別途直接導入してからUnityHubに導入してください。

UnityHubを使って楽々なバージョン管理ライフを送っていきたいですね。

【Unity】GAS + スプレットシートで C#スクリプトを自動生成しよう! 【マスターデータに使える!】

f:id:Wojtek:20191108004857j:plain


Unity基盤を作っているのですが、そろそろマスターデータ関連に着手したいと思いました。

初めはスプレットシートにマスターデータを作って、それをcsvファイルにして読み込もオーソドックスな仕組みを作ってましたが、

ふと、csvファイルと一緒にcsスクリプトも自動生成しちゃえば楽じゃない? ということに気づきました。

今回はGASを使ってGoogleドライブにcsファイルを自動生成する方法を解説します。


Googleドライブに専用のフォルダを作る


まずはGoogleドライブに生成したスクリプトファイルを保存するフォルダを作成します。

フォルダを作ったら、その中にスプレッドシートを作成しましょう。



スプレッドシートにマスターデータの値を記述する

次に作ったスプレッドシートの表をうめて行きます。

今回はマスターデータのスクリプトを自動生成するように作るため


・行にスクリプトで使う変数の名前
・2行にその変数の型名を記載します。
・3行 以降はその項目にあった値を記述します



f:id:Wojtek:20191108020205p:plain




今回は画像のような内容になります

ここまででスプレッドシートの順位が整いました。

次はスクリプトエディタの作成をしましょう


スクリプトエディタでファイルの自動生成を行おう

f:id:Wojtek:20191108144246p:plain


「ツール」→「スクリプトエディタ」からスクリプト作成に移ります。


スプレッドシートの値を取得する

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スクリプトを起動しましょう。


f:id:Wojtek:20191108151201p:plain


左上の矢印ボタンを押して起動してください。

成功すれば 冒頭で作成したドライブに csファイルが生成されています。


f:id:Wojtek:20191108151253p:plain


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とキャッシュな保管クラスを作ってみた

f:id:Wojtek:20191107000155j:plain

作成中の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)

f:id:Wojtek:20191029225320j:plain



前回のBot作成中に起こったできごとを赤裸々に書いていきます。


www.wojtekmt.com



ある文字列から特定の文字を削除したい! って思うときあると思います。

私は「Androidストアから引っ張ってきた最新のアプリバージョン」を文字列で取得する処理を実装しました。

ですが、引っ張ってきた文字列には「不要なモノ」が含まれていました。

こんな感じ

f:id:Wojtek:20191104232222p:plain


そう、文字列の最後に\n (改行コード) が含まれていたのです!

iOSでは起きなかったので意外でしたが、これが思わぬ曲者でした。

文字列を分割できないか調べる


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を作成!

f:id:Wojtek:20191102004424j:plain



ある日同僚から「ストアのアプリバージョンが更新されたら知らせてくれるBotとか作れる?」との要望をいただきました。
ちょうどAPIトークンやBotの勉強をしたいと思っていたので2つ返事で挑戦することにしました。


まずは python slackbot を導入する!


slackbot で調べたらちょうど良さそうなのが出てきたので導入。


参考にした記事様
PythonのslackbotライブラリでSlackボットを作る - Qiita


上記の記事通りに導入を行い、slackでbotの動作が確認できたら完了です。

ただし、上記のレスポンスbotは一度起動するとそれ以外の処理を受け付けなくなります。

今回は「一定間隔ごとに設定した処理を実行する」bot を作りたいので、今後はbot.run()は使いません。


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を任意の型に変換する拡張メソッドを作ってみました

f:id:Wojtek:20191031230201p:plain


最近は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する際の型変換時に行うと、汎用的に使えてとても便利です。

是非皆さんも試してみてください。