使用Corutine检测何时按下或未按下按键?

时间:2018-03-23 11:49:38

标签: c# unity3d unityscript

我对C#很新,我试图为敌人AI编写脚本。我想要的是如果" S"关键是按下敌人消失(淡出然后淡化回使用协程)。如果在一段时间内未按任何键,游戏将重置。相反,敌人的Debug.Log重置在开始时出现(这是有意义的,因为它在我的启动函数中。但是,如果我把它置于更新它更新每一帧。我应该使用FixedUpdate吗?我需要一个明确的例子如何这应该去。

public GameObject gameOverPanel;
public float TimeLimit = 10f;
private bool pressS;

private void Update() {
    if (Input.GetKeyDown("S")) {
        pressS = true;
        //Kills Owl
    }
    //Test
    if (!Input.GetKeyDown("S")) { //If key is not pressed within certian time
        pressS = false;
        //Reset screen Appears
        StopCoroutine(Reset());
        StartCoroutine(Reset());
    }
}

private IEnumerator Reset() {
    Debug.Log("Reset Taking place")
    yield return new WaitForSeconds(TimeLimit);

    //GameOverScreen Appears
    gameOverPanel.SetActive(true);
}

2 个答案:

答案 0 :(得分:1)

您要求的是使用Coroutines的基于状态的引擎。对于这种特殊情况,有四种状态:

  1. Enemy Fades In。
  2. 敌人等待来自玩家的输入。
  3. Enemy Fades Out。
  4. 敌人胜利。游戏重启。
  5. 以下代码是您发布的代码的修订版。我重构了Start()Update() Monobehaviours,专注于启动状态引擎并分别监控玩家的输入。

    Start()只需要为状态引擎中的未来操作准备敌人,所以我使用该位置来执行EnemyFadeIn()协程。

    Update()之前不会重置输入标志,因此建议所有输入调用都在更新循环中发生。这也是从Start() Monobehaviour中删除输入处理的原因。您可以在Unity Article for Input中找到有关此内容的更多信息。但是,代码中显示的所有剩余函数都可以在协同程序中顺利运行。

    using System.Collections;
    using UnityEngine;
    
    public class NewBehaviourScript : MonoBehaviour {
    
        public float waitTime = 10.0f;
        public float fadeTime = 3.0f;
        public float betweenFadesTime = 2.0f;
    
        // Flag to determine whether or not the player may respond.
        public bool canRespond = false;
    
        // Flag to determine if the player has responded within the wait time.
        public bool hasResponded = false;
    
        public GameObject enemy;
    
        void Start()
        { StartCoroutine(EnemyFadeIn(fadeTime, betweenFadesTime, waitTime)); }
    
        void Update() {
            if ((Input.GetKeyDown(KeyCode.S)) && (canRespond))
            { hasResponded = true; }
        }
    
        IEnumerator EnemyFadeIn(float timeToFade, float timeBetweenFades, float timeToWait) {
            Debug.Log("An Enemy Is Fading In");
            // Simulating Fade In Time.
            yield return new WaitForSeconds(timeToFade);
            // Fade in
            // iTween.FadeTo(enemy, 1, 1);
            // Invoke("SetMaterialOpaque", 1f);
            Debug.Log("An Enemy Has Appeared");
    
            yield return ListenForInput(timeToFade, timeBetweenFades, timeToWait);
        }
    
        IEnumerator EnemyFadeOut(float timeToFade, float timeBetweenFades, float timeToWait) {
            Debug.Log("An Enemy Is Fading Away");
            // Simulating Fade Out Time.
            yield return new WaitForSeconds(timeToFade);
            // Fade out
            // SetMaterialTransparent();
            // iTween.FadeTo(enemy, 0, 1);
            Debug.Log("An Enemy Has Departed");
            // Simulating Time Between Fades.
            yield return new WaitForSeconds(timeBetweenFades);
    
            yield return EnemyFadeIn(timeToFade, timeBetweenFades, timeToWait);
        }
    
        // Responsible for reacting to the 'S' key input.
        IEnumerator ListenForInput(float timeToFade, float timeBetweenFades, float timeToWait) {
            canRespond = true;
            Debug.Log("Press the 'S' Key to Destroy the Enemy!");
            float startTime = Time.time;
    
            // Check every 0.25 seconds to see if the S key was pressed.
            while (Time.time < (startTime + timeToWait)) {
                if (hasResponded) {
                    Debug.Log("The 'S' Key was Pressed!");
                    hasResponded = false;
                    canRespond = false;
                    yield return EnemyFadeOut(timeToFade, timeBetweenFades, timeToWait);
                }
                yield return new WaitForSeconds(0.25f);
            }
    
            Debug.Log("The 'S' Key was not Pressed!");
            canRespond = false;
            yield return ResetGame();
        }
    
        IEnumerator ResetGame() {
            Debug.Log("Game is Performing a Reset");
            //Simulating Game Reset Time.
            yield return new WaitForSeconds(10);
            Debug.Log("Game has Restarted. End of Coroutine!");
        }
    }
    

    我创建了EnemyFadeOut()ListenForInput()方法以配合EnemyFadeIn()ResetGame()方法。这是你的四个州。行为流程如下:

    首先,Start() Monobehaviour启动EnemyFadeIn()协程。

    接下来,EnemyFadeIn()协程会在敌人完全进入游戏世界后将控制权传递给ListenForInput()

    接下来,如果在给定的waitTime中按下'S'键,ListenForInput()协程会将控制权传递给EnemyFadeOut(),如果没有'S'键,则ResetGame()及时按下。

    如果控制权传递给EnemyFadeOut(),敌人将逐步退出世界,然后控制权将转移到EnemyFadeIn()并且循环将继续直到玩家未能按下'S'键

    如果控制传递给ResetGame(),则玩家未能及时按下'S'键,游戏将执行所有必要的功能以重启。

    控制台Debug.Log()yield return new WaitForSeconds()用于模拟目的。由于iTween不是我的本机库,因此必须注释掉一些淡入/淡出代码。

答案 1 :(得分:0)

目前,您正在Start()函数中启动Couroutine EnemyFadeIn(),这意味着只要脚本附加的对象被实例化,就会调用它。你的ResetEnemy()方法也会被调用,除非你设法在对象被实例化的那一刻按下S键,这是不太可能的。所以EnemyFadeIn()方法只被调用一次。如果你想在一段时间内没有按任何键时调用ResetEnemy(),你需要在每次按下一个键时设置一个时间戳:

float lastTimePressedButton;

void Start() {
    lastTimePressedButton = Time.time;
}

void Update() {
    if(Input.GetKeyCode(KeyCode.S)) {
        lastTimePressedButton = Time.time;
    }
    if(Time.time >= lastTimePressedButton + 5f) {
         ResetEnemyOrWhatever();
         lastTimePressedButton = Time.time;
    }
}

FixedUpdate只应该用于处理Rigidbodys只是一个不同的循环然后更新。

另外,GetKeyDown,GetKeyUp和GetKeyUp被认为是不好的做法,你应该使用GetButtonDown,GetButtonUp和GetButton。

仅供参考,在Stackoverflow上询问时,您应该编写您实际调用的函数。 Itween不是.Net Framework或Unity的一部分,我怀疑很多人都知道这个库(我想它是一个库)是做什么的。