山傘のプログラミング勉強日記

プログラミングに関する日記とどうでもよい雑記からなるブログです。

Unityでボウリングを作る その4

久しぶりの更新

久しぶりのブログの更新ですが、進捗があまりなかったのでお休みしていました。

今回で一旦、ボウリングの作成は中止したいと思います。Javaの勉強やUnityのチュートリアルをやろうと思います。

ボウリング

今回の進捗

二投目の処理を追加しました。

それとクラスをいじって変な感じになりました。

動画

youtu.be

激やばコード

public class GameManager : MonoBehaviour {

    public enum GameState {
        Initialize,
        Play,
        Result,
    }

    public static GameState gameState = GameState.Play;
    
    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        if(gameState == GameState.Initialize) {

        }else if(gameState == GameState.Play) {
            
        }else if(gameState == GameState.Result) {

        }
    }
}

public class PlayManager : MonoBehaviour {
    public enum TurnState {
        First,
        Second,
    }
    public enum BallState {
        Ready,
        Unready,
    }
    public enum PinState {
        Ready,
        Unready,
    }
    public static TurnState turnState = TurnState.First;
    public static BallState ballState = BallState.Unready;
    public static PinState pinState = PinState.Unready;
    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    /*
   void Update () {
       if(GameManager.gameState == GameManager.GameState.Play 
            && ballState == BallState.Unready) {
            if(turnState == TurnState.First) {
                ballState = BallState.Ready;
            } else if(turnState == TurnState.Second){
                ballState = BallState.Ready;
            }
        }
   }
    */

}

public class PinManager : MonoBehaviour {
    
    public GameObject pinPrefab;
    private GameObject[] pin = new GameObject[10];
    private Vector3[] pinPos = new Vector3[10];
    private static bool[] pinFlag = new bool[10];
    private PIN_STATE[] pinState = new PIN_STATE[10];
    private enum PIN_STATE {
        IN,
        OUT,
    }
    private void Start() {
        InitPin();
        //Debug.Log("------");
    }
    private void Update() {
        if(GameManager.gameState == GameManager.GameState.Play) {
            if(PlayManager.pinState == PlayManager.PinState.Unready) {
                if (PlayManager.turnState == PlayManager.TurnState.First) {
                    DestroyAllPin();
                    Invoke("InitPin", 3.5f);
                    //InitPin();
                    PlayManager.pinState = PlayManager.PinState.Ready;
                } else if (PlayManager.turnState == PlayManager.TurnState.Second) {
                    
                    Invoke("UpdatePin", 3.5f);
                    Invoke("ArrangePin", 3.5f);
                    //ArrangePin();
                    PlayManager.pinState = PlayManager.PinState.Ready;
                }

            }
            if (PlayManager.pinState == PlayManager.PinState.Ready) {
                Invoke("UpdatePin", 3.5f);
            }
            //UpdatePin();
        }
    }
    // 一投目のときのピンの配置
    public void InitPin() {
        InitPinFlag();
        InitPinPosition();
        for (int i = 0; i < 10; i++) {
            pin[i] = Instantiate(pinPrefab);
            pin[i].transform.position = pinPos[i];
        }
    }
    // 二投目のときのピンの配置
    public void ArrangePin() {
        for(int i = 0; i < 10; i++) {
            if(pinFlag[i] == true) {
                pin[i].transform.position = pinPos[i];
            }
        }
    }
    public void UpdatePin() {
        CheckPin();
        DestroyPin();
    }

    // ピンの生存フラグの初期化
    void InitPinFlag() {
        for (int i = 0; i < 10; i++) {
            pinFlag[i] = true;
        }
    }
    void InitPinFlagFalse() {
        for (int i = 0; i < 10; i++) {
            pinFlag[i] = false;
        }
    }
    // ピンの初期位置の配列を初期化する
    void InitPinPosition() {
        float dist = 1f;
        // 1番ピンの位置
        pinPos[0] = new Vector3(1.4f, 3.0f, 12.65f);
        for (int i = 1; i < 10; i++) {
            if (i == 1) {
                Vector3 p = pinPos[0];
                pinPos[i] = new Vector3(p.x - dist, p.y, p.z + 2 * dist);
            } else if (i == 3) {
                Vector3 p = pinPos[1];
                pinPos[i] = new Vector3(p.x - dist, p.y, p.z + 2 * dist);
            } else if (i == 6) {
                Vector3 p = pinPos[3];
                pinPos[i] = new Vector3(p.x - dist, p.y, p.z + 2 * dist);
            } else {
                Vector3 p = pinPos[i - 1];
                pinPos[i] = new Vector3(p.x + 2 * dist, p.y, p.z);
            }
        }
    }
    // 全てのピンを消滅させる
    void DestroyAllPin() {
        for(int i = 0; i < 10; i++) {
            if(pinFlag[i] == true) {
                Destroy(pin[i]);
                pinFlag[i] = false;
            }
        }
    }
    // ピンが外に出たときに消滅させる
    void DestroyPin() {
        for (int i = 0; i < 10; i++) {
            if (pinFlag[i] == true) {
                if (pin[i].transform.position.y < -5.0f) {
                    Destroy(pin[i]);
                    pinFlag[i] = false;
                    pinState[i] = PIN_STATE.OUT;
                }
            }
        }
    }
    // 倒れた又は場外に出たピンのフラグの管理
    void CheckPin() {
        for (int i = 0; i < 10; i++) {
            if (pinFlag[i] == true) {
                if (pin[i].transform.position.y < 2.0f) {
                    pinFlag[i] = false;
                    StartCoroutine(DelayDestroy(i));
                    //Destroy(pin[i]);
                }
            }
        }
    }
    IEnumerator DelayDestroy(int i) {
        yield return new WaitForSeconds(3.0f);
        Destroy(pin[i]);
    }
    // 倒したピンの数
    public static int CountPin() {
        int ret = 0;
        for (int i = 0; i < 10; i++) {
            if (pinFlag[i] == false) {
                ret++;
            }
        }
        return ret;
    }
}

public class BallManager : MonoBehaviour {

    public GameObject ballPrefab;
    private GameObject ball;
 
    // speedを制御する
    public float speed = 10;
    
    void InitBall() {
        ball = Instantiate(ballPrefab);
        ball.transform.position = new Vector3(1.18f, 3.0f, -26.26f);
    }
    private void FixedUpdate() {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        // 同一のGameObjectが持つRigidbodyコンポーネントを取得
        if (ball != null) {
            Rigidbody rigidbody = ball.GetComponent<Rigidbody>();
            // rigidbodyのx軸(横)とz軸(奥)に力を加える
            rigidbody.AddForce(speed * x, 0, speed * z);

            if (ball.transform.position.y < -5.0f) {
                Destroy(ball);
                PlayManager.ballState = PlayManager.BallState.Unready;
                PlayManager.pinState = PlayManager.PinState.Unready;
                if(PinManager.CountPin() != 10) {
                    PlayManager.turnState = PlayManager.TurnState.Second;
                } else {
                    PlayManager.turnState = PlayManager.TurnState.First;
                }
            }
        }
        if(PlayManager.ballState == PlayManager.BallState.Unready) {
            InitBall();
            PlayManager.ballState = PlayManager.BallState.Ready;
        }
        if (Input.GetKey(KeyCode.Space)) {
            Destroy(ball);
            PlayManager.ballState = PlayManager.BallState.Unready;
            InitBall();
        }
    }
}

public class ControlScore : MonoBehaviour {
    public GameObject score;
    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        int cnt = PinManager.CountPin();
        score.GetComponent<TextMesh>().text = cnt.ToString();
    }
}

感想

他の所でクラスを色々いじっていたのですが、上手いこといかなかったので、なかなか進みませんでした。

UMLを使ってきちんと設計した方が良いとおもうので、そういった勉強もしようと思います。

ゲームは状態を管理して作っていくものだと思うんですが、その部分がうまく表現できていないですね。それと、Update()メソッドのような周期的に実行する処理が絡み合うのが難しいと感じています。

Unityはコンポーネント指向でMonoBehaviourクラスでは新たにインスタンスを生成しないという決まりがあるようですね。これもしっくりきていないですね。

なので、いったんチュートリアルに戻って写経をするところから始めようと思います。