作ったゲームのバグを直した話


コインゲッチュ★ユニティちゃん

 
以前公開したこちらのゲーム、公開して暫く経ってからバグ報告を頂きました。
「取ったコインが消えないんだけど?」
と。
 
確認してみました。
using System.Collections;
using UnityEngine;

public class CoinController : MonoBehaviour
{

    private Vector3 posArray;

    private Vector3 pos1 = new Vector3(-6,26,0);
    private Vector3 pos2 = new Vector3(-6,14,0);
    private Vector3 pos3 = new Vector3(-6,4,0);
    private Vector3 pos4 = new Vector3(0,20,0);
    private Vector3 pos5 = new Vector3(0,9,0);
    private Vector3 pos6 = new Vector3(6,26,0);
    private Vector3 pos7 = new Vector3(6,14,0);
    private Vector3 pos8 = new Vector3(6,4,0);

    private Vector3 currentPos;

    public AudioClip getCoin;

    void Start() {
        posArray = new Vector3{pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8};

    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            AudioSourceController.instance.PlayOneShot(getCoin);
            ChangePos();
        }
    }

    void ChangePos() {
        int i = (int)(Random.value * 7);
        if (posArray[i].x == currentPos.x && posArray[i].y == currentPos.yChangePos ();
        gameObject.transform.position = posArray[i];
        currentPos = posArray [i];
    }
}
 
あれ、一応対策してるつもりだったんだけど。。。
if (posArray[i].x == currentPos.x && posArray[i].y == currentPos.yChangePos ();
ここで。
コイン取得したら同じ場所に出現しないようにしてる(つもり)
 
ただ、実際にプレイして検証してみると、確かにバグってる。

f:id:Twintaro:20140805224554p:plain

 

なんでだろう。。。

で、ログ仕込んで確認したところ、、、最初は原因がよくわかりませんでした。

とりあえず、以下のようにしたら直りました。

    void ChangePos() {
        int i = (int)(Random.value * 7);
        if (posArray[i].x == currentPos.x && posArray[i].y == currentPos.y) {
            ChangePos ();
        } else {
            gameObject.transform.position = posArray[i];
            currentPos = posArray [i];
        }
    }

 

で、再度考察したら原因がわかりました。コード的には前の状態でも問題ないと思っていたのですが、、、お恥ずかしい。

 

changePos(コインの位置を移動させる関数)はランダムで生成した変数から移動先の位置を算出するのですが、もし移動先の位置と現在のコインの位置が同じであれば、再度changePosが呼ばれるようになっています。これが原因でした。

 

どういうことかといいますと、、、順を追って説明します。

1 ユニティちゃんとコインが接触したタイミングでchangePosが呼ばれる(呼び出し①)

2 ランダム変数から移動先の位置を取得(posArray[A])

3 posArray[A]が現在のコインの位置と同じだったので再度changePosを呼び出す(呼び出し②)

4 再度ランダム変数から移動先(posArray[B])を取得し、現在のコインのポジションと別のポジションだったので、コインをその位置に移動(呼び出し②が完了)

5 呼び出し②が終わったタイミングで、呼び出し①の処理に戻ってしまう

6 ①がメソッド内部から②を呼び出している、かつ、呼び出し後の処理が分岐されていないためそのまま次の処理を継続してしまう

7 最終的に①の処理の最初で取得した移動先(posArray[A])に移動してしまう

8 posArray[A]は現在ユニティちゃんと同じ位置のため、一見すると同じ位置から移動していないように見えてしまう

 

と、いったことが原因でした。

再帰呼び出しとか、やるもんじゃないっすね。。。

ゆえに、if else で処理を分岐してあげることで、解決したというわけです。

 

いやあ、、、我ながらひどいコードでした。

ただ、リファクタけっこう好きなんで、けっこう楽しかったです。

 

やっぱりコード書いて、直して、書いて、直して、、、っていうのは楽しいですね。

過去の自分との対話みたいで。

 

このゲームではそんなにコード書いてないので、次作るやつは、もっとガッツリとロジック書けるようなゲームを考えたいですね。