4
5

More than 5 years have passed since last update.

unityでオブジェクト指向な作り方ってなんなの\(^o^)/ その2.5(GameChara,SpaceShipクラスの修正)

Last updated at Posted at 2016-09-30

概要

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

unityでオブジェクト指向な作り方ってなんなの\(^o^)/ その2

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

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

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

クラスの修正

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 () {

    }
}

これも(ry

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

まとめ(感想と次回に向けて)

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

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

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

4
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5