使Update()内的项目独立于FPS

时间:2016-05-09 16:14:41

标签: c# unity3d

我正在创建一个反应时间游戏,我已经看到结果的多样性,基于我正在使用的设备和运行的FPS数量(例如PC 60 FPS 0.25平均反应,智能手机30 FPS 0.5平均反应)。

我正在二维环境中工作,如图所示:

enter image description here

玩家具有静态Y轴,而红色三角形(障碍物)沿Y轴负向移动。

我有两个班,一个是我的玩家:

public ObstacleSpawn oScript;

    public GameObject player;

    public Text warningText;

    public float playerDimensionY;
    float warningFade;
    float warningAlpha;

    public bool isRight = true;
    public bool inAir = false;
    public bool mouseClicked = false;
    public bool mouseClickedTimeCheck;
    public bool thereHaveBeenClicked = false;
    bool warningTextAlive;

    public int flyingSpeed;

    float timeStamp1;
    float timeStamp2;

    // Use this for initialization
    void Start () {
        Vector2 sprite_size = GetComponent<SpriteRenderer> ().sprite.rect.size;
        Vector2 spriteScale = transform.localScale;
        float sizeAndScaleY = sprite_size.y * spriteScale.y;
        float player_local_sprite_sizeY = (sizeAndScaleY / GetComponent<SpriteRenderer> ().sprite.pixelsPerUnit) * 0.5F;
        playerDimensionY = player_local_sprite_sizeY;
    }

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

        warningText.GetComponent<CanvasRenderer> ().SetAlpha (warningAlpha);
        mouseClickedTimeCheck = false;

        if (oScript.maxClicks != 10) {

            if (isRight == true && mouseClicked == true) {
                transform.position += Vector3.right * flyingSpeed * Time.deltaTime;
            } else if (isRight == false && mouseClicked) {
                transform.position += Vector3.left * flyingSpeed * Time.deltaTime;
            }

        if (warningTextAlive == true) {
                if (warningFade < 400F) {
                    warningAlpha = 1F;
                    warningFade++;
                } else if (warningFade < 500F) {
                    warningAlpha -= 0.01F;
                    warningFade++;
                } else if (warningFade == 500F) {
                    warningText.text = "";
                    warningAlpha = 1F;
                    warningTextAlive = false;
                    warningFade = 0F;
                }
            }

            if (Input.GetMouseButtonDown (0) && oScript.instantiatedObstacle == null) {
                warningText.text = "Slow down - do not click without an obstacle visible" + "\nObstacle spawn-time reset";
                warningTextAlive = true;
                oScript.CancelInvoke ();
                oScript.InvokeRepeating ("Spawn", Random.Range (oScript.randomSpawnMin, oScript.randomSpawnMax), Random.Range (oScript.randomSpawnMin, oScript.randomSpawnMax));
            } else if (Input.GetMouseButtonDown (0) && inAir == false && oScript.instantiatedObstacle != null && thereHaveBeenClicked == false) {
                mouseClicked = true;
                inAir = true;
                mouseClickedTimeCheck = true;
                oScript.canSpawn = true;
                thereHaveBeenClicked = true;

                if (isRight == true) {
                    isRight = false;
                } else if (isRight == false) {
                    isRight = true;
                } 
            } else if (Input.GetMouseButtonDown (0) && inAir == true && oScript.instantiatedObstacle != null) {
                warningText.text = "Slow down - do not click without an obstacle visible" + "\nObstacle spawn-time reset";
                warningTextAlive = true;
                oScript.CancelInvoke ();
                oScript.InvokeRepeating ("Spawn", Random.Range (oScript.randomSpawnMin, oScript.randomSpawnMax), Random.Range (oScript.randomSpawnMin, oScript.randomSpawnMax));
            }
        }
    }

    void OnCollisionEnter2D(Collision2D coll) {
        inAir = false;
        mouseClicked = false;
    }
}

和我的障碍之一:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class ObstacleSpawn : MonoBehaviour {

    //Reaction times: 1.0(4F), 0.9(3.6F), 0.8(3.2F), 0.7(2.8F), 0.6(2.4F), 0.5(2F), 0.4(1.6F), 0.35(1.4F), 0.3(1.2F), 0.25(1F); 

    public PlayerScript pScript;

    public GameObject player;
    public GameObject obstacle;
    public GameObject endGamePanel;
    public GameObject infoText;
    public Text Average;
    public Text BestReaction;

    public GameObject instantiatedObstacle;

    public float randomSpawnMin;
    public float randomSpawnMax;
    public float endingSpeed;
    public float speed;
    public float canvasMoveTowardsSpeed;
    public float spawnTime;
    public float maxReactionTime;
    public float reactionTime;

    float obstacleDimensionY;
    float spawnTimeDistance;
    float reactionClick;
    float amountOfTries;
    float panelAlpha = 0F;
    float gamePanelAlpha = 1F;
    private float[] reactionTimeArray = new float[10];

    public int maxClicks;

    public bool canSpawn = true;

    bool reactionCap;
    bool pointOneChange;

    int fade = 0;

    // Use this for initialization
    void Start () {
        spawnTimeDistance = 4F;
        maxReactionTime = 1F;

        InvokeRepeating ("Spawn", Random.Range (randomSpawnMin, randomSpawnMax), Random.Range (randomSpawnMin, randomSpawnMax));

        Vector2 sprite_size = obstacle.GetComponent<SpriteRenderer> ().sprite.rect.size;
        Vector2 spriteScale = obstacle.transform.localScale;
        float sizeAndScaleY = sprite_size.y * spriteScale.y;
        float obstacle_local_sprite_sizeY = (sizeAndScaleY / obstacle.GetComponent<SpriteRenderer> ().sprite.pixelsPerUnit) * 0.5F;
        obstacleDimensionY = obstacle_local_sprite_sizeY;
    }

    // Update is called once per frame
    void Update () { 
        endGamePanel.GetComponent<CanvasRenderer> ().SetAlpha (panelAlpha);
        Average.GetComponent<CanvasRenderer> ().SetAlpha (panelAlpha);
        BestReaction.GetComponent<CanvasRenderer> ().SetAlpha (panelAlpha);
        infoText.GetComponent<CanvasRenderer> ().SetAlpha (gamePanelAlpha);

        if (instantiatedObstacle != null) {
            if (instantiatedObstacle.transform.position.x > 1.78F) {
                instantiatedObstacle.transform.position += new Vector3 (-1, -1, 0) * speed * Time.deltaTime;
            } else if (instantiatedObstacle.transform.position.x < -1.78) {
                instantiatedObstacle.transform.position += new Vector3 (1, -1, 0) * speed * Time.deltaTime;
            } else {
                instantiatedObstacle.transform.position += new Vector3 (0, -1, 0) * speed * Time.deltaTime;
            }   

            if (instantiatedObstacle.GetComponent<Renderer> ().isVisible != true ) {
                Destroy (instantiatedObstacle);
                pScript.thereHaveBeenClicked = false;
            }
        }

        if (amountOfTries == 10) {
            float moveTowardsSpeed = endingSpeed * Time.deltaTime;
            player.transform.position = Vector2.MoveTowards (player.transform.position, new Vector2 (0, -2), moveTowardsSpeed);
            if (fade < 100) {
                panelAlpha += 0.01F;    
                gamePanelAlpha -= 0.1F;
                fade++;
            }

        }

        if (maxReactionTime >= 0.4F) {
            pointOneChange = true;
        } else if (maxReactionTime < 0.4F) {
            pointOneChange = false;
        }

        if (maxReactionTime == 1F) {
            reactionCap = true;
        } else {
            reactionCap = false;
        }

        if (pScript.mouseClickedTimeCheck == true && amountOfTries <= 10 && maxClicks != 10) {
            reactionClick = Time.unscaledTime;
            amountOfTries += 1;
            maxClicks += 1;

            reactionTime = reactionClick - spawnTime;

            if (reactionTimeArray [0] == 0) {
                reactionTimeArray [0] = reactionTime;
            } else if (reactionTimeArray [1] == 0) {
                reactionTimeArray [1] = reactionTime;
            } else if (reactionTimeArray [2] == 0) {
                reactionTimeArray [2] = reactionTime;
            } else if (reactionTimeArray [3] == 0) {
                reactionTimeArray [3] = reactionTime;
            } else if (reactionTimeArray [4] == 0) {
                reactionTimeArray [4] = reactionTime;
            } else if (reactionTimeArray [5] == 0) {
                reactionTimeArray [5] = reactionTime;
            } else if (reactionTimeArray [6] == 0) {
                reactionTimeArray [6] = reactionTime;
            } else if (reactionTimeArray [7] == 0) {
                reactionTimeArray [7] = reactionTime;
            } else if (reactionTimeArray [8] == 0) {
                reactionTimeArray [8] = reactionTime;
            } else if (reactionTimeArray [9] == 0) {
                reactionTimeArray [9] = reactionTime;
            }

            float averageReaction = (reactionTimeArray[0] + reactionTimeArray [1] + reactionTimeArray [2] + reactionTimeArray [3] + reactionTimeArray [4] + reactionTimeArray [5] + reactionTimeArray [6] + reactionTimeArray [7] + reactionTimeArray [8] + reactionTimeArray [9]) / 10;

            BestReaction.text = "Best reaction: " + Mathf.Min(reactionTimeArray[0], reactionTimeArray[1], reactionTimeArray[2], reactionTimeArray[3], reactionTimeArray[4], reactionTimeArray[5], reactionTimeArray[6], reactionTimeArray[7], reactionTimeArray[8], reactionTimeArray[9]);
            Average.text = "Average reaction: " + averageReaction;

            if (reactionTime <= maxReactionTime && pointOneChange == true) {
                maxReactionTime -= 0.1F;
                spawnTimeDistance -= 0.4F;
            } else if (reactionTime <= maxReactionTime && pointOneChange == false) {
                maxReactionTime -= 0.05F;
                spawnTimeDistance -= 0.2F;
            } else if (reactionTime > maxReactionTime && pointOneChange == true && reactionCap == false) {
                maxReactionTime += 0.1F;
                spawnTimeDistance += 0.4F;
            } else if (reactionTime > maxReactionTime && pointOneChange == false && reactionCap == false) {
                maxReactionTime += 0.05F;
                spawnTimeDistance += 0.2F;
            }
            Debug.Log (string.Format ("ReactionClick: " + reactionClick));
            Debug.Log (string.Format ("ReactionTime: " + reactionTime));
            Debug.Log (string.Format ("Max Reaction Time: " + maxReactionTime));
        }
    }

    public void Spawn() {
        if (pScript.isRight == true && pScript.inAir == false) {
            obstacle.transform.localScale = new Vector3 (-1, 1, 1);
            spawnTime = Time.unscaledTime;
            instantiatedObstacle = (GameObject)Instantiate (obstacle, player.transform.position + new Vector3(0.50F , (spawnTimeDistance + obstacleDimensionY + pScript.playerDimensionY), -1), Quaternion.identity);
            Debug.Log (string.Format ("Spawn time: " + spawnTime));

        } else if (pScript.isRight == false && pScript.inAir == false) {
            obstacle.transform.localScale = new Vector3 (1, 1, 1);
            spawnTime = Time.unscaledTime;
            instantiatedObstacle = (GameObject)Instantiate (obstacle, player.transform.position + new Vector3(-0.50F , (spawnTimeDistance + obstacleDimensionY + pScript.playerDimensionY), -1), Quaternion.identity);
            Debug.Log (string.Format ("Spawn time: " + spawnTime));
        }
    }
}

正如您在我的障碍课程中所看到的,我正在通过以下行获得用户的反应时间:

reactionTime = reactionClick - spawnTime;

spawnTime是障碍物出现时的Time.time 和 reactionClick是玩家点击时的Time.time。

但是,由于此行在我的Update()函数中被调用,因此它非常依赖于FPS,这导致我的问题先前说明了。

如何使结果独立于设备FPS,以便它们在不同设备上保持稳定?

我已经考虑并尝试过非标定时间和多线程,但没有运气。

2 个答案:

答案 0 :(得分:0)

使用FixedUpdate函数代替/除了Update函数之外,还应该解决这个问题。

  

如果启用了MonoBehaviour,则每个固定帧率帧都会调用此(FixedUpdate)函数。 http://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html

这意味着无论渲染帧率如何,您都可以更准确地计算时间。

可以在此处找到FixedUpdate的其他信息和说明: http://answers.unity3d.com/questions/10993/whats-the-difference-between-update-and-fixedupdat.html

答案 1 :(得分:0)

除了@Zze,我想与你分享Time.deltaTime。它说的是:

  

完成最后一帧所花费的时间(只读)。

     

使用此功能可以使您的游戏帧速率独立。

您当前场景的同类示例是:

  

如果你在每一帧中添加或减去一个值,你应该有机会   乘以Time.deltaTime。当你与Time.deltaTime相乘时   你基本上表达:我想把这个物体移动10米   而不是每帧10米。

     

从MonoBehaviour的FixedUpdate内部调用时,返回固定的   帧率增量时间。

所以如果你想做一些独立于框架的东西,你应该使用Time.deltaTime并将它与你的乘法一起使用。