9.4K Views
May 08, 24
スライド概要
以下イベントで使用した資料です。
Unreal Engine Meetup in Osaka Vol.02
https://indie-us-games.connpass.com/event/312840/
Blueprintを読みやすくする技術
自己紹介 • 上谷 • UE歴 • UE4は結構使った • UE5はぷちコンで使うくらい • 経歴 • 2017年入社のプログラマ(今年で8年目)
注意 • なにかしら表に出ている物の開発事例とかではないです。 (期待していた方がおられましたらすみません) • 登壇者がプライベートでゲームを作る際に、プロジェクトメン バーにBPを教える機会が多く、そのドキュメントを基に本スラ イドを作成しています。
なにを話するの?
なにを話するの? 今回のセッションでは アンリアルエンジンの機能であるBlueprintを扱う際において、 書いた処理の内容を読みやすくするために、 簡単に実践できる内容を共有出来たらと思います。
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
「読みやすい」って何? どのようないいことがあるの?
「読みやすい」って何? どのようないいことがあるの? • メンバー間でコードを理解する時間が短縮され、 実質的に開発速度の向上になる。
「読みやすい」って何? どのようないいことがあるの? • メンバー間でコードを理解する時間が短縮され、 実質的に開発速度の向上になる。 • バグの早期発見がしやすくなり、メンテナンス性が向上する。
「読みやすい」って何? どのようないいことがあるの? • メンバー間でコードを理解する時間が短縮され、 実質的に開発速度の向上になる。 • バグの早期発見がしやすくなり、メンテナンス性が向上する。 • 見る人の精神が安定する。
読みやすい処理について
読みやすい処理について 読みやすい処理に必要な要素 「一個の処理や変数の役割が他人から見ても明確なこと」 「使用者を驚かせないこと」 「処理の意図が外部から見てもわかるようにすること」
読みやすい処理について 一個の処理や変数の役割が他人から見ても明確なこと
読みやすい処理について 一個の処理や変数の役割が他人から見ても明確なこと 関数や変数の名前がないと 何をしているのかがわからない。
読みやすい処理について 一個の処理や変数の役割が他人から見ても明確なこと 抽象的な名前もよくない!
読みやすい処理について 使用者を驚かせないこと
読みやすい処理について 使用者を驚かせないこと これはどのような動作をする 関数だと思いますか?
読みやすい処理について 使用者を驚かせないこと 中身を見てみると、座標移動以外も色々処理されていた...(驚)
読みやすい処理について 使用者を驚かせないこと • 「関数や変数の名前で示していること以外を行わない」
読みやすい処理について 「なぜこのような処理を書いたのか」がわかるようにす ること
読みやすい処理について 「なぜこのような処理を書いたのか」がわかるようにす ること 生まれた頃から削除が確定している場合 「TODO」という表記をして削除される ことを明示的にするとよい。
読みやすい処理について 読みやすい処理に必要な要素 「一個の処理や変数の役割が他人から見ても明確なこと」 「使用者を驚かせないこと」 「処理の意図が外部から見てもわかるようにすること」
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
「ベタ書き」とは?
ベタ書きすることについて ベタ書きの利点
ベタ書きすることについて ベタ書きの利点 実装速度が速い
ベタ書きすることについて こうゆう場面ならやってもいいと思います(個人的感想) 「対話中などで即興で実装を書くとき」 「読み返す必要がなく、対応を急がないといけない場合」 「機能検証用などで、そもそも読み返す想定がない場合」 「一人で開発するとき」
重複処理をまとめよう • 重複処理とは? • 単純に意味が同じで処理の内容も同じ処理のこと • なぜ重複処理はだめ? • 処理が間違っていた場合に直す手間が増える。 • “特に“作業中に処理をコピペした場合 それが関数化できないか検討しましょう。
重複処理をまとめよう 具体例
重複処理をまとめよう あるプログラマーが、 このように非ダメージ時に HPを減らす処理が二つ実装しました。 ところがある日、防御力の概念が入り、 処理に追加の実装が必要になりました。
重複処理をまとめよう 実装しました。完璧ですね。 ところが、ある日のこと、 またまた追加実装が入りました。 今度はダメージのバリエーションが 追加で25パターンほど増えることになる とのことでした。
重複処理をまとめよう
重複処理をまとめよう さてさてこれでひと段落。。。 と思っていたところ、問題が発生しました。 防御力が高いキャラがダメージを受けると、 回復するというバグが報告されたとのことです。
重複処理をまとめよう もう一度、 HP減算の処理を見てみましょう。 ・・・なるほど。 問題はすぐにわかりました。
重複処理をまとめよう 原因は、このように、 防御力が被ダメの値より大きかった場合、 HPが回復する計算になっていました。 これなら修正は簡単だと思い、 プログラマーは計算の修正を行います。 (20) HP – (-10) 10 – (20) = -10
重複処理をまとめよう これで攻撃時に受ける被ダメージの 処理の修正が終わりました。 完璧ですね。 あとは24個、同じ修正を行うだけです。
重複処理をまとめよう どれだけ小さい処理だったとしても、 コピペするなら関数化できないか検討
重複処理をまとめよう このように別イベントに白ノードを伸ばす場合も関数化を検討
処理を要約できる部分で関数化 処理の区切りごとに関数化できないか検討 • 再利用可能な物、複雑な処理など たとえば・・・ プレイヤーがアイテムを拾ったとき、 得点を更新する処理が複数の場所で必要だとします。 あるプログラマーは、前回の重複処理の経験から、 この処理をUpdateScoreという関数に抽象化し、 アイテムの種類や得点をパラメータとして渡すことで、 どこからでも再利用できるようにしました...
処理を要約できる部分で関数化 実際に出来上がった関数がこちら
処理を要約できる部分で関数化 要望対応したものがこちら
処理を要約できる部分で関数化 処理の区切りごとにコメントで分けてみた物
処理を要約できる部分で関数化 関数化したものがこちら
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
変数と関数の名前について • 変数や関数の命名は Blueprintを使った開発で非常に重要となる要素です。 • なぜなら、適切な命名は処理の読みやすさに直結し、 保守性を大きく向上させるものとなるためです。
名前は明確でシンプルに • 変数や関数の名前は、それが何を表しているのか、 または何をするのかを一目で理解できるようにしましょう。 • 明確でシンプルな名前は、コードを読む際の混乱を避け、他の メンバーがコードを理解しやすくします。 • 単語の省略も極力減らした方がいいこともあります
名前は明確でシンプルに • アイテムの数をカウントする変数 • 良い例:ItemCount • 推奨しない例:Count
状態を示すbool型変数や関数の命名 • Is(状態や条件を示す) • 使用例: IsVisible, IsEnabled, IsValid • Can(許可を示す) • 使用例: CanAttack, CanEdit, CanSave • Has(所有や存在を示す) • 使用例: HasLicense, HasChildren, HasWeapon
ここまでのまとめ • 処理の読みやすさと重要性 • べた書きすると読みにくくなりやすい • コピペをした場合は関数化できないか検討 • 読みやすいと読み手の精神が安定する • 具体的な命名について • 単語はなるべく省略しない • 判定関数や変数の場合はIs、Can、Hasなどを使用する
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
マクロは必ず出力を返すようにしよう マクロは関数と異なり、出力を返さないことができますが、 使用者側から見ると判別がつきづらい物となるので注意が必要
マクロは必ず出力を返すようにしよう
マクロは必ず出力を返すようにしよう
マクロは必ず出力を返すようにしよう
マクロは必ず出力を返すようにしよう 実行ピンはマクロの詳細パネルから アウトプットの変数のピンタイプを 「実行」にすると増やせます。
関数内部はできるだけシンプルに • なるべく1つの意味に絞って処理をまとめましょう。 • 可能であれば1つの関数につき5つ以内のノードだと 内容も把握しやすいものになりやすいです。
判定関数や取得関数は内部を変更しない • 判定関数とは? • Is~、Can~、Has~などの状態を表すだけの関数 • 取得関数とは? • Get~などの値を返すだけの関数 • たとえば: GetName、GetPlayerController このような関数はやめてほしい…
判定関数や取得関数は内部を変更しない 早い話・・・ 判定関数や取得関数は詳細パネルで const のチェックを付けてください。 これを付けることでメンバーの変更が 行われていた場合はエラーになります。
判定関数や取得関数は内部を変更しない
変数もconstを付けられる 詳細パネルから 「ブループリント読み取り専用」で 変数も同様に変更できなくなる。 不変値などがあるならば、 やっておいてもいいと思います。
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
コメントについて • Blueprintを使用する際、 どうしても複雑なロジックを扱わないといけない、 いい感じの関数や変数の名前が思いつかない、 この処理だと読み手に意図が伝わるか不安。 などで悩んだことはありませんか? • その場合コメントが使えるかもしれません。
コメントについて コメントを書く目的としては主に以下3つ 「コードの意図を明確にしたい場合」 「コードでは推し量れない事情を読み手に伝えたい場合」 「複雑なノードの要約として記載したい場合」
コメントについて コードの意図を明確にしたい場合 • 冒頭でもお話していた通り、意図を名前で表現できるならそれ がベストです。 • ただし、いろいろな事情や背景から名前では表現できないよう な処理がでてくることも、稀にあります。 • その場合は補足として、その処理の意図をコメントで残すよう にしてください。
コメントについて コードでは推し量れない事情を読み手に伝えたい場合 • 他の実装との兼ね合いで いびつな処理になった場合 • ROMに向けての暫定対処 消す予定の場合は「TODO: 」を 忘れずに記載しておいてください。
コメントについて 複雑なノードの要約として記載したい場合 このような感じで処理を要約したい場合に使用
コメントで誤解を与えないように • 長く開発を行っていると、コメントの更新漏れなどで 実装とコメントの内容が一致していない物を見ることが たまにあります。 • そのため、コードが変更された場合、 そのコメントも一緒に修正する必要が あるかチェックしましょう。 コメントではプレイヤーの配置処理だけど、 実装はエネミーの配置処理でどっちなん?となる図。
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
線をクロスさせないようにしよう • 多少は仕方ありませんが、不必要にノードの線が重なっている のは非推奨です。 • 関数化することで問題が解消することもあります。
• 「読みやすい」って何? • ベタ書きすることについて • 変数と関数の名前について • マクロと関数について • コメントについて • ノード配置について • コミットログについて
コミットログについて • Blueprintで意図がわからない処理を見かけた場合の手がかりに なるので、コミットメッセージはしっかりと書きましょう。 • 「~BPを更新」や「バグ対応」だけで終わらず、 なぜそのコミットが必要だったのかを明記しましょう。 • なるべく作業単位でコミットしてください。 ログが追いやすいので特定が楽になります。
まとめ • 楽に読みやすくしたいなら関数化するのが一番手っ取り早い • いくつかの名付けには慣習的な物があるので、 UEソースなどで似た物を見つけて真似すれば間違いないです • なるべく読み手に負担のかからないように意識してもらえると、 読む側としてはとても助かり、精神が安定します
さいごに...
さいごに ここまで色々言いましたが、、、 基本的に我々はゲームなどの作品を作っています。 処理が汚かろうが良い作品を作っていればそれが正義です。 プロジェクトの目標とユーザーの満足を常に念頭において、 バランスのとれた開発を心がけましょう。
ご清聴ありがとうございました