- 投稿日:2020-04-26T23:06:57+09:00
Unityのモバイルゲーム向けクラッキングが行われるポイントを整理してみた
免責事項
この記事に記載されている内容を、実際に試して発生した損害に対していかなる責任も負いません(補償しません)。
すべて自己責任のもとで行ってください。リリースされているアプリやゲーム、ソフトウェア利用許諾契約(EULA)やアプリケーション利用規約などでリバースエンジニアリングは禁止されています。
実際に試す場合は、自分で開発しているアプリやゲームや脆弱性確認用でリリースされているアプリやゲームを使いましょう。勘違いして理解しており、誤ったことを記載しているところもあるかもしれません。
実際に対策を行うときは、専門家に相談してください。はじめに
目的
「Unityのモバイルゲーム向けセキュリティ関連覚書 - Qiita」の資料を全部読むのは大変です。 1
理解が進みやすいように、クラッキングが行われる目的、ポイント、対策を整理してみました。
なるべく一般的な名称を使っているつもりです。長くなるため細かく解説をつけていません。
必要に応じて、覚書で調べるか、ググっていただけると助かります。(各種対応方法の詳細も覚書を確認してください)ここ間違っている、ここもう少し詳しくなどコメントもらえると助かります。
対応方法
この後に出てくる対応方法は、書かれている対応を行えば絶対に安全というものではありません。
基本、無限のコスト(人と時間)をかけられる攻撃者の方が有利です。
どこまで対応する必要があるかは、守りたい情報やアセットの重要度と、実装(対応)コストを、勘案する必要があります。暗号化
エンコーディング(base64など)は、暗号化ではありません。
暗号化は、System.Security.CryptographyなどでAESやRAS使用したもののことを指しています。暗号化にも強度があります。現在のPCでは暗号強度が弱いものだと解析されてしまいます。
適切な暗号強度のアルゴリズムと暗号化キーをを設定する必要があります。
(ハッシュアルゴリズムにも強度があります。適切なアルゴリズムを選択する必要があります。)その他
Unityのモバイルゲームと銘打っていますが。
「WindowsやmacOSのPC環境」、「AndroidやiOS環境ネイティブアプリやゲーム」、「PlayStation 4、Xbox One、Switchなどコンソール機」、「Webサービスやゲーム」でもクラッキングのターゲットになり対策が必要です。クラッキングの目的
私見になりますが。 2
ゲームをクラッキングする目的としては、「人より有利に進めたい」、「技術的興味」、「営利目的」などが考えられます。
- 人より有利に進めたいは、「他の人に(お金を使わないで)簡単勝ちたい」、「時間短縮」、「欲しいユニットやアイテムを簡単に手に入れたい」などが考えられます。有利とは別に、元画像、3Dモデル、音楽データが欲しいなども考えられます。
- 技術的興味は、対処のゲームがどのような構造で作られているか、セキュリティーを破りたいなど自分の欲求を満たすため。また、技術力を見せるためにクラッキングの方法やツールを公開することもあります。3
- 営利目的は、「人より有利に進めたい」人でクラッキング能力がない人向けに、簡単に使えるクラッキングツール、改造済みのゲームアプリ、アカウントを提供して利益をえる。また、サービスを攻撃して停止に追い込み要求をだしたり。ユーザーデータなど価値あるものを手に入れて販売したりすることが考えられます。
対策が必要な条件は、上記の目的を持つ人が現れる場合に行う必要があります。
対策は守りたいポイントを明確にして、必要処置を行いましょう。
セキュリティ対策を後から入れる場合は、最初から対策よりもコストが高くなります。4全体像
大きく分けて、クライアント、ネットワーク、サーバに対するクラッキングのポイントを記載していきます。
- クライアントは、クライアント内にある情報に対する攻撃
- ネットワークは、クライアントとサーバ間で行う通信に対する攻撃
- サーバは、サーバ内にある情報に対する攻撃
クライアント
スマートフォン(Android、iOS)端末内で行われる、クラッキングの内容と対策になります。
静的解析
プログラムが実行されていない状態で解析を行うことです。
パッケージ
Androidはapkファイル。iOSはipaファイル。
root(Android)、jailbreak(iOS)状態の端末から環境で取得したり、専用サイトを使用してダウンロードできる。(Androidはroot化してなくても端末から取り出せるかも)apk、ipa共にzipファイルのため解凍するだけで中身をみることができます。
パッケージ情報の一部ファイルはプレーンテキストではなく、バイナリファイルに変換されています。
変換ツールを使ってプレーンテキストに戻すことができます。(apktoolツールなど)改変したものをインストールするためには、apk、ipa共にパッケケージを再署名する必要があります。
実行ファイル
Windowsでいうと.exe。macだと.app(正確には実行許可ビットが立っているファイル)。
逆コンンパイル(逆アセンブル)を行われた場合に、可読性の高い状態でコードが復元されてしまいます。
- ソースコードに実際使われないなコードやメソッドを挿入する
- ソースコードを難読化(関数名や変数名を推測しにく名前に変えるなど)し、逆コンンパイルをされても解析しにくいようにする
セーブデータや通信時の暗号化キー、開発用サーバのエントリーポイントなどをconst、static
readonlyなどで文字列定義すると。
実行ファイル内にそのまま文字列として含まれる。逆コンパイルや「strings」コマンドなどで文字列を発見されてしまいます。
- 不要な情報は含めないようにする
- 暗号化や難読化する
- 常にサーバから取得する(ローカルには保存しないようにする)
アセット
Unityだと、シーンファイル、シーンから参照しているリソースファイル、Resourcesフォルダ内のファイル、StreamingAssetsフォルダ内のファイルなどが対象になります。
シーンファイル、Prefab、画像、3Dモデル、音声データ、フォントなどが同梱されます。対処方法は「静的解析→ストレージ→アセット」の項目を参照してください。
マスターデータが含まれる場合もあります。対処方法は「静的解析→ストレージ→マスターデータ」の項目を参照してください。ストレージ
ストレージは、ROMと表現される内蔵ストレージ。AndroidはSDカードで拡張した領域も含みます。
root(Android)、jailbreak(iOS)端末や、デバッグが許可されているアプリケーションの場合ストレージのデータにアクセスして取得できます。AndroidのSDカードに書き込んだデータは、PCに接続してマウントしたり、SDカードリーダで簡単に読み出すことができます。
アカウント
ユーザーを識別する必要がある場合には、どのユーザーか認識するためにUUIDや専用アカウントを準備すると思います。
独自で実装する場合して、PlayerPrefs、テキストファイル、バイナリファイルに保存する場合は注意する必要があります。プレーンテキスト、PlayerPrefs、バイナリファイルに保存すると内容がテキストエディターやバイナリエディターで読むことができます。
- 暗号化や難読化する
- OSのセキュアに保存する機能で保護して保存する(AndroidはAccountManager、iOSはKeychainなど)
- idとパスワードではなく、セッショントークンを保存しておく。一定時間でセッショントークンは更新されるようにしておきクラッカーに渡っても永続的に使用できないようにする
マスターデータ
マスターデータはキャラクターデータ(HPやSTRなど)、敵キャラクターデータ、ステージ情報など、ゲーム初期や動作を設定するための情報をさしています。
敵キャラクターのHPをすべて1に変更して、バトルを有利に進めるられると困ります。
Sqliteや専用のバイナリフォーマットなどを、ストレージに保存している場合は解析が可能です。
マスターデータを取り出し。解析をしてパラメータ変更が行えます。
- 改変されても問題のないデータのみ格納する
- 暗号化や難読化する
- 常にサーバから取得する(ローカルには保存しないようにする)
- 重要な情報は、複数の場所にデータを保存しておき、比較して改変チェックを行う
- ハッシュ値も合わせて保存しておき改変チェックを行う
開発用のデータなど、リリース版のアプリに不要な情報は含めないようにしましょう。
ユーザーデータ
ユーザーデータは、ゲームの設定(ユーザー名、BGMのボリュームなど)、フレンド情報、ゲームの中断データなどがあります。
BGMのボリュームは書き換えられても問題ありません。ですが、ゲームの中断データを改変されクリアしたことになる、勝利したことになると問題になります。
PlayerPrefs、テキストファイル、バイナリファイルでストレージに保存した場合はファイルを取り出し。
ファイルを解析をしてパラメータ変更が行えます。
- 改変されても問題のないデータのみ格納する
- 暗号化や難読化する
- 常にサーバから取得する(ローカルには保存しないようにする)
- 重要な情報は、複数の場所にデータを保存しておき、比較して改変チェックを行う
- ハッシュ値も合わせて保存しておき改変チェックを行う
アセット
パッケージに含まれているものや、クラウドストレージ(AmazonのS3など)からダウンロードしてくるデータをさします。
UnityだとAssetbundleファイルのこと。
Assetbundleではなく、専用のフォーマットで保持する場合もあるかもしれません。シーンファイル、Prefabなどにテキストで入力してあるセーブデータ、通信時の暗号化キー、開発用サーバのエントリーポイントなどは文字列として保存されてしまいます
- 不要な情報は含めないようにする
- 暗号化や難読化する
- 常にサーバから取得する(ローカルには保存しないようにする)
画像、3Dモデルな、音声データ、フォントなどを変換してPCで閲覧できます。
- 暗号化や難読化する
- 専用フォーマットにして、解析しにくようにする
- 常にサーバから取得する(ローカルには保存しないようにする)
動的解析
プログラムが実行いる状態で解析を行うことです。
攻撃方法
デバッガー
実行中のプログラムを動作を確認するための方法。
通常は開発中のアプリケーションの動作を見るために使用します。
- 実行中のプログラムにアタッチして、実行中のプログラム動作を確認する
- プログラムの動作からチェックロジックなどを探し出す
- 回避ロジックを、実行ファイルにパッチを当て改造アプリを作成する
- アプリケーションを再署名する
メモリ改変
プログラムはメモリ内にロードされて実行されます。
プログラムがロードされたメモリを書き換えて目的の状態に変更する方法です。
- メモリ調査用のアプリを動作させて、アプリケーションを動作させる
- HPなど変化を確認したい箇所をプレイする
- メモリ内の変化を確認して、変更すべき場所を探す
- メモリを書き換えるアプリケーションを使用して、HPなど減らないようにパッチを当てる
常にサーバから取得する(ローカルには保存しないようにする)
サーバーからダウンロード行い、メモリにアセットが常駐している場合はメモリをダンプしてファイルに保存する。
一般的なファイルフォーマットの場合は保存したファイルから、データを一般的なツールを使い表示できます。暗号化して常駐しさせていれば保存しただけでは表示できません。
ですが、複合ロジックが解析された場合には、アセットのデータと合わせて元のデータを復元される可能性があります。インジェクション 5
対象のアプリケーションに、ハッキング用のアプリケーションを同梱して実行・攻撃する方法です。
- アプリケーションのハックするためのバイナリを付与する
- アプリケーションを再署名する
- 実機でアプリケーションを動かして動作や変更したいポイントを調査する
- パッチを作り必要に応じてアプリケーションの動作を変更する
対応方法
解析をするようなアクションが行われたことを検知してアプリケーションをクラッシュさせる。
注意点としては、検出ロジックで端末やOSのバージョンによって想定した挙動と異なる場合。
普通にプレイしている場合でもクラッシュさせてしまう可能性があります。
メーカー、OS、バージョン、端末の設定、常駐するアプリをイロイロなパターン組み合わせてチェックする必要があります。
- 端末がroot(Android)、jailbreak(iOS)されていないかチックする
- 特徴的なファイルを検知してアプリケーションを終了させる
- エミュレータチェック
- 特徴的なファイルを検知してアプリケーションを終了させる
- アプリケーションが改変されていないか
- 署名のチェックを行う
- ファイルのハッシュチェックを行い、ファイルが置き換えられていないか確認する
- チェックに引っかかった場合はアプリケーションを終了する
- デバッグモードの設定がオン(許可)になっていないかをチェックする
- デバッグモードがオン(許可)にはアプリケーションを終了する
- デバッガーがアタッチされていないかチックする
- アタッチされている場合はアプリケーションを終了する
- シンボル情報を残さないようにする
- メモリ書き換え
- 複数箇所に書き込みを行い定期的に比較する
- 書き換えられて胃が場合にはアプリケーションを終了する
すべてのチェックを同じタイミングで行うと、まとめて対策コードが潰される可能性があります。
コードを分散する、チェックタイミングを分散する、複数準備して別々にチェックするなど対応を行う必要があります。ネットワーク
スマートフォン(Android、iOS)とサーバ間の通信で行われるクラッキングの内容と対策になります。
解析
WebAPI
https(SSL/TLS)を使用して呼び出している場合は、そのままではクラッキングされることはありません。
- 最近はAndroid/iOS共に、アプリケーションからのhttpアクセスはは許可されていない。そのため、通信内容を簡単には見れません
- バージョンや設定になどにより通信内容を見たり、改変でき、クラッキングされるケースはある
証明書の正当性チェックをしない実装になっていると、証明書を端末にインストールすることで通信内容の読み取りおよび改変されてしまいます。
(デバッグのために証明書チェックを切った状態でリリースしてしまったなど)証明書の正当性チェックを行なっていても、実行ファイルの証明書チェックコードを無効化されたり。
プログラム実行中にパッチを当てて無効化される可能性があります。
通信内容にチェックサムを付けてリクエスト内容が改変されていないかをサーバ側で確認する必要があります。
チェックサム自身も解析される可能性があります。
対策方法に関しては、静的解析、動的解析の項目を確認してください。WebAPIのリクエストエラー時に表示するテキストも解析される可能性があります。
リリース時には、エラーコードのみにして詳細なエラー内容を表示するための文字列を含まないようにしましょう。
(エラーコードとエラー内容の対応表をチーム内のみ参照できるようにする)Tcp、Udp
オリジナルデータ構造をそのまま送信している場合には暗号化されません。
データ内容を読み改変できないように暗号化する。
パケットが改変されていないかチェックサムを付与してチェックする必要があります。暗号化キーや証明書の管理、チェックサムロジックを解析されないように注意する必要があります。
対策方法に関しては、静的解析、動的解析の項目を確認してください。ミドルウェア
ミドルウェア(Photon、モノビットエンジンなど)では通信内容を暗号化機能機能を搭載しています。
暗号化キーや証明書の管理に注意する必要があります。
対策方法に関しては、静的解析、動的解析の項目を確認してください。生成
リプレイ
端末とゲームサーバの中間にProxyサーバを置き、WebAPIやパケット(Tcp/Udp)送信したものをもう一度送る攻撃方法です。
Proxyで一部のパラメータを変更して送信することも可能です。
例えば、スコアの項目を増やして送るなどです。証明書の正当性チェックを行い通信内容を改変できないようにましょう。
リクエスト生成
解析した情報を元にクライアントを使用せずにゲームの情報が操作できるようになります。(ゲームの仕様に即した範囲までの操作)
WebAPIはcurl。Tcp/UdpはScapyでリクエストを生成できます。対策
- 暗号化キーやロジック変更する
- 一定タイミングで、暗号化キーを切り替える
- チェックサムのロジック変更
- リクエストの監視をして、一定処理を繰り返している、明らかに実行できないアカウントを抽出する
- アカウントを削除する。もしくは行動制限をする
- F2Pタイトルだとすぐに新しいアカウントが生成できてしまう。そのため、イタチごっこにはなってしまう
BOT
解析した情報を元に、WebAPIやパケット(Tcp/Udp)のリクエスト生成する。キャラクター操作など自動でゲームが進行するように自動的に操作を生成する手法です。6
(MMOなどでは、開発時に負荷チェックやデバッグために使ったりもする)リクエスト解析を解析するだけではなく、追加のアプリや、OSの機能、エミュレータなどで簡易操作BOTを作成することもできます。
- スマホ(Android)を自動タップ操作でゲームプレイ!Root化不要のオートクリッカーの設定方法・使い方など。キャプテン翼で検証。│生活向上委員会!
- iPhoneで自動タップ!ゲームの周回が超ラクになるスイッチコントロールとは?|ガラクタブログ
- 「NoxPlayer」or「Androidスマホ」で高速リセマラする方法 | 下手だけどゲーム好きのブログ
対策
- 暗号化キーやロジック変更する
- 一定タイミングで、暗号化キーを切り替える
- チェックサムのロジック変更
- リクエストの監視をして、一定処理を繰り返している、明らかに実行できないアカウントを抽出する
- アカウントを削除する。もしくは行動制限をする
- F2Pタイトルだとすぐに新しいアカウントが生成できてしまう。そのため、イタチごっこにはなってしまう
関連資料
- ゲーム世界を崩壊に追い込むチートbot 1日2億件の不正ログインの実態 (1/5) - ITmedia NEWS
- BOT業者の活動を“ほぼ壊滅”に追いやるまでの軌跡――「ドラゴンネスト」運営チームによる1年半の不正行為対策を振り返る - 4Gamer.net
- 検出不可能なゲームのチートが発表、今後のオンラインゲームのデザインはこのチートを前提に設計しなければならない
サーバ
サーバへ行われるクラッキングの内容と対策になります。
サーバはクラウドサービス(orオンプレミス)、マネージドサービス、mBaasなど使用するサービスにより対応するべき範囲が変わります。
例えば、クラウドサービスではサーバ構成、OSからアプリケーションまで自分たちで面倒見なくてはいけません。(オンプレミスだとハードウェアやハウジング環境もプラスされる)
mBaaSではサーバ上で実行するスクリプトを考慮すれば問題ありません。
(正確には、mBaasサービスを運営しているチームがサーバやOSを管理してくれているだけです。
mBaaSの運営チームのスキルレベルにより問題が発生した場合に、自分たちで使用しているmBaaSサービスの解決できない問題になる可能性はあります)専門ではないので、よく出ているワードと資料へのリンクになります。
- DoS攻撃:サーバリソースを枯渇させてサーバを使用できない状態にする
- インジェクション攻撃:SQLやOSのコマンドを外部から実行さすることができてしまう問題
- ディレクトリ・トラバーサル攻撃:Webサーバをクローリングを行い、不正にアクセスしファイルの閲覧や改ざんをする攻撃
- ゼロデイ攻撃:サーバ、OS、ミドルウェア、アプリケーションが持つ脆弱性が発見されてから、ベンダーによりセキュリティパッチ(修正プログラム)が適用されるまでの期間を狙って実行されるサイバー攻撃
- ブルートフォースアタック:IDとパスワードでユーザー認証する際のパスワードを手当たり次第試して、パスワードを解析しようとする手法
関連資料
その他
ハードウェア
GPS、加速度センサー、ジャイロセンサーなど位置ゲーを作成する場合に使用する。
位置情報は、GPSだけではなく、無線LANのアクセスポイント、mobile(4Gなど)での位置情報計測も含まれる。
位置情報の補正や、歩数などに加速度センサー、ジャイロセンサーを使用している。
- エミュレータやデバッグ機能でデータを設定されていないかを確認する
- チェックに引っかかった場合は、アプリケーションを終了させる。もしくはデータを採用しない。
- 取得したパラメータが、理論上ありえない移動数値だった場合
- データを採用しないようにする
- 合わせてログを自社で管理するサーバ取得して通知するようにする
- 怪しいユーザーがいた場合に、移動量などが可視化するツールを作成して確認できるようにする
ソーシャルハッキング
ソーシャルハッキング(そーしゃるはっきんぐ)とは - コトバンク
ユーザーIDやパスワードを盗み出すのに、技術的な手段を利用せず、直接本人の口から聞き出す、タイプ内容を盗み見る、書類やメモを入手する、といった手段を利用する行為。盗み見た上司のパスワードを使って情報を盗む組織内犯罪や、掃除夫などを装ってオフィスに侵入する手口等がある。システム管理者の技術的な対応では防ぐことが困難であり、個人個人にセキュリティー意識を徹底させることが重要である。
ソフトウェアからだけではなく、人間自身がセキュリティーホールになる場合もあります。
おすすめ資料
合わせて読むと理解が進むと思います。
- 投稿日:2020-04-26T22:22:45+09:00
[Unity初級]UIの色を変更する
- 投稿日:2020-04-26T20:10:45+09:00
Unity ContentSiaeFitterのHorizontalFitのモードをスクリプトから選ぶ方法
これも分かり辛かったのでメモ。
var fitter = object.GetComponent<ContentSizeFitter>(); fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;最後のPreferredSizeはモードの種類なので、好きなものを選んでください。
- 投稿日:2020-04-26T19:47:51+09:00
C# Enumの文字列変換は重い
EnumをToStringすると激重なので、事前にswitch文やarrayで文字列を定義しておくと、パフォーマンスを上げることができる
コード
[RankColumn] public class EnumTest { [Params(Weapon.WeaponType.A)] public Weapon.WeaponType weaponType; [Benchmark] public string Case1() { return weaponType.GetNameSwitch(); } [Benchmark] public string Case2() { return weaponType.GetNameArray(); } [Benchmark] public string Case3() { return weaponType.GetNameToString(); } } public static class Weapon { public enum WeaponType { A, B, C, } private static string[] weaponTypeArray = { "A", "B", "C", }; public static string GetNameSwitch(this WeaponType type) { switch (type) { case WeaponType.A: return "A"; case WeaponType.B: return "B"; case WeaponType.C: return "C"; } throw new NotImplementedException(); } public static string GetNameArray(this WeaponType type) { return weaponTypeArray[(int)type]; } public static string GetNameToString(this WeaponType type) { return type.ToString(); } }結果
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362 //Intel Core i5-9600K CPU 3.70GHz(Coffee Lake), 1 CPU, 6 logical and 6 physical cores // [Host] : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT // DefaultJob : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT //| Method | weaponType | Mean | Error | StdDev | Rank | //|------- |----------- |------------:|----------:|----------:|-----:| //| Case1 | A | 1.2287 ns | 0.0263 ns | 0.0246 ns | 2 | //| Case2 | A | 0.0523 ns | 0.0123 ns | 0.0115 ns | 1 | //| Case3 | A | 282.2946 ns | 1.4594 ns | 1.3652 ns | 3 |
- 投稿日:2020-04-26T19:45:18+09:00
C# Stringパフォーマンス計測
よく使うintから文字列への変換Performance測定
計測コード
[MemoryDiagnoser, RankColumn] public class ScoreBoard { [Params(999999)] public int score; [Benchmark] public string Case1() { return "Score : " + score.ToString(); } [Benchmark] public string Case2() { return "Score : " + score; } [Benchmark] public string Case3() { string scoreText = score.ToString(); return string.Format("Score : {0}", scoreText); } [Benchmark] public string Case4() { return string.Format("Score : {0}", score); } [Benchmark] public string Case5() { return $"Score : {score}"; } [Benchmark] public string Case6() { string scoreText = score.ToString(); return $"Score : {scoreText}"; } [Benchmark] public string Case7() { string scoreText = score.ToString(); return ZString.Concat("Score : " + scoreText); } [Benchmark] public string Case8() { return ZString.Concat("Score : ", score); } [Benchmark] public string Case9() { string scoreText = score.ToString(); return ZString.Format("Score : {0}", scoreText); } [Benchmark] public string Case10() { return ZString.Format("Score : {0}", score); } }結果
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362 //Intel Core i5-9600K CPU 3.70GHz(Coffee Lake), 1 CPU, 6 logical and 6 physical cores // [Host] : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT // DefaultJob : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT //| Method | score | Mean | Error | StdDev | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated | //|------- |------- |----------:|---------:|---------:|-----:|-------:|------:|------:|----------:| //| Case1 | 999999 | 59.98 ns | 0.670 ns | 0.627 ns | 2 | 0.0204 | - | - | 96 B | //| Case2 | 999999 | 60.23 ns | 0.331 ns | 0.310 ns | 2 | 0.0204 | - | - | 96 B | //| Case3 | 999999 | 132.33 ns | 1.099 ns | 0.975 ns | 5 | 0.0203 | - | - | 96 B | //| Case4 | 999999 | 139.31 ns | 1.503 ns | 1.406 ns | 6 | 0.0253 | - | - | 120 B | //| Case5 | 999999 | 139.09 ns | 0.712 ns | 0.666 ns | 6 | 0.0253 | - | - | 120 B | //| Case6 | 999999 | 61.18 ns | 0.730 ns | 0.683 ns | 2 | 0.0204 | - | - | 96 B | //| Case7 | 999999 | 117.34 ns | 0.965 ns | 0.903 ns | 4 | 0.0323 | - | - | 152 B | //| Case8 | 999999 | 51.19 ns | 0.522 ns | 0.488 ns | 1 | 0.0119 | - | - | 56 B | //| Case9 | 999999 | 196.12 ns | 1.129 ns | 1.056 ns | 7 | 0.0203 | - | - | 96 B | //| Case10 | 999999 | 108.29 ns | 0.723 ns | 0.676 ns | 3 | 0.0118 | - | - | 56 B |
ZStringが使えるならこれを使ったほうが一番パフォーマンスがいい。
無理なら
ToString() と +演算子の組み合わせ
ToString() と $ - 文字列補間がパフォーマンスが良い文字列の変換数が増えるとパフォーマンスは変わってくるが...
- 投稿日:2020-04-26T17:39:11+09:00
Unityを使ってクリエィティブなゲームを作れるようになるまで。(2日目)
題名を(〇日目)のようにしました。
色んなゲームを作る予定ですので、私の成長過程を楽しんでもらえたら幸いです!今日は何を作るの?
ネットサーフィンをしていると、なんとN予備校の受講が無料らしいとの事!!
引用:N予備校
https://www.nnn.ed.nico/中を漁ってみると、なんとunityのコースが!
早速受講してゲームを作ろう!作成したゲームはこれ
受講したコース通り、キャラクターの後ろに付いている赤い球を箱にぶつけるゲームを作りました。
学んだこと
- Terrainオブジェクトを使用して、簡単に地形が作れる。
- Spring jointでキャラクターと玉の位置関係、バネの力で制御することができる。
- scriptの中のpublicで定義された変数・クラスは、GUIから代入することができる。
- ↑の仕組みであるため、script内にconstructorは持たない。
- 投稿日:2020-04-26T17:38:18+09:00
【Unity + AdMob + CocoaPods + iOS】エラーなくビルドを通すための最適解【Androidにも応用できる】
こんにちは!
ねこじょーかー(@nekojoker1234)と申します。みなさんは、UnityEditor 上だけでなく、実機で動作確認したことはありますか?
実機で動作確認をするには「ビルド」が必要になるのですが、これがまた本当にやっかいです。
何がやっかいなのかと言うと、とにかくエラーが出ることが多く、そしてそのエラー解決も一筋縄ではいきません。私が遭遇したやっかいなエラーたちは以下の通り。
- GoogleMobileAds/GoogleMobileAds.h' file not found
- Undefined symbols for architecture arm64
- Undefined symbols for architecture armv7
- linker command failed with exit code 1
エラー内容で調べるといろいろと情報は出てくるのですが、Unity のバージョンが新しいせいか、どれも解決にはいたりませんでした。
もうダメかな...と諦めかけていたとき、ついに解決方法を見つけ、無事にエラーなくビルドすることができるようになりました。
私は解決に数日間かかりハゲそうになったので、他の人がハゲてしまわないよう、この記事に残しておきます。
ということで、さっそく見ていきましょう。
エラーなくビルドを通すための最適解
External Dependency Manager for Unity のインポート
まずは、External Dependency Manager for Unityをダウンロードしてください。
これが今回の肝となるプラグインで、簡単な記述をするだけで、iOS や Android でやっかいな依存関係のエラーを解決してくれるという優れものです。
Google が出しているプラグインなので、安心ですね。
この中にある、
external-dependency-manager-latest.unitypackage
をインポートしていきます。こんな画面が出てくるので、そのままインポートしましょう。
Google Mobile Ads Unity Plugin をすでに入れている場合は、一部更新マークになります。
すると、インポート中にできたゴミファイルを削除していいか聞かれるので、Apply で削除しておきましょう。
ここから少し時間が経つと、統計情報の取得をしてもいいか聞かれます。
どちらでもいいですが、私は No を選択しました。
あと2画面出てくるのですが、両方とも右下のボタンを押せばOKです。
「Add Selected Registries」を選択
「Apply」を選択
これでインポートは完了です。
Dependencies.xml の準備
続いて、SampleDependencies.xml をダウンロードしてきます。
これをプロジェクトのフォルダに置くのですが、2つルールがあるので注意してください。
MyPlugin/Editor
の直下に置く- Editor の上位階層のフォルダ名と、Dependencies の前につけた文字列を一致させる。(今回の例だと
MyPluginDependencies.xml
)たとえば、上位階層のフォルダが「DownhillRush」だとすると、以下の構造になっていればOKです。
次に、XML ファイルの中身を修正していきます。
ファイルの一番下を見ると、以下の記載があります。
<iosPod name="Google-Mobile-Ads-SDK" path="../google-mobile-ads-sdk" version="~> 7.0" bitcodeEnabled="true" minTargetSdk="6.0"> <!-- Set of source URIs to search for this Cocoapod spec. By default Cocoapods will attempt to fetch the pod specs from: * $HOME/.cocoapods/repos * https://github.com/CocoaPods/Specs --> <sources> <source>https://github.com/CocoaPods/Specs</source> </sources> </iosPod>今回は、
Google-Mobile-Ads-SDK
だけあればいいので、ここを少し修正します。<iosPod name="Google-Mobile-Ads-SDK" version="~> 7.0" bitcodeEnabled="false" minTargetSdk="6.0">
bitcodeEnabled
は色んなサイトで「false にしとけ」と書かれていたので、とりあえず false にしておきます。
path
はローカルの CocoaPod のパスらしいのですが、よくわからないので消しました。また、ビルド時に「cocoapods.mycompany.com/Specs が見つからない」とエラーになるので、以下の
sources
タグはコメントアウトしておきましょう。修正前
<!-- Global set of sources to search for Cocoapods. These sources will be searched for all Cocoapods specified by iosPod. --> <sources> <source>https://cocoapods.mycompany.com/Specs</source> </sources>修正後
<!-- Global set of sources to search for Cocoapods. These sources will be searched for all Cocoapods specified by iosPod. --> <!--<sources> <source>https://cocoapods.mycompany.com/Specs</source> </sources>-->これで XML の準備は完了です。
iOS Resolver の設定変更
Assets > External Dependency Manager > iOS Resolver > Settings
を開きます。Cocoapods Integration を、
Xcode Project - Add Cocoapods to the Xcode project
に変更します。xcworkspace のファイルを作らずに、Xcode のプロジェクトファイルの中に CocoaPods の設定を含めるようにする、という変更です。
これですべての準備が整いました。
ビルド
あとはビルドをすれば、エラーなくビルドができるはずです。
私はこの方法にたどり着くまでに、35回もビルドを失敗してしまいました...
今回は iOS で試しましたが、Android でも専用の手順の通りやることで、ビルドが通るようになると思います。
みなさんがこの記事を参考に、一発でビルドが通れば嬉しいです。
おまけ
PlayFab に関するブログも書いているので、よければ合わせてご覧ください。
https://playfab-master.com/
- 投稿日:2020-04-26T17:37:57+09:00
【Unity】UIの透過をスクリプトからまとめて調整するCanvasGroup
環境
Unity 2019.3.7f1
はじめに
ボタンの透過率を変更しても
ボタンに付けているテキストの透過率は一緒に変化しません。まとめて透過率を変更したいときはCanvasGroupが便利です。
手順
1.透過値を変更したいUIを適当オブジェクトにまとめる
2.まとめたオブジェクトにCanvasGroupコンポーネントを追加
3.スクリプトからCanvasGroupコンポーネントを取得しアルファ値を変更する
CanvasGroup型の変数.alpha=0f~1f;具体例
3つのボタンの透過値を実行後50%に変更していきます。
1.ボタンを3つ作成
2.CanvasにCanvasGroupコンポーネントを追加
3.スクリプト作成
スクリプトを新規作成します。スクリプト名はCanvasTestとしました。CanvasTestusing System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;//UIを使うとき追加 public class CanvasTest : MonoBehaviour { [SerializeField] private CanvasGroup a;//CanvasGroup型の変数aを宣言 あとでCanvasGroupをアタッチする void Start() { a.alpha = 0.5f;//変数aのalpha値を変更 } }5.スクリプトにCanvasGroupをアタッチ
Canvasを空のオブジェクトのスクリプトの変数a欄にアタッチ
おわりに
個別の透過率変更とはサヨナラです♪
- 投稿日:2020-04-26T16:29:27+09:00
【Unity】否定演算子の使い方
環境
Unity 2019.3.7f1
はじめに
否定演算子の使い方がわからなくなるのでメモ
使い方
使い方は2種類
・if文で使用
if(変数 != 数値)
{
処理内容
}・trueとfalseを逆にする
変数 = !変数;具体例
・if文で使用
using System.Collections; using System.Collections.Generic; using UnityEngine; public class test : MonoBehaviour { int a; void Start() { a = 2; //aが1ではないなら処理 if(a != 1) { Debug.Log("aは1じゃないよ");//コンソールに表示 } } }
・trueとfalseを逆にするusing System.Collections; using System.Collections.Generic; using UnityEngine; public class test : MonoBehaviour { bool a; void Start() { a = true; a = !a; Debug.Log("a=" + a); a = !a; Debug.Log("a=" + a); a = !a; Debug.Log("a=" + a); a = !a; Debug.Log("a=" + a); } }おわりに
なにかと使える否定演算子
- 投稿日:2020-04-26T16:11:11+09:00
[Azure] Microsoft Azure で出来ること
はじめに
さて、皆さんは Microsoft Azure をご存知でしょうか?
恐らく「Azure って、クラウドサーバーでしょ?」って感じで認識されていると思いますが、実は結構色々なサーバーを利用したサービスが統合されているソリューションと思っていただいたほうがいいです。Microsoft Azure で出来ること
では、具体的に何が出来るかというと…
- Unity や UE の作成したプロジェクトをクラウドで自動ビルド (Azure DevOps Pipelines)
- ビルドの配信 (Visual Studio App Center)
- ライブラリの社内のプライベートなメンバーへの配信 (Azure DevOps Artifacts)
- パフォーマンス監視 (Visual Studio App Center)
- クラッシュログを収集 (Visual Studio App Center)
という感じです。
他にも色々あるのですが特に利用する頻度が高いものを列挙しています。おわりに
今後はこの辺りの紹介や説明を公開していきたいと思います。
- 投稿日:2020-04-26T15:10:08+09:00
【Unity】 Transform.SetParentを使わずに子オブジェクトの相対位置を追従させたい
何がしたいのか
Transform.SetParent
を使わずに、衝突したオブジェクトとの相対位置を一致させたい。
(こういうの。CubeとSphereはそれぞれ独立したオブジェクトだが、相対値を維持している。)実装例
using UnityEngine; public class AttachSample : MonoBehaviour { /// <summary> /// 追従する対象 /// </summary> private Transform _target; /// <summary> /// 相対位置 /// </summary> private Vector3 _deltaPosition; /// <summary> /// 相対角度 /// </summary> private Quaternion _deltaRotation; private void Update() { if (_target != null) { // 相対ベクトルにぶつかったときの角度の逆を反映してから、 // 現在の角度を反映させる transform.position = _target.position + _target.rotation * _deltaRotation * _deltaPosition; } } /// <summary> /// 衝突したらくっつく /// </summary> /// <param name="other"></param> private void OnCollisionEnter(Collision other) { _target = other.transform; // 衝突したワールド座標 var cp = other.contacts[0]; // 対象の中心部から衝突地点への相対ベクトル _deltaPosition = cp.point - _target.position; // 対象の現在角度の「逆」 _deltaRotation = Quaternion.Inverse(_target.rotation); } }備考
- 追従する側の回転角は操作していません(位置のみ追従)
- 対象のScaleが変化したことを考慮していません
- 投稿日:2020-04-26T15:05:11+09:00
[Azure DevOps] Unity Tools for Azure DevOps の使い方
はじめに
Unity Tools for Azure DevOps とは Azure DevOps の Pipelines で利用可能な Unity のビルドタスクです。
ただ、注意点としては、まだ結構内容に変更が多いです。
執筆時点でのバージョンは V3 ですが、V3 と言いながら違う動作をする V3 がデプロイされています。
また、Github で公開されているソースコードと実際にタスクを利用した時の挙動が違います。
この記事は Github も参照してますが、実際に Pipelines で実行してみた結果を記載しております。
とはいえ、この投稿以降でも更新されている可能性はありますのでご注意を…。Azure DevOps Marketplace:
https://marketplace.visualstudio.com/items?itemName=DinomiteStudios.64e90d50-a9c0-11e8-a356-d3eab7857116
Github:
https://github.com/Dinomite-Studios/unity-azure-pipelines-tasksタスク一覧
Unity Tools for Azure DevOps には以下のタスクが実装されています。
- UnityGetProjectVersion
- UnityActivateLicense
- UnityBuild
- UnityCMD
- UnityTest
UnityGetProjectVersion
このタスクの利用目的はプロジェクトで利用している Unity のバージョンと同じバージョンをインストールするためです。
これは指定された Unity プロジェクトで利用している Unity のバージョンを ProjectVersion.txt から読み込んで返します。
成功すると projectVersion にバージョン番号が設定されます。
引数 省略 説明 projectPath ○ Unity プロジェクトへのパス Unity プロジェクトがリポジトリ直下にある場合は projectPath には $(Build.SourcesDirectory) を渡しておけば問題ないです。
戻値 説明 projectVersion Unity のバージョン番号 Unity プロジェクトに設定されているバージョン番号が返ります。
- task: UnityGetProjectVersionTask@1 name: UnityGetProjectVersion displayName: 'Getting a version of Unity' inputs: unityProjectPath: '$(Unity.ProjectPath)'UnityActiveteLicense
このタスクの利用目的は Unity のライセンスをアクティベートするためです。
また、ポスト処理が入っており、ジョブ終了時にそのライセンスをリリースも実行してくれます。Microsoft-hosted で実行する場合、毎度新規で Unity をインストールしますし、ライセンスが毎度がリリースされますので、この処理が必要になります。
引数 省略 説明 username × ユーザー名 password × パスワード serial × シリアル番号 unityEditorsPathMode ○ Unity エディタのインストールディレクトリモードを選択。省略された場合は unityHub が設定される。
unityHub(デフォルト):Unity Hub のデフォルトのパスを利用
environmentVariable:環境変数 $UNITYHUB_EDITORS_FOLDER_LOCATION に指定されたパスを利用
specify:customUnityEditorsPath に指定されたパスを利用customUnityEditorsPath ○ Unity エディタへのパスを絶対パスで指定。unityEditorsPathMode に specify が指定された場合に有効。省略した場合はカレントディレクトリが使用される。 unityProjectPath ○ Unity のプロジェクトが配置されているパス。省略された場合はカレントディレクトリが設定される。
戻値 説明 logsOutputPath ログファイルパス - task: UnityActivateLicenseTask@1 displayName: 'Unity License Activations.' condition: succeeded() inputs: username: $(Unity.UserName) password: $(Unity.Password) serial: $(Unity.SerialKey) unityEditorsPathMode: 'unityHub' unityProjectPath: '$(Unity.ProjectPath)'UnityBuild
このタスクは Unity プロジェクトをビルドするために利用します。
Unity を利用した場合に、バッチビルドで様々な処理をさせずに単にビルドしたいというだけであれば、バッチファイルも自動生成してくれますので非常に便利に使えます。
引数 省略 説明 additionalCmdArgs ○ 追加でコマンドラインに渡したい引数がある場合に、この引数で指定する。自前のバッチビルドファイルを指定する時に -quit とかに利用できる。 buildScriptType ○ ビルドに利用するスクリプトの指定。
default:ビルドスクリプトは自動生成されたものを利用する。
inline:inlineBulidScript に記述されたスクリプトを利用する。
existing(デフォルト):
inlineBuildScript ○ buildScriptType に 'inline' が指定された場合に executeMethod で実行されるスクリプトを指定する。 buildTarget × ビルドするターゲット名を指定する。指定方法は『Unity のコマンドライン』の『-buildTarget』を参照。 unityEditorsPathMode ○ UnityActiveteLicense と同じ。 customUnityEditorsPath ○ UnityActiveteLicense と同じ。 unityProjectPath ○ UnityActiveteLicense と同じ。 outputFileName ○ 出力するファイル名。省略された場合は 'drop' という名前に設定される。 outputPath ○ 出力するディレクトリパス。省略された場合はカレントディレクトリが設定される。
戻値 説明 logsOutputPath UnityActiveteLicense と同じ。 - task: UnityBuildTask@3 displayName: 'Building.' condition: succeeded() inputs: unityEditorsPathMode: 'unityHub' buildTarget: '$(Unity.TargetBuild)' unityProjectPath: '$(Unity.ProjectPath)' outputPath: '$(Build.BinariesDirectory)' outputFileName: 'Build'UnityCMD
このタスクは、ビルドまで大層な事をしたいわけではなく、バッチ処理をしたいというときには手軽に使えるタスクです。
UnityBuild の細かい設定を全部自前でやるというだけのタスクです。
引数 省略 説明 cmdArgs ○ 追加でコマンドラインに渡したい引数がある場合に、この引数で指定する。自前のバッチビルドファイルを指定する時に -quit とかに利用できる。 buildTarget × UnityBuild と同じ。 unityEditorsPathMode ○ UnityActiveteLicense と同じ。 customUnityEditorsPath ○ UnityActiveteLicense と同じ。 unityProjectPath ○ UnityActiveteLicense と同じ。 UnityTest
(省略)
おわりに
正直言って、結構ソースコードの内容を読まないとまともにパラメータの指定方法も分からなかったりで苦労しましたが、Unity と Pipelines で利用するには重宝するタスクに違いありません。
どちらにせよ、直接 YAML を編集する上ではこの辺りのタスクは覚えておいて損はしませんので!
- 投稿日:2020-04-26T13:21:53+09:00
Unity コンポーネントの有無を調べる方法
ちょっと引っかかったのでメモ。
var component = object.GetComponent<Image>(); if(component == null) { //メソッド }コンポーネントが無い場合にコンポーネントを追加する方法。
var component = object.GetComponent<Image>(); if(component == null) { object.AddComponent<Image>(); }
- 投稿日:2020-04-26T12:40:16+09:00
【Unity】シーンの事前ロード
環境
Unity 2019.3.7f1
はじめに
移動先のシーンが重くて遷移まで間が開いてしまう問題を解決するべく
シーンの事前ロードについて調べました。方法
事前ロードし、ボタンを押したらシーン移動するコード
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;//追加 public class SceneTest : MonoBehaviour { AsyncOperation a;//AsyncOperation型の変数aを宣言 void Start() { //SceneManager.LoadSceneAsync("GameScene")の返り値(型はAsyncOperation)を変数aに代入 a = SceneManager.LoadSceneAsync("GameScene"); //AsyncOperationの中の変数allowSceneActivationをfalseにする //これがtrueになるとシーン移動する a.allowSceneActivation = false; } //ボタンに割り当て public void Change_Scene_button() { //trueにしてシーン移動 a.allowSceneActivation = true; } }解説
SceneManager.LoadSceneAsync("シーン名");のみを使ってシーン移動する場合、
下図のことが処理されています。
allowSceneActivationの情報を下図のように一旦falseにしておくことで
シーン読み込み後のシーン移動をストップします。
おわりに
ちょっとややこしいですが、定型文として覚えておく程度で良いと思います。
動けばOKの精神♪
- 投稿日:2020-04-26T08:11:49+09:00
UnityのPackageManagerに自分のパッケージを入れるまで
概要
最近、自作のEditor拡張等を入れてAssetフォルダに増えるのが厳しい感じがしたので、Unityの機能であるPackageManagerに登録することにしました。その備忘録になります。
PCに直接npmやらVerdaccio入れるのはつらい気持ちがあるので、Dockerなるものを使います。材料
※私の環境はWindows10 Homeのため
* Docker Toolbox - v19.03.1手順
1. 下準備
上記のDocker Toolboxはあらかじめインストールしておきます。
参考 - Windows環境にDocker Toolboxをインストールする2. docker-compose.ymlを作る
docker composeってなんぞや?
Compose とは、複数のコンテナを使う Docker アプリケーションを、定義・実行するツールです。Compose はアプリケーションのサービスの設定に、Compose ファイルを使います。そして、コマンドを1つ実行するだけで、設定した全てのサービスを作成・起動します。 - Docker ドキュメント日本語化プロジェクトより
その複数のコンテナを使う Docker アプリケーションを、定義するためのファイルがdocker-compose.ymlとのことです。
まずは今回のプロジェクト用のフォルダを作成し、その中にdocker-compose.ymlファイルを配置します。
フォルダ構成はこんな感じ。(Cドライブのどこかに置くこと)- LocalNpmPackageServer ├ verdaccio │ ├ config │ │ └ config.yml │ ├ plugins │ └ storage └ docker-compose.yml中身は下記
docker-compose.ymlversion: '3.1' services: verdaccio: image: verdaccio/verdaccio container_name: "verdaccio" networks: - node-network environment: - VERDACCIO_PORT=4873 ports: - "4873:4873" volumes: - "./verdaccio/storage:/verdaccio/storage" - "./verdaccio/config:/verdaccio/conf" - "./verdaccio/plugins:/verdaccio/plugins" networks: node-network: driver: bridge今回はUnityのPackageManagerのレジストリサーバーとして、Verdaccioの構成を定義しています。
3. config.yamlを作る
Verdaccioのコンフィグファイルを作成します。docker-compose.ymlのvolumesに定義されている ./verdaccio/configに配置します。
中身は下記。config.ymlstorage: ../storage auth: htpasswd: file: ./htpasswd uplinks: npmjs: url: https://registry.npmjs.org/ packages: '**': access: $all publish: $authenticated proxy: npmjs logs: - {type: stdout, format: pretty, level: http}ここで定義されているstoregeの位置はdocker-compose.ymlのvolumesに定義した./verdaccio/storageの位置です。
4.起動する
Docker Toolboxを入れたタイミングでDocker Quickstart Terminalが追加されているはずなので、起動します。
くじらのAAの黒い画面が出てきたら、docker is configured to use the default machine with IP なんとか
と、IPアドレスが出ているので覚えておきましょう。
そしてdocker-compose.ymlを置いたプロジェクトフォルダへ移動します。コマンドcd "プロジェクトフォルダのパス"移動したらDockerを起動するためのコマンドを入れます。
コマンド# デーモン状態で起動する場合はこっち(このターミナルを閉じても動いてる) docker-compose up -d # 普通に動かす場合はこっち docker-compose up
http://先ほど出ていたIPアドレス:4873
をブラウザに入れて、Verdaccioの画面が表示されたらこれで環境は作成完了です。5. パッケージを作成する
参考 - UNITYPACKAGEMANAGERのレジストリサーバーを立てる話
Unityでの作業になります。
- パッケージ構成について
個人的にはこのようなフォルダ構成にしています。
- OriginalPackage │ ├ Runtime │ │ └ OriginalPackage.Runtime.asmdef │ ├ Editor │ │ └ OriginalPackage.Editor.asmdef └ package.jsonこの時に注意するのはEditorのAssembly DefinitionのPlatformsの設定で、Any Platformのチェックを外し、Editorのみにしておきます。
また、後ほどPackageManagerからインストールする際に既に存在しているとインストールできないため、同じプロジェクトに入れる場合は最初の作成が終わったら登録する前に別の(プロジェクト外の)場所に移しておきましょう。
- package.jsonについて
中身は下記
package.json{ "name": "jp.co.mypackage.originalpackage", "displayName": "Original Package", "version": "1.0.0", "unity": "2018.1", "description": "My original package.", "keywords": [ "editor" ], "category": "", "relatedPackages": {}, "dependencies": {}, "repository": {}, "author": { "name": "My Name", "url": "" }, "license": { "type": "MIT", "url": "https://monry.mit-license.org" } }このうち、上から5項目(name・displayName・version・unity・description)は必須です。
上記の必須でない項目の一部はVerdaccioで表示されたりします。6.パッケージを登録する
またDocker Quickstart Terminalに戻ります。
まずユーザー登録をします。
コマンドnpm adduser --registry http://4で出てたIP:4873ユーザー名、パスワード、メアドを登録します。
で、ログイン。コマンドnpm login --registry http://4で出てたIP:4873で、登録。
コマンドcd "OriginalPackageのフォルダパス" npm publish --registry http://4で出てた:4873これで登録完了です。
ちなみに上記のコマンドたちは、立ち上げたVerdaccioのページに書いてあるのでコピペすると良いです。この状態でVerdaccioのページを読み込み直すとパッケージが登録されているのが確認できると思います。
7.UnityのPackageManagerからインストールする
最後です。Unityのプロジェクトフォルダ/Package/manifest.jsonを開きます。
そこに下記のようにscopedRegistriesを追加します。(dependencies以下は元からあるはずです)manifest.json{ "scopedRegistries": [ { "name": "my-package-name", "url": "http://4で出てたIP:4873/", "scopes": [ "jp.co.mypackage" ] } ], "dependencies": { "com.unity.collab-proxy": "1.2.16", "com.unity.ide.rider": "1.1.4", "com.unity.ide.vscode": "1.1.4", "com.unity.test-framework": "1.1.11", "com.unity.textmeshpro": "2.0.1", "com.unity.timeline": "1.2.12" } }これでUnityに戻りPackageManagerを見ると出ていると思います。
- 投稿日:2020-04-26T06:17:42+09:00
【Unity】繰り返しアニメーションさせるだけのコンポーネント
経緯
Unityで2Dゲームを作る際、繰り返しアニメーションをするだけのオブジェクトや、アニメーションが終わったら消滅するだけのオブジェクトを配置する事はよくありますが、一つひとつUnity標準のAnimatorControllerを使っていてはキリがありません。そこで、繰り返しアニメーションさせるだけのコンポーネントを実装しました。
実装
「SpriteAnimation」というスクリプトを作成し、下記をコピペして使用できます。
SpriteAnimation.csusing System.Collections.Generic; using UnityEngine; using System; public class SpriteAnimation : MonoBehaviour { [SerializeField] SpriteRenderer spriteRenderer; [SerializeField] List<Sprite> sprites; [SerializeField] bool loop, destroy; [SerializeField] float second; int count; float time; void Start() { spriteRenderer.sprite = sprites[0]; } void Update() { time += Time.deltaTime; if (time > second) { time -= second; count++; spriteRenderer.sprite = sprites[count]; if (count < sprites.Count - 1) return; if (loop) count = -1; else if (destroy) Destroy(gameObject); else disposable.Dispose(); } } }インスペクター上の項目説明
- SpriteRenderer : アニメーションさせるSpriteRendererをアタッチ
- Sprites : アニメーションに使用するSpriteを順番にアタッチ
- Loop : Loopさせる場合はチェック
- Destroy : アニメーションの終了後に破壊するならチェック
- Second : アニメーションの速度
UniRX版
こっちの方が低負荷
SpriteAnimation.csusing System.Collections.Generic; using UnityEngine; using UniRx; using System; public class SpriteAnimation : MonoBehaviour { [SerializeField] SpriteRenderer spriteRenderer; [SerializeField] List<Sprite> sprites; [SerializeField] bool loop, destroy; [SerializeField] float second; int count; IDisposable disposable; void Start() { spriteRenderer.sprite = sprites[0]; disposable = Observable.Interval(TimeSpan.FromSeconds(second)) .Subscribe(_=> { count++; spriteRenderer.sprite = sprites[count]; if (count < sprites.Count - 1) return; if (loop) count = -1; else if (destroy) Destroy(gameObject); else disposable.Dispose(); }).AddTo(this); } }
- 投稿日:2020-04-26T02:02:27+09:00
Unity 2DGameKit Gunner戦
2DGameKitの導入や詳細はこちらのページが詳しいので任せる
目次
1.Gunner戦とは
2DGameKitのZone5シーンでGunnerというボスが登場する。2.主人公 Ellen
3.Gunner
ライフ設計
Gunnerにはシールド(青いゲージ)があって、シールドを削り切るとライフ(赤いゲージ)にダメージを与える事が出来ます。
シールド(青いゲージ)について
GuunerShieldというGameObjectがシールドの役割を担っています。
シールドに主人公が触れたら、主人公はダメージを受ける設計になっています。
Damagerがその役割を持っています。
Damageableが主人公からダメージを受ける役割を持っています。ライフ(赤いゲージ)について
Damageableが主人公からダメージを受ける役割を持っています。Components
Gunner戦において必要となるComponentについて
Damager
Damagerはその名の通り、ダメージを与える役割をもったComponentです。Damageable
Damagerがダメージを与える役割をもったComponentに対して、Damageableはダメージを受け取る役割をもったComponentです。