ウンcodeプログラマの日常

底辺大学生プログラマの技術的なメモです

Unityでの開発ノウハウ?

芝浦工業大学デジクリ アドベントカレンダー3日目。
今回は共同開発する上でのUnity&C#&プログラミングのノウハウを紹介していきたいと思います。
(自分と同じサークルの方は分かると思いますが、ネタはかなりrgb_rpg企画から出ています。)

経緯

自分が参加しているサークルで行われていたゲーム開発にPGとしてピンチヒッターとして参加したところ、なんかヤバイことになっていた(´・ω・`)
全体のお話はデジクリアドベントカレンダー1日目に記載されているのでそちらを見てください。

hackmd.io

Unity初めて触る人大量&プログラムの設計を事前に行って居なかったため、まあ酷いUnityプロジェクトとなっていました。
そこで、プログラムの設計をするSEがいないなどの組織的な問題は別にしてプログラム・設計の面+Unityで何をしなければならなかったのかを、まとめて行こうと思う。

参考例環境

PGだけでも12人ほどいた、サークルとしては大人数での開発
Unityによる2Dゲーム・アクションRPG

プログラミング一般

まずはバッドコードの例を。
実際にrpg_rgb企画のバッドコードを例に使います。

このコードについて今から話していきます。

コメントを適切に書こう

いつコメントを使うか

コメントを書きましょうと書きましたが、全ての行にコメントを書く必要はありません。
変数の宣言部分に関しても、明らかに何が入るかわかる変数にはコメントは必要無いでしょう。
コメントに関しては、処理のコードのブロックごとに何をしているのかなどをメモする程度で書けば良いと思います。
コメントというよりも処理ごとにメソッドにまとめて、メソッド名でどんな処理をしているのかを分かるようにするのがベストですね。

Summaryを活用せよ

VisualStudioの機能としてSummaryというものがあります。
変数やメソッドの前にスラッシュ三本を使って書くことで、変数やメソッドを使う時に書いたコメントをVisualStudioが表示してくれます。
f:id:MogamiTsuchikawa:20191202221849p:plain f:id:MogamiTsuchikawa:20191202223059p:plain f:id:MogamiTsuchikawa:20191202223106p:plain

特に書いた本人以外が使用する可能性があるpublicなメソッドの場合、絶対に書きましょう。

製作者を明記しよう

チーム開発の時、このように製作者やクラスのちょっとした使い方や説明などを書いておくと、バグの報告や質問などがしやすいです。
デジクリではメンバーが全員オフラインで作業するのはなかなかないので、しっかりとslack名やメールアドレス等を記載しておくのもいいかもしれません。

命名規則をしっかり守ろう

C#では変数名などはCamel形式、クラス名・メソッド名はPascal形式となっています。
- Pascal形式:Time / Text
- Camel形式:time / text

また配列やListなどはsなどをつけて複数形の名前にしたり
bool型ではflag_**is**のような名前を心がけましょう。

メソッドをつくろう

参考コードのGenerateメソッドの中を見てみましょう。
このコードの問題点としては、

  • メソッド内のコードの量が多い
  • ネストが深い
  • 局所局所に何の処理をしているかのコメント等がない。

正直上の問題を挙げていますが、このコードはまだ読める(何をやっているのか想像しやすい)方な気がします。 他のクラスではUpdateメソッド内に大量のif文・深いネストがあるヤバイやつがあったので...

このコードの場合、三角形(132~163行目)・四角形(117~129行目)・円形(167~174行目)を生成するところをそれぞれprivateなメソッドにするのがよさそうですね。
処理方法を思いついて無心に書いているときにはだら~っと書きがちなので書いた後にネストが深くないかなど客観的に見れるポイントでチェックしておきましょう

列挙体を活用しよう

一定の種類しか無いもので処理をわけたりなどするときは列挙型を使いましょう。あまりサンプルコードでは見られませんが、stringで頑張っているコードが多い気がします。
例えば当たったものがどのキャラクターか判断するコードを書くとして、それの判別をstringで行った場合、"Player""player"として書き間違えるだけで処理が上手くいきませんし問題の発見も難しいです。
UnityのGameObjectタグなどで経験した方も多いのではないでしょうか?
まあ、詳しい使い方などはC#ツヨツヨな方のサイトをみましょう。

ufcpp.net

配列・List・辞書型を適切に使おう

結構全体のコードを見て思うのが、配列以外のListや辞書型、列挙型がなかなか上手く利用されていないのを感じます。
Listや列挙型などはUnity側で操作がしやすいのでよく利用するのがお勧めです。
具体的な例として、自分が開発しているものを見せます。
List型をpublicなどで作っておくと図のようにUnity側から入力が可能です。
f:id:MogamiTsuchikawa:20191203004858p:plain speedSetsList<int>speedSetsNameList<string>です。
宣言時は[SerializeField] List<int> speedSets = new List<int>();でできます。
列挙型はUnityの画面ではListBoxで表示されます。 f:id:MogamiTsuchikawa:20191203005655p:plain また、列挙型なListも作って表示が出来ます。面白いですね。 f:id:MogamiTsuchikawa:20191203005854p:plain ただ残念なことにDictionaryではこのようにUnity側で変更できるように使えないのでちょこっと不便ですね。

プロパティを活用せよ

クラス外からは変数のように振る舞い、内部からはメソッドのように振る舞う。それがプロパティです。
例えばstring型の変数に文字を代入したらUnity内部のUIのTextにも反映させるといったことや、値を取り出した回数などを記録するなどのことが出来ます。

privatei_txttxtの実態です。
また、取得はクラス外でもOKだが代入はクラス外はNGにしたい場合、プロパティ全体をpublic(上のコードのような状態)にして、setprivateをたしてprivate setとします。
このように出し入れで違うアクセス修飾子を付けたい場合でもプロパティは有効です。
また、このようにアクセス修飾子目的で使う場合、txtの実態であるi_txtは省略することが出来ます。(i_txtのような実態はシステムが自動生成します。)

また、getterのみ記述するものもあります。これではreadonlyなものが内部で生成されます。readonly要素を付けるよりはstring hoge{get;}と書くように心がけましょう。

C#の知らない機能をもっと知ろう

++C++を読め!💢

ufcpp.net

Unity

こっからが本番です。(はぁもう書くの疲れてきたので雑に行きます)

GameObject.Find() GetComponentは魔の呪文

GameObject.Find()GetComponentは重いので極力書かないようにしてください。
よくStart()内に書いてRigidBodyなりいろいろなComponentを変数に参照させていますが、そんな邪悪な書き方をせずに[SerializeField]で変数を作り、それにUnity上からドラッグアンドドロップしましょう。

GameObject.tagを乱用するな

これは特に最初の設計である程度考えておかないといけない物ですが、tagは必要最低限にしましょう。tagはstringということもありスペルミスでバグが起きたりする可能性も高いですし、全部の識別にtagを使用していてはtagの量が大量になってしまいます。
タグを大量に使うだけでは無く、タグに.区切りでデータを保管しているようなコードも見受けられました...正直最初何をやっているコードかわかりませんでしたし、分かってからめちゃ怖かったです。

で、タグを乱用しないように自分では以下のような方法で解決しています。

  • tagは大きく役割が違う物にしか付けない
  • 共通のtagを持つ物には共通のクラスを付ける
  • 共通のクラス内に列挙型などで詳しい種類を指定できるようにする

例えばEnemyタグを持った物にはEnemyBaseというクラスを付け列挙型EnemyKindやEnemyには確実に必要であるHPやダメージを受取るOnDamage()などを実装したりします。
このような組み方をするだけで、tagによるミスだけでなく列挙型が使えることによりエディタからの支援も受けれます。

オブジェクトに複数のスクリプトを付けよう

共通の処理などをする部分は、普通のプログラミングでは継承を用いて楽をしますが、Unityでは操作するオブジェクトに対して複数のスクリプトが当てれるので、役割をスクリプトごとに分けて共通化を図れるようにしましょう。

リソースに日本語を使うな

リソース(画像など)に日本語を使わないでください。 テキストなどを使う際もShift_JISなんて使わないように。
僕はUnityプロジェクトを開いて数分後に見たiOSの画像(1).pngがトラウマになって夜も寝れません(寝れています)

Gitを使うときは注意せよ

UnityでGitを使う際にはいくつも注意すべき点があります。

gitnore

gitnoreにしっかりと無視する物を書きましょう。Libraryとか全然無視してかまいません。
とりあえず簡単に使えるようにサンプルを落としておきます。

Sceneを弄る人間は限定せよ

皆さん知って居るとおりSceneを複数人で同時に弄ることにより、直すことが難しいコンフリクトを起こします。 Sceneを弄る人は限定しましょう。

GitLFSを活用せよ

UnityではGitが本来扱うに適していないバイナリーデータを大量に扱い、画像などの素材はかなりの容量があります。
GitHubなどのリポジトリは2GBを超えると警告メールが飛んでくるので、GitLFSを用いてバイナリーふぁいるを極力リポジトリから減らしましょう。
GitLFSでは指定されたバイナリーファイルはLFSサーバー上に保管され、リポジトリの方にはポインタファイルが保管されます。
ローカルリポジトリでは特に変わることはないので使ってみましょう。
ただGitLFSはむりょうでは1GBしか使えないため、課金して50GB使えるようにするのがおすすめです。月5ドルしかしないので非常にお安い!!!!!!!

終わりに

はぁもう2時30です。眠いです。
自分の言いたいことはまだまだありますが、とりあえずはここまでと。
rgb企画はここからリスタート。同じプロジェクトの皆さん。一緒に頑張りましょう。
自分はSEとしてクラス設計などの設計をメインにPGの方を支えていきます。
Unityのことについての質問など気軽にしてください。