unityでオブジェクト指向な作り方ってなんなの＼(^o^)／　その２.５（GameChara,SpaceShipクラスの修正）

# 概要

前回、unity公式チュートリアルの2Dシューティングゲームの第四回でSpaceshipクラスを作り、それを自分なりにGameCharaクラスを継承してそれっぽいオブジェクト指向な作りにしました。

[unityでオブジェクト指向な作り方ってなんなの＼(^o^)／　その２](http://qiita.com/hypxyosukephl/items/36305c62c1f907111d29)

しかし、継承を意識したせいでunityの本来の特性を生かした、コンポーネントの作成ができておりませんでした。
その後、@mizoguche さんから
「継承による差分プログラミングをするよりも、ひとつのGameObjectに複数の(小さめの)MonoBehaviourをアタッチする方が、再利用しやすく、保守性が高くなる」

というアドバイスをいただき、さらにオブジェクト指向設計についての参考サイトや、今まで作ったクラスの参考例等、様々な助言をいただきました！（本当にありがとうございます！）

そのため、一旦自分のスクリプトを整理しようと思い、その３というよりも復習で２.５にしました。


## クラスの修正

### MoveObjectクラス（GameCharaクラスから名前変更）

```csharp.MoveObject.cs

using UnityEngine;

[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(SpriteRenderer))]
public class MoveObject : MonoBehaviour {
	[SerializeField]
	public float x_speed;
	[SerializeField]
	public float y_speed;

	public float speed;

	// Use this for initialization
	void Start () {
	
	}

	// Update is called once per frame
	void Update () {
	
	}

	public void Move(Vector2 direction){
		direction.Set (direction.x * x_speed, direction.y * y_speed);
		GetComponent<Rigidbody2D> ().velocity = direction;
	}
}
```

あくまでもキャラが動くだけのコンポーネントとして使うクラスです。
x_speedとy_speedをなるべくクラス内で完結するように、Move関数を変更しました。
Vector2クラスのSet関数を使ってますが、もっとマシな書き方ありそう…

### 変更後のSpaceshipクラス

```csharp.Spaceship.cs
using UnityEngine;
using System.Collections;

public class SpaceShip : MonoBehaviour {

	//弾の発射間隔
	public float shotDelay;
	//弾を打てるか
	public bool canShot;
	//次の弾の
	private bool isRunning = false;

	public GameObject bulletPrefab;

	public GameObject explosionPrefab;

	public IEnumerator Shot(Transform origin){
		//弾を打てるか
		if (!canShot)
			yield break;
		//弾の発射準備中か
		if (isRunning)
			yield break;
		isRunning = true;
		Instantiate (bulletPrefab, origin.position, origin.rotation);
		yield return new WaitForSeconds(shotDelay);
		isRunning = false;
	}
}

```

ここもあまり変更がないですが、Shot関数をpublicにしました。

### 変更後のプレイヤークラス

```csharp.Player.cs

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MoveObject))]
[RequireComponent(typeof(SpaceShip))]
public class Player : MonoBehaviour {

	private MoveObject moveObject;
	private SpaceShip spaceShip;

	void Awake() {
		moveObject = GetComponent<MoveObject> ();
		spaceShip = GetComponent<SpaceShip> ();
	}

	// Use this for initialization
	void Start () {
		
	}

	// Update is called once per frame
	void Update () {
		float x = Input.GetAxisRaw ("Horizontal");

		float y = Input.GetAxisRaw ("Vertical");
		//移動する向きを求める
		Vector2 direction = new Vector2 (x, y);

		moveObject.Move (direction);

		if (Input.GetKey (KeyCode.Z)) {
			//プレイヤーと同じ位置/角度で発射
			StartCoroutine(spaceShip.Shot(transform));
		}
	}
}

```

こちらはしっかりコンポーネントを使うような形にしました。

### 変更後の敵クラス

```csharp.Enemy.cs

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MoveObject))]
[RequireComponent(typeof(SpaceShip))]
public class Enemy : MonoBehaviour {

	private MoveObject moveObject;
	private SpaceShip spaceShip;

	void Awake() {
		moveObject = GetComponent<MoveObject> ();
		spaceShip = GetComponent<SpaceShip> ();
	}

	// Use this for initialization
	void Start () {
	
	}

	// Update is called once per frame
	void Update () {
		Vector2 direction = new Vector2 (1, 1);
		moveObject.Move (direction);
		StartCoroutine(spaceShip.Shot(transform));
	}
}
```

これもプレイヤークラスと同じような形になりました。


### 変更後の弾クラス

```csharp.Bullet.cs

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MoveObject))]
public class Bullet : MonoBehaviour {

	private MoveObject moveObject;

	void Awake() {
		moveObject = GetComponent<MoveObject> ();
	}

	// Use this for initialization
	void Start () {
		Vector2 direction = new Vector2 (1, 1);
		moveObject.Move (direction);
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

```

これも（ｒｙ

スクリプトを修正した後、プレハブやスクリプトをアタッチし直して、挙動が変わらずに動かすことが出来ました。

# まとめ（感想と次回に向けて）
まだ初期段階にアドバイスをもらえたのが幸いで、比較的楽に修正が出来ました！
修正してて感じたこととしては、細かくアタッチしていくとそれはそれで覚えきれなくなりそう…？とも思ったのですが、その辺はバランスなのでしょうか？
でも確実に一つ一つコンポーネントを切り離して考えることはできるので、それは良いですね。（動くクラスとか弾を撃つクラスとか）

次回はようやく当たり判定ですが、これは動く物体として扱うとなるとMoveObjectクラスに書こうかなーと思っているところです。

この回は以上です。
この時点でアドバイスがあればお願い致します！