2ちゃんねる ■掲示板に戻る■ 全部 1- 最新50    

Unity初心者の俺が調べたことをメモするスレ

1 :名前は開発中のものです。:2023/08/30(水) 21:52:43.22 ID:zQtYmNBI.net
ちなスペックは
コード作成は生成AI頼り・基礎的なコンポーネントの使い方すら理解してない・C#の経験皆無
こういうレベル

2 :名前は開発中のものです。:2023/08/30(水) 21:58:13.30 ID:zQtYmNBI.net
基礎的なことすら理解してないから一歩ずつ調べてメモしていきたい

今日調べたこと

・EventSystemとPlayerInputの実行順序について
Project SettingのScriptExecutionOrderでは、EventSystemが-1000・PlayerInputが-100の実行順既定値が設定されている
これを見るとEventSystemの処理の方がPlayerInputより先に行われるように見えるが、EventSystemによるUI操作はUpdate関数でInput.Actionを購読しに行く形で行われる一方、PlayerInputはPreUpdateのタイミングでInput.Actionを生成しイベントを発火させるので、実はPlayerInputによる関数コールの方がEventSystemのUI操作より先に行われる

3 :名前は開発中のものです。:2023/08/30(水) 22:04:40.12 ID:zQtYmNBI.net
あとで見返すために番号付けとくか
なるべく毎日調べたこと書きたいね

4 :名前は開発中のものです。:2023/08/31(木) 18:16:21.62 ID:SnlLP3DA.net
その2 I〇〇Handlerについて
Unityでは独自のインターフェースとして、ISubmitHandlerなどのUIイベント発生時にコールバックを受け取る機能が実装されている。
インターフェースという概念自体はあくまでクラス外部向けに内部実装の設計を規律するものにすぎず、I〇〇Handlerを実装してもC#としてコールバックを受け取る機能そのものが実装されるわけではない。
コールバックの発火は@ フォーカス、決定やキャンセルイベントなどEventSystemが発火を決定 → イベントを作成(BaseEventData) → ExecuteEventsに依頼してインターフェースを実装する該当クラスに送信してコールバックを発火するケースと、A マウスイベントなどInputModuleが自分でイベントを作成(PointerEventData) → ExecuteEventsに依頼して〜、という二つの異なるパターンがあるらしい(もっとあるかも)。
疑問としては、InputSystem導入後にInputModuleとInputSystemUIInputModuleの二つを統合するBaseInputModuleクラスが導入されたらしいが、この場合はマウスイベントを発火させるのは何処なのだろうか?

5 :名前は開発中のものです。:2023/08/31(木) 18:16:23.48 ID:SnlLP3DA.net
その2 I〇〇Handlerについて
Unityでは独自のインターフェースとして、ISubmitHandlerなどのUIイベント発生時にコールバックを受け取る機能が実装されている。
インターフェースという概念自体はあくまでクラス外部向けに内部実装の設計を規律するものにすぎず、I〇〇Handlerを実装してもC#としてコールバックを受け取る機能そのものが実装されるわけではない。
コールバックの発火は@ フォーカス、決定やキャンセルイベントなどEventSystemが発火を決定 → イベントを作成(BaseEventData) → ExecuteEventsに依頼してインターフェースを実装する該当クラスに送信してコールバックを発火するケースと、A マウスイベントなどInputModuleが自分でイベントを作成(PointerEventData) → ExecuteEventsに依頼して〜、という二つの異なるパターンがあるらしい(もっとあるかも)。
疑問としては、InputSystem導入後にInputModuleとInputSystemUIInputModuleの二つを統合するBaseInputModuleクラスが導入されたらしいが、この場合はマウスイベントを発火させるのは何処なのだろうか?

6 :名前は開発中のものです。:2023/08/31(木) 18:33:55.46 ID:SnlLP3DA.net
なんか多重送信されてるわ

「PlayerInputの方がEventSystemより実行タイミングが早い」っていう昨日の話だけ覚えておけば、どこが発火するかなんて正直割とどうでもいい気はするが念のため調べてみた。
ところでEventSystem(UnityのUI)って基本的にはイベントが発生したことは取得できるけど、「どういうキーが押されてイベントが発生したか」っていう情報を取得するのが難しい(できない?)気がする
例えば、画面上にA・B・Cの三つのUIが横並びで配置されていて、「B」がフォーカスを取得した時に発生させるイベントの内容を、直前のフォーカスが右にあったか左にあったかで条件分岐したい場合、
UIイベントが発生する原因となったキー操作そのものをEventSystemはEventDataに内包してくれる訳ではないっぽいので、工夫をしないとこの分岐は実現できなさそう

一つの案は直前までにフォーカスを取得していたA又はCにIDeselectHandlerを実装(又はSelectableがA・Cの基底クラスにあるならオーバーライド)して、フォーカスを失ってOnDeselectが実行された時に自身の情報をマネージャークラスに渡しておいてBにそれを見て判断させるという方法
この方法は分かりやすいけどUIのゲームオブジェクトが変動する・動的に生成される場合には「隣にいた」認定の処理が面倒になりそう
もう一つの案はPlayerInputを利用して、該当するキー入力があった際に入力があったことをマネージャークラスやBに渡す方法
BがAの方から来たなら右キー、Cの方向から来たなら左キーが入力されているはずなので、Bはこの入力情報を見ればどっちから来たかが分かるし、UI要素が変動しても対応しやすい
ただしイベント発火が絡む関係でパフォーマンス面では前者の手法に劣りそう

7 :名前は開発中のものです。:2023/08/31(木) 18:49:55.41 ID:/dI3F1uF.net
んなややこしいことせんと
先入れ先出しのスタック1つ作っておけば?

8 :名前は開発中のものです。:2023/08/31(木) 19:22:23.67 ID:SnlLP3DA.net
>>7
独自のデータロード式スクロールビューに利用するんだけどもう後者を採用(PlayerInput)して一応完成させたのよね

上下キーでは要素1個ずつ移動、左右キーでは表示エリア全部をページ送りする機能を実装したかったんだけど
A(画面上では不可視)
B
C
D
E
F
G(画面上では不可視)
この順に子要素が並んでいて、Aにフォーカスが入った時に上方向にデータロードして子要素を並び替え(上からGABCDEFになる)、Gにフォーカスが入った時下方向にデータロードして並び替え(BCDEFGAになる)をする感じで動く
例えばBにいる状態で下キーをを押しっぱなしにするとCDEFGAB…ってループしながらリストや配列の次のデータを読み込みながらフォーカスを変えていく

各子要素には上下方向は上下に、左方向はAに右方向はGにSelectableのナビゲーションを設定してるんだけど、このデータロードを行う際にB→AやF→Gのフォーカスの移行が「上下キー」で行われたのか「左右キー」で行われたのかを判別する必要があったのよね
それでPlayerInput使う方法を思いついた

9 :名前は開発中のものです。:2023/09/01(金) 15:34:09.80 ID:p9KeXpxb.net
普通に詳しいじゃん

10 :名前は開発中のものです。:2023/09/01(金) 18:06:12.03 ID:jPfSgGL6.net
>>9
その都度調べてはいるけど結構忘れちゃうわ
自分のコードすら翌日見るとよく分からん

その3 ゲーム上のアイテムシステムの管理について
Unity特定の機能というよりどうやってこういう概念を実装したらいいのかな?って話
アイテムの入手と管理をどうやってゲームシステムとして実装するか
@ノベルゲー寄りの小規模なゲーム(アイテムは入手か未入手だけで特定の場面でしか利用しない。同じアイテムの複数個所持もない。)
正直一つずつbool値を設定して管理しても何とかなりそう。とは言っても場面毎に必要なアイテムを設定する際の利便性を考えると、スクリプタブルオブジェクト、Enumや通し番号あたりを割り振る必要性は結局あるかもしれない
A一般的なゲーム(それなりのアイテム数で複数個所持もある)
Dictionaryで、アイテム種類別管理データ(スクリプタブルオブジェクト、Enumや通し番号あたり)をキーに、値を所持数にして格納すると楽そう。
Bハクスラ要素のあるゲーム(同じアイテムでも性能が違っていたりする。Minecraftのエンチャントようなシステムもこのタイプ)
アイテム種類別管理データだけではなく、個別アイテムの管理データも必要になる。雑に調べた限りではこのパターンは意外とネットに情報がない。自分は購入したノーコード系アセットのサンプルゲームを見て、Dictionaryの値を個別アイテムインスタンスにする方法で実装できることを知った。
public class MyItem
{
private int itemNo; // アイテム種類別管理データに対応する enumでも何でもない
private int myAbility;// 個別データとか
}
こういうクラスを実装して、アイテム入手時にこのクラスのコンストラクターに個別情報を渡してインスタンス化して、そのままDictionaryに入れる。キーを0から始まる通し番号にでもしてキー自体を更に別のコレクションで管理すれば、疑似的なインデックスとして入手順にアイテムの個別インスタンスにアクセスすることも可能。(SortedDictionaryとどっちが早いかは未検証)

11 :名前は開発中のものです。:2023/09/01(金) 18:09:01.68 ID:jPfSgGL6.net
コンストラクタに渡して〜って言ったけどコードにコンストラクタ含めてなかったわ
自分のプロジェクトではもうちゃんと実装しているからセーフ(適当)

12 :名前は開発中のものです。:2023/09/02(土) 21:04:00.56 ID:zmatsJxn.net
その4をまとめられるほど学習が進まなかったわ
デザイン方向と機能案に時間を多く割いた結果、有名アセットとしてFinalIKを購入してデモを見て使い方をほんの少し覚えるだけで終わった

FinalIKそのものの話ではないけど、FinalIKは昔はアニメーション時にイベントを発生させる方法がSendMessageしか用意されていなかったっぽいのね(古いデモ動画見たらこれしかインスペクターに映ってなかった)
今はUnityEventにも対応しているので基本的にこっちを使うことになりそう
そもそもUnityにイベントを発生させる方法って何があるの?って再度調べてみると、現在ではUnityEventとC#Eventの二つが主流っぽい?
他にもSendMessageやBroadCastMessageというイベント発生機能も用意されているが、パフォーマンス面や管理のコストの問題を指摘する記事が多い印象(ゲームオブジェクト全体にイベントを送信してしまうため重い、関数を名前で指定するからゲームシステムを設計変更したりすると変更漏れとかが生じやすい?)
ちなみにEventSystemが入力情報を経てコールバックを発火するのに使うExecuteEventsもIEventSystemHandlerを実装するコンポーネントの関数をコールするものらしいので実はイベント発生に利用できるらしい(使う必要性があるかは知らない)

13 :名前は開発中のものです。:2023/09/03(日) 22:10:58.50 ID:OCQOviyY.net
今日は独自のスクロールビューとスクロールバーをより汎用的に使えるようにコードの調整を始めた
今のコードではスクロール自体のクラスとスクロールにコンテンツを渡すクラスが密接に結びついているので、その繋がりを弱めていきたい
そこで方法を調べてみると、抽象クラスやインターフェースを利用する方法があるらしい
実は前にも抽象クラスとインターフェースについて購入したアセット素材を解読するために調べたことがあったが、正直その頃は「実装が持てない」以外のことがよく分からなかった
自分で抽象クラス・インターフェースを使ってみようと調べ直した結果、前よりは理解ができたので、ひとまずコードが少なくて調整が楽そうな独自スクロールバーにこの二つを実装してみて、ビューとバーの繋がりを弱めてみた

その4 抽象クラスとインターフェースについて
抽象クラスもインターフェースも、これを継承したクラスに対して自身が要求する関数などメンバーを実装するように強制させる機能を有する。
他の類似点としては、両方ともインスタンスを生成することができない。抽象クラスはMonoBehaviourを継承していてもゲームオブジェクトにアタッチすることができない(エディタ上で警告文が出てアタッチ処理自体が行われない)。
逆にこの二つの違いは、
@抽象クラスは(C#では多重継承が不可能であるため)直接的には1個しか継承できないが、インターフェースは2個以上を継承することができる
A抽象クラスはフィールドを持つことができるが、インターフェースは持てない
B抽象クラスや実装のある(中身のある)関数等を持つができるため、普通の基底クラスとしても利用できる。インターフェースは持てないっぽい?(実はデフォルト実装という機能があるらしいが、C#の新しい機能だそうでUnityで対応しているかよく調べてない。しかも今のところあまり利用が推奨されないらしい)
C抽象クラスの抽象メソッドはアクセス修飾子はpublic又はprotectedでなければならない。protected(自身と派生クラスのみアクセス可能)が許されている点から抽象クラスはクラスの内部向けルールを定める性質が強い。一方でインターフェースのメンバーはpublicに限定される。インターフェースはInter + Faceの語源通りクラスの外部向けルールを定める性質が強い

14 :名前は開発中のものです。:2023/09/03(日) 22:30:09.73 ID:OCQOviyY.net
今回は、インターフェースの「他のクラスのメンバーにアクセスしたいとき、そのクラスがインターフェースを実装していることさえ分かっていれば、クラス内の細かい実装を知る必要がない」という利点を体感することができた
他のクラスへの参照をインターフェースの型で取得することで、そのクラスがどんなクラスであってもそのインターフェースの実装たるメンバには確実にアクセスすることができるようになるのだ(もちろんメンバで滅茶苦茶な内容が実装されている可能性はある。ここはコードを書く人の良心任せ)
自分のプロジェクトでは独自のスクロールビューとスクロールバーを利用しているが、このうち「スクロールビューからスクロールバーに数値を渡す関数」をインターフェースの実装とすることで、スクロールバーは独自スクロールビューがどんなクラスでも数値を受け取れるようになった(今後用途に応じてスクロールビュークラスを拡張や派生させても、スクロールバークラスをその都度修正する必要がなくなった)
ちなみにスクロールビュークラス側には、今後の拡張に備えて抽象クラスを作成してその抽象クラス内でインターフェースを抽象メンバとして実装したのだが、この辺は自分でもどういう利点があるのかまだ理解しきれてないのでまた今度

15 :名前は開発中のものです。:2023/09/04(月) 22:59:12.23 ID:8vO4bi2+.net
書こうと思ったけどTMP・文字列・GCの復習をしていたら時間がなくなったから今日は終わり!

16 :名前は開発中のものです。:2023/09/04(月) 23:14:20.64 ID:DD6FCi8L.net
てかUnityというより
C#の仕様

17 :名前は開発中のものです。:2023/09/05(火) 22:27:53.86 ID:1xAiAK3x.net
いまシステム面とUIを重点的に作ってるからどうしてもC#寄りになるね

その5はまとめられてないからUnityのマジックメソッドについて少し
StartやUpdateといったUnity独自の関数はランタイムによってゲーム実行時
(?)だったかに呼び出しリストが作成される
Unityの内部クラスが呼んでる訳ではないのでこれらのマジックメソッドはprivateでも呼び出しが行われる
逆にこれが原因なのか、通常の関数より呼び出しコストが高い
Update100個より1個のUpdateが100個の独自アプデ関数呼ぶ方がコール回数が1回多いはずなのに動作が軽いのは有名な話(らしい)

加えてawake OnEnable startの呼び出し順には多少注意が必要かもしれない
具体的にはStartよりOnEnableの方が早いので、Startで外部参照の設定するコードを書いてると先にOnEnableが呼ばれてヌルリファだったり意図しない挙動が起きがち
メニュー画面などのUI要素をGameObject.SetActiveで有効無効を切り替えてその際にOnEnable/OnDisableで初期化や再設定を行う設計を採っている時は扱いに注意(n敗)
ちなみにアセットのサンプル見てたら、OnEnableでコルーチン呼んで1f待機することで先に確実にStartを通す設計をしているものが見つかった
無理やりな気もするけどどうなんだろうね

18 :名前は開発中のものです。:2023/09/05(火) 22:33:42.70 ID:Ts+LtVa/.net
UIやってるなら今ならちょうど

ユニティ・テクノロジーズ・ジャパンは、日本語の電子書籍『Unityにおけるユーザーインターフェースのデザインと実装』を無料で提供。専用ページから申し込めばダウンロードできるようになりました

てことで無料で見られるよ
Startを1frame待つのは理にかなってるんじゃないかな
Start関数は画面表示前の処理だし、1frameということは表示してからだから
確実だよね

19 :名前は開発中のものです。:2023/09/05(火) 22:42:05.64 ID:JlRpf2nJ.net
>>18
マジか
良いこと聞いた

20 :名前は開発中のものです。:2023/09/06(水) 22:29:47.35 ID:xeaBYfjk.net
>>18
情報サンクス
早速ダウンロードしてみたわ
UIToolKitはまだ全く手付かずだからどういうものか早く勉強しないとなあ

サンプルシーンで1f待ってるのはStartじゃなくてOnEnableね
そのサンプルはアイテム管理システムで、マネージャークラスがOnEnableでコルーチンで1f待機している間に、ゲーム開始後に道具メニューを開いた時に初めて生成されるアイテム表示用プレハブたちがStartで参照情報をマネージャーに渡してくる設計になっていた
マネージャーのOnEnableでプレハブの描画更新とイベントへのデリゲートの登録をやってるので、仮に1f待機がないとプレハブが生成される最初の1回目だけ参照情報をまだ受け取っておらずヌルリファが発生するからだと思われる


その5 「抽象クラスの個人開発における利点がよく分からない」
まとめというより疑問に近い。
抽象クラスのメリットを調べると、大抵のサイトや記事では「抽象化によって複数人の開発で統一が取れたコードが作成できる」といった内容が挙げられている。では、個人開発における抽象クラスの利点は何なのだろうか。
結論から言うと調べても自分にはあまり理解できなかった。「無い」や「殆ど無い」としている記事も散見される。
というのも、単に複数のクラスで共通したルールを実装したいなら純粋に基底クラスを継承して利用すればだいたい足りる気がする。
たしかに抽象クラスで関数の名称やシグネチャなどを設定して派生クラスにそれに沿った実装を強制するのは、コードの統一性を確保する上では有用ではあるが、個人開発だとコードを弄るのは基本的に自分だけなので、自分で注意すればよくない?という気も
まあC#に限らずヒューマンエラーを防げます系機能は究極的には全部「自分で注意すりゃよくない?」になるし、もちろん自分にそんな神みたいなこと無理なんで…(OnEnableとStartで何回もエラー引き起こす程の低い注意力)
自分としては抽象クラスは「インスタンスは絶対これで生成しないけど共通・統一された処理を実装したい」ケースでお守り的に使っていこうかなと思った(適当)

21 :名前は開発中のものです。:2023/09/07(木) 23:01:59.92 ID:zzCLMbJH.net
眠いから雑なぼやき

シングルトンを初めて自分のゲームに導入してみた。理由はどういうものか使ってみたかったから。
戦闘システム管理クラスをシングルトンにした。戦闘キャラクラスからたくさんアクセスする。
これが密結合か?
グローバル変数化を目的として作っちゃいけないという話は聞いたことあるけど、これもその一つかもしれない。
この辺のコード作成のパターンの理念について何も知らないからそろそろ勉強するときかなあ

22 :名前は開発中のものです。:2023/09/08(金) 22:50:45.01 ID:whCfvpks.net
GCalloc(ヒープメモリアロケーション)にまとめたいけどまだ理解が足りていない
今日は有料アセットのGCalloc潰しを中心に作業をしたが、フィールドのList<構造体>をSortする箇所でアロケーションが発生する理由がイマイチよく分からなかった
引数としてデリゲートを渡すとアロケーションが発生するのはその都度コンパイラがnewしてしまうからで、「デリゲートの代わりにメンバを参照しないラムダ式を利用する」と初回のみのアロケーションで済むらしい
実際ラムダ式に変えたら毎フレームのGCallocが消えたのだが、「IComparerを実装したクラスのインスタンスを利用する」という方法もあると聞き、こちらも試してみたところGCallocは消えないどころか増えた
なんかボックス化というものが絡んでいるような気もするがよく分からないので今日はこれで終わり

23 :名前は開発中のものです。:2023/09/09(土) 23:03:59.62 ID:DhDPacVH.net
GCalloc潰し二日目
昨日IComparerでGCallocが防止出来なかった理由については未だに分かっていない(というか殆ど調べていない)
「ラムダ式でメンバを参照する」コードを複数の有料アセットで見かける
GCalloc対策の話題でまず槍玉に上がる点だと思うのだが、あまり気にされていない・自分が気にしすぎなのだろうか?

24 :名前は開発中のものです。:2023/09/09(土) 23:10:00.18 ID:O6P9FobY.net
えーと
研究者なら気にしてもいいかと
アプリ開発するなら今のハード考えると気にし過ぎじゃね
てか気にする必要ないでしょ

25 :名前は開発中のものです。:2023/09/09(土) 23:34:12.06 ID:DhDPacVH.net
>>24
やっぱり気にし過ぎかなあ
特に今作っているゲームはPC向けだから尚更処理落ちやクラッシュはし辛いだろうし
一応自分でコード書く時はアロケーションは基本的に避けるようにしてるけど、有料アセットまで潰して回る必要はないか

26 :名前は開発中のものです。:2023/09/09(土) 23:46:32.90 ID:tG9qh3d0.net
ガベージコレクションなんかC#の基本なんだから気にしなくていいだろ
そんなに嫌ならBurstCompilerでもJobSystemでもECSでも使えば良い

27 :名前は開発中のものです。:2023/09/10(日) 00:04:42.69 ID:u9L0A1tk.net
結構規模の大きいものを作ってるから可能な限り潰しておきたい感はあるのよね
数時間のプレイに堪えられるような設計にしたい

28 :名前は開発中のものです。:2023/09/10(日) 00:11:59.35 ID:nCKHuG8g.net
>>27
ECS,BurstCompiler使えよ

29 :名前は開発中のものです。:2023/09/10(日) 09:03:38.32 ID:hFRQptHY.net
>>23
かける労力と得られるものが釣り合ってると思えるならそれぞれの判断でいいと思うけどね
今自分の作ってるやつはインクリメンタルGCついてても数分に一回3~7msくらいのGC Collectが発生してて
シューティングゲームなんでもう少しGCAlloc潰したほうがいいだろうなと思ってる

30 :名前は開発中のものです。:2023/09/10(日) 15:42:12.07 ID:j4PqFMUR.net
あかん、行こう

31 :名前は開発中のものです。:2023/09/10(日) 21:59:14.98 ID:u9L0A1tk.net
>>28
ECSは全然理解してないし有料アセットとの兼ね合いが悪い(自分で調整できない/作業量多すぎ)だから導入するつもりは現状ないかなあ
アセット開発者がDiscordで今からECS対応は難しいって言っているのも見かけたし

>>29
どういうコードがGCalloc発生するのか自分で見て覚えていきたいってのもあるし、しばらくは続けようかな
シューティングゲームって弾幕GameObjectのinitialize/Destroyやオブジェクトプール行き来のDisable/Enableで最適化が大変そうだなあ
差し支えなければ教えてほしいんだけど重い処理を行っている時ってフレーム毎にどのくらいGCalloc発生してますか?

>>30
?

今日はNPC(アセットのコンポーネント)のUpdate30個をOnUpdateに変えるお試し軽量化をしてみた
0.5msぐらいの改善が見られた 他にも自分のゲームに使用しない無駄な機能がついていたりするから削っていこう
アセットに更新があった時に面倒だが、勉強道具にしたり自分で色々と改造したりできるから完全なC#コードが提供されているものは便利(DLLで提供されているものがあるか知らんけど)

アセットとC#の話で一つ複雑だなと思うのは、AssemblyDefinitionによってアセンブリが定義・分割されているとアセット側からこちらの自作コードにそのままではアクセスできない点。コード弄り始めた頃は原因が分からなくて四苦八苦した。
自作コードにAssemblyDefinitionsを設定していない場合は自動的にAssembly-Csharpに配置されるが、このAssembly-Csharpと他アセンブリのアクセスは一方通行の関係にある。すなわち、Assembly-Csharpから他アセンブリにはアクセスできるが、他アセンブリからAssembly-Csharpにアクセスすることはできない。
なので自分のコードに弄ったアセット側からアクセスしたい場合は、自分のコードをアセンブリ定義・分割して参照設定を追加するか、自分のコードをアセット側のアセンブリ内に入れる必要がある。
まあむしろアセットでアセンブリ定義・分割されてない方が色々と問題らしいので自分の経験は初心者特有の躓きって感じだな

32 :名前は開発中のものです。:2023/09/10(日) 22:01:38.99 ID:pyk4erDp.net
ところでヌシはタイトルには初心者って書いてるけど
所持がガベージとか気にしないよね?

ナニモン?

33 :名前は開発中のものです。:2023/09/10(日) 22:01:57.78 ID:pyk4erDp.net
所持ちゃう、初心者

60 KB
新着レスの表示

掲示板に戻る 全部 前100 次100 最新50
名前: E-mail (省略可) :

read.cgi ver.24052200