我正在创建一个反应时间游戏,我已经看到结果的多样性,基于我正在使用的设备和运行的FPS数量(例如PC 60 FPS 0.25平均反应,智能手机30 FPS 0.5平均反应)。
我正在二维环境中工作,如图所示:
玩家具有静态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,以便它们在不同设备上保持稳定?
我已经考虑并尝试过非标定时间和多线程,但没有运气。
答案 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并将它与你的乘法一起使用。