Unity2D 禁用玩家移动 X 秒

Unity2D Disable player movement for X seconds

我试图在玩家与特定对象发生碰撞时将其移动禁用 1 秒。对象发生碰撞,它检测到一切正常,但目前整个游戏都冻结了,没有 return。

我已经使用计时器为 X 和 Y 运动实现了 0 值(如在其他示例中所见)。这会完全冻结游戏,我必须终止进程并重新打开 Unity。

public Boolean frozen = false;
    float shipDisabledTimer = 1f;
    // Start is called before the first frame update
    void Start()
    {
        SetUpMoveBoundaries();
        gameSession = FindObjectOfType<GameSession>();

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

        Move(frozen);
        Fire();

        if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("Game"))
        {
            if (Input.GetKey(KeyCode.Escape))

                SceneManager.LoadScene("Game Over");
        }
    }



    public void Move(Boolean Frozen)
    {

        UnityEngine.Debug.Log("Update1 - " + Frozen);



            var deltaX = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
            var deltaY = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;

            var newXPos = Mathf.Clamp(transform.position.x + deltaX, xMin, xMax);
            var newYPos = Mathf.Clamp(transform.position.y + deltaY, yMin, yMax);
            transform.position = new Vector2(newXPos, newYPos);

        if (frozen == true)
        {
            float timer = 0f;
            timer += Time.deltaTime;
            UnityEngine.Debug.Log(frozen);
            while (timer < shipDisabledTimer)
            {
                newXPos = 0;
                newYPos = 0;

            }
            disableship(frozen = false);

        }

    }


    public Boolean disableship(Boolean frozen)
    {
        return frozen;
    }
    private void OnTriggerEnter2D(Collider2D other)
    {
        UnityEngine.Debug.Log(other.gameObject.name);
        if (other.gameObject.name.Equals("Orb Shot(Clone)"))
        {
            UnityEngine.Debug.Log("Orb hit player");
            //StartCoroutine(countdownTimer());
            disableship(frozen = true);
        }
    }

单独的船应该冻结。没有其他游戏对象应该冻结。所有分数、计数器、敌人都应该继续前进。只有玩家 X,Y 被禁用 1 秒。

这个

while (timer < shipDisabledTimer)
{
    newXPos = 0;
    newYPos = 0;
}

完全阻塞游戏的主线程,因为 timershipDisabledTime 都不会在循环中更改,因此它永远不会结束。

这里有几种方法。

调用

Invoke 允许您在一定延迟后调用方法,这样您就可以轻松地执行类似

的操作
public void Freeze()
{
    frozen = true;
    Invoke("Unfreeze"; shipDisabledTime);
}

private void Unfreeze()
{
    frozen = false;
}

协程

A Coroutine is like a temporary Update method. Simplest way in your case is using WaitForSeconds 并做类似

的事情
public void Freeze()
{
    StartCoroutine (FreezeRoutine());
}

private IEnumerator FreezeRoutine()
{
    frozen = true;

    yield return new WaitForSeconds(shipDisabledTime);

    frozen = false;
}

简单的计时器

或者您可以使用一个简单的计时器,但在 Update(不是 while 循环)中,例如

private float timer = -1;

public void Freeze()
{
    frozen = true;
    timer = shipDisabledTime;
}

private void Update()
{
    if(timer > 0)
    {
        timer -= Time.deltaTime;
        if(timer <= 0)
        {
            timer = -1;
            frozen = false;
        }
    }

    ...
}

然后无论哪种方式,您都不会在此期间进行任何移动输入

public void Move()
{
    if(frozen) return;

    ...
}

除了 Invoke 解决方案,您还可以扩展它们并决定是否要,例如堆叠多个冻结,在已经冻结时忽略它们或简单地重新启动计时器。


一般注意事项:在 c# 中,只需使用 bool 它基本相同但更易于阅读和编写 ;)


还要注意这个调用

disableship(frozen = false);

...

public Boolean disableship(Boolean frozen)
{
    return frozen;
}

很奇怪...首先,这个方法除了 return 与您作为参数传入的相同值之外什么都不做。您 隐藏 frozen 字段具有相同的命名参数,所以这什么都不做!

第二个你的方法 returns a Boolean 但你没有将它分配给任何东西。

如果您想更改该值,只需使用 frozen = XY 进行设置即可,但不要进一步将其作为参数传递。


Aa 并避免在每一帧调用 Debug.Log .. 即使在您甚至看不到日志的构建中,它也会降低您的应用程序的速度!