床ずれのバグについて

バグ内容

画面外のクリックや処理落ち(あってはならない)などで床がずれるバグがある。

5年前にも起こることがあるとは認知していたが原因を探すより実装の優先が先のため放置していました。

原因

原因は床を動かすスクリプトの中にあった。

↓床を作るスクリプト

public class WallCreater : MonoBehaviour {


    public List<GameObject> WallObjects;
    public float wallWidth;
    public int firstCreateNum;
    public static int WallNum;
    private int counter = 0;

	// Use this for initialization
	void Start () {
	

        //初回に一定数生成
        for(int i=0;i<=this.firstCreateNum; i++)
        {
            Instantiate(WallObjects[i% WallObjects.Count],new Vector3(0.0f,0.0f,-i*this.wallWidth), Quaternion.identity);
            WallNum = i;
        }

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

        //数が定数より減っていれば生成
        if (firstCreateNum > WallNum)
 
        {
            Instantiate(WallObjects[counter % WallObjects.Count], new Vector3(0.0f, 0.0f, -this.firstCreateNum * this.wallWidth), Quaternion.identity);
            WallNum++;
            counter++;
            counter %= WallObjects.Count;
        }
	}
}

↓床を動かす

public class WallMove : MonoBehaviour {

    public float  confSpeed;
    public static float Speed;
    public float confDeletePosZ;
    public static float DeletePosZ;

    // Use this for initialization
    void Start () { 

        //床を動かす速度を設定
        if(this.confSpeed >= 0.0f)
        {
            Speed = confSpeed;
        }

        if (this.confDeletePosZ >= 0.0f)
        {
            DeletePosZ = confDeletePosZ;
        }
    }
	
	// Update is called once per frame
	void Update () {

        //床を動かす
        transform.Translate(0.0f,0.0f,Speed*Time.deltaTime);

        //閾値を越えたらオブジェクトを削除
        if(transform.position.z > DeletePosZ)
        {
            Destroy(gameObject, 0f);
            WallCreater.WallNum--;
        }
	}
}

挙動としては

  • 床を一定数生成
  • インスペクタで設定されたSpeed値をUpdateで動かす
  • 一定の位置を越えたら削除
  • 床が一定数未満なら新しく生成

となっている。

全体で見たら床を動かすだけならこれで十分だが

Update内で床を動かすときこのようにしていた。

transform.Translate(0.0f,0.0f,Speed*Time.deltaTime);

特にこれを使用しているのが問題だった

Time.deltaTime

リファレンスは

https://docs.unity3d.com/ScriptReference/Time-deltaTime.html

Description

The interval in seconds from the last frame to the current one (Read Only).

When this is called from inside MonoBehaviour.FixedUpdate, it returns Time.fixedDeltaTime.

deltaTime inside MonoBehaviour.OnGUI is not reliable, because Unity might call it multiple times per frame.

これは前回のフレームから今回のフレームまでかかった時間のため、環境によって毎回違う。

通常は問題ないが

床を作るスクリプトのUpdateで床を生成している処理と合わせると。

この過程でアプリが止まるとずれてしまう

  1. 一定の位置を越えたら削除
  2. 床を作るスクリプトがUpdateで床を生成
  3. ここでアプリの処置が停止か遅延!!!
  4. 床を動かすスクリプトがUpdateで床を移動させる                     この時前回のフレームから今回のフレームまでかかった時間をSpeedで乗算されるので    非常に大きな値で移動する
  5. 「床を作るスクリプトがUpdateで床を生成」の床が初めて床を動かすスクリプトが     Updateで処理落ち前の値で移動する

つまり

生成されたものと

すでに生成されている床が

処理落ちした瞬間だけ移動量が大幅に違うことになる。

解決方法

そもそも論になるが

Time.deltaTimeは面倒な前回のフレームから今回のフレームまでかかった時間を計測してくれているので非常に便利なものではあるが、

ここに関してはTime.deltaTimeを使用しなくてもよい

その他問題

床がずれるバグのほかに

処理に関してあまり非効率なやり方をしているので見直す必要がある。

その件に関してはまた次回


コメントを残す

メールアドレスが公開されることはありません。

ABOUT US

vuniformity誰でもない人
トレンドの行く末を見守っている
仮名を名乗るエンジニア

ゲーム開発は仕事であり趣味である
プログラムだけでなく多種多様なスキルを数多く持つ

ゲーム開発は
ソーシャルゲームを開発運用の経験アリ
ゲーム以外にも経験アリ
Webサービス保守開発等に携わる

ゲームプレイの主な戦場は
FGO
FEH
MTGA
マビノギ
ここでは主にunityroomで公開しているゲーム作り直しの軌跡を綴っていきます