質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1639閲覧

UnityとC#の単一責任の原則の学習教材に於ける正しい適用方法がわからない

chawanmushi

総合スコア11

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2022/10/17 07:11

前提

UnityとC#の勉強をしています。
Githubにある、ゲーム開発におけるデザインパターンの学習教材で単一責任の原則を学ぼうと思ったのですが、
単一責任を適用したスクリプトの動作方法がわからず困っています。

実現したいこと

  • 単一責任の原則を適用したコードを動かしたい

発生している問題・エラーメッセージ

元コードの場合はオブジェクトにアタッチすることでオブジェクトが移動するのですが、 そのコードに単一責任の原則を適用したコードの場合は、オブジェクトにアタッチするだけではオブジェクトを動かせない。

該当のソースコード

元のコード

C#

1namespace DesignPatterns.SRP 2{ 3 // Even though this class is short, it violates single-responsibility. 4 // Too many things will cause the class to update, and extending the class will be more difficult. 5 6 public class UnrefactoredPlayer : MonoBehaviour 7 { 8 9 [SerializeField] private string _inputAxisName; 10 11 [SerializeField] private float _positionMultiplier; 12 13 private float _yPosition; 14 15 private AudioSource _bounceSfx; 16 17 private void Start() 18 { 19 _bounceSfx = GetComponent<AudioSource>(); 20 } 21 22 private void Update() 23 { 24 float delta = Input.GetAxis(_inputAxisName) * Time.deltaTime; 25 26 _yPosition = Mathf.Clamp(_yPosition + delta, -1, 1); 27 28 transform.position = new Vector3(transform.position.x, _yPosition * _positionMultiplier, transform.position.z); 29 } 30 31 private void OnTriggerEnter(Collider other) 32 { 33 _bounceSfx.Play(); 34 } 35 } 36 37}

適用したコード

C#

1namespace DesignPatterns.SRP 2{ 3 [RequireComponent(typeof(PlayerAudio), typeof(PlayerInput), typeof(PlayerMovement))] 4 public class Player : MonoBehaviour 5 { 6 [SerializeField] private PlayerAudio playerAudio; 7 [SerializeField] private PlayerInput playerInput; 8 [SerializeField] private PlayerMovement playerMovement; 9 10 private void Start() 11 { 12 playerAudio = GetComponent<PlayerAudio>(); 13 playerInput = GetComponent<PlayerInput>(); 14 playerMovement = GetComponent<PlayerMovement>(); 15 } 16 17 } 18}

C#

1namespace DesignPatterns.SRP 2{ 3 // sample code to demo single-responsibility: 4 public class PlayerInput : MonoBehaviour 5 { 6 [SerializeField] private string inputAxisName; 7 8 private void Update() 9 { 10 float delta = Input.GetAxis(inputAxisName) * Time.deltaTime; 11 } 12 } 13} 14

C#

1namespace DesignPatterns.SRP 2{ 3 // sample code to demo single-responsibility 4 public class PlayerMovement : MonoBehaviour 5 { 6 [SerializeField] private float positionMultiplier; 7 private float yPosition; 8 9 private void Update() 10 { 11 transform.position = new Vector3(transform.position.x, yPosition * positionMultiplier, transform.position.z); 12 yPosition++; 13 } 14 } 15}

試したこと

unity内にてinputAxisNameを設定した。
PlayerでplayerInputを使って入力を受け取り、playerMovementのyPositionに代入して動かそうと思ったが、
yPositionがprivateのため、その動かし方は想定してないと判断。

補足情報(FW/ツールのバージョンなど)

Unity 2021.3.11f1
VisualStudio 2022 17.3.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

教材を見ないと適用後コードの意図が分からないので適当なことしか言えませんが、とりあえず普通にpublicなメソッドとかプロパティを設定しないとどうしようもないと思います。


普通に書けば以下の感じのPlayerクラスだと、いい感じに単一責任原則です。(修正前のコードを見る限り、PlayerはPlayerAudioを知る必要すらありません。)

入力に関する責任も移動に関する責任もPlayer自体は持っていないので簡潔かつ何をやっているのか分かりやすいです。
playerInput.GetInput();はプレイヤーの入力をvector3で返してくれるメソッド、
playerMovement.Move(input)は、入ってきたvector3に沿って移動するメソッドです。

「いや、playerMovement.Move()とかplayerInput.GetInput()とか俺知らねぇんだけど!?」とお思いでしょうが、そこが一番のキモです。
Playerから見たとき、「中で何をやっているか知らないけど、やれって行ったらやってくれることは知ってる」みたいにするのが重要です。

PlayerでplayerInputを使って入力を受け取り、playerMovementのyPositionに代入して動かそうと思ったが、
yPositionがprivateのため

単一責任にするなら、Playerは「playerMovementがyPositionを持っているから、移動するならこいつのyPositionに代入してtransformを動かさないとな」と考えちゃダメです。
それは結局移動のロジックについて、Playerも責任持って関わっていることになるので、単一責任原則ではありません。

C#

1 public class Player : MonoBehaviour 2 { 3 [SerializeField] private PlayerInput playerInput; 4 [SerializeField] private PlayerMovement playerMovement; 5 6 private void Start() 7 { 8 playerInput = GetComponent<PlayerInput>(); 9 playerMovement = GetComponent<PlayerMovement>(); 10 } 11 12 private void Update() 13 { 14 Vector3 input = playerInput.GetInput(); 15 playerMovement.Move(input); 16 } 17 }

投稿2022/10/17 08:15

編集2022/10/17 10:46
UnchFullburst

総合スコア663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chawanmushi

2022/10/17 12:01

Playerクラスをどう書き換えたら単一責任原則に沿った実装を出来るのかが知りたかったため、 それにぴったりな解答が頂けて本当に嬉しいです。 自分が最初に試したことも単一責任原則に反しているとはまだまだ理解できていないんだと認識出来ました。 丁寧な解答をありがとうございました! 非常に勉強になりましたm(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問